diff --git a/DEPS b/DEPS
index 5953735..7ba5d28 100644
--- a/DEPS
+++ b/DEPS
@@ -111,11 +111,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': '7d20bc42f45330104bfa603047e6d032130f9688',
+  'skia_revision': '1de48d8040aa263d4f79c023f9c31445310432a9',
   # 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': 'a4f6a37da361b69c87c9230152d8cfb8ce351428',
+  'v8_revision': 'd2036a9f91efb2fa671c4b9c328ccfe5f569de31',
   # 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.
@@ -123,7 +123,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '3ce69ba3eb600c6565bff26f6dd4ab13fdfffc04',
+  'angle_revision': '4a22f4b04619fd92138f4b37f861eebc2b0bfc6b',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling build tools
   # and whatever else without interference from each other.
@@ -135,7 +135,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': '6fe32f898af3eea875fd01a6d18f719d17dd72f3',
+  'pdfium_revision': 'b7c4a0243e82f6c4ff91cd90b5bae336100c3c70',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling openmax_dl
   # and whatever else without interference from each other.
@@ -171,7 +171,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': '687f318e303c48b791fa608da923c23b31cd6afe',
+  'catapult_revision': '00755b36f6d2dcf7228d6f6bb7f851f82ee5d21e',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -650,7 +650,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'f74d12074e1988ffc5095a6310a82cd0549256c7',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '9201a4e1a9369d1618bc8737a97d9f6ded6d6e3e',
       'condition': 'checkout_linux',
   },
 
@@ -675,7 +675,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '2b71832f6d8dc74119589992836cf95aeb8a9842',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'cb629a482b3d3c13e46a66031ba4c0cc3679d200',
 
   'src/third_party/devtools-node-modules':
     Var('chromium_git') + '/external/github.com/ChromeDevTools/devtools-node-modules' + '@' + Var('devtools_node_modules_revision'),
@@ -816,7 +816,7 @@
     Var('chromium_git') + '/chromium/deps/hunspell_dictionaries.git' + '@' + 'a9bac57ce6c9d390a52ebaad3259f5fdb871210e',
 
   'src/third_party/icu':
-    Var('chromium_git') + '/chromium/deps/icu.git' + '@' + 'b029971f1fc6b20d06887c47c7afebd5881f31ff',
+    Var('chromium_git') + '/chromium/deps/icu.git' + '@' + '42d5027992a0946942839b8821765e1512afbc21',
 
   'src/third_party/icu4j': {
       'packages': [
@@ -1004,7 +1004,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' +  '57c89d98ac4c8b87aecdfb8eaab25dcc356984c1',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' +  'a56061dd6c202a9497843d72604934135bff55c6',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + 'ac0d98b5cee6c024b0cffeb4f8f45b6fc5ccdb78',
@@ -1066,7 +1066,7 @@
       'packages': [
           {
               'package': 'chromium/third_party/r8',
-              'version': 'version:1.2.48',
+              'version': 'version:1.4.4-cr0',
           },
       ],
       'condition': 'checkout_android',
@@ -1156,7 +1156,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '0d55c887e92b645f6effe753528323ab2ffd94c2',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + 'fdee701fa8e439384dc930ebf70f884a7b26c385',
+    Var('webrtc_git') + '/src.git' + '@' + '72864963fe626e0971d7725b878a49d3784b6f87',
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
@@ -1187,7 +1187,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@1ef5883ceab723fc4cbf923c04c4223f5bb72d96',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@0a47db54fa15928f891e86d0c2637b222bd391a6',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/android_webview/aapt2.config b/android_webview/aapt2.config
new file mode 100644
index 0000000..6e6b76b
--- /dev/null
+++ b/android_webview/aapt2.config
@@ -0,0 +1 @@
+string/license_activity_title#no_obfuscate
diff --git a/android_webview/apk/java/src/com/android/webview/chromium/LicenseActivity.java b/android_webview/apk/java/src/com/android/webview/chromium/LicenseActivity.java
index 7427d0d..f7a4678 100644
--- a/android_webview/apk/java/src/com/android/webview/chromium/LicenseActivity.java
+++ b/android_webview/apk/java/src/com/android/webview/chromium/LicenseActivity.java
@@ -29,6 +29,9 @@
                 String.format("content://%s.%s", packageName, LICENSES_URI_SUFFIX);
         intent.setDataAndType(Uri.parse(licenseUri), LICENSES_CONTENT_TYPE);
         intent.addCategory(Intent.CATEGORY_DEFAULT);
+        // Resources are accessed via getIdentifier because resource ids in the standalone system
+        // webview apk have incorrect package_ids. Accessing resources via getIdentifier needs to be
+        // whitelisted in //android_webview/aapt2.config. see https://crbug.com/894208
         final int titleId =
                 getResources().getIdentifier("license_activity_title", "string", packageName);
         if (titleId != 0) {
diff --git a/android_webview/browser/browser_view_renderer.cc b/android_webview/browser/browser_view_renderer.cc
index 06db5f0..055c042d 100644
--- a/android_webview/browser/browser_view_renderer.cc
+++ b/android_webview/browser/browser_view_renderer.cc
@@ -15,7 +15,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "base/supports_user_data.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "components/viz/common/quads/compositor_frame.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
diff --git a/android_webview/browser/render_thread_manager.cc b/android_webview/browser/render_thread_manager.cc
index 65e54f81..7233bfe5 100644
--- a/android_webview/browser/render_thread_manager.cc
+++ b/android_webview/browser/render_thread_manager.cc
@@ -19,7 +19,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/time/time.h"
 #include "base/trace_event/trace_event.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "components/viz/common/quads/compositor_frame.h"
 
 namespace android_webview {
diff --git a/ash/accelerators/accelerator_controller.cc b/ash/accelerators/accelerator_controller.cc
index fd4b0e6..7f19638 100644
--- a/ash/accelerators/accelerator_controller.cc
+++ b/ash/accelerators/accelerator_controller.cc
@@ -51,7 +51,6 @@
 #include "ash/system/status_area_widget.h"
 #include "ash/system/toast/toast_data.h"
 #include "ash/system/toast/toast_manager.h"
-#include "ash/system/tray/system_tray.h"
 #include "ash/system/tray/system_tray_notifier.h"
 #include "ash/system/unified/unified_system_tray.h"
 #include "ash/touch/touch_observer_hud.h"
@@ -426,61 +425,27 @@
   Shell::Get()->screenshot_controller()->TakeScreenshotForAllRootWindows();
 }
 
-bool CanHandleToggleMessageCenterBubble() {
-  if (features::IsSystemTrayUnifiedEnabled())
-    return true;
+void HandleToggleSystemTrayBubbleInternal() {
   aura::Window* target_root = Shell::GetRootWindowForNewWindows();
-  StatusAreaWidget* status_area_widget =
-      Shelf::ForWindow(target_root)->shelf_widget()->status_area_widget();
-  return status_area_widget &&
-         status_area_widget->notification_tray()->visible();
+  UnifiedSystemTray* tray = RootWindowController::ForWindow(target_root)
+                                ->GetStatusAreaWidget()
+                                ->unified_system_tray();
+  if (tray->IsBubbleShown()) {
+    tray->CloseBubble();
+  } else {
+    tray->ShowBubble(false /* show_by_click */);
+    tray->ActivateBubble();
+  }
 }
 
 void HandleToggleSystemTrayBubble() {
   base::RecordAction(UserMetricsAction("Accel_Toggle_System_Tray_Bubble"));
-  aura::Window* target_root = Shell::GetRootWindowForNewWindows();
-  if (features::IsSystemTrayUnifiedEnabled()) {
-    UnifiedSystemTray* tray = RootWindowController::ForWindow(target_root)
-                                  ->GetStatusAreaWidget()
-                                  ->unified_system_tray();
-    if (tray->IsBubbleShown()) {
-      tray->CloseBubble();
-    } else {
-      tray->ShowBubble(false /* show_by_click */);
-      tray->ActivateBubble();
-    }
-  } else {
-    SystemTray* tray =
-        RootWindowController::ForWindow(target_root)->GetSystemTray();
-    if (tray->HasSystemBubble()) {
-      tray->CloseBubble();
-    } else {
-      tray->ShowDefaultView(BUBBLE_CREATE_NEW, false /* show_by_click */);
-      tray->ActivateBubble();
-    }
-  }
+  HandleToggleSystemTrayBubbleInternal();
 }
 
 void HandleToggleMessageCenterBubble() {
   base::RecordAction(UserMetricsAction("Accel_Toggle_Message_Center_Bubble"));
-  if (features::IsSystemTrayUnifiedEnabled()) {
-    HandleToggleSystemTrayBubble();
-    return;
-  }
-  aura::Window* target_root = Shell::GetRootWindowForNewWindows();
-  StatusAreaWidget* status_area_widget =
-      Shelf::ForWindow(target_root)->shelf_widget()->status_area_widget();
-  if (!status_area_widget)
-    return;
-  NotificationTray* notification_tray = status_area_widget->notification_tray();
-  if (!notification_tray->visible())
-    return;
-  if (notification_tray->IsMessageCenterVisible()) {
-    notification_tray->CloseBubble();
-  } else {
-    notification_tray->ShowBubble(false /* show_by_click */);
-    notification_tray->ActivateBubble();
-  }
+  HandleToggleSystemTrayBubbleInternal();
 }
 
 void HandleShowTaskManager() {
@@ -1350,7 +1315,7 @@
     case TOGGLE_FULLSCREEN_MAGNIFIER:
       return true;
     case TOGGLE_MESSAGE_CENTER_BUBBLE:
-      return CanHandleToggleMessageCenterBubble();
+      return true;
     case TOGGLE_MIRROR_MODE:
       return true;
     case TOUCH_HUD_CLEAR:
diff --git a/ash/app_list/views/app_list_folder_view.cc b/ash/app_list/views/app_list_folder_view.cc
index ff85713..0fcd0db 100644
--- a/ash/app_list/views/app_list_folder_view.cc
+++ b/ash/app_list/views/app_list_folder_view.cc
@@ -449,8 +449,7 @@
   AddChildView(background_view_);
   view_model_->Add(background_view_, kIndexBackground);
 
-  contents_container_->SetPaintToLayer();
-  contents_container_->layer()->SetFillsBoundsOpaquely(false);
+  contents_container_->SetPaintToLayer(ui::LAYER_NOT_DRAWN);
   AddChildView(contents_container_);
   view_model_->Add(contents_container_, kIndexContentsContainer);
 
diff --git a/ash/app_list/views/app_list_view.cc b/ash/app_list/views/app_list_view.cc
index 427d925..824adc9 100644
--- a/ash/app_list/views/app_list_view.cc
+++ b/ash/app_list/views/app_list_view.cc
@@ -227,22 +227,28 @@
 // The view for the app list background shield which changes color and radius.
 class AppListBackgroundShieldView : public views::View {
  public:
-  AppListBackgroundShieldView()
+  explicit AppListBackgroundShieldView(ui::LayerType layer_type)
       : color_(AppListView::kDefaultBackgroundColor), corner_radius_(0) {
-    SetPaintToLayer();
+    SetPaintToLayer(layer_type);
     layer()->SetFillsBoundsOpaquely(false);
+    if (layer()->type() == ui::LAYER_SOLID_COLOR)
+      layer()->SetColor(color_);
   }
 
   ~AppListBackgroundShieldView() override = default;
 
   void UpdateColor(SkColor color) {
     color_ = color;
-    SchedulePaint();
+    if (layer()->type() == ui::LAYER_SOLID_COLOR)
+      layer()->SetColor(color);
+    else
+      SchedulePaint();
   }
 
   void UpdateCornerRadius(int corner_radius) {
     corner_radius_ = corner_radius;
-    SchedulePaint();
+    if (!layer())
+      SchedulePaint();
   }
 
   // Overridden from views::View:
@@ -496,11 +502,14 @@
 void AppListView::InitContents(int initial_apps_page) {
   // The shield view that colors/blurs the background of the app list and
   // makes it transparent.
-  app_list_background_shield_ = new AppListBackgroundShieldView();
+  bool use_background_blur =
+      is_background_blur_enabled_ && !IsHomeLauncherEnabledInTabletMode();
+  app_list_background_shield_ = new AppListBackgroundShieldView(
+      use_background_blur ? ui::LAYER_SOLID_COLOR : ui::LAYER_TEXTURED);
   app_list_background_shield_->layer()->SetOpacity(
       is_background_blur_enabled_ ? kAppListOpacityWithBlur : kAppListOpacity);
   SetBackgroundShieldColor();
-  if (is_background_blur_enabled_ && !IsHomeLauncherEnabledInTabletMode()) {
+  if (use_background_blur) {
     app_list_background_shield_mask_ = views::Painter::CreatePaintedLayer(
         views::Painter::CreateSolidRoundRectPainter(SK_ColorBLACK,
                                                     kAppListBackgroundRadius));
@@ -1339,7 +1348,6 @@
   gfx::NativeView native_view = fullscreen_widget_->GetNativeView();
   ::wm::ConvertRectFromScreen(native_view->parent(), &new_widget_bounds);
   native_view->SetBounds(new_widget_bounds);
-
   UpdateChildViewsYPositionAndOpacity();
 }
 
diff --git a/ash/display/window_tree_host_manager.cc b/ash/display/window_tree_host_manager.cc
index 7d28fa39d..523aa58 100644
--- a/ash/display/window_tree_host_manager.cc
+++ b/ash/display/window_tree_host_manager.cc
@@ -18,12 +18,10 @@
 #include "ash/host/root_window_transformer.h"
 #include "ash/magnifier/magnification_controller.h"
 #include "ash/magnifier/partial_magnification_controller.h"
-#include "ash/public/cpp/ash_features.h"
 #include "ash/root_window_controller.h"
 #include "ash/root_window_settings.h"
 #include "ash/shell.h"
 #include "ash/system/status_area_widget.h"
-#include "ash/system/tray/system_tray.h"
 #include "ash/system/unified/unified_system_tray.h"
 #include "ash/wm/window_util.h"
 #include "ash/ws/window_service_owner.h"
@@ -532,19 +530,11 @@
     RootWindowController* new_root_window_controller =
         ash::Shell::Get()->GetPrimaryRootWindowController();
     TrayBackgroundView* old_tray =
-        features::IsSystemTrayUnifiedEnabled()
-            ? static_cast<TrayBackgroundView*>(
-                  old_root_window_controller->GetStatusAreaWidget()
-                      ->unified_system_tray())
-            : static_cast<TrayBackgroundView*>(
-                  old_root_window_controller->GetSystemTray());
+        old_root_window_controller->GetStatusAreaWidget()
+            ->unified_system_tray();
     TrayBackgroundView* new_tray =
-        features::IsSystemTrayUnifiedEnabled()
-            ? static_cast<TrayBackgroundView*>(
-                  new_root_window_controller->GetStatusAreaWidget()
-                      ->unified_system_tray())
-            : static_cast<TrayBackgroundView*>(
-                  new_root_window_controller->GetSystemTray());
+        new_root_window_controller->GetStatusAreaWidget()
+            ->unified_system_tray();
     if (old_tray->GetWidget()->IsVisible()) {
       new_tray->SetVisible(true);
       new_tray->GetWidget()->Show();
diff --git a/ash/extended_desktop_unittest.cc b/ash/extended_desktop_unittest.cc
index 9bf942f..a4d9463 100644
--- a/ash/extended_desktop_unittest.cc
+++ b/ash/extended_desktop_unittest.cc
@@ -2,7 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/public/cpp/ash_features.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/root_window_controller.h"
 #include "ash/shell.h"
@@ -164,15 +163,11 @@
 
  protected:
   bool IsBubbleShown() {
-    return features::IsSystemTrayUnifiedEnabled()
-               ? GetPrimaryUnifiedSystemTray()->IsBubbleShown()
-               : GetPrimarySystemTray()->HasSystemBubble();
+    return GetPrimaryUnifiedSystemTray()->IsBubbleShown();
   }
 
   gfx::Rect GetSystemTrayBoundsInScreen() {
-    return features::IsSystemTrayUnifiedEnabled()
-               ? GetPrimaryUnifiedSystemTray()->GetBoundsInScreen()
-               : GetPrimarySystemTray()->GetBoundsInScreen();
+    return GetPrimaryUnifiedSystemTray()->GetBoundsInScreen();
   }
 
  private:
diff --git a/ash/first_run/first_run_helper.cc b/ash/first_run/first_run_helper.cc
index 7d4c5ac8..e188b8cf 100644
--- a/ash/first_run/first_run_helper.cc
+++ b/ash/first_run/first_run_helper.cc
@@ -9,7 +9,6 @@
 
 #include "ash/app_list/views/app_list_view.h"
 #include "ash/first_run/desktop_cleaner.h"
-#include "ash/public/cpp/ash_features.h"
 #include "ash/root_window_controller.h"
 #include "ash/session/session_controller.h"
 #include "ash/shelf/app_list_button.h"
@@ -17,8 +16,6 @@
 #include "ash/shelf/shelf_widget.h"
 #include "ash/shell.h"
 #include "ash/system/status_area_widget.h"
-#include "ash/system/tray/system_tray.h"
-#include "ash/system/tray/system_tray_bubble.h"
 #include "ash/system/unified/unified_system_tray.h"
 #include "base/logging.h"
 #include "ui/gfx/geometry/rect.h"
@@ -57,46 +54,24 @@
 }
 
 void FirstRunHelper::OpenTrayBubble(OpenTrayBubbleCallback cb) {
-  if (features::IsSystemTrayUnifiedEnabled()) {
-    UnifiedSystemTray* tray = Shell::Get()
-                                  ->GetPrimaryRootWindowController()
-                                  ->GetStatusAreaWidget()
-                                  ->unified_system_tray();
-    tray->ShowBubble(false /* show_by_click */);
-    std::move(cb).Run(tray->GetBubbleBoundsInScreen());
-  } else {
-    SystemTray* tray = Shell::Get()->GetPrimarySystemTray();
-    tray->ShowPersistentDefaultView();
-    views::View* bubble = tray->GetSystemBubble()->bubble_view();
-    std::move(cb).Run(bubble->GetBoundsInScreen());
-  }
+  UnifiedSystemTray* tray = Shell::Get()
+                                ->GetPrimaryRootWindowController()
+                                ->GetStatusAreaWidget()
+                                ->unified_system_tray();
+  tray->ShowBubble(false /* show_by_click */);
+  std::move(cb).Run(tray->GetBubbleBoundsInScreen());
 }
 
 void FirstRunHelper::CloseTrayBubble() {
-  if (features::IsSystemTrayUnifiedEnabled()) {
-    Shell::Get()
-        ->GetPrimaryRootWindowController()
-        ->GetStatusAreaWidget()
-        ->unified_system_tray()
-        ->CloseBubble();
-  } else {
-    Shell::Get()->GetPrimarySystemTray()->CloseBubble();
-  }
+  Shell::Get()
+      ->GetPrimaryRootWindowController()
+      ->GetStatusAreaWidget()
+      ->unified_system_tray()
+      ->CloseBubble();
 }
 
 void FirstRunHelper::GetHelpButtonBounds(GetHelpButtonBoundsCallback cb) {
-  if (features::IsSystemTrayUnifiedEnabled()) {
-    std::move(cb).Run(gfx::Rect());
-    return;
-  }
-  SystemTray* tray = Shell::Get()->GetPrimarySystemTray();
-  views::View* help_button = tray->GetHelpButtonView();
-  // |help_button| could be null if the tray isn't open.
-  if (!help_button) {
-    std::move(cb).Run(gfx::Rect());
-    return;
-  }
-  std::move(cb).Run(help_button->GetBoundsInScreen());
+  std::move(cb).Run(gfx::Rect());
 }
 
 void FirstRunHelper::OnLockStateChanged(bool locked) {
diff --git a/ash/login/login_screen_controller_unittest.cc b/ash/login/login_screen_controller_unittest.cc
index 3b186d7..ec4a93a 100644
--- a/ash/login/login_screen_controller_unittest.cc
+++ b/ash/login/login_screen_controller_unittest.cc
@@ -6,7 +6,6 @@
 
 #include "ash/login/mock_login_screen_client.h"
 #include "ash/login/ui/lock_screen.h"
-#include "ash/public/cpp/ash_features.h"
 #include "ash/public/cpp/ash_pref_names.h"
 #include "ash/root_window_controller.h"
 #include "ash/session/session_controller.h"
@@ -38,11 +37,7 @@
   aura::Window::Windows root_windows = Shell::GetAllRootWindows();
   RootWindowController* controller =
       RootWindowController::ForWindow(root_windows[index]);
-  return features::IsSystemTrayUnifiedEnabled()
-             ? controller->GetStatusAreaWidget()
-                   ->unified_system_tray()
-                   ->visible()
-             : controller->GetSystemTray()->visible();
+  return controller->GetStatusAreaWidget()->unified_system_tray()->visible();
 }
 
 TEST_F(LoginScreenControllerTest, RequestAuthentication) {
diff --git a/ash/magnifier/docked_magnifier_controller.cc b/ash/magnifier/docked_magnifier_controller.cc
index 5bfe355..56b10bd3 100644
--- a/ash/magnifier/docked_magnifier_controller.cc
+++ b/ash/magnifier/docked_magnifier_controller.cc
@@ -29,6 +29,7 @@
 #include "ui/base/ime/text_input_client.h"
 #include "ui/compositor/layer.h"
 #include "ui/compositor/reflector.h"
+#include "ui/compositor/scoped_layer_animation_settings.h"
 #include "ui/display/screen.h"
 #include "ui/views/widget/widget.h"
 #include "ui/wm/core/coordinate_conversion.h"
diff --git a/ash/mojo_test_interface_factory.cc b/ash/mojo_test_interface_factory.cc
index 9646f3b0..ac73874 100644
--- a/ash/mojo_test_interface_factory.cc
+++ b/ash/mojo_test_interface_factory.cc
@@ -7,7 +7,6 @@
 #include <utility>
 
 #include "ash/metrics/time_to_first_present_recorder_test_api.h"
-#include "ash/public/cpp/ash_features.h"
 #include "ash/public/interfaces/shelf_test_api.mojom.h"
 #include "ash/public/interfaces/shell_test_api.mojom.h"
 #include "ash/public/interfaces/status_area_widget_test_api.mojom.h"
@@ -16,7 +15,6 @@
 #include "ash/shelf/shelf_test_api.h"
 #include "ash/shell_test_api.h"
 #include "ash/system/status_area_widget_test_api.h"
-#include "ash/system/tray/system_tray_test_api.h"
 #include "ash/system/unified/unified_system_tray_test_api.h"
 #include "base/bind.h"
 #include "base/single_thread_task_runner.h"
@@ -43,10 +41,7 @@
 
 void BindSystemTrayTestApiOnMainThread(
     mojom::SystemTrayTestApiRequest request) {
-  if (features::IsSystemTrayUnifiedEnabled())
-    UnifiedSystemTrayTestApi::BindRequest(std::move(request));
-  else
-    SystemTrayTestApi::BindRequest(std::move(request));
+  UnifiedSystemTrayTestApi::BindRequest(std::move(request));
 }
 
 void BindTimeToFirstPresentRecorderTestApiOnMainThread(
diff --git a/ash/public/cpp/app_menu_constants.h b/ash/public/cpp/app_menu_constants.h
index f52ea9b..b1b429e 100644
--- a/ash/public/cpp/app_menu_constants.h
+++ b/ash/public/cpp/app_menu_constants.h
@@ -30,6 +30,10 @@
   // Used by AppMenuModelAdapter.
   NOTIFICATION_CONTAINER = 9,
 
+  // Used by CrostiniShelfContextMenu.
+  CROSTINI_USE_LOW_DENSITY = 10,
+  CROSTINI_USE_HIGH_DENSITY = 11,
+
   // Used by AppContextMenu.
   LAUNCH_NEW = 100,
   TOGGLE_PIN = 101,
diff --git a/ash/public/cpp/ash_features.cc b/ash/public/cpp/ash_features.cc
index 32efa1d1..bd1fcee 100644
--- a/ash/public/cpp/ash_features.cc
+++ b/ash/public/cpp/ash_features.cc
@@ -40,6 +40,9 @@
 
 const base::Feature kNightLight{"NightLight", base::FEATURE_ENABLED_BY_DEFAULT};
 
+const base::Feature kNotificationExpansionAnimation{
+    "NotificationExpansionAnimation", base::FEATURE_DISABLED_BY_DEFAULT};
+
 const base::Feature kNotificationScrollBar{"NotificationScrollBar",
                                            base::FEATURE_DISABLED_BY_DEFAULT};
 
@@ -82,6 +85,10 @@
   return base::FeatureList::IsEnabled(kNightLight);
 }
 
+bool IsNotificationExpansionAnimationEnabled() {
+  return base::FeatureList::IsEnabled(kNotificationExpansionAnimation);
+}
+
 bool IsNotificationScrollBarEnabled() {
   return base::FeatureList::IsEnabled(kNotificationScrollBar);
 }
diff --git a/ash/public/cpp/ash_features.h b/ash/public/cpp/ash_features.h
index 0053904..3966fb2 100644
--- a/ash/public/cpp/ash_features.h
+++ b/ash/public/cpp/ash_features.h
@@ -57,6 +57,9 @@
 // Enables the Night Light feature.
 ASH_PUBLIC_EXPORT extern const base::Feature kNightLight;
 
+// Enabled notification expansion animation.
+ASH_PUBLIC_EXPORT extern const base::Feature kNotificationExpansionAnimation;
+
 // Enables notification scroll bar in UnifiedSystemTray.
 ASH_PUBLIC_EXPORT extern const base::Feature kNotificationScrollBar;
 
@@ -89,6 +92,8 @@
 
 ASH_PUBLIC_EXPORT bool IsNightLightEnabled();
 
+ASH_PUBLIC_EXPORT bool IsNotificationExpansionAnimationEnabled();
+
 ASH_PUBLIC_EXPORT bool IsNotificationScrollBarEnabled();
 
 ASH_PUBLIC_EXPORT bool IsSystemTrayUnifiedEnabled();
diff --git a/ash/public/cpp/network_icon_image_source.cc b/ash/public/cpp/network_icon_image_source.cc
index a923d42..4384853 100644
--- a/ash/public/cpp/network_icon_image_source.cc
+++ b/ash/public/cpp/network_icon_image_source.cc
@@ -5,7 +5,6 @@
 #include "ash/public/cpp/network_icon_image_source.h"
 
 #include "ash/public/cpp/ash_constants.h"
-#include "ash/public/cpp/ash_features.h"
 #include "third_party/skia/include/core/SkPath.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/geometry/insets.h"
@@ -70,12 +69,8 @@
   if (badges_.center.icon)
     paint_badge(badges_.center, icon_x, icon_y, icon_.width());
 
-  // The other badges are flush against the edges of the canvas, except at the
-  // top, where the badge is only 1dp higher than the base image.
-  const int top_badge_y =
-      features::IsSystemTrayUnifiedEnabled() ? icon_y : icon_y - 1;
   if (badges_.top_left.icon)
-    paint_badge(badges_.top_left, 0, top_badge_y);
+    paint_badge(badges_.top_left, 0, icon_y);
   if (badges_.bottom_left.icon) {
     paint_badge(
         badges_.bottom_left, 0,
diff --git a/ash/resources/vector_icons/BUILD.gn b/ash/resources/vector_icons/BUILD.gn
index 82fed09..6a57c93e 100644
--- a/ash/resources/vector_icons/BUILD.gn
+++ b/ash/resources/vector_icons/BUILD.gn
@@ -176,10 +176,6 @@
     "system_power_button_menu_power_off.icon",
     "system_power_button_menu_sign_out.icon",
     "system_tray_accessibility.icon",
-    "system_tray_battery_alert.icon",
-    "system_tray_battery_bolt.icon",
-    "system_tray_battery_unreliable.icon",
-    "system_tray_battery_x.icon",
     "system_tray_caps_lock.icon",
     "system_tray_cast.icon",
     "system_tray_do_not_disturb.icon",
diff --git a/ash/resources/vector_icons/system_tray_battery_alert.icon b/ash/resources/vector_icons/system_tray_battery_alert.icon
deleted file mode 100644
index d343134..0000000
--- a/ash/resources/vector_icons/system_tray_battery_alert.icon
+++ /dev/null
@@ -1,31 +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.
-
-CANVAS_DIMENSIONS, 32,
-MOVE_TO, 15, 11,
-R_H_LINE_TO, 2,
-R_V_LINE_TO, 8,
-R_H_LINE_TO, -2,
-R_V_LINE_TO, -8,
-CLOSE,
-R_MOVE_TO, 0, 10,
-R_H_LINE_TO, 2,
-R_V_LINE_TO, 2,
-R_H_LINE_TO, -2,
-R_V_LINE_TO, -2,
-CLOSE
-
-CANVAS_DIMENSIONS, 16,
-MOVE_TO, 7, 5,
-R_H_LINE_TO, 2,
-R_V_LINE_TO, 4,
-H_LINE_TO, 7,
-V_LINE_TO, 5,
-CLOSE,
-R_MOVE_TO, 0, 5,
-R_H_LINE_TO, 2,
-R_V_LINE_TO, 2,
-H_LINE_TO, 7,
-R_V_LINE_TO, -2,
-CLOSE
diff --git a/ash/resources/vector_icons/system_tray_battery_bolt.icon b/ash/resources/vector_icons/system_tray_battery_bolt.icon
deleted file mode 100644
index 3eeced88b..0000000
--- a/ash/resources/vector_icons/system_tray_battery_bolt.icon
+++ /dev/null
@@ -1,21 +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.
-
-CANVAS_DIMENSIONS, 32,
-MOVE_TO, 15.03f, 17,
-H_LINE_TO, 12,
-R_LINE_TO, 5.05f, -9,
-R_V_LINE_TO, 7,
-H_LINE_TO, 20,
-R_LINE_TO, -4.97f, 9,
-CLOSE
-
-CANVAS_DIMENSIONS, 16,
-MOVE_TO, 7.52f, 8.5f,
-H_LINE_TO, 6,
-LINE_TO, 8.53f, 4,
-R_V_LINE_TO, 3.5f,
-H_LINE_TO, 10,
-LINE_TO, 7.52f, 12,
-CLOSE
diff --git a/ash/resources/vector_icons/system_tray_battery_unreliable.icon b/ash/resources/vector_icons/system_tray_battery_unreliable.icon
deleted file mode 100644
index d11e8eb..0000000
--- a/ash/resources/vector_icons/system_tray_battery_unreliable.icon
+++ /dev/null
@@ -1,27 +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.
-
-CANVAS_DIMENSIONS, 32,
-MOVE_TO, 13.51f, 17.98f,
-R_CUBIC_TO, -1.98f, 0.02f, -2.5f, 1, -2.5f, 1,
-R_V_LINE_TO, -1.97f,
-CUBIC_TO, 11.01f, 17.01f, 11.55f, 16, 13.52f, 16,
-R_CUBIC_TO, 1.97f, 0, 3, 1.95f, 5.05f, 1.95f,
-CUBIC_TO, 20.62f, 17.95f, 21, 17, 21, 17,
-R_V_LINE_TO, 1.98f,
-R_CUBIC_TO, 0, 0, -0.38f, 1.05f, -2.44f, 1.05f,
-R_CUBIC_TO, -2.06f, 0, -3.07f, -2.08f, -5.06f, -2.05f,
-CLOSE
-
-CANVAS_DIMENSIONS, 16,
-MOVE_TO, 7.25f, 9.19f,
-R_CUBIC_TO, -0.99f, 0.01f, -1.25f, 0.6f, -1.25f, 0.6f,
-V_LINE_TO, 8.6f,
-CUBIC_TO, 6, 8.6f, 6.27f, 8, 7.26f, 8,
-R_CUBIC_TO, 0.99f, 0, 1.5f, 1.17f, 2.53f, 1.17f,
-R_CUBIC_TO, 1.03f, 0, 1.21f, -0.57f, 1.21f, -0.57f,
-R_V_LINE_TO, 1.19f,
-R_CUBIC_TO, 0, 0, -0.19f, 0.63f, -1.22f, 0.63f,
-R_CUBIC_TO, -1.03f, 0, -1.53f, -1.25f, -2.53f, -1.23f,
-CLOSE
diff --git a/ash/resources/vector_icons/system_tray_battery_x.icon b/ash/resources/vector_icons/system_tray_battery_x.icon
deleted file mode 100644
index 3571d142..0000000
--- a/ash/resources/vector_icons/system_tray_battery_x.icon
+++ /dev/null
@@ -1,35 +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.
-
-CANVAS_DIMENSIONS, 32,
-MOVE_TO, 17.33f, 18,
-LINE_TO, 20, 15.33f,
-LINE_TO, 18.67f, 14,
-LINE_TO, 16, 16.67f,
-LINE_TO, 13.33f, 14,
-LINE_TO, 12, 15.33f,
-LINE_TO, 14.67f, 18,
-LINE_TO, 12, 20.67f,
-LINE_TO, 13.33f, 22,
-LINE_TO, 16, 19.33f,
-LINE_TO, 18.67f, 22,
-LINE_TO, 20, 20.67f,
-LINE_TO, 17.33f, 18,
-CLOSE
-
-CANVAS_DIMENSIONS, 16,
-MOVE_TO, 8.67f, 9,
-LINE_TO, 10, 7.67f,
-LINE_TO, 9.33f, 7,
-LINE_TO, 8, 8.33f,
-LINE_TO, 6.67f, 7,
-LINE_TO, 6, 7.67f,
-LINE_TO, 7.33f, 9,
-LINE_TO, 6, 10.33f,
-R_LINE_TO, 0.67f, 0.67f,
-LINE_TO, 8, 9.67f,
-LINE_TO, 9.33f, 11,
-R_LINE_TO, 0.67f, -0.67f,
-LINE_TO, 8.67f, 9,
-CLOSE
diff --git a/ash/root_window_controller.cc b/ash/root_window_controller.cc
index a7898b3..698a82e 100644
--- a/ash/root_window_controller.cc
+++ b/ash/root_window_controller.cc
@@ -21,7 +21,6 @@
 #include "ash/lock_screen_action/lock_screen_action_background_controller.h"
 #include "ash/login_status.h"
 #include "ash/public/cpp/ash_constants.h"
-#include "ash/public/cpp/ash_features.h"
 #include "ash/public/cpp/ash_switches.h"
 #include "ash/public/cpp/shelf_types.h"
 #include "ash/public/cpp/shell_window_ids.h"
@@ -373,11 +372,7 @@
 }
 
 bool RootWindowController::IsSystemTrayVisible() {
-  TrayBackgroundView* tray = nullptr;
-  if (features::IsSystemTrayUnifiedEnabled())
-    tray = GetStatusAreaWidget()->unified_system_tray();
-  else
-    tray = GetSystemTray();
+  TrayBackgroundView* tray = GetStatusAreaWidget()->unified_system_tray();
   return tray && tray->GetWidget()->IsVisible() && tray->visible();
 }
 
diff --git a/ash/shelf/shelf_layout_manager_unittest.cc b/ash/shelf/shelf_layout_manager_unittest.cc
index 2c24665..8210c891 100644
--- a/ash/shelf/shelf_layout_manager_unittest.cc
+++ b/ash/shelf/shelf_layout_manager_unittest.cc
@@ -12,7 +12,6 @@
 #include "ash/app_list/test/app_list_test_helper.h"
 #include "ash/focus_cycler.h"
 #include "ash/public/cpp/app_list/app_list_features.h"
-#include "ash/public/cpp/ash_features.h"
 #include "ash/public/cpp/ash_switches.h"
 #include "ash/public/cpp/immersive/immersive_fullscreen_controller_test_api.h"
 #include "ash/public/cpp/shell_window_ids.h"
@@ -910,15 +909,9 @@
   EXPECT_EQ(display_bottom, display.work_area().bottom());
 
   // Tap the system tray when shelf is shown should open the system tray menu.
-  if (features::IsSystemTrayUnifiedEnabled()) {
-    generator->GestureTapAt(
-        GetPrimaryUnifiedSystemTray()->GetBoundsInScreen().CenterPoint());
-    EXPECT_TRUE(GetPrimaryUnifiedSystemTray()->IsBubbleShown());
-  } else {
-    generator->GestureTapAt(
-        GetPrimarySystemTray()->GetBoundsInScreen().CenterPoint());
-    EXPECT_TRUE(GetPrimarySystemTray()->HasSystemBubble());
-  }
+  generator->GestureTapAt(
+      GetPrimaryUnifiedSystemTray()->GetBoundsInScreen().CenterPoint());
+  EXPECT_TRUE(GetPrimaryUnifiedSystemTray()->IsBubbleShown());
 
   // Move mouse back up and click to dismiss the opened system tray menu.
   generator->MoveMouseTo(0, 0);
@@ -2126,10 +2119,7 @@
       TOGGLE_SYSTEM_TRAY_BUBBLE);
   EXPECT_EQ(SHELF_AUTO_HIDE, shelf->GetVisibilityState());
   EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->GetAutoHideState());
-  if (features::IsSystemTrayUnifiedEnabled())
-    EXPECT_TRUE(GetPrimaryUnifiedSystemTray()->IsBubbleShown());
-  else
-    EXPECT_TRUE(GetPrimarySystemTray()->HasSystemBubble());
+  EXPECT_TRUE(GetPrimaryUnifiedSystemTray()->IsBubbleShown());
 }
 
 TEST_F(ShelfLayoutManagerTest, WorkAreaChangeWorkspace) {
diff --git a/ash/shelf/shelf_widget.cc b/ash/shelf/shelf_widget.cc
index 0338a39..563ad7d 100644
--- a/ash/shelf/shelf_widget.cc
+++ b/ash/shelf/shelf_widget.cc
@@ -243,6 +243,7 @@
     if (!mask_) {
       mask_ = views::Painter::CreatePaintedLayer(
           views::Painter::CreateSolidRoundRectPainter(SK_ColorBLACK, radius));
+      mask_->layer()->SetFillsBoundsOpaquely(false);
       opaque_background_.SetMaskLayer(mask_->layer());
     }
     if (mask_->layer()->bounds() != opaque_background_bounds)
diff --git a/ash/system/caps_lock_notification_controller.cc b/ash/system/caps_lock_notification_controller.cc
index c410279..92d5767d 100644
--- a/ash/system/caps_lock_notification_controller.cc
+++ b/ash/system/caps_lock_notification_controller.cc
@@ -5,7 +5,6 @@
 #include "ash/system/caps_lock_notification_controller.h"
 
 #include "ash/accessibility/accessibility_controller.h"
-#include "ash/public/cpp/ash_features.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/session/session_controller.h"
 #include "ash/shell.h"
@@ -44,8 +43,7 @@
           message_center::RichNotificationData(), nullptr,
           kNotificationCapslockIcon,
           message_center::SystemNotificationWarningLevel::NORMAL);
-  if (features::IsSystemTrayUnifiedEnabled())
-    notification->set_pinned(true);
+  notification->set_pinned(true);
   return notification;
 }
 
@@ -98,13 +96,10 @@
               : mojom::AccessibilityAlert::CAPS_OFF);
 
   if (enabled) {
-    if (!notification_shown_ || features::IsSystemTrayUnifiedEnabled()) {
-      Shell::Get()->metrics()->RecordUserMetricsAction(
-          UMA_STATUS_AREA_CAPS_LOCK_POPUP);
+    Shell::Get()->metrics()->RecordUserMetricsAction(
+        UMA_STATUS_AREA_CAPS_LOCK_POPUP);
 
-      MessageCenter::Get()->AddNotification(CreateNotification());
-      notification_shown_ = true;
-    }
+    MessageCenter::Get()->AddNotification(CreateNotification());
   } else if (MessageCenter::Get()->FindVisibleNotificationById(
                  kCapsLockNotificationId)) {
     MessageCenter::Get()->RemoveNotification(kCapsLockNotificationId, false);
diff --git a/ash/system/caps_lock_notification_controller.h b/ash/system/caps_lock_notification_controller.h
index 9286e5d..5238cc52 100644
--- a/ash/system/caps_lock_notification_controller.h
+++ b/ash/system/caps_lock_notification_controller.h
@@ -29,8 +29,6 @@
   void OnKeyboardLayoutNameChanged(const std::string&) override {}
 
  private:
-  bool notification_shown_ = false;
-
   DISALLOW_COPY_AND_ASSIGN(CapsLockNotificationController);
 };
 
diff --git a/ash/system/cast/cast_notification_controller.cc b/ash/system/cast/cast_notification_controller.cc
index a866b48..2aec527 100644
--- a/ash/system/cast/cast_notification_controller.cc
+++ b/ash/system/cast/cast_notification_controller.cc
@@ -4,7 +4,6 @@
 
 #include "ash/system/cast/cast_notification_controller.h"
 
-#include "ash/public/cpp/ash_features.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/shell.h"
 #include "ash/strings/grit/ash_strings.h"
@@ -67,10 +66,6 @@
 
 void CastNotificationController::OnDevicesUpdated(
     std::vector<mojom::SinkAndRoutePtr> devices) {
-  // The notification is only shown when UnifiedSystemTray is enabled.
-  if (!features::IsSystemTrayUnifiedEnabled())
-    return;
-
   if (ShouldShowNotification())
     ShowNotification(std::move(devices));
   else
diff --git a/ash/system/date/date_view.cc b/ash/system/date/date_view.cc
index 4729a6b4..7241bed 100644
--- a/ash/system/date/date_view.cc
+++ b/ash/system/date/date_view.cc
@@ -4,7 +4,6 @@
 
 #include "ash/system/date/date_view.h"
 
-#include "ash/public/cpp/ash_features.h"
 #include "ash/session/session_controller.h"
 #include "ash/shell.h"
 #include "ash/strings/grit/ash_strings.h"
@@ -278,7 +277,7 @@
 }
 
 void TimeView::UpdateClockLayout(ClockLayout clock_layout) {
-  SetBorderFromLayout(clock_layout);
+  SetBorder(views::NullBorder());
   if (clock_layout == ClockLayout::HORIZONTAL_CLOCK) {
     RemoveChildView(vertical_label_hours_.get());
     RemoveChildView(vertical_label_minutes_.get());
@@ -319,15 +318,6 @@
   UpdateText();
 }
 
-void TimeView::SetBorderFromLayout(ClockLayout clock_layout) {
-  if (!features::IsSystemTrayUnifiedEnabled() &&
-      clock_layout == ClockLayout::HORIZONTAL_CLOCK) {
-    SetBorder(views::CreateEmptyBorder(gfx::Insets(0, kTrayImageItemPadding)));
-  } else {
-    SetBorder(views::NullBorder());
-  }
-}
-
 void TimeView::SetupLabels() {
   horizontal_label_.reset(new views::Label());
   SetupLabel(horizontal_label_.get());
diff --git a/ash/system/date/date_view.h b/ash/system/date/date_view.h
index d68d672..254a51c 100644
--- a/ash/system/date/date_view.h
+++ b/ash/system/date/date_view.h
@@ -146,7 +146,6 @@
   bool OnMousePressed(const ui::MouseEvent& event) override;
   void OnGestureEvent(ui::GestureEvent* event) override;
 
-  void SetBorderFromLayout(ClockLayout clock_layout);
   void SetupLabels();
   void SetupLabel(views::Label* label);
 
diff --git a/ash/system/ime_menu/ime_list_view.cc b/ash/system/ime_menu/ime_list_view.cc
index e10c7f0a..aee69aaf 100644
--- a/ash/system/ime_menu/ime_list_view.cc
+++ b/ash/system/ime_menu/ime_list_view.cc
@@ -8,7 +8,6 @@
 #include "ash/ime/ime_switch_type.h"
 #include "ash/keyboard/ash_keyboard_controller.h"
 #include "ash/keyboard/virtual_keyboard_controller.h"
-#include "ash/public/cpp/ash_features.h"
 #include "ash/public/interfaces/ime_info.mojom.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/shell.h"
@@ -188,7 +187,7 @@
 };
 
 ImeListView::ImeListView(DetailedViewDelegate* delegate)
-    : ImeListView(delegate, features::IsSystemTrayUnifiedEnabled()) {}
+    : ImeListView(delegate, true) {}
 
 ImeListView::ImeListView(DetailedViewDelegate* delegate, bool use_unified_theme)
     : TrayDetailedView(delegate),
diff --git a/ash/system/message_center/arc/BUILD.gn b/ash/system/message_center/arc/BUILD.gn
index b3e4846..59ebaaf 100644
--- a/ash/system/message_center/arc/BUILD.gn
+++ b/ash/system/message_center/arc/BUILD.gn
@@ -30,6 +30,7 @@
   ]
 
   deps = [
+    "//ash/public/cpp:cpp",
     "//base",
     "//components/account_id",
     "//components/arc:arc_metrics_constants",
diff --git a/ash/system/message_center/arc/arc_notification_content_view_unittest.cc b/ash/system/message_center/arc/arc_notification_content_view_unittest.cc
index 47d0ef9..b0e276c 100644
--- a/ash/system/message_center/arc/arc_notification_content_view_unittest.cc
+++ b/ash/system/message_center/arc/arc_notification_content_view_unittest.cc
@@ -8,7 +8,6 @@
 #include <string>
 #include <utility>
 
-#include "ash/public/cpp/ash_features.h"
 #include "ash/shell.h"
 #include "ash/system/message_center/arc/arc_notification_content_view.h"
 #include "ash/system/message_center/arc/arc_notification_delegate.h"
@@ -19,7 +18,6 @@
 #include "ash/system/message_center/arc/arc_notification_view.h"
 #include "ash/system/message_center/arc/mock_arc_notification_item.h"
 #include "ash/system/message_center/message_center_view.h"
-#include "ash/system/message_center/notification_tray.h"
 #include "ash/system/status_area_widget.h"
 #include "ash/system/status_area_widget_test_helper.h"
 #include "ash/system/unified/unified_system_tray.h"
@@ -346,22 +344,10 @@
           }));
 
   // Show MessageCenterView and activate its widget.
-  if (features::IsSystemTrayUnifiedEnabled()) {
-    auto* unified_system_tray =
-        StatusAreaWidgetTestHelper::GetStatusAreaWidget()
-            ->unified_system_tray();
-    unified_system_tray->ShowBubble(false /* show_by_click */);
-    unified_system_tray->ActivateBubble();
-  } else {
-    auto* notification_tray =
-        StatusAreaWidgetTestHelper::GetStatusAreaWidget()->notification_tray();
-    notification_tray->ShowBubble(false /* show_by_click */);
-    notification_tray->GetBubbleView()
-        ->GetWidget()
-        ->widget_delegate()
-        ->set_can_activate(true);
-    notification_tray->GetBubbleView()->GetWidget()->Activate();
-  }
+  auto* unified_system_tray =
+      StatusAreaWidgetTestHelper::GetStatusAreaWidget()->unified_system_tray();
+  unified_system_tray->ShowBubble(false /* show_by_click */);
+  unified_system_tray->ActivateBubble();
 
   auto notification_item =
       std::make_unique<MockArcNotificationItem>(notification_key);
diff --git a/ash/system/message_center/arc/arc_notification_manager.cc b/ash/system/message_center/arc/arc_notification_manager.cc
index 5373701..9456ed2d 100644
--- a/ash/system/message_center/arc/arc_notification_manager.cc
+++ b/ash/system/message_center/arc/arc_notification_manager.cc
@@ -7,10 +7,12 @@
 #include <memory>
 #include <utility>
 
+#include "ash/public/cpp/ash_features.h"
 #include "ash/system/message_center/arc/arc_notification_delegate.h"
 #include "ash/system/message_center/arc/arc_notification_item_impl.h"
 #include "ash/system/message_center/arc/arc_notification_manager_delegate.h"
 #include "ash/system/message_center/arc/arc_notification_view.h"
+#include "base/command_line.h"
 #include "base/stl_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "components/arc/mojo_channel.h"
@@ -27,6 +29,8 @@
 using arc::mojom::ArcNotificationPriority;
 using arc::mojom::ArcDoNotDisturbStatus;
 using arc::mojom::ArcDoNotDisturbStatusPtr;
+using arc::mojom::NotificationConfiguration;
+using arc::mojom::NotificationConfigurationPtr;
 using arc::mojom::NotificationsHost;
 using arc::mojom::NotificationsInstance;
 using arc::mojom::NotificationsInstancePtr;
@@ -144,6 +148,9 @@
 
   // Sync the initial quiet mode state with Android.
   SetDoNotDisturbStatusOnAndroid(message_center_->IsQuietMode());
+
+  // Set configuration variables for notifications on arc.
+  SetNotificationConfiguration();
 }
 
 void ArcNotificationManager::OnConnectionClosed() {
@@ -517,4 +524,22 @@
   notifications_instance->CancelLongPress(key);
 }
 
+void ArcNotificationManager::SetNotificationConfiguration() {
+  auto* notifications_instance = ARC_GET_INSTANCE_FOR_METHOD(
+      instance_owner_->holder(), SetNotificationConfiguration);
+
+  if (!notifications_instance) {
+    VLOG(2) << "Trying to set notification expansion animations"
+            << ", but the ARC channel has already gone.";
+    return;
+  }
+
+  NotificationConfigurationPtr configuration = NotificationConfiguration::New();
+  configuration->expansion_animation =
+      ash::features::IsNotificationExpansionAnimationEnabled();
+
+  notifications_instance->SetNotificationConfiguration(
+      std::move(configuration));
+}
+
 }  // namespace ash
diff --git a/ash/system/message_center/arc/arc_notification_manager.h b/ash/system/message_center/arc/arc_notification_manager.h
index 1fcf87e..8823a2c 100644
--- a/ash/system/message_center/arc/arc_notification_manager.h
+++ b/ash/system/message_center/arc/arc_notification_manager.h
@@ -70,6 +70,7 @@
   void SendNotificationToggleExpansionOnChrome(const std::string& key);
   void SetDoNotDisturbStatusOnAndroid(bool enabled);
   void CancelLongPress(const std::string& key);
+  void SetNotificationConfiguration();
 
  private:
   // Helper class to own MojoChannel and ConnectionHolder.
diff --git a/ash/system/message_center/arc_notification_manager_delegate_impl.cc b/ash/system/message_center/arc_notification_manager_delegate_impl.cc
index f4bc85c..b31f6ad 100644
--- a/ash/system/message_center/arc_notification_manager_delegate_impl.cc
+++ b/ash/system/message_center/arc_notification_manager_delegate_impl.cc
@@ -5,12 +5,10 @@
 #include "ash/system/message_center/arc_notification_manager_delegate_impl.h"
 
 #include "ash/login_status.h"
-#include "ash/public/cpp/ash_features.h"
 #include "ash/root_window_controller.h"
 #include "ash/session/session_controller.h"
 #include "ash/shell.h"
 #include "ash/system/message_center/message_center_controller.h"
-#include "ash/system/message_center/notification_tray.h"
 #include "ash/system/status_area_widget.h"
 #include "ash/system/unified/unified_system_tray.h"
 
@@ -43,31 +41,20 @@
 }
 
 void ArcNotificationManagerDelegateImpl::ShowMessageCenter() {
-  if (features::IsSystemTrayUnifiedEnabled()) {
-    Shell::Get()
-        ->GetPrimaryRootWindowController()
-        ->GetStatusAreaWidget()
-        ->unified_system_tray()
-        ->ShowBubble(false /* show_by_click */);
-  } else {
-    Shell::Get()->GetNotificationTray()->ShowMessageCenter(
-        false /* show_by_click */);
-  }
+  Shell::Get()
+      ->GetPrimaryRootWindowController()
+      ->GetStatusAreaWidget()
+      ->unified_system_tray()
+      ->ShowBubble(false /* show_by_click */);
 }
 
 void ArcNotificationManagerDelegateImpl::HideMessageCenter() {
   // Close the message center on all the displays.
   for (auto* root_window_controller :
        RootWindowController::root_window_controllers()) {
-    if (features::IsSystemTrayUnifiedEnabled()) {
-      root_window_controller->GetStatusAreaWidget()
-          ->unified_system_tray()
-          ->CloseBubble();
-    } else {
-      root_window_controller->GetStatusAreaWidget()
-          ->notification_tray()
-          ->ShowMessageCenter(false /* show_by_click */);
-    }
+    root_window_controller->GetStatusAreaWidget()
+        ->unified_system_tray()
+        ->CloseBubble();
   }
 }
 
diff --git a/ash/system/message_center/message_center_scroll_bar.cc b/ash/system/message_center/message_center_scroll_bar.cc
index 5c2d649..fc60310e 100644
--- a/ash/system/message_center/message_center_scroll_bar.cc
+++ b/ash/system/message_center/message_center_scroll_bar.cc
@@ -29,8 +29,7 @@
 MessageCenterScrollBar::MessageCenterScrollBar(
     MessageCenterScrollBar::Observer* observer)
     : views::OverlayScrollBar(false), observer_(observer) {
-  GetThumb()->layer()->SetVisible(!features::IsSystemTrayUnifiedEnabled() ||
-                                  features::IsNotificationScrollBarEnabled());
+  GetThumb()->layer()->SetVisible(features::IsNotificationScrollBarEnabled());
 }
 
 bool MessageCenterScrollBar::OnKeyPressed(const ui::KeyEvent& event) {
diff --git a/ash/system/message_center/message_center_style.h b/ash/system/message_center/message_center_style.h
index 2c03c846..bab101e 100644
--- a/ash/system/message_center/message_center_style.h
+++ b/ash/system/message_center/message_center_style.h
@@ -26,6 +26,14 @@
 
 constexpr int kSettingsTransitionDurationMs = 500;
 
+// Layout parameters for swipe control of notifications in message center.
+constexpr int kSwipeControlButtonImageSize = 20;
+constexpr int kSwipeControlButtonSize = 36;
+constexpr int kSwipeControlButtonVerticalMargin = 24;
+constexpr int kSwipeControlButtonHorizontalMargin = 8;
+constexpr SkColor kSwipeControlBackgroundColor =
+    SkColorSetRGB(0xee, 0xee, 0xee);
+
 }  // namespace message_center_style
 
 }  // namespace ash
diff --git a/ash/system/message_center/notification_swipe_control_view.cc b/ash/system/message_center/notification_swipe_control_view.cc
index 19abc73..5a8789f 100644
--- a/ash/system/message_center/notification_swipe_control_view.cc
+++ b/ash/system/message_center/notification_swipe_control_view.cc
@@ -4,11 +4,11 @@
 
 #include "ash/system/message_center/notification_swipe_control_view.h"
 
+#include "ash/system/message_center/message_center_style.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/events/event.h"
 #include "ui/gfx/color_palette.h"
 #include "ui/gfx/paint_vector_icon.h"
-#include "ui/message_center/public/cpp/message_center_constants.h"
 #include "ui/message_center/vector_icons.h"
 #include "ui/message_center/views/message_view.h"
 #include "ui/message_center/views/notification_background_painter.h"
@@ -27,9 +27,9 @@
     : message_view_(message_view) {
   auto* layout = SetLayoutManager(std::make_unique<views::BoxLayout>(
       views::BoxLayout::kHorizontal,
-      gfx::Insets(message_center::kSwipeControlButtonVerticalMargin,
-                  message_center::kSwipeControlButtonHorizontalMargin),
-      message_center::kSwipeControlButtonHorizontalMargin));
+      gfx::Insets(message_center_style::kSwipeControlButtonVerticalMargin,
+                  message_center_style::kSwipeControlButtonHorizontalMargin),
+      message_center_style::kSwipeControlButtonHorizontalMargin));
   layout->set_cross_axis_alignment(
       views::BoxLayout::CROSS_AXIS_ALIGNMENT_START);
   layout->set_main_axis_alignment(views::BoxLayout::MAIN_AXIS_ALIGNMENT_END);
@@ -81,8 +81,8 @@
   int control_button_count =
       (has_settings_button ? 1 : 0) + (has_snooze_button ? 1 : 0);
   int control_button_width =
-      message_center::kSwipeControlButtonSize * control_button_count +
-      message_center::kSwipeControlButtonHorizontalMargin *
+      message_center_style::kSwipeControlButtonSize * control_button_count +
+      message_center_style::kSwipeControlButtonHorizontalMargin *
           (control_button_count + 1);
   message_view_->SetSlideButtonWidth(control_button_width);
 }
@@ -92,7 +92,7 @@
   SetBackground(views::CreateBackgroundFromPainter(
       std::make_unique<message_center::NotificationBackgroundPainter>(
           top_radius, bottom_radius,
-          message_center::kSwipeControlBackgroundColor)));
+          message_center_style::kSwipeControlBackgroundColor)));
   SchedulePaint();
 }
 
@@ -101,14 +101,15 @@
     settings_button_ = new views::ImageButton(this);
     settings_button_->SetImage(
         views::Button::STATE_NORMAL,
-        gfx::CreateVectorIcon(message_center::kNotificationSettingsButtonIcon,
-                              message_center::kSwipeControlButtonImageSize,
-                              gfx::kChromeIconGrey));
+        gfx::CreateVectorIcon(
+            message_center::kNotificationSettingsButtonIcon,
+            message_center_style::kSwipeControlButtonImageSize,
+            gfx::kChromeIconGrey));
     settings_button_->SetImageAlignment(views::ImageButton::ALIGN_CENTER,
                                         views::ImageButton::ALIGN_MIDDLE);
     settings_button_->SetPreferredSize(
-        gfx::Size(message_center::kSwipeControlButtonSize,
-                  message_center::kSwipeControlButtonSize));
+        gfx::Size(message_center_style::kSwipeControlButtonSize,
+                  message_center_style::kSwipeControlButtonSize));
 
     settings_button_->SetAccessibleName(l10n_util::GetStringUTF16(
         IDS_MESSAGE_NOTIFICATION_SETTINGS_BUTTON_ACCESSIBLE_NAME));
@@ -131,14 +132,15 @@
     snooze_button_ = new views::ImageButton(this);
     snooze_button_->SetImage(
         views::Button::STATE_NORMAL,
-        gfx::CreateVectorIcon(message_center::kNotificationSnoozeButtonIcon,
-                              message_center::kSwipeControlButtonImageSize,
-                              gfx::kChromeIconGrey));
+        gfx::CreateVectorIcon(
+            message_center::kNotificationSnoozeButtonIcon,
+            message_center_style::kSwipeControlButtonImageSize,
+            gfx::kChromeIconGrey));
     snooze_button_->SetImageAlignment(views::ImageButton::ALIGN_CENTER,
                                       views::ImageButton::ALIGN_MIDDLE);
     snooze_button_->SetPreferredSize(
-        gfx::Size(message_center::kSwipeControlButtonSize,
-                  message_center::kSwipeControlButtonSize));
+        gfx::Size(message_center_style::kSwipeControlButtonSize,
+                  message_center_style::kSwipeControlButtonSize));
 
     snooze_button_->SetAccessibleName(l10n_util::GetStringUTF16(
         IDS_MESSAGE_NOTIFICATION_SETTINGS_BUTTON_ACCESSIBLE_NAME));
diff --git a/ash/system/message_center/notifier_settings_view.cc b/ash/system/message_center/notifier_settings_view.cc
index fbea4738..c1c675e 100644
--- a/ash/system/message_center/notifier_settings_view.cc
+++ b/ash/system/message_center/notifier_settings_view.cc
@@ -10,7 +10,6 @@
 #include <string>
 #include <utility>
 
-#include "ash/public/cpp/ash_features.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/shell.h"
 #include "ash/strings/grit/ash_strings.h"
@@ -92,8 +91,6 @@
 constexpr gfx::Insets kQuietModeViewPadding(0, 18, 0, 0);
 constexpr gfx::Insets kQuietModeLabelPadding(16, 0, 15, 0);
 constexpr gfx::Insets kQuietModeTogglePadding(0, 14);
-constexpr SkColor kTopLabelColor = gfx::kGoogleBlue500;
-constexpr SkColor kLabelColor = SkColorSetA(SK_ColorBLACK, 0xDE);
 constexpr SkColor kTopBorderColor = SkColorSetA(SK_ColorBLACK, 0x1F);
 constexpr SkColor kDisabledNotifierFilterColor =
     SkColorSetA(SK_ColorWHITE, 0xB8);
@@ -253,9 +250,7 @@
 class EmptyNotifierView : public views::View {
  public:
   EmptyNotifierView() {
-    SkColor color = features::IsSystemTrayUnifiedEnabled()
-                        ? kUnifiedMenuTextColor
-                        : message_center_style::kEmptyViewColor;
+    SkColor color = kUnifiedMenuTextColor;
     auto layout = std::make_unique<views::BoxLayout>(
         views::BoxLayout::kVertical, gfx::Insets(), 0);
     layout->set_main_axis_alignment(
@@ -302,9 +297,7 @@
       name_view_(new views::Label(notifier_ui_data.name)),
       checkbox_(new views::Checkbox(base::string16(), this /* listener */)) {
   name_view_->SetAutoColorReadabilityEnabled(false);
-  name_view_->SetEnabledColor(features::IsSystemTrayUnifiedEnabled()
-                                  ? kUnifiedMenuTextColor
-                                  : kLabelColor);
+  name_view_->SetEnabledColor(kUnifiedMenuTextColor);
   name_view_->SetSubpixelRenderingEnabled(false);
   // "Roboto-Regular, 13sp" is specified in the mock.
   name_view_->SetFontList(
@@ -328,9 +321,7 @@
     const gfx::ImageSkia& icon) {
   if (icon.isNull()) {
     icon_view_->SetImage(gfx::CreateVectorIcon(
-        message_center::kProductIcon, kEntryIconSize,
-        features::IsSystemTrayUnifiedEnabled() ? kUnifiedMenuIconColor
-                                               : gfx::kChromeIconGrey));
+        message_center::kProductIcon, kEntryIconSize, kUnifiedMenuIconColor));
   } else {
     icon_view_->SetImage(icon);
     icon_view_->SetImageSize(gfx::Size(kEntryIconSize, kEntryIconSize));
@@ -394,9 +385,7 @@
   if (!enabled()) {
     views::ImageView* policy_enforced_icon = new views::ImageView();
     policy_enforced_icon->SetImage(gfx::CreateVectorIcon(
-        kSystemMenuBusinessIcon, kEntryIconSize,
-        features::IsSystemTrayUnifiedEnabled() ? kUnifiedMenuIconColor
-                                               : gfx::kChromeIconGrey));
+        kSystemMenuBusinessIcon, kEntryIconSize, kUnifiedMenuIconColor));
     cs->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 0, GridLayout::FIXED,
                   kEntryIconSize, 0);
     layout->AddView(policy_enforced_icon);
@@ -443,9 +432,7 @@
   quiet_mode_label->SetFontList(
       gfx::FontList().DeriveWithSizeDelta(kLabelFontSizeDelta));
   quiet_mode_label->SetAutoColorReadabilityEnabled(false);
-  quiet_mode_label->SetEnabledColor(features::IsSystemTrayUnifiedEnabled()
-                                        ? kUnifiedMenuTextColor
-                                        : kLabelColor);
+  quiet_mode_label->SetEnabledColor(kUnifiedMenuTextColor);
   quiet_mode_label->SetSubpixelRenderingEnabled(false);
   quiet_mode_label->SetBorder(views::CreateEmptyBorder(kQuietModeLabelPadding));
   quiet_mode_view->AddChildView(quiet_mode_label);
@@ -468,9 +455,7 @@
   top_label_->SetFontList(gfx::FontList().Derive(
       kLabelFontSizeDelta, gfx::Font::NORMAL, gfx::Font::Weight::MEDIUM));
   top_label_->SetAutoColorReadabilityEnabled(false);
-  top_label_->SetEnabledColor(features::IsSystemTrayUnifiedEnabled()
-                                  ? kUnifiedMenuTextColor
-                                  : kTopLabelColor);
+  top_label_->SetEnabledColor(kUnifiedMenuTextColor);
   top_label_->SetSubpixelRenderingEnabled(false);
   top_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
   top_label_->SetMultiLine(true);
@@ -505,15 +490,13 @@
 void NotifierSettingsView::SetQuietModeState(bool is_quiet_mode) {
   quiet_mode_toggle_->SetIsOn(is_quiet_mode, false /* animate */);
   if (is_quiet_mode) {
-    quiet_mode_icon_->SetImage(gfx::CreateVectorIcon(
-        kNotificationCenterDoNotDisturbOnIcon, kMenuIconSize,
-        features::IsSystemTrayUnifiedEnabled() ? kUnifiedMenuIconColor
-                                               : kMenuIconColor));
+    quiet_mode_icon_->SetImage(
+        gfx::CreateVectorIcon(kNotificationCenterDoNotDisturbOnIcon,
+                              kMenuIconSize, kUnifiedMenuIconColor));
   } else {
-    quiet_mode_icon_->SetImage(gfx::CreateVectorIcon(
-        kNotificationCenterDoNotDisturbOffIcon, kMenuIconSize,
-        features::IsSystemTrayUnifiedEnabled() ? kUnifiedMenuIconColorDisabled
-                                               : kMenuIconColorDisabled));
+    quiet_mode_icon_->SetImage(
+        gfx::CreateVectorIcon(kNotificationCenterDoNotDisturbOffIcon,
+                              kMenuIconSize, kUnifiedMenuIconColorDisabled));
   }
 }
 
diff --git a/ash/system/model/system_tray_model.cc b/ash/system/model/system_tray_model.cc
index 66b4b4fc..6045469 100644
--- a/ash/system/model/system_tray_model.cc
+++ b/ash/system/model/system_tray_model.cc
@@ -4,10 +4,8 @@
 
 #include "ash/system/model/system_tray_model.h"
 
-#include "ash/public/cpp/ash_features.h"
 #include "ash/root_window_controller.h"
 #include "ash/shell.h"
-#include "ash/system/audio/tray_audio.h"
 #include "ash/system/model/clock_model.h"
 #include "ash/system/model/enterprise_domain_model.h"
 #include "ash/system/model/session_length_limit_model.h"
@@ -15,7 +13,6 @@
 #include "ash/system/model/update_model.h"
 #include "ash/system/model/virtual_keyboard_model.h"
 #include "ash/system/status_area_widget.h"
-#include "ash/system/tray/system_tray.h"
 #include "ash/system/unified/unified_system_tray.h"
 #include "base/logging.h"
 
@@ -40,20 +37,12 @@
 }
 
 void SystemTrayModel::SetPrimaryTrayEnabled(bool enabled) {
-  if (features::IsSystemTrayUnifiedEnabled()) {
-    UnifiedSystemTray* tray = Shell::GetPrimaryRootWindowController()
-                                  ->GetStatusAreaWidget()
-                                  ->unified_system_tray();
-    if (!tray)
-      return;
-    tray->SetTrayEnabled(enabled);
-  } else {
-    ash::SystemTray* tray =
-        Shell::GetPrimaryRootWindowController()->GetSystemTray();
-    if (!tray)
-      return;
-    tray->SetTrayEnabled(enabled);
-  }
+  UnifiedSystemTray* tray = Shell::GetPrimaryRootWindowController()
+                                ->GetStatusAreaWidget()
+                                ->unified_system_tray();
+  if (!tray)
+    return;
+  tray->SetTrayEnabled(enabled);
 }
 
 void SystemTrayModel::SetPrimaryTrayVisible(bool visible) {
@@ -100,21 +89,12 @@
 
 void SystemTrayModel::ShowVolumeSliderBubble() {
   // Show the bubble on all monitors with a system tray.
-  if (features::IsSystemTrayUnifiedEnabled()) {
-    for (RootWindowController* root : Shell::GetAllRootWindowControllers()) {
-      UnifiedSystemTray* system_tray =
-          root->GetStatusAreaWidget()->unified_system_tray();
-      if (!system_tray)
-        continue;
-      system_tray->ShowVolumeSliderBubble();
-    }
-  } else {
-    for (RootWindowController* root : Shell::GetAllRootWindowControllers()) {
-      ash::SystemTray* system_tray = root->GetSystemTray();
-      if (!system_tray)
-        continue;
-      system_tray->GetTrayAudio()->ShowPopUpVolumeView();
-    }
+  for (RootWindowController* root : Shell::GetAllRootWindowControllers()) {
+    UnifiedSystemTray* system_tray =
+        root->GetStatusAreaWidget()->unified_system_tray();
+    if (!system_tray)
+      continue;
+    system_tray->ShowVolumeSliderBubble();
   }
 }
 
diff --git a/ash/system/network/network_icon.cc b/ash/system/network/network_icon.cc
index 80fdaf9..0f6b12cf 100644
--- a/ash/system/network/network_icon.cc
+++ b/ash/system/network/network_icon.cc
@@ -4,7 +4,6 @@
 
 #include "ash/system/network/network_icon.h"
 
-#include "ash/public/cpp/ash_features.h"
 #include "ash/public/cpp/network_icon_image_source.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/strings/grit/ash_strings.h"
@@ -42,16 +41,6 @@
 
 namespace {
 
-// Constants for offseting the badge displayed on top of the signal strength
-// icon. The badge will extend outside of the base icon bounds by these amounts.
-// All values are in dp.
-
-// The badge offsets are different depending on whether the icon is in the tray
-// or menu.
-const int kTrayIconBadgeOffset = 3;
-const int kMenuIconBadgeOffset = 2;
-
-//------------------------------------------------------------------------------
 // class used for maintaining a map of network state and images.
 class NetworkIconImpl {
  public:
@@ -175,18 +164,12 @@
     return kTrayIconColor;
   if (icon_type == ICON_TYPE_TRAY_OOBE)
     return kOobeTrayIconColor;
-  if (features::IsSystemTrayUnifiedEnabled())
-    return kUnifiedMenuIconColor;
-  else
-    return kMenuIconColor;
+  return kUnifiedMenuIconColor;
 }
 
 bool IconTypeIsDark(IconType icon_type) {
-  if (features::IsSystemTrayUnifiedEnabled()) {
-    // Dark icon is used for OOBE tray icon because the background is white.
-    return icon_type == ICON_TYPE_TRAY_OOBE;
-  }
-  return icon_type != ICON_TYPE_TRAY_REGULAR;
+  // Dark icon is used for OOBE tray icon because the background is white.
+  return icon_type == ICON_TYPE_TRAY_OOBE;
 }
 
 bool IconTypeHasVPNBadge(IconType icon_type) {
@@ -194,14 +177,7 @@
 }
 
 gfx::Size GetSizeForBaseIconSize(const gfx::Size& base_icon_size) {
-  if (features::IsSystemTrayUnifiedEnabled())
-    return base_icon_size;
-  gfx::Size size = base_icon_size;
-  const int badge_offset = base_icon_size.width() == kTrayIconSize
-                               ? kTrayIconBadgeOffset
-                               : kMenuIconBadgeOffset;
-  size.Enlarge(badge_offset * 2, badge_offset * 2);
-  return size;
+  return base_icon_size;
 }
 
 gfx::ImageSkia CreateNetworkIconImage(const gfx::ImageSkia& icon,
@@ -243,15 +219,14 @@
   int size = kMenuIconSize;
   if (IsTrayIcon(icon_type)) {
     size = TrayConstants::GetTrayIconSize();
-  } else if (features::IsSystemTrayUnifiedEnabled() &&
-             icon_type == ICON_TYPE_DEFAULT_VIEW) {
+  } else if (icon_type == ICON_TYPE_DEFAULT_VIEW) {
     size = kUnifiedFeaturePodVectorIconSize;
   }
   return gfx::Size(size, size);
 }
 
 int GetPaddingForIconType(IconType icon_type) {
-  if (features::IsSystemTrayUnifiedEnabled() && IsTrayIcon(icon_type))
+  if (IsTrayIcon(icon_type))
     return kUnifiedTrayNetworkIconPadding;
   return kTrayNetworkIconPadding;
 }
@@ -312,8 +287,7 @@
 }
 
 Badge ConnectingVpnBadge(double animation, IconType icon_type) {
-  return {features::IsSystemTrayUnifiedEnabled() ? &kUnifiedNetworkBadgeVpnIcon
-                                                 : &kNetworkBadgeVpnIcon,
+  return {&kUnifiedNetworkBadgeVpnIcon,
           SkColorSetA(GetDefaultColorForIconType(icon_type), 0xFF * animation)};
 }
 
@@ -362,9 +336,7 @@
                        IconType icon_type,
                        int strength_index) {
   if (network->Matches(NetworkTypePattern::Ethernet())) {
-    return gfx::CreateVectorIcon(features::IsSystemTrayUnifiedEnabled()
-                                     ? vector_icons::kEthernetIcon
-                                     : kNetworkEthernetIcon,
+    return gfx::CreateVectorIcon(vector_icons::kEthernetIcon,
                                  GetDefaultColorForIconType(icon_type));
   }
   if (network->Matches(NetworkTypePattern::Wireless())) {
@@ -508,9 +480,7 @@
           NetworkTypePattern::VPN());
   Badge vpn_badge = {};
   if (vpn)
-    vpn_badge = {features::IsSystemTrayUnifiedEnabled()
-                     ? &kUnifiedNetworkBadgeVpnIcon
-                     : &kNetworkBadgeVpnIcon,
+    vpn_badge = {&kUnifiedNetworkBadgeVpnIcon,
                  GetDefaultColorForIconType(icon_type_)};
   if (vpn_badge != vpn_badge_) {
     vpn_badge_ = vpn_badge;
@@ -527,10 +497,7 @@
   if (type == shill::kTypeWifi) {
     if (network->security_class() != shill::kSecurityNone &&
         !IsTrayIcon(icon_type_)) {
-      badges->bottom_right = {features::IsSystemTrayUnifiedEnabled()
-                                  ? &kUnifiedNetworkBadgeSecureIcon
-                                  : &kNetworkBadgeSecureIcon,
-                              icon_color};
+      badges->bottom_right = {&kUnifiedNetworkBadgeSecureIcon, icon_color};
     }
   } else if (type == shill::kTypeWimax) {
     technology_badge_ = {&kNetworkBadgeTechnology4gIcon, icon_color};
@@ -554,9 +521,7 @@
     badges->top_left = technology_badge_;
     badges->bottom_left = vpn_badge_;
     if (behind_captive_portal_)
-      badges->bottom_right = {features::IsSystemTrayUnifiedEnabled()
-                                  ? &kUnifiedNetworkBadgeCaptivePortalIcon
-                                  : &kNetworkBadgeCaptivePortalIcon,
+      badges->bottom_right = {&kUnifiedNetworkBadgeCaptivePortalIcon,
                               icon_color};
   }
 }
@@ -611,7 +576,7 @@
 }
 
 gfx::ImageSkia GetImageForWiFiEnabledState(bool enabled, IconType icon_type) {
-  if (features::IsSystemTrayUnifiedEnabled() && !enabled) {
+  if (!enabled) {
     return gfx::CreateVectorIcon(kUnifiedMenuWifiOffIcon,
                                  GetSizeForIconType(icon_type).width(),
                                  GetDefaultColorForIconType(icon_type));
diff --git a/ash/system/network/network_list.cc b/ash/system/network/network_list.cc
index 186dd9f..14f187b88 100644
--- a/ash/system/network/network_list.cc
+++ b/ash/system/network/network_list.cc
@@ -8,7 +8,6 @@
 #include <utility>
 
 #include "ash/metrics/user_metrics_recorder.h"
-#include "ash/public/cpp/ash_features.h"
 #include "ash/public/cpp/ash_view_ids.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/session/session_controller.h"
@@ -168,12 +167,9 @@
   void InitializeLayout() {
     TrayPopupUtils::ConfigureAsStickyHeader(this);
     SetLayoutManager(std::make_unique<views::FillLayout>());
-    bool show_spacing = features::IsSystemTrayUnifiedEnabled();
-    container_ = TrayPopupUtils::CreateSubHeaderRowView(show_spacing);
-    if (show_spacing) {
-      container_->AddView(TriView::Container::START,
-                          TrayPopupUtils::CreateMainImageView());
-    }
+    container_ = TrayPopupUtils::CreateSubHeaderRowView(true);
+    container_->AddView(TriView::Container::START,
+                        TrayPopupUtils::CreateMainImageView());
     AddChildView(container_);
 
     network_row_title_view_ = new NetworkRowTitleView(title_id_);
@@ -454,20 +450,11 @@
     gfx::ImageSkia disabled_image = network_icon::GetImageForNewWifiNetwork(
         SkColorSetA(prominent_color, kDisabledJoinIconAlpha),
         SkColorSetA(prominent_color, kDisabledJoinBadgeAlpha));
-    if (features::IsSystemTrayUnifiedEnabled()) {
-      auto* join_button = new TopShortcutButton(
-          this, vector_icons::kWifiAddIcon, IDS_ASH_STATUS_TRAY_OTHER_WIFI);
-      join_button->SetEnabled(enabled);
-      container()->AddView(TriView::Container::END, join_button);
-      join_button_ = join_button;
-    } else {
-      auto* join_button = new SystemMenuButton(
-          this, normal_image, disabled_image, IDS_ASH_STATUS_TRAY_OTHER_WIFI);
-      join_button->SetInkDropColor(prominent_color);
-      join_button->SetEnabled(enabled);
-      container()->AddView(TriView::Container::END, join_button);
-      join_button_ = join_button;
-    }
+    auto* join_button = new TopShortcutButton(this, vector_icons::kWifiAddIcon,
+                                              IDS_ASH_STATUS_TRAY_OTHER_WIFI);
+    join_button->SetEnabled(enabled);
+    container()->AddView(TriView::Container::END, join_button);
+    join_button_ = join_button;
   }
 
   void ButtonPressed(views::Button* sender, const ui::Event& event) override {
@@ -965,10 +952,6 @@
   // Set up layout and apply sticky row property.
   TriView* connection_warning = TrayPopupUtils::CreateDefaultRowView();
   TrayPopupUtils::ConfigureAsStickyHeader(connection_warning);
-  if (!features::IsSystemTrayUnifiedEnabled()) {
-    connection_warning->SetBackground(
-        views::CreateSolidBackground(kHeaderBackgroundColor));
-  }
 
   // Set 'info' icon on left side.
   views::ImageView* image_view = TrayPopupUtils::CreateMainImageView();
diff --git a/ash/system/network/network_row_title_view.cc b/ash/system/network/network_row_title_view.cc
index da2a87d..21c17e5 100644
--- a/ash/system/network/network_row_title_view.cc
+++ b/ash/system/network/network_row_title_view.cc
@@ -4,7 +4,6 @@
 
 #include "ash/system/network/network_row_title_view.h"
 
-#include "ash/public/cpp/ash_features.h"
 #include "ash/system/tray/tray_popup_item_style.h"
 #include "ash/system/tray/tray_popup_utils.h"
 #include "base/strings/string16.h"
@@ -17,10 +16,7 @@
 
 namespace {
 
-const int kLineHeightTitle = 4;
-const int kLineHeightSubtitle = 3;
-// In UnifiedSystemTray, both line heights are same.
-const int kLineHeightUnified = 20;
+const int kLineHeight = 20;
 
 }  // namespace
 
@@ -32,18 +28,14 @@
 
   TrayPopupItemStyle title_style(TrayPopupItemStyle::FontStyle::SUB_HEADER);
   title_style.SetupLabel(title_);
-  subtitle_->SetLineHeight(features::IsSystemTrayUnifiedEnabled()
-                               ? kLineHeightUnified
-                               : kLineHeightTitle);
+  title_->SetLineHeight(kLineHeight);
   title_->SetText(l10n_util::GetStringUTF16(title_message_id));
   AddChildView(title_);
 
   TrayPopupItemStyle subtitle_style(TrayPopupItemStyle::FontStyle::SYSTEM_INFO);
   subtitle_style.SetupLabel(subtitle_);
   subtitle_->SetMultiLine(true);
-  subtitle_->SetLineHeight(features::IsSystemTrayUnifiedEnabled()
-                               ? kLineHeightUnified
-                               : kLineHeightSubtitle);
+  subtitle_->SetLineHeight(kLineHeight);
   subtitle_->SetVisible(false);
   AddChildView(subtitle_);
 }
diff --git a/ash/system/network/vpn_list_view.cc b/ash/system/network/vpn_list_view.cc
index c7990624..b648e18 100644
--- a/ash/system/network/vpn_list_view.cc
+++ b/ash/system/network/vpn_list_view.cc
@@ -8,7 +8,6 @@
 #include <vector>
 
 #include "ash/metrics/user_metrics_recorder.h"
-#include "ash/public/cpp/ash_features.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/shell.h"
 #include "ash/strings/grit/ash_strings.h"
@@ -83,12 +82,9 @@
       : vpn_provider_(vpn_provider) {
     TrayPopupUtils::ConfigureAsStickyHeader(this);
     SetLayoutManager(std::make_unique<views::FillLayout>());
-    bool show_spacing = features::IsSystemTrayUnifiedEnabled();
-    TriView* tri_view = TrayPopupUtils::CreateSubHeaderRowView(show_spacing);
-    if (show_spacing) {
-      tri_view->AddView(TriView::Container::START,
-                        TrayPopupUtils::CreateMainImageView());
-    }
+    TriView* tri_view = TrayPopupUtils::CreateSubHeaderRowView(true);
+    tri_view->AddView(TriView::Container::START,
+                      TrayPopupUtils::CreateMainImageView());
     AddChildView(tri_view);
 
     views::Label* label = TrayPopupUtils::CreateDefaultLabel();
diff --git a/ash/system/power/power_status.cc b/ash/system/power/power_status.cc
index 51aec02a..0926b16 100644
--- a/ash/system/power/power_status.cc
+++ b/ash/system/power/power_status.cc
@@ -7,7 +7,6 @@
 #include <algorithm>
 #include <cmath>
 
-#include "ash/public/cpp/ash_features.h"
 #include "ash/public/cpp/power_utils.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/strings/grit/ash_strings.h"
@@ -66,24 +65,19 @@
   void Draw(gfx::Canvas* canvas) override {
     canvas->Save();
     const float dsf = canvas->UndoDeviceScaleFactor();
-    // All constants below are expressed relative to a canvas size of 16. The
-    // actual canvas size (i.e. |size()|) may not be 16.
-    const float kAssumedCanvasSize =
-        features::IsSystemTrayUnifiedEnabled() ? 20 : 16;
+    // All constants below are expressed relative to a canvas size of 20. The
+    // actual canvas size (i.e. |size()|) may not be 20.
+    const float kAssumedCanvasSize = 20;
     const float const_scale = dsf * size().height() / kAssumedCanvasSize;
 
     // The two shapes in this path define the outline of the battery icon.
     SkPath path;
-    gfx::RectF top = features::IsSystemTrayUnifiedEnabled()
-                         ? gfx::RectF(8, 3, 4, 2)
-                         : gfx::RectF(6.5f, 2, 3, 1);
+    gfx::RectF top = gfx::RectF(8, 3, 4, 2);
     top.Scale(const_scale);
     top = gfx::RectF(gfx::ToEnclosingRect(top));
     path.addRect(gfx::RectFToSkRect(top));
 
-    gfx::RectF bottom = features::IsSystemTrayUnifiedEnabled()
-                            ? gfx::RectF(6, 5, 8, 12)
-                            : gfx::RectF(4.5f, 3, 7, 11);
+    gfx::RectF bottom = gfx::RectF(6, 5, 8, 12);
     bottom.Scale(const_scale);
     // Align the top of bottom rect to the bottom of the top one. Otherwise,
     // they may overlap and the top will be too small.
@@ -347,24 +341,17 @@
   info->alert_if_low = !IsLinePowerConnected();
 
   if (!IsUsbChargerConnected() && !IsBatteryPresent()) {
-    info->icon_badge = features::IsSystemTrayUnifiedEnabled()
-                           ? &kUnifiedMenuBatteryXIcon
-                           : &kSystemTrayBatteryXIcon;
+    info->icon_badge = &kUnifiedMenuBatteryXIcon;
     info->charge_percent = 0;
     return;
   }
 
-  if (IsUsbChargerConnected()) {
-    info->icon_badge = features::IsSystemTrayUnifiedEnabled()
-                           ? &kUnifiedMenuBatteryUnreliableIcon
-                           : &kSystemTrayBatteryUnreliableIcon;
-  } else if (IsLinePowerConnected()) {
-    info->icon_badge = features::IsSystemTrayUnifiedEnabled()
-                           ? &kUnifiedMenuBatteryBoltIcon
-                           : &kSystemTrayBatteryBoltIcon;
-  } else {
+  if (IsUsbChargerConnected())
+    info->icon_badge = &kUnifiedMenuBatteryUnreliableIcon;
+  else if (IsLinePowerConnected())
+    info->icon_badge = &kUnifiedMenuBatteryBoltIcon;
+  else
     info->icon_badge = nullptr;
-  }
 
   info->charge_percent = GetBatteryPercent();
 
@@ -372,9 +359,7 @@
   // have a badge assigned.
   if (GetBatteryPercent() < kCriticalBatteryChargePercentage &&
       !info->icon_badge) {
-    info->icon_badge = features::IsSystemTrayUnifiedEnabled()
-                           ? &kUnifiedMenuBatteryAlertIcon
-                           : &kSystemTrayBatteryAlertIcon;
+    info->icon_badge = &kUnifiedMenuBatteryAlertIcon;
   }
 }
 
diff --git a/ash/system/screen_security/screen_security_notification_controller.cc b/ash/system/screen_security/screen_security_notification_controller.cc
index ddeb6f4..97401d6d 100644
--- a/ash/system/screen_security/screen_security_notification_controller.cc
+++ b/ash/system/screen_security/screen_security_notification_controller.cc
@@ -4,7 +4,6 @@
 
 #include "ash/system/screen_security/screen_security_notification_controller.h"
 
-#include "ash/public/cpp/ash_features.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/shell.h"
 #include "ash/strings/grit/ash_strings.h"
@@ -77,8 +76,7 @@
           data, std::move(delegate), kNotificationScreenshareIcon,
           message_center::SystemNotificationWarningLevel::NORMAL);
   notification->SetSystemPriority();
-  if (features::IsSystemTrayUnifiedEnabled())
-    notification->set_pinned(true);
+  notification->set_pinned(true);
   message_center::MessageCenter::Get()->AddNotification(
       std::move(notification));
 }
diff --git a/ash/system/status_area_widget.cc b/ash/system/status_area_widget.cc
index 8e8cb2c..68e0b64 100644
--- a/ash/system/status_area_widget.cc
+++ b/ash/system/status_area_widget.cc
@@ -4,7 +4,6 @@
 
 #include "ash/system/status_area_widget.h"
 
-#include "ash/public/cpp/ash_features.h"
 #include "ash/session/session_controller.h"
 #include "ash/shelf/shelf.h"
 #include "ash/shell.h"
@@ -50,20 +49,8 @@
   overview_button_tray_ = std::make_unique<OverviewButtonTray>(shelf_);
   status_area_widget_delegate_->AddChildView(overview_button_tray_.get());
 
-  if (features::IsSystemTrayUnifiedEnabled()) {
-    unified_system_tray_ = std::make_unique<UnifiedSystemTray>(shelf_);
-    status_area_widget_delegate_->AddChildView(unified_system_tray_.get());
-  } else {
-    system_tray_ = std::make_unique<SystemTray>(shelf_);
-    status_area_widget_delegate_->AddChildView(system_tray_.get());
-  }
-
-  // Must happen after the widget is initialized so the native window exists.
-  if (!features::IsSystemTrayUnifiedEnabled()) {
-    notification_tray_ =
-        std::make_unique<NotificationTray>(shelf_, GetNativeWindow());
-    status_area_widget_delegate_->AddChildView(notification_tray_.get());
-  }
+  unified_system_tray_ = std::make_unique<UnifiedSystemTray>(shelf_);
+  status_area_widget_delegate_->AddChildView(unified_system_tray_.get());
 
   palette_tray_ = std::make_unique<PaletteTray>(shelf_);
   status_area_widget_delegate_->AddChildView(palette_tray_.get());
@@ -93,12 +80,7 @@
   status_area_widget_delegate_->UpdateLayout();
 
   // Initialize after all trays have been created.
-  if (notification_tray_) {
-    system_tray_->InitializeTrayItems(notification_tray_.get());
-    notification_tray_->Initialize();
-  } else {
-    unified_system_tray_->Initialize();
-  }
+  unified_system_tray_->Initialize();
   palette_tray_->Initialize();
   virtual_keyboard_tray_->Initialize();
   ime_menu_tray_->Initialize();
@@ -115,12 +97,6 @@
 }
 
 StatusAreaWidget::~StatusAreaWidget() {
-  if (system_tray_)
-    system_tray_->Shutdown();
-
-  notification_tray_.reset();
-  // Must be destroyed after |notification_tray_|.
-  system_tray_.reset();
   unified_system_tray_.reset();
   ime_menu_tray_.reset();
   select_to_speak_tray_.reset();
@@ -136,12 +112,7 @@
 }
 
 void StatusAreaWidget::UpdateAfterShelfAlignmentChange() {
-  if (system_tray_)
-    system_tray_->UpdateAfterShelfAlignmentChange();
-  if (unified_system_tray_)
-    unified_system_tray_->UpdateAfterShelfAlignmentChange();
-  if (notification_tray_)
-    notification_tray_->UpdateAfterShelfAlignmentChange();
+  unified_system_tray_->UpdateAfterShelfAlignmentChange();
   logout_button_tray_->UpdateAfterShelfAlignmentChange();
   virtual_keyboard_tray_->UpdateAfterShelfAlignmentChange();
   ime_menu_tray_->UpdateAfterShelfAlignmentChange();
@@ -160,19 +131,13 @@
     return;
   login_status_ = login_status;
 
-  if (system_tray_)
-    system_tray_->UpdateAfterLoginStatusChange(login_status);
-  if (unified_system_tray_)
-    unified_system_tray_->UpdateAfterLoginStatusChange();
+  unified_system_tray_->UpdateAfterLoginStatusChange();
   logout_button_tray_->UpdateAfterLoginStatusChange();
   overview_button_tray_->UpdateAfterLoginStatusChange(login_status);
 }
 
 void StatusAreaWidget::SetSystemTrayVisibility(bool visible) {
-  TrayBackgroundView* tray =
-      unified_system_tray_
-          ? static_cast<TrayBackgroundView*>(unified_system_tray_.get())
-          : static_cast<TrayBackgroundView*>(system_tray_.get());
+  TrayBackgroundView* tray = unified_system_tray_.get();
   tray->SetVisible(visible);
   // Opacity is set to prevent flakiness in kiosk browser tests. See
   // https://crbug.com/624584.
@@ -192,43 +157,29 @@
   if (overview_button_tray_->layer()->GetTargetVisibility())
     return overview_button_tray_.get();
 
-  if (unified_system_tray_)
-    return unified_system_tray_.get();
-  return system_tray_.get();
+  return unified_system_tray_.get();
 }
 
 bool StatusAreaWidget::ShouldShowShelf() const {
-  // If UnifiedSystemTray is enabled, and it has main bubble, return true.
-  if (unified_system_tray_ && unified_system_tray_->IsBubbleShown())
+  // If it has main bubble, return true.
+  if (unified_system_tray_->IsBubbleShown())
     return true;
 
-  // If UnifiedSystemTray is enabled, and it has a slider bubble, return false.
-  if (unified_system_tray_ && unified_system_tray_->IsSliderBubbleShown())
+  // If it has a slider bubble, return false.
+  if (unified_system_tray_->IsSliderBubbleShown())
     return false;
 
-  // The system tray bubble may or may not want to force the shelf to be
-  // visible.
-  if (system_tray_ && system_tray_->IsSystemBubbleVisible())
-    return system_tray_->ShouldShowShelf();
-
   // All other tray bubbles will force the shelf to be visible.
   return TrayBubbleView::IsATrayBubbleOpen();
 }
 
 bool StatusAreaWidget::IsMessageBubbleShown() const {
-  return (unified_system_tray_ && unified_system_tray_->IsBubbleShown()) ||
-         (!unified_system_tray_ && system_tray_->IsSystemBubbleVisible()) ||
-         (notification_tray_ && notification_tray_->IsMessageCenterVisible());
+  return unified_system_tray_->IsBubbleShown();
 }
 
 void StatusAreaWidget::SchedulePaint() {
   status_area_widget_delegate_->SchedulePaint();
-  if (notification_tray_)
-    notification_tray_->SchedulePaint();
-  if (system_tray_)
-    system_tray_->SchedulePaint();
-  if (unified_system_tray_)
-    unified_system_tray_->SchedulePaint();
+  unified_system_tray_->SchedulePaint();
   virtual_keyboard_tray_->SchedulePaint();
   logout_button_tray_->SchedulePaint();
   ime_menu_tray_->SchedulePaint();
@@ -254,12 +205,7 @@
 }
 
 void StatusAreaWidget::UpdateShelfItemBackground(SkColor color) {
-  if (notification_tray_)
-    notification_tray_->UpdateShelfItemBackground(color);
-  if (system_tray_)
-    system_tray_->UpdateShelfItemBackground(color);
-  if (unified_system_tray_)
-    unified_system_tray_->UpdateShelfItemBackground(color);
+  unified_system_tray_->UpdateShelfItemBackground(color);
   virtual_keyboard_tray_->UpdateShelfItemBackground(color);
   ime_menu_tray_->UpdateShelfItemBackground(color);
   select_to_speak_tray_->UpdateShelfItemBackground(color);
diff --git a/ash/system/status_area_widget.h b/ash/system/status_area_widget.h
index ce08a7ac..bcbf78d 100644
--- a/ash/system/status_area_widget.h
+++ b/ash/system/status_area_widget.h
@@ -59,19 +59,21 @@
   void SetSystemTrayVisibility(bool visible);
 
   // Get the tray button that the system tray bubble and the notification center
-  // bubble will be anchored. Usually |system_tray_|, but when the overview
-  // button is visible (i.e. tablet mode is enabled), it returns
+  // bubble will be anchored. Usually |unified_system_tray_|, but when the
+  // overview button is visible (i.e. tablet mode is enabled), it returns
   // |overview_button_tray_|.
   TrayBackgroundView* GetSystemTrayAnchor() const;
 
   StatusAreaWidgetDelegate* status_area_widget_delegate() {
     return status_area_widget_delegate_;
   }
-  SystemTray* system_tray() { return system_tray_.get(); }
+  // TODO(tetsui): Remove this getter.  https://crbug.com/898419
+  SystemTray* system_tray() { return nullptr; }
   UnifiedSystemTray* unified_system_tray() {
     return unified_system_tray_.get();
   }
-  NotificationTray* notification_tray() { return notification_tray_.get(); }
+  // TODO(tetsui): Remove this getter.  https://crbug.com/898419
+  NotificationTray* notification_tray() { return nullptr; }
   DictationButtonTray* dictation_button_tray() {
     return dictation_button_tray_.get();
   }
@@ -129,9 +131,7 @@
 
   std::unique_ptr<OverviewButtonTray> overview_button_tray_;
   std::unique_ptr<DictationButtonTray> dictation_button_tray_;
-  std::unique_ptr<SystemTray> system_tray_;
   std::unique_ptr<UnifiedSystemTray> unified_system_tray_;
-  std::unique_ptr<NotificationTray> notification_tray_;
   std::unique_ptr<LogoutButtonTray> logout_button_tray_;
   std::unique_ptr<PaletteTray> palette_tray_;
   std::unique_ptr<VirtualKeyboardTray> virtual_keyboard_tray_;
diff --git a/ash/system/status_area_widget_delegate.cc b/ash/system/status_area_widget_delegate.cc
index ee71a21..12f08e9 100644
--- a/ash/system/status_area_widget_delegate.cc
+++ b/ash/system/status_area_widget_delegate.cc
@@ -5,7 +5,6 @@
 #include "ash/system/status_area_widget_delegate.h"
 
 #include "ash/focus_cycler.h"
-#include "ash/public/cpp/ash_features.h"
 #include "ash/root_window_controller.h"
 #include "ash/session/session_controller.h"
 #include "ash/shelf/shelf.h"
@@ -27,8 +26,6 @@
 
 constexpr int kAnimationDurationMs = 250;
 
-constexpr int kPaddingFromEdgeOfShelf = 3;
-
 constexpr int kPaddingBetweenWidgetsNewUi = 8;
 
 class StatusAreaWidgetDelegateAnimationSettings
@@ -203,16 +200,9 @@
   int top_edge = vertical_padding;
   int left_edge = 0;
   int bottom_edge = vertical_padding;
-  int right_edge =
-      !features::IsSystemTrayUnifiedEnabled() && extend_border_to_edge
-          ? kPaddingFromEdgeOfShelf
-          : 0;
-
-  // Since all corners are rounded, add some extra space so that borders
-  // don't overlap. This padding between items also takes care of padding
-  // at the edge of the shelf.
-  right_edge = kPaddingBetweenWidgetsNewUi;
-  left_edge = 0;
+  // Add some extra space so that borders don't overlap. This padding between
+  // items also takes care of padding at the edge of the shelf.
+  int right_edge = kPaddingBetweenWidgetsNewUi;
 
   // Swap edges if alignment is not horizontal (bottom-to-top).
   if (!shelf_->IsHorizontalAlignment()) {
diff --git a/ash/system/status_area_widget_unittest.cc b/ash/system/status_area_widget_unittest.cc
index 1f21bf39..56f9cd3 100644
--- a/ash/system/status_area_widget_unittest.cc
+++ b/ash/system/status_area_widget_unittest.cc
@@ -5,7 +5,6 @@
 #include "ash/system/status_area_widget.h"
 
 #include "ash/focus_cycler.h"
-#include "ash/public/cpp/ash_features.h"
 #include "ash/public/cpp/ash_switches.h"
 #include "ash/session/session_controller.h"
 #include "ash/session/test_session_controller_client.h"
@@ -54,12 +53,7 @@
 
   // Default trays are constructed.
   EXPECT_TRUE(status->overview_button_tray());
-  if (features::IsSystemTrayUnifiedEnabled()) {
-    EXPECT_TRUE(status->unified_system_tray());
-  } else {
-    EXPECT_TRUE(status->system_tray());
-    EXPECT_TRUE(status->notification_tray());
-  }
+  EXPECT_TRUE(status->unified_system_tray());
   EXPECT_TRUE(status->logout_button_tray_for_testing());
   EXPECT_TRUE(status->ime_menu_tray());
   EXPECT_TRUE(status->virtual_keyboard_tray_for_testing());
@@ -71,12 +65,7 @@
 
   // Default trays are visible.
   EXPECT_FALSE(status->overview_button_tray()->visible());
-  if (features::IsSystemTrayUnifiedEnabled()) {
-    EXPECT_TRUE(status->unified_system_tray()->visible());
-  } else {
-    EXPECT_TRUE(status->system_tray()->visible());
-    EXPECT_TRUE(status->notification_tray()->visible());
-  }
+  EXPECT_TRUE(status->unified_system_tray()->visible());
   EXPECT_FALSE(status->logout_button_tray_for_testing()->visible());
   EXPECT_FALSE(status->ime_menu_tray()->visible());
   EXPECT_FALSE(status->virtual_keyboard_tray_for_testing()->visible());
@@ -142,72 +131,7 @@
 
 // Tests that tab traversal through status area widget in non-active session
 // could properly send FocusOut event.
-TEST_F(StatusAreaWidgetFocusTest, FocusOutObserver) {
-  // This is old SystemTray version.
-  if (features::IsSystemTrayUnifiedEnabled())
-    return;
-
-  // Set session state to LOCKED.
-  SessionController* session = Shell::Get()->session_controller();
-  ASSERT_TRUE(session->IsActiveUserSessionStarted());
-  TestSessionControllerClient* client = GetSessionControllerClient();
-  client->SetSessionState(SessionState::LOCKED);
-  ASSERT_TRUE(session->IsScreenLocked());
-
-  StatusAreaWidget* status = StatusAreaWidgetTestHelper::GetStatusAreaWidget();
-  // Default trays are constructed.
-  ASSERT_TRUE(status->overview_button_tray());
-  ASSERT_TRUE(status->system_tray());
-  ASSERT_TRUE(status->notification_tray());
-  ASSERT_TRUE(status->logout_button_tray_for_testing());
-  ASSERT_TRUE(status->ime_menu_tray());
-  ASSERT_TRUE(status->virtual_keyboard_tray_for_testing());
-
-  // Needed because NotificationTray updates its initial visibility
-  // asynchronously.
-  base::RunLoop().RunUntilIdle();
-
-  // Default trays are visible.
-  ASSERT_FALSE(status->overview_button_tray()->visible());
-  ASSERT_TRUE(status->system_tray()->visible());
-  ASSERT_TRUE(status->notification_tray()->visible());
-  ASSERT_FALSE(status->logout_button_tray_for_testing()->visible());
-  ASSERT_FALSE(status->ime_menu_tray()->visible());
-  ASSERT_FALSE(status->virtual_keyboard_tray_for_testing()->visible());
-
-  // Set focus to status area widget, which will be be system tray.
-  ASSERT_TRUE(Shell::Get()->focus_cycler()->FocusWidget(status));
-  views::FocusManager* focus_manager = status->GetFocusManager();
-  EXPECT_EQ(status->system_tray(), focus_manager->GetFocusedView());
-
-  // A tab key event will move focus to notification tray.
-  GenerateTabEvent(false);
-  EXPECT_EQ(status->notification_tray(), focus_manager->GetFocusedView());
-  EXPECT_EQ(0, test_observer_->focus_out_count());
-  EXPECT_EQ(0, test_observer_->reverse_focus_out_count());
-
-  // Another tab key event will send FocusOut event, since we are not handling
-  // this event, focus will still be moved to system tray.
-  GenerateTabEvent(false);
-  EXPECT_EQ(status->system_tray(), focus_manager->GetFocusedView());
-  EXPECT_EQ(1, test_observer_->focus_out_count());
-  EXPECT_EQ(0, test_observer_->reverse_focus_out_count());
-
-  // A reverse tab key event will send reverse FocusOut event, since we are not
-  // handling this event, focus will still be moved to notification tray.
-  GenerateTabEvent(true);
-  EXPECT_EQ(status->notification_tray(), focus_manager->GetFocusedView());
-  EXPECT_EQ(1, test_observer_->focus_out_count());
-  EXPECT_EQ(1, test_observer_->reverse_focus_out_count());
-}
-
-// Tests that tab traversal through status area widget in non-active session
-// could properly send FocusOut event.
 TEST_F(StatusAreaWidgetFocusTest, FocusOutObserverUnified) {
-  // This is UnifiedSystemTray version.
-  if (!features::IsSystemTrayUnifiedEnabled())
-    return;
-
   // Set session state to LOCKED.
   SessionController* session = Shell::Get()->session_controller();
   ASSERT_TRUE(session->IsActiveUserSessionStarted());
diff --git a/ash/system/system_notification_controller.cc b/ash/system/system_notification_controller.cc
index 5335e64..54760de 100644
--- a/ash/system/system_notification_controller.cc
+++ b/ash/system/system_notification_controller.cc
@@ -4,7 +4,6 @@
 
 #include "ash/system/system_notification_controller.h"
 
-#include "ash/public/cpp/ash_features.h"
 #include "ash/system/caps_lock_notification_controller.h"
 #include "ash/system/cast/cast_notification_controller.h"
 #include "ash/system/network/auto_connect_notifier.h"
@@ -29,12 +28,8 @@
           std::make_unique<ScreenSecurityNotificationController>()),
       session_limit_(std::make_unique<SessionLimitNotificationController>()),
       supervised_(std::make_unique<SupervisedNotificationController>()),
-      tracing_(features::IsSystemTrayUnifiedEnabled()
-                   ? std::make_unique<TracingNotificationController>()
-                   : nullptr),
-      update_(features::IsSystemTrayUnifiedEnabled()
-                  ? std::make_unique<UpdateNotificationController>()
-                  : nullptr),
+      tracing_(std::make_unique<TracingNotificationController>()),
+      update_(std::make_unique<UpdateNotificationController>()),
       wifi_toggle_(std::make_unique<WifiToggleNotificationController>()) {}
 
 SystemNotificationController::~SystemNotificationController() = default;
diff --git a/ash/system/tracing_notification_controller.cc b/ash/system/tracing_notification_controller.cc
index 4719bbf..aec8cf20 100644
--- a/ash/system/tracing_notification_controller.cc
+++ b/ash/system/tracing_notification_controller.cc
@@ -4,7 +4,6 @@
 
 #include "ash/system/tracing_notification_controller.h"
 
-#include "ash/public/cpp/ash_features.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/shell.h"
 #include "ash/strings/grit/ash_strings.h"
@@ -35,7 +34,6 @@
 
 TracingNotificationController::TracingNotificationController()
     : model_(Shell::Get()->system_tray_model()->tracing()) {
-  DCHECK(features::IsSystemTrayUnifiedEnabled());
   model_->AddObserver(this);
   OnTracingModeChanged();
 }
diff --git a/ash/system/tray/hover_highlight_view.cc b/ash/system/tray/hover_highlight_view.cc
index 76a4407..fee86d71 100644
--- a/ash/system/tray/hover_highlight_view.cc
+++ b/ash/system/tray/hover_highlight_view.cc
@@ -4,7 +4,6 @@
 
 #include "ash/system/tray/hover_highlight_view.h"
 
-#include "ash/public/cpp/ash_features.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/system/tray/tray_constants.h"
 #include "ash/system/tray/tray_popup_utils.h"
@@ -21,7 +20,7 @@
 namespace ash {
 
 HoverHighlightView::HoverHighlightView(ViewClickListener* listener)
-    : HoverHighlightView(listener, features::IsSystemTrayUnifiedEnabled()) {}
+    : HoverHighlightView(listener, true) {}
 
 HoverHighlightView::HoverHighlightView(ViewClickListener* listener,
                                        bool use_unified_theme)
diff --git a/ash/system/tray/tray_constants.cc b/ash/system/tray/tray_constants.cc
index a6a7a239..e7feb3ed 100644
--- a/ash/system/tray/tray_constants.cc
+++ b/ash/system/tray/tray_constants.cc
@@ -4,7 +4,6 @@
 
 #include "ash/system/tray/tray_constants.h"
 
-#include "ash/public/cpp/ash_features.h"
 #include "base/logging.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/gfx/color_palette.h"
@@ -87,8 +86,7 @@
 
 // static
 int TrayConstants::GetTrayIconSize() {
-  return features::IsSystemTrayUnifiedEnabled() ? kUnifiedTrayIconSize
-                                                : kTrayIconSize;
+  return kUnifiedTrayIconSize;
 }
 
 }  // namespace ash
diff --git a/ash/system/tray/tray_constants.h b/ash/system/tray/tray_constants.h
index 6bb0c41..cf3731a8 100644
--- a/ash/system/tray/tray_constants.h
+++ b/ash/system/tray/tray_constants.h
@@ -237,6 +237,7 @@
 constexpr gfx::Insets kUnifiedDetailedViewTitlePadding(0, 0, 0, 16);
 constexpr int kUnifiedDetailedViewTitleRowHeight = 64;
 
+// TODO(tetsui): Remove this class.
 class TrayConstants {
  public:
   // Returns the width of a line used to separate tray items in the shelf.
diff --git a/ash/system/tray/tray_container.cc b/ash/system/tray/tray_container.cc
index f871a6c..be32e7f 100644
--- a/ash/system/tray/tray_container.cc
+++ b/ash/system/tray/tray_container.cc
@@ -6,7 +6,6 @@
 
 #include <utility>
 
-#include "ash/public/cpp/ash_features.h"
 #include "ash/shelf/shelf.h"
 #include "ash/system/tray/tray_constants.h"
 #include "ui/gfx/geometry/insets.h"
@@ -86,8 +85,7 @@
 
   auto layout = std::make_unique<views::BoxLayout>(
       orientation, gfx::Insets(vertical_margin, horizontal_margin),
-      features::IsSystemTrayUnifiedEnabled() ? kUnifiedTraySpacingBetweenIcons
-                                             : 0);
+      kUnifiedTraySpacingBetweenIcons);
   layout->set_minimum_cross_axis_size(kTrayItemSize);
   views::View::SetLayoutManager(std::move(layout));
 
diff --git a/ash/system/tray/tray_detailed_view.cc b/ash/system/tray/tray_detailed_view.cc
index cc3c99e..f7573f7 100644
--- a/ash/system/tray/tray_detailed_view.cc
+++ b/ash/system/tray/tray_detailed_view.cc
@@ -4,7 +4,6 @@
 
 #include "ash/system/tray/tray_detailed_view.h"
 
-#include "ash/public/cpp/ash_features.h"
 #include "ash/public/cpp/ash_view_ids.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/system/tray/detailed_view_delegate.h"
@@ -372,8 +371,7 @@
 
 TriView* TrayDetailedView::AddScrollListSubHeader(const gfx::VectorIcon& icon,
                                                   int text_id) {
-  TriView* header = TrayPopupUtils::CreateSubHeaderRowView(
-      features::IsSystemTrayUnifiedEnabled() || !icon.is_empty());
+  TriView* header = TrayPopupUtils::CreateSubHeaderRowView(true);
   TrayPopupUtils::ConfigureAsStickyHeader(header);
 
   views::Label* label = TrayPopupUtils::CreateDefaultLabel();
@@ -382,13 +380,11 @@
   style.SetupLabel(label);
   header->AddView(TriView::Container::CENTER, label);
 
-  if (features::IsSystemTrayUnifiedEnabled() || !icon.is_empty()) {
-    views::ImageView* image_view = TrayPopupUtils::CreateMainImageView();
-    image_view->SetImage(gfx::CreateVectorIcon(
-        icon, GetNativeTheme()->GetSystemColor(
-                  ui::NativeTheme::kColorId_ProminentButtonColor)));
-    header->AddView(TriView::Container::START, image_view);
-  }
+  views::ImageView* image_view = TrayPopupUtils::CreateMainImageView();
+  image_view->SetImage(gfx::CreateVectorIcon(
+      icon, GetNativeTheme()->GetSystemColor(
+                ui::NativeTheme::kColorId_ProminentButtonColor)));
+  header->AddView(TriView::Container::START, image_view);
 
   scroll_content_->AddChildView(header);
   return header;
diff --git a/ash/system/tray/tray_event_filter_unittest.cc b/ash/system/tray/tray_event_filter_unittest.cc
index cb837e3..6d98c8e8 100644
--- a/ash/system/tray/tray_event_filter_unittest.cc
+++ b/ash/system/tray/tray_event_filter_unittest.cc
@@ -4,11 +4,9 @@
 
 #include "ash/system/tray/tray_event_filter.h"
 
-#include "ash/public/cpp/ash_features.h"
 #include "ash/root_window_controller.h"
 #include "ash/shell.h"
 #include "ash/system/status_area_widget.h"
-#include "ash/system/tray/system_tray.h"
 #include "ash/system/unified/unified_system_tray.h"
 #include "ash/test/ash_test_base.h"
 #include "base/macros.h"
@@ -41,37 +39,19 @@
 
  protected:
   void ShowSystemTrayMainView() {
-    if (features::IsSystemTrayUnifiedEnabled()) {
-      GetPrimaryUnifiedSystemTray()->ShowBubble(false /* show_by_click */);
-    } else {
-      GetPrimarySystemTray()->ShowDefaultView(BUBBLE_CREATE_NEW,
-                                              false /* show_by_click */);
-    }
+    GetPrimaryUnifiedSystemTray()->ShowBubble(false /* show_by_click */);
   }
 
   bool IsBubbleShown() {
-    if (features::IsSystemTrayUnifiedEnabled()) {
-      return GetPrimaryUnifiedSystemTray()->IsBubbleShown();
-    } else {
-      return GetPrimarySystemTray()->HasSystemBubble() &&
-             GetPrimarySystemTray()->IsSystemBubbleVisible();
-    }
+    return GetPrimaryUnifiedSystemTray()->IsBubbleShown();
   }
 
   gfx::Rect GetSystemTrayBoundsInScreen() {
-    if (features::IsSystemTrayUnifiedEnabled()) {
-      return GetPrimaryUnifiedSystemTray()->GetBubbleBoundsInScreen();
-    } else {
-      return GetPrimarySystemTray()->GetBoundsInScreen();
-    }
+    return GetPrimaryUnifiedSystemTray()->GetBubbleBoundsInScreen();
   }
 
   TrayEventFilter* GetTrayEventFilter() {
-    if (features::IsSystemTrayUnifiedEnabled()) {
-      return GetPrimaryUnifiedSystemTray()->tray_event_filter();
-    } else {
-      return GetPrimarySystemTray()->tray_event_filter();
-    }
+    return GetPrimaryUnifiedSystemTray()->tray_event_filter();
   }
 
   UnifiedSystemTray* GetPrimaryUnifiedSystemTray() {
diff --git a/ash/system/tray/tray_popup_item_style.cc b/ash/system/tray/tray_popup_item_style.cc
index 20c083b..971c42e 100644
--- a/ash/system/tray/tray_popup_item_style.cc
+++ b/ash/system/tray/tray_popup_item_style.cc
@@ -4,7 +4,6 @@
 
 #include "ash/system/tray/tray_popup_item_style.h"
 
-#include "ash/public/cpp/ash_features.h"
 #include "ash/system/tray/tray_constants.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/gfx/color_palette.h"
@@ -41,7 +40,7 @@
 }
 
 TrayPopupItemStyle::TrayPopupItemStyle(FontStyle font_style)
-    : TrayPopupItemStyle(font_style, features::IsSystemTrayUnifiedEnabled()) {}
+    : TrayPopupItemStyle(font_style, true) {}
 
 TrayPopupItemStyle::TrayPopupItemStyle(FontStyle font_style,
                                        bool use_unified_theme)
@@ -80,8 +79,7 @@
 
 void TrayPopupItemStyle::SetupLabel(views::Label* label) const {
   label->SetEnabledColor(GetTextColor());
-  if (features::IsSystemTrayUnifiedEnabled())
-    label->SetAutoColorReadabilityEnabled(false);
+  label->SetAutoColorReadabilityEnabled(false);
 
   const gfx::FontList& base_font_list = views::Label::GetDefaultFontList();
   switch (font_style_) {
diff --git a/ash/system/tray/tray_popup_utils.cc b/ash/system/tray/tray_popup_utils.cc
index e6176683..7739f9e 100644
--- a/ash/system/tray/tray_popup_utils.cc
+++ b/ash/system/tray/tray_popup_utils.cc
@@ -9,7 +9,6 @@
 #include <utility>
 
 #include "ash/public/cpp/ash_constants.h"
-#include "ash/public/cpp/ash_features.h"
 #include "ash/public/cpp/ash_view_ids.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/session/session_controller.h"
@@ -21,14 +20,11 @@
 #include "ui/gfx/color_palette.h"
 #include "ui/gfx/geometry/insets.h"
 #include "ui/gfx/paint_vector_icon.h"
-#include "ui/native_theme/native_theme.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"
 #include "ui/views/animation/ink_drop_mask.h"
 #include "ui/views/animation/square_ink_drop_ripple.h"
-#include "ui/views/background.h"
-#include "ui/views/border.h"
 #include "ui/views/controls/button/button.h"
 #include "ui/views/controls/button/md_text_button.h"
 #include "ui/views/controls/button/toggle_button.h"
@@ -160,15 +156,7 @@
 views::Label* TrayPopupUtils::CreateDefaultLabel() {
   views::Label* label = new views::Label();
   label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
-  if (features::IsSystemTrayUnifiedEnabled()) {
-    label->SetSubpixelRenderingEnabled(false);
-  } else {
-    // Frequently the label will paint to a layer that's non-opaque, so subpixel
-    // rendering won't work unless we explicitly set a background. See
-    // https://crbug.com/686363
-    label->SetBackground(views::CreateThemedSolidBackground(
-        label, ui::NativeTheme::kColorId_BubbleBackground));
-  }
+  label->SetSubpixelRenderingEnabled(false);
   return label;
 }
 
@@ -226,11 +214,6 @@
 
 void TrayPopupUtils::ConfigureAsStickyHeader(views::View* view) {
   view->set_id(VIEW_ID_STICKY_HEADER);
-
-  if (!features::IsSystemTrayUnifiedEnabled()) {
-    view->SetBackground(views::CreateThemedSolidBackground(
-        view, ui::NativeTheme::kColorId_BubbleBackground));
-  }
   view->SetBorder(
       views::CreateEmptyBorder(gfx::Insets(kMenuSeparatorVerticalPadding, 0)));
   view->SetPaintToLayer();
diff --git a/ash/system/unified/unified_system_tray_unittest.cc b/ash/system/unified/unified_system_tray_unittest.cc
index c28c11c..cb2d025 100644
--- a/ash/system/unified/unified_system_tray_unittest.cc
+++ b/ash/system/unified/unified_system_tray_unittest.cc
@@ -4,7 +4,6 @@
 
 #include "ash/system/unified/unified_system_tray.h"
 
-#include "ash/public/cpp/ash_features.h"
 #include "ash/system/status_area_widget.h"
 #include "ash/system/status_area_widget_test_helper.h"
 #include "ash/system/unified/unified_slider_bubble_controller.h"
@@ -33,9 +32,6 @@
 };
 
 TEST_F(UnifiedSystemTrayTest, ShowVolumeSliderBubble) {
-  if (!features::IsSystemTrayUnifiedEnabled())
-    return;
-
   // The volume popup is not visible initially.
   EXPECT_FALSE(IsSliderBubbleShown());
 
diff --git a/ash/system/update/update_notification_controller.cc b/ash/system/update/update_notification_controller.cc
index 2c76b79..4580fbb 100644
--- a/ash/system/update/update_notification_controller.cc
+++ b/ash/system/update/update_notification_controller.cc
@@ -4,7 +4,6 @@
 
 #include "ash/system/update/update_notification_controller.h"
 
-#include "ash/public/cpp/ash_features.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/shell.h"
 #include "ash/strings/grit/ash_strings.h"
@@ -29,7 +28,6 @@
 
 UpdateNotificationController::UpdateNotificationController()
     : model_(Shell::Get()->system_tray_model()->update_model()) {
-  DCHECK(features::IsSystemTrayUnifiedEnabled());
   model_->AddObserver(this);
   OnUpdateAvailable();
 }
diff --git a/ash/test/ash_test_helper.cc b/ash/test/ash_test_helper.cc
index dd1c79a..e51f421 100644
--- a/ash/test/ash_test_helper.cc
+++ b/ash/test/ash_test_helper.cc
@@ -53,7 +53,6 @@
 #include "ui/base/ime/input_method_initializer.h"
 #include "ui/base/material_design/material_design_controller.h"
 #include "ui/base/platform_window_defaults.h"
-#include "ui/base/test/material_design_controller_test_api.h"
 #include "ui/base/ui_base_features.h"
 #include "ui/base/ui_base_switches_util.h"
 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
@@ -279,9 +278,6 @@
   // last cursor visibility state, etc.
   ::wm::CursorManager::ResetCursorVisibilityStateForTest();
 
-  // ContentTestSuiteBase might have already initialized
-  // MaterialDesignController in unit_tests suite.
-  ui::test::MaterialDesignControllerTestAPI::Uninitialize();
   ui::MaterialDesignController::Initialize();
 
   CreateShell();
diff --git a/ash/wm/overview/scoped_transform_overview_window.cc b/ash/wm/overview/scoped_transform_overview_window.cc
index 2ce0906..f5d66b8 100644
--- a/ash/wm/overview/scoped_transform_overview_window.cc
+++ b/ash/wm/overview/scoped_transform_overview_window.cc
@@ -181,6 +181,7 @@
       window_(window),
       ignored_by_shelf_(wm::GetWindowState(window)->ignored_by_shelf()),
       original_opacity_(window->layer()->GetTargetOpacity()),
+      original_mask_layer_(window_->layer()->layer_mask_layer()),
       weak_ptr_factory_(this) {
   type_ = GetWindowDimensionsType(window);
 }
@@ -215,7 +216,6 @@
     Shell::Get()->shadow_controller()->UpdateShadowForWindow(window_);
   wm::GetWindowState(window_)->set_ignored_by_shelf(ignored_by_shelf_);
   if (minimized_widget_) {
-    mask_.reset();
     // Fade out the minimized widget. This animation continues past the
     // lifetime of |this|.
     FadeOutWidgetAndMaybeSlideOnExit(
@@ -247,6 +247,7 @@
   ScopedOverviewAnimationSettings animation_settings(
       selector_item_->GetExitOverviewAnimationType(), window_);
   SetOpacity(original_opacity_);
+  window_->layer()->SetMaskLayer(original_mask_layer_);
 }
 
 void ScopedTransformOverviewWindow::BeginScopedAnimation(
@@ -257,15 +258,8 @@
 
   // Remove the mask before animating because masks affect animation
   // performance. Observe the animation and add the mask after animating if the
-  // animation type is layouting selector items.
-  mask_.reset();
-  selector_item_->SetShadowBounds(base::nullopt);
-  selector_item_->DisableBackdrop();
-
-  if (window_->GetProperty(aura::client::kShowStateKey) !=
-      ui::SHOW_STATE_MINIMIZED) {
-    window_->layer()->SetMaskLayer(original_mask_layer_);
-  }
+  // animation type is layouting selector items during overview.
+  selector_item_->UpdateMaskAndShadow(/*show=*/false);
 
   for (auto* window : wm::GetTransientTreeIterator(GetOverviewWindow())) {
     auto settings = std::make_unique<ScopedOverviewAnimationSettings>(
@@ -284,12 +278,10 @@
     animation_settings->push_back(std::move(settings));
   }
 
-  const bool is_layout_animation =
-      animation_type == OVERVIEW_ANIMATION_LAY_OUT_SELECTOR_ITEMS_ON_ENTER ||
-      animation_type == OVERVIEW_ANIMATION_LAY_OUT_SELECTOR_ITEMS_IN_OVERVIEW ||
-      animation_type == OVERVIEW_ANIMATION_LAY_OUT_SELECTOR_ITEMS_ON_EXIT;
-  if (is_layout_animation && animation_settings->size() > 0u)
+  if (animation_type == OVERVIEW_ANIMATION_LAY_OUT_SELECTOR_ITEMS_IN_OVERVIEW &&
+      animation_settings->size() > 0u) {
     animation_settings->front()->AddObserver(this);
+  }
 }
 
 bool ScopedTransformOverviewWindow::Contains(const aura::Window* target) const {
@@ -414,6 +406,7 @@
     CloseWidget();
     return;
   }
+
   base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
       FROM_HERE, base::Bind(&ScopedTransformOverviewWindow::CloseWidget,
                             weak_ptr_factory_.GetWeakPtr()),
@@ -441,11 +434,6 @@
           std::make_unique<LayerCachingAndFilteringObserver>(window->layer()));
     }
   }
-
-  // Apply rounded edge mask. Windows which are animated into overview mode
-  // will have their mask removed before the animation begins and reapplied
-  // after the animation ends.
-  CreateAndApplyMaskAndShadow();
 }
 
 void ScopedTransformOverviewWindow::CloseWidget() {
@@ -479,6 +467,24 @@
   window_selector_bounds_.reset();
 }
 
+void ScopedTransformOverviewWindow::UpdateMask(bool show) {
+  if (!show) {
+    mask_.reset();
+    return;
+  }
+
+  // Add the mask which gives the window selector items rounded corners, and add
+  // the shadow around the window.
+  ui::Layer* layer = minimized_widget_
+                         ? minimized_widget_->GetNativeWindow()->layer()
+                         : window_->layer();
+
+  mask_ = std::make_unique<WindowMask>(GetOverviewWindow());
+  mask_->layer()->SetBounds(layer->bounds());
+  mask_->set_top_inset(GetTopInset());
+  layer->SetMaskLayer(mask_->layer());
+}
+
 void ScopedTransformOverviewWindow::CancelAnimationsListener() {
   StopObservingImplicitAnimations();
 }
@@ -502,7 +508,7 @@
 }
 
 void ScopedTransformOverviewWindow::OnImplicitAnimationsCompleted() {
-  CreateAndApplyMaskAndShadow();
+  selector_item_->UpdateMaskAndShadow(/*show=*/true);
   selector_item_->OnDragAnimationCompleted();
 }
 
@@ -545,28 +551,4 @@
       /*slide=*/false);
 }
 
-void ScopedTransformOverviewWindow::CreateAndApplyMaskAndShadow() {
-  // Add the mask which gives the window selector items rounded corners, and add
-  // the shadow around the window.
-  ui::Layer* layer = minimized_widget_
-                         ? minimized_widget_->GetNativeWindow()->layer()
-                         : window_->layer();
-
-  if (!minimized_widget_)
-    original_mask_layer_ = window_->layer()->layer_mask_layer();
-
-  mask_ = std::make_unique<WindowMask>(GetOverviewWindow());
-  mask_->layer()->SetBounds(layer->bounds());
-  mask_->set_top_inset(GetTopInset());
-  layer->SetMaskLayer(mask_->layer());
-  // Do not apply the shadow for the drop target in overview.
-  if (selector_item_->window_grid()->IsDropTargetWindow(window_)) {
-    selector_item_->SetShadowBounds(base::nullopt);
-  } else {
-    selector_item_->SetShadowBounds(
-        base::make_optional(GetTransformedBounds()));
-    selector_item_->EnableBackdropIfNeeded();
-  }
-}
-
 }  // namespace ash
diff --git a/ash/wm/overview/scoped_transform_overview_window.h b/ash/wm/overview/scoped_transform_overview_window.h
index f2126a24..088b37ec 100644
--- a/ash/wm/overview/scoped_transform_overview_window.h
+++ b/ash/wm/overview/scoped_transform_overview_window.h
@@ -164,6 +164,10 @@
   // change. Must be called before PositionWindows in WindowGrid.
   void UpdateWindowDimensionsType();
 
+  // Updates the mask which gives rounded corners on the windows. Shows the mask
+  // if |show| is true, otherwise removes it.
+  void UpdateMask(bool show);
+
   // Stop listening to any animations to finish.
   void CancelAnimationsListener();
 
@@ -186,10 +190,6 @@
 
   void CreateMirrorWindowForMinimizedState();
 
-  // Creates and applys a mask which adds rounded edges to windows in overview
-  // mode.
-  void CreateAndApplyMaskAndShadow();
-
   // Makes Close() execute synchronously when used in tests.
   static void SetImmediateCloseForTests();
 
diff --git a/ash/wm/overview/start_animation_observer.h b/ash/wm/overview/start_animation_observer.h
index 7780e96..98382a6 100644
--- a/ash/wm/overview/start_animation_observer.h
+++ b/ash/wm/overview/start_animation_observer.h
@@ -35,4 +35,4 @@
 
 }  // namespace ash
 
-#endif  // ASH_WM_OVERVIEW_START_ANIMATION_OBSERVER_H_
+#endif  // ASH_WM_OVERVIEW_START_ANIMATION_OBSERVER_H_
\ No newline at end of file
diff --git a/ash/wm/overview/window_selector.cc b/ash/wm/overview/window_selector.cc
index 0243024c..8201488 100644
--- a/ash/wm/overview/window_selector.cc
+++ b/ash/wm/overview/window_selector.cc
@@ -740,6 +740,13 @@
     grid->UpdateYPositionAndOpacity(new_y, opacity, work_area, callback);
 }
 
+void WindowSelector::UpdateMaskAndShadow(bool show) {
+  for (auto& grid : grid_list_) {
+    for (auto& window : grid->window_list())
+      window->UpdateMaskAndShadow(show);
+  }
+}
+
 void WindowSelector::OnDisplayRemoved(const display::Display& display) {
   // TODO(flackr): Keep window selection active on remaining displays.
   CancelSelection();
diff --git a/ash/wm/overview/window_selector.h b/ash/wm/overview/window_selector.h
index 4156fdc0..9c3b7af 100644
--- a/ash/wm/overview/window_selector.h
+++ b/ash/wm/overview/window_selector.h
@@ -214,6 +214,9 @@
       const gfx::Rect& work_area,
       UpdateAnimationSettingsCallback callback);
 
+  // Shows or hides all the window selector items' mask and shadow.
+  void UpdateMaskAndShadow(bool show);
+
   WindowSelectorDelegate* delegate() { return delegate_; }
 
   SplitViewDragIndicators* split_view_drag_indicators() {
diff --git a/ash/wm/overview/window_selector_controller.cc b/ash/wm/overview/window_selector_controller.cc
index 0e81821..8125ca6 100644
--- a/ash/wm/overview/window_selector_controller.cc
+++ b/ash/wm/overview/window_selector_controller.cc
@@ -343,7 +343,7 @@
 }
 
 bool WindowSelectorController::IsSelecting() const {
-  return window_selector_.get() != nullptr;
+  return window_selector_ != nullptr;
 }
 
 bool WindowSelectorController::IsCompletingShutdownAnimations() {
@@ -488,6 +488,7 @@
   is_shutting_down_ = true;
   Shell::Get()->NotifyOverviewModeEnding();
   auto* window_selector = window_selector_.release();
+  window_selector->UpdateMaskAndShadow(/*show=*/false);
   window_selector->Shutdown();
   // There may be no delayed animations in tests, so unblur right away.
   if (delayed_animations_.empty() && IsBlurAllowed())
@@ -536,6 +537,7 @@
   if (!previous_empty && start_animations_.empty()) {
     Shell::Get()->NotifyOverviewModeStartingAnimationComplete(
         /*canceled=*/false);
+    window_selector_->UpdateMaskAndShadow(/*show=*/true);
   }
 }
 
diff --git a/ash/wm/overview/window_selector_item.cc b/ash/wm/overview/window_selector_item.cc
index f2cc56e..18180b4 100644
--- a/ash/wm/overview/window_selector_item.cc
+++ b/ash/wm/overview/window_selector_item.cc
@@ -1026,6 +1026,20 @@
   shadow_->SetContentBounds(bounds_in_item);
 }
 
+void WindowSelectorItem::UpdateMaskAndShadow(bool show) {
+  transform_window_.UpdateMask(show);
+
+  // Do not apply the shadow for the drop target in overview.
+  if (!show || window_grid_->IsDropTargetWindow(GetWindow())) {
+    SetShadowBounds(base::nullopt);
+    DisableBackdrop();
+    return;
+  }
+
+  SetShadowBounds(transform_window_.GetTransformedBounds());
+  EnableBackdropIfNeeded();
+}
+
 void WindowSelectorItem::SetOpacity(float opacity) {
   item_widget_->SetOpacity(opacity);
   transform_window_.SetOpacity(opacity);
diff --git a/ash/wm/overview/window_selector_item.h b/ash/wm/overview/window_selector_item.h
index 5e7e701e..4f19356 100644
--- a/ash/wm/overview/window_selector_item.h
+++ b/ash/wm/overview/window_selector_item.h
@@ -233,6 +233,9 @@
   // the shadow is hidden.
   void SetShadowBounds(base::Optional<gfx::Rect> bounds_in_screen);
 
+  // Show or hide the mask and shadow on this window item.
+  void UpdateMaskAndShadow(bool show);
+
   // Changes the opacity of all the windows the item owns.
   void SetOpacity(float opacity);
   float GetOpacity();
diff --git a/ash/wm/overview/window_selector_unittest.cc b/ash/wm/overview/window_selector_unittest.cc
index 98bb2de..293e5f3 100644
--- a/ash/wm/overview/window_selector_unittest.cc
+++ b/ash/wm/overview/window_selector_unittest.cc
@@ -25,7 +25,6 @@
 #include "ash/shelf/shelf_view_test_api.h"
 #include "ash/shell.h"
 #include "ash/shell_test_api.h"
-#include "ash/system/tray/system_tray.h"
 #include "ash/system/unified/unified_system_tray.h"
 #include "ash/test/ash_test_base.h"
 #include "ash/wm/overview/cleanup_animation_observer.h"
@@ -1717,12 +1716,7 @@
   EXPECT_TRUE(showing_filter_widget());
 
   // Open system bubble shifting focus from the text filter.
-  if (features::IsSystemTrayUnifiedEnabled()) {
-    GetPrimaryUnifiedSystemTray()->ShowBubble(false /* show_by_click */);
-  } else {
-    SystemTray* tray = GetPrimarySystemTray();
-    tray->ShowDefaultView(BUBBLE_CREATE_NEW, false /* show_by_click */);
-  }
+  GetPrimaryUnifiedSystemTray()->ShowBubble(false /* show_by_click */);
 
   base::RunLoop().RunUntilIdle();
 
diff --git a/ash/wm/splitview/split_view_controller.cc b/ash/wm/splitview/split_view_controller.cc
index 28889c3..2f38eeca 100644
--- a/ash/wm/splitview/split_view_controller.cc
+++ b/ash/wm/splitview/split_view_controller.cc
@@ -1347,8 +1347,17 @@
   // active.
   aura::Window* stacking_target =
       (window == left_window_) ? right_window_ : left_window_;
-  if (stacking_target)
-    window->parent()->StackChildBelow(stacking_target, window);
+
+  // Only try to restack the snapped windows if they have the same parent
+  // window. Otherwise, just make sure the |stacking_target| is the top
+  // child window of its parent.
+  // TODO(xdai): Find better ways to handle this case.
+  if (stacking_target) {
+    if (stacking_target->parent() == window->parent())
+      stacking_target->parent()->StackChildBelow(stacking_target, window);
+    else
+      stacking_target->parent()->StackChildAtTop(stacking_target);
+  }
 }
 
 void SplitViewController::SetWindowsTransformDuringResizing() {
diff --git a/ash/wm/splitview/split_view_controller_unittest.cc b/ash/wm/splitview/split_view_controller_unittest.cc
index add0205..5f1a528 100644
--- a/ash/wm/splitview/split_view_controller_unittest.cc
+++ b/ash/wm/splitview/split_view_controller_unittest.cc
@@ -1719,6 +1719,33 @@
   EXPECT_EQ(divider_closest_ratio(), 0.33f);
 }
 
+// Test that if we snap an always on top window in splitscreen, there should be
+// no crash and the window should stay always on top.
+TEST_F(SplitViewControllerTest, AlwaysOnTopWindow) {
+  const gfx::Rect bounds(0, 0, 400, 400);
+  std::unique_ptr<aura::Window> always_on_top_window(CreateWindow(bounds));
+  always_on_top_window->SetProperty(aura::client::kAlwaysOnTopKey, true);
+  std::unique_ptr<aura::Window> normal_window(CreateWindow(bounds));
+
+  split_view_controller()->SnapWindow(always_on_top_window.get(),
+                                      SplitViewController::LEFT);
+  split_view_controller()->SnapWindow(normal_window.get(),
+                                      SplitViewController::RIGHT);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::BOTH_SNAPPED);
+  EXPECT_TRUE(always_on_top_window->GetProperty(aura::client::kAlwaysOnTopKey));
+
+  wm::ActivateWindow(always_on_top_window.get());
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::BOTH_SNAPPED);
+  EXPECT_TRUE(always_on_top_window->GetProperty(aura::client::kAlwaysOnTopKey));
+
+  wm::ActivateWindow(normal_window.get());
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::BOTH_SNAPPED);
+  EXPECT_TRUE(always_on_top_window->GetProperty(aura::client::kAlwaysOnTopKey));
+}
+
 // Test the tab-dragging related functionalities in tablet mode. Tab(s) can be
 // dragged out of a window and then put in split view mode or merge into another
 // window.
diff --git a/ash/wm/workspace/workspace_layout_manager_unittest.cc b/ash/wm/workspace/workspace_layout_manager_unittest.cc
index a98b10e..2d366f43 100644
--- a/ash/wm/workspace/workspace_layout_manager_unittest.cc
+++ b/ash/wm/workspace/workspace_layout_manager_unittest.cc
@@ -1943,7 +1943,7 @@
   EXPECT_GE(test_state()->num_system_ui_area_changes(), 1);
   test_state()->reset_num_system_ui_area_changes();
 
-  keyboard_controller->MoveKeyboard(gfx::Rect(0, 0, 100, 100));
+  keyboard_controller->SetKeyboardWindowBounds(gfx::Rect(0, 0, 100, 100));
   EXPECT_GE(test_state()->num_system_ui_area_changes(), 1);
 }
 
diff --git a/ash/ws/window_service_delegate_impl_unittest.cc b/ash/ws/window_service_delegate_impl_unittest.cc
index e6a17b6..4f5ffaf 100644
--- a/ash/ws/window_service_delegate_impl_unittest.cc
+++ b/ash/ws/window_service_delegate_impl_unittest.cc
@@ -368,14 +368,7 @@
 
   display::Screen* screen = display::Screen::GetScreen();
   display::Display display1 = screen->GetPrimaryDisplay();
-  display::Display display2;
-  for (const auto& iter : screen->GetAllDisplays()) {
-    if (iter.id() != display1.id()) {
-      display2 = iter;
-      break;
-    }
-  }
-  ASSERT_TRUE(display2.is_valid());
+  display::Display display2 = GetSecondaryDisplay();
   EXPECT_EQ(display1.id(),
             screen->GetDisplayNearestWindow(top_level_.get()).id());
 
@@ -395,4 +388,33 @@
                          base::NumberToString(display2.id())));
 }
 
+TEST_F(WindowServiceDelegateImplTest, RemoveDisplay) {
+  UpdateDisplay("500x400,500x400");
+  display::Display display1 = display::Screen::GetScreen()->GetPrimaryDisplay();
+  display::Display display2 = GetSecondaryDisplay();
+
+  GetWindowTreeClientChanges()->clear();
+  top_level_->SetBoundsInScreen(gfx::Rect(600, 100, 100, 100),
+                                GetSecondaryDisplay());
+  EXPECT_EQ(Shell::GetRootWindowForDisplayId(display2.id()),
+            top_level_->GetRootWindow());
+  EXPECT_TRUE(
+      ContainsChange(*GetWindowTreeClientChanges(),
+                     std::string("DisplayChanged window_id=0,1 display_id=") +
+                         base::NumberToString(display2.id())));
+
+  GetWindowTreeClientChanges()->clear();
+  UpdateDisplay("500x400");
+  EXPECT_EQ(Shell::GetRootWindowForDisplayId(display1.id()),
+            top_level_->GetRootWindow());
+  EXPECT_TRUE(
+      ContainsChange(*GetWindowTreeClientChanges(),
+                     std::string("DisplayChanged window_id=0,1 display_id=") +
+                         base::NumberToString(display1.id())));
+  EXPECT_TRUE(ContainsChange(
+      *GetWindowTreeClientChanges(),
+      std::string("BoundsChanged window=0,1 old_bounds=* "
+                  "new_bounds=100,100 104x100 local_surface_id=*")));
+}
+
 }  // namespace ash
diff --git a/base/BUILD.gn b/base/BUILD.gn
index 9b3b755..c361e8c 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -390,6 +390,7 @@
     "mac/scoped_ioobject.h",
     "mac/scoped_ioplugininterface.h",
     "mac/scoped_launch_data.h",
+    "mac/scoped_mach_msg_destroy.h",
     "mac/scoped_mach_port.cc",
     "mac/scoped_mach_port.h",
     "mac/scoped_mach_vm.cc",
@@ -498,6 +499,8 @@
     "metrics/dummy_histogram.h",
     "metrics/field_trial.cc",
     "metrics/field_trial.h",
+    "metrics/field_trial_memory_mac.cc",
+    "metrics/field_trial_memory_mac.h",
     "metrics/field_trial_param_associator.cc",
     "metrics/field_trial_param_associator.h",
     "metrics/field_trial_params.cc",
@@ -947,6 +950,8 @@
     "trace_event/memory_usage_estimator.h",
     "trace_event/process_memory_dump.cc",
     "trace_event/process_memory_dump.h",
+    "trace_event/trace_arguments.cc",
+    "trace_event/trace_arguments.h",
     "trace_event/trace_buffer.cc",
     "trace_event/trace_buffer.h",
     "trace_event/trace_category.h",
@@ -1274,6 +1279,8 @@
       "android/event_log.h",
       "android/field_trial_list.cc",
       "android/important_file_writer_android.cc",
+      "android/int_string_callback.cc",
+      "android/int_string_callback.h",
       "android/java_exception_reporter.cc",
       "android/java_exception_reporter.h",
       "android/java_handler_thread.cc",
@@ -2364,6 +2371,7 @@
     "message_loop/message_pump_io_ios_unittest.cc",
     "message_loop/message_pump_mac_unittest.mm",
     "metrics/bucket_ranges_unittest.cc",
+    "metrics/field_trial_memory_mac_unittest.cc",
     "metrics/field_trial_params_unittest.cc",
     "metrics/field_trial_unittest.cc",
     "metrics/histogram_base_unittest.cc",
@@ -2523,6 +2531,7 @@
     "trace_event/memory_infra_background_whitelist_unittest.cc",
     "trace_event/memory_usage_estimator_unittest.cc",
     "trace_event/process_memory_dump_unittest.cc",
+    "trace_event/trace_arguments_unittest.cc",
     "trace_event/trace_category_unittest.cc",
     "trace_event/trace_config_unittest.cc",
     "trace_event/trace_event_filter_test_utils.cc",
@@ -2843,6 +2852,7 @@
       "android/java/src/org/chromium/base/EventLog.java",
       "android/java/src/org/chromium/base/FieldTrialList.java",
       "android/java/src/org/chromium/base/ImportantFileWriterAndroid.java",
+      "android/java/src/org/chromium/base/IntStringCallback.java",
       "android/java/src/org/chromium/base/JNIUtils.java",
       "android/java/src/org/chromium/base/JavaExceptionReporter.java",
       "android/java/src/org/chromium/base/JavaHandlerThread.java",
@@ -2927,6 +2937,7 @@
       "android/java/src/org/chromium/base/FieldTrialList.java",
       "android/java/src/org/chromium/base/FileUtils.java",
       "android/java/src/org/chromium/base/ImportantFileWriterAndroid.java",
+      "android/java/src/org/chromium/base/IntStringCallback.java",
       "android/java/src/org/chromium/base/JNIUtils.java",
       "android/java/src/org/chromium/base/JavaExceptionReporter.java",
       "android/java/src/org/chromium/base/JavaHandlerThread.java",
diff --git a/base/android/int_string_callback.cc b/base/android/int_string_callback.cc
new file mode 100644
index 0000000..355aebcbd
--- /dev/null
+++ b/base/android/int_string_callback.cc
@@ -0,0 +1,28 @@
+// 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.
+
+// This file encapsulates the JNI headers generated for IntStringCallback, so
+// that the methods defined in the generated headers only end up in one object
+// file. This is similar to //base/android/callback_android.*.
+
+#include "base/android/int_string_callback.h"
+
+#include <jni.h>
+
+#include "base/android/jni_string.h"
+#include "jni/IntStringCallback_jni.h"
+
+namespace base {
+namespace android {
+
+void RunIntStringCallbackAndroid(const JavaRef<jobject>& callback,
+                                 int int_arg,
+                                 const std::string& str_arg) {
+  JNIEnv* env = AttachCurrentThread();
+  Java_IntStringCallback_onResult(env, callback, int_arg,
+                                  ConvertUTF8ToJavaString(env, str_arg));
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/int_string_callback.h b/base/android/int_string_callback.h
new file mode 100644
index 0000000..c0cabeeaf
--- /dev/null
+++ b/base/android/int_string_callback.h
@@ -0,0 +1,25 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_INT_STRING_CALLBACK_H_
+#define BASE_ANDROID_INT_STRING_CALLBACK_H_
+
+#include <string>
+
+#include "base/android/scoped_java_ref.h"
+#include "base/base_export.h"
+
+namespace base {
+namespace android {
+
+// Runs the Java |callback| by calling its onResult method and passing the
+// integer and string as its arguments.
+void BASE_EXPORT RunIntStringCallbackAndroid(const JavaRef<jobject>& callback,
+                                             int int_arg,
+                                             const std::string& str_arg);
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_INT_STRING_CALLBACK_H_
diff --git a/base/android/java/src/org/chromium/base/IntStringCallback.java b/base/android/java/src/org/chromium/base/IntStringCallback.java
new file mode 100644
index 0000000..fe0c413eb
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/IntStringCallback.java
@@ -0,0 +1,29 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import org.chromium.base.annotations.CalledByNative;
+
+/**
+ * A simple 2-argument callback with an int and a String as arguments.
+ *
+ * This is used to call a 2-argument Java callback from C++ code. The generic {@link
+ * org.chromium.base.Callback} cannot be used because it is limited to a single argument.
+ * Alternative approaches like encoding the two arguments into one string or one array of objects
+ * with different types were considered, but their downside was both a lot of boilerplate (creating
+ * the composed object in C++ and checking and decoding it in Java) and lack of clarity. This
+ * 2-argument callback also adds a few code lines but it is clear and the compiler does the type
+ * checking.
+ */
+public interface IntStringCallback {
+    /**
+     * Invoked with the result of a computation.
+     *
+     * @param number Integer part of the result.
+     * @param string String part of the result.
+     */
+    @CalledByNative
+    void onResult(int number, String string);
+}
diff --git a/base/android/jni_generator/SampleForTests_jni.golden b/base/android/jni_generator/SampleForTests_jni.golden
index 79092078..049f6bcf 100644
--- a/base/android/jni_generator/SampleForTests_jni.golden
+++ b/base/android/jni_generator/SampleForTests_jni.golden
@@ -227,38 +227,44 @@
 static jint Java_SampleForTests_javaMethod(JNIEnv* env, const base::android::JavaRef<jobject>& obj,
     JniIntWrapper foo,
     JniIntWrapper bar) {
+  jclass clazz = org_chromium_example_jni_1generator_SampleForTests_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       org_chromium_example_jni_1generator_SampleForTests_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, org_chromium_example_jni_1generator_SampleForTests_clazz(env),
+          env,
+          clazz,
           "javaMethod",
           "(II)I",
           &g_org_chromium_example_jni_1generator_SampleForTests_javaMethod);
 
   jint ret =
       env->CallIntMethod(obj.obj(),
-          method_id, as_jint(foo), as_jint(bar));
-  jni_generator::CheckException(env);
+          call_context.base.method_id, as_jint(foo), as_jint(bar));
   return ret;
 }
 
 static std::atomic<jmethodID>
     g_org_chromium_example_jni_1generator_SampleForTests_staticJavaMethod(nullptr);
 static jboolean Java_SampleForTests_staticJavaMethod(JNIEnv* env) {
-  CHECK_CLAZZ(env, org_chromium_example_jni_1generator_SampleForTests_clazz(env),
+  jclass clazz = org_chromium_example_jni_1generator_SampleForTests_clazz(env);
+  CHECK_CLAZZ(env, clazz,
       org_chromium_example_jni_1generator_SampleForTests_clazz(env), false);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_STATIC>(
-          env, org_chromium_example_jni_1generator_SampleForTests_clazz(env),
+          env,
+          clazz,
           "staticJavaMethod",
           "()Z",
           &g_org_chromium_example_jni_1generator_SampleForTests_staticJavaMethod);
 
   jboolean ret =
-      env->CallStaticBooleanMethod(org_chromium_example_jni_1generator_SampleForTests_clazz(env),
-          method_id);
-  jni_generator::CheckException(env);
+      env->CallStaticBooleanMethod(clazz,
+          call_context.base.method_id);
   return ret;
 }
 
@@ -266,18 +272,21 @@
     g_org_chromium_example_jni_1generator_SampleForTests_packagePrivateJavaMethod(nullptr);
 static void Java_SampleForTests_packagePrivateJavaMethod(JNIEnv* env, const
     base::android::JavaRef<jobject>& obj) {
+  jclass clazz = org_chromium_example_jni_1generator_SampleForTests_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       org_chromium_example_jni_1generator_SampleForTests_clazz(env));
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, org_chromium_example_jni_1generator_SampleForTests_clazz(env),
+          env,
+          clazz,
           "packagePrivateJavaMethod",
           "()V",
           &g_org_chromium_example_jni_1generator_SampleForTests_packagePrivateJavaMethod);
 
      env->CallVoidMethod(obj.obj(),
-          method_id);
-  jni_generator::CheckException(env);
+          call_context.base.method_id);
 }
 
 static std::atomic<jmethodID>
@@ -285,18 +294,21 @@
 static void Java_SampleForTests_methodWithGenericParams(JNIEnv* env, const
     base::android::JavaRef<jobject>& obj, const base::android::JavaRef<jobject>& foo,
     const base::android::JavaRef<jobject>& bar) {
+  jclass clazz = org_chromium_example_jni_1generator_SampleForTests_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       org_chromium_example_jni_1generator_SampleForTests_clazz(env));
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, org_chromium_example_jni_1generator_SampleForTests_clazz(env),
+          env,
+          clazz,
           "methodWithGenericParams",
           "(Ljava/util/Map;Ljava/util/LinkedList;)V",
           &g_org_chromium_example_jni_1generator_SampleForTests_methodWithGenericParams);
 
      env->CallVoidMethod(obj.obj(),
-          method_id, foo.obj(), bar.obj());
-  jni_generator::CheckException(env);
+          call_context.base.method_id, foo.obj(), bar.obj());
 }
 
 static std::atomic<jmethodID>
@@ -304,19 +316,22 @@
 static base::android::ScopedJavaLocalRef<jobject> Java_SampleForTests_Constructor(JNIEnv* env,
     JniIntWrapper foo,
     JniIntWrapper bar) {
-  CHECK_CLAZZ(env, org_chromium_example_jni_1generator_SampleForTests_clazz(env),
+  jclass clazz = org_chromium_example_jni_1generator_SampleForTests_clazz(env);
+  CHECK_CLAZZ(env, clazz,
       org_chromium_example_jni_1generator_SampleForTests_clazz(env), NULL);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, org_chromium_example_jni_1generator_SampleForTests_clazz(env),
+          env,
+          clazz,
           "<init>",
           "(II)V",
           &g_org_chromium_example_jni_1generator_SampleForTests_Constructor);
 
   jobject ret =
-      env->NewObject(org_chromium_example_jni_1generator_SampleForTests_clazz(env),
-          method_id, as_jint(foo), as_jint(bar));
-  jni_generator::CheckException(env);
+      env->NewObject(clazz,
+          call_context.base.method_id, as_jint(foo), as_jint(bar));
   return base::android::ScopedJavaLocalRef<jobject>(env, ret);
 }
 
@@ -324,35 +339,42 @@
     g_org_chromium_example_jni_1generator_SampleForTests_methodThatThrowsException(nullptr);
 static void Java_SampleForTests_methodThatThrowsException(JNIEnv* env, const
     base::android::JavaRef<jobject>& obj) {
+  jclass clazz = org_chromium_example_jni_1generator_SampleForTests_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       org_chromium_example_jni_1generator_SampleForTests_clazz(env));
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextUnchecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, org_chromium_example_jni_1generator_SampleForTests_clazz(env),
+          env,
+          clazz,
           "methodThatThrowsException",
           "()V",
           &g_org_chromium_example_jni_1generator_SampleForTests_methodThatThrowsException);
 
      env->CallVoidMethod(obj.obj(),
-          method_id);
+          call_context.method_id);
 }
 
 static std::atomic<jmethodID>
     g_org_chromium_example_jni_1generator_SampleForTests_javaMethodWithAnnotatedParam(nullptr);
 static void Java_SampleForTests_javaMethodWithAnnotatedParam(JNIEnv* env, const
     base::android::JavaRef<jobject>& obj, JniIntWrapper foo) {
+  jclass clazz = org_chromium_example_jni_1generator_SampleForTests_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       org_chromium_example_jni_1generator_SampleForTests_clazz(env));
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, org_chromium_example_jni_1generator_SampleForTests_clazz(env),
+          env,
+          clazz,
           "javaMethodWithAnnotatedParam",
           "(I)V",
           &g_org_chromium_example_jni_1generator_SampleForTests_javaMethodWithAnnotatedParam);
 
      env->CallVoidMethod(obj.obj(),
-          method_id, as_jint(foo));
-  jni_generator::CheckException(env);
+          call_context.base.method_id, as_jint(foo));
 }
 
 static std::atomic<jmethodID>
@@ -360,19 +382,22 @@
 static base::android::ScopedJavaLocalRef<jobject> Java_InnerStructA_create(JNIEnv* env, jlong l,
     JniIntWrapper i,
     const base::android::JavaRef<jstring>& s) {
-  CHECK_CLAZZ(env, org_chromium_example_jni_1generator_SampleForTests_00024InnerStructA_clazz(env),
+  jclass clazz = org_chromium_example_jni_1generator_SampleForTests_00024InnerStructA_clazz(env);
+  CHECK_CLAZZ(env, clazz,
       org_chromium_example_jni_1generator_SampleForTests_00024InnerStructA_clazz(env), NULL);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_STATIC>(
-          env, org_chromium_example_jni_1generator_SampleForTests_00024InnerStructA_clazz(env),
+          env,
+          clazz,
           "create",
           "(JILjava/lang/String;)Lorg/chromium/example/jni_generator/SampleForTests$InnerStructA;",
           &g_org_chromium_example_jni_1generator_SampleForTests_00024InnerStructA_create);
 
   jobject ret =
-env->CallStaticObjectMethod(org_chromium_example_jni_1generator_SampleForTests_00024InnerStructA_clazz(env),
-          method_id, l, as_jint(i), s.obj());
-  jni_generator::CheckException(env);
+      env->CallStaticObjectMethod(clazz,
+          call_context.base.method_id, l, as_jint(i), s.obj());
   return base::android::ScopedJavaLocalRef<jobject>(env, ret);
 }
 
@@ -380,54 +405,63 @@
     g_org_chromium_example_jni_1generator_SampleForTests_addStructA(nullptr);
 static void Java_SampleForTests_addStructA(JNIEnv* env, const base::android::JavaRef<jobject>& obj,
     const base::android::JavaRef<jobject>& a) {
+  jclass clazz = org_chromium_example_jni_1generator_SampleForTests_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       org_chromium_example_jni_1generator_SampleForTests_clazz(env));
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, org_chromium_example_jni_1generator_SampleForTests_clazz(env),
+          env,
+          clazz,
           "addStructA",
           "(Lorg/chromium/example/jni_generator/SampleForTests$InnerStructA;)V",
           &g_org_chromium_example_jni_1generator_SampleForTests_addStructA);
 
      env->CallVoidMethod(obj.obj(),
-          method_id, a.obj());
-  jni_generator::CheckException(env);
+          call_context.base.method_id, a.obj());
 }
 
 static std::atomic<jmethodID>
     g_org_chromium_example_jni_1generator_SampleForTests_iterateAndDoSomething(nullptr);
 static void Java_SampleForTests_iterateAndDoSomething(JNIEnv* env, const
     base::android::JavaRef<jobject>& obj) {
+  jclass clazz = org_chromium_example_jni_1generator_SampleForTests_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       org_chromium_example_jni_1generator_SampleForTests_clazz(env));
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, org_chromium_example_jni_1generator_SampleForTests_clazz(env),
+          env,
+          clazz,
           "iterateAndDoSomething",
           "()V",
           &g_org_chromium_example_jni_1generator_SampleForTests_iterateAndDoSomething);
 
      env->CallVoidMethod(obj.obj(),
-          method_id);
-  jni_generator::CheckException(env);
+          call_context.base.method_id);
 }
 
 static std::atomic<jmethodID>
     g_org_chromium_example_jni_1generator_SampleForTests_00024InnerStructB_getKey(nullptr);
 static jlong Java_InnerStructB_getKey(JNIEnv* env, const base::android::JavaRef<jobject>& obj) {
+  jclass clazz = org_chromium_example_jni_1generator_SampleForTests_00024InnerStructB_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       org_chromium_example_jni_1generator_SampleForTests_00024InnerStructB_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, org_chromium_example_jni_1generator_SampleForTests_00024InnerStructB_clazz(env),
+          env,
+          clazz,
           "getKey",
           "()J",
           &g_org_chromium_example_jni_1generator_SampleForTests_00024InnerStructB_getKey);
 
   jlong ret =
       env->CallLongMethod(obj.obj(),
-          method_id);
-  jni_generator::CheckException(env);
+          call_context.base.method_id);
   return ret;
 }
 
@@ -435,19 +469,22 @@
     g_org_chromium_example_jni_1generator_SampleForTests_00024InnerStructB_getValue(nullptr);
 static base::android::ScopedJavaLocalRef<jstring> Java_InnerStructB_getValue(JNIEnv* env, const
     base::android::JavaRef<jobject>& obj) {
+  jclass clazz = org_chromium_example_jni_1generator_SampleForTests_00024InnerStructB_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       org_chromium_example_jni_1generator_SampleForTests_00024InnerStructB_clazz(env), NULL);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, org_chromium_example_jni_1generator_SampleForTests_00024InnerStructB_clazz(env),
+          env,
+          clazz,
           "getValue",
           "()Ljava/lang/String;",
           &g_org_chromium_example_jni_1generator_SampleForTests_00024InnerStructB_getValue);
 
   jstring ret =
       static_cast<jstring>(env->CallObjectMethod(obj.obj(),
-          method_id));
-  jni_generator::CheckException(env);
+          call_context.base.method_id));
   return base::android::ScopedJavaLocalRef<jstring>(env, ret);
 }
 
@@ -455,38 +492,44 @@
     g_org_chromium_example_jni_1generator_SampleForTests_getInnerInterface(nullptr);
 static base::android::ScopedJavaLocalRef<jobject> Java_SampleForTests_getInnerInterface(JNIEnv* env)
     {
-  CHECK_CLAZZ(env, org_chromium_example_jni_1generator_SampleForTests_clazz(env),
+  jclass clazz = org_chromium_example_jni_1generator_SampleForTests_clazz(env);
+  CHECK_CLAZZ(env, clazz,
       org_chromium_example_jni_1generator_SampleForTests_clazz(env), NULL);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_STATIC>(
-          env, org_chromium_example_jni_1generator_SampleForTests_clazz(env),
+          env,
+          clazz,
           "getInnerInterface",
           "()Lorg/chromium/example/jni_generator/SampleForTests$InnerInterface;",
           &g_org_chromium_example_jni_1generator_SampleForTests_getInnerInterface);
 
   jobject ret =
-      env->CallStaticObjectMethod(org_chromium_example_jni_1generator_SampleForTests_clazz(env),
-          method_id);
-  jni_generator::CheckException(env);
+      env->CallStaticObjectMethod(clazz,
+          call_context.base.method_id);
   return base::android::ScopedJavaLocalRef<jobject>(env, ret);
 }
 
 static std::atomic<jmethodID>
     g_org_chromium_example_jni_1generator_SampleForTests_getInnerEnum(nullptr);
 static base::android::ScopedJavaLocalRef<jobject> Java_SampleForTests_getInnerEnum(JNIEnv* env) {
-  CHECK_CLAZZ(env, org_chromium_example_jni_1generator_SampleForTests_clazz(env),
+  jclass clazz = org_chromium_example_jni_1generator_SampleForTests_clazz(env);
+  CHECK_CLAZZ(env, clazz,
       org_chromium_example_jni_1generator_SampleForTests_clazz(env), NULL);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_STATIC>(
-          env, org_chromium_example_jni_1generator_SampleForTests_clazz(env),
+          env,
+          clazz,
           "getInnerEnum",
           "()Lorg/chromium/example/jni_generator/SampleForTests$InnerEnum;",
           &g_org_chromium_example_jni_1generator_SampleForTests_getInnerEnum);
 
   jobject ret =
-      env->CallStaticObjectMethod(org_chromium_example_jni_1generator_SampleForTests_clazz(env),
-          method_id);
-  jni_generator::CheckException(env);
+      env->CallStaticObjectMethod(clazz,
+          call_context.base.method_id);
   return base::android::ScopedJavaLocalRef<jobject>(env, ret);
 }
 
diff --git a/base/android/jni_generator/jni_generator.py b/base/android/jni_generator/jni_generator.py
index ee6a52bb..4f14628 100755
--- a/base/android/jni_generator/jni_generator.py
+++ b/base/android/jni_generator/jni_generator.py
@@ -1136,7 +1136,7 @@
 
     if called_by_native.static or called_by_native.is_constructor:
       first_param_in_declaration = ''
-      first_param_in_call = ('%s_clazz(env)' % GetBinaryClassName(java_class))
+      first_param_in_call = 'clazz'
     else:
       first_param_in_declaration = (
           ', const base::android::JavaRef<jobject>& obj')
@@ -1153,9 +1153,11 @@
     if called_by_native.static_cast:
       pre_call = 'static_cast<%s>(' % called_by_native.static_cast
       post_call = ')'
-    check_exception = ''
+    check_exception = 'Unchecked'
+    method_id_member_name = 'call_context.method_id'
     if not called_by_native.unchecked:
-      check_exception = 'jni_generator::CheckException(env);'
+      check_exception = 'Checked'
+      method_id_member_name = 'call_context.base.method_id'
     return_type = JavaDataTypeToC(called_by_native.return_type)
     optional_error_return = JavaReturnValueToC(called_by_native.return_type)
     if optional_error_return:
@@ -1202,6 +1204,7 @@
         'PROFILING_LEAVING_NATIVE': profiling_leaving_native,
         'JNI_NAME': jni_name,
         'JNI_SIGNATURE': jni_signature,
+        'METHOD_ID_MEMBER_NAME': method_id_member_name,
         'METHOD_ID_VAR_NAME': called_by_native.method_id_var_name,
         'METHOD_ID_TYPE': 'STATIC' if called_by_native.static else 'INSTANCE',
         'JAVA_NAME_FULL': java_name_full,
@@ -1220,11 +1223,15 @@
     template = Template("""
 static std::atomic<jmethodID> g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME}(nullptr);
 ${FUNCTION_HEADER}
+  jclass clazz = ${JAVA_CLASS}_clazz(env);
   CHECK_CLAZZ(env, ${FIRST_PARAM_IN_CALL},
       ${JAVA_CLASS}_clazz(env)${OPTIONAL_ERROR_RETURN});
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContext${CHECK_EXCEPTION} call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_${METHOD_ID_TYPE}>(
-          env, ${JAVA_CLASS}_clazz(env),
+          env,
+          clazz,
           "${JNI_NAME}",
           ${JNI_SIGNATURE},
           &g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME});
@@ -1233,8 +1240,7 @@
 ${PROFILING_LEAVING_NATIVE}\
   ${RETURN_DECLARATION}
      ${PRE_CALL}env->${ENV_CALL}(${FIRST_PARAM_IN_CALL},
-          method_id${PARAMS_IN_CALL})${POST_CALL};
-  ${CHECK_EXCEPTION}
+          ${METHOD_ID_MEMBER_NAME}${PARAMS_IN_CALL})${POST_CALL};
   ${RETURN_CLAUSE}
 }""")
     values = self.GetCalledByNativeValues(called_by_native)
@@ -1254,7 +1260,7 @@
 
   def GetTraceEventForNameTemplate(self, name_template, values):
     name = Template(name_template).substitute(values)
-    return '  TRACE_EVENT0("jni", "%s");' % name
+    return '  TRACE_EVENT0("jni", "%s");\n' % name
 
 
 def WrapOutput(output):
diff --git a/base/android/jni_generator/jni_generator_helper.h b/base/android/jni_generator/jni_generator_helper.h
index 3347fee1..ab69280 100644
--- a/base/android/jni_generator/jni_generator_helper.h
+++ b/base/android/jni_generator/jni_generator_helper.h
@@ -10,6 +10,8 @@
 #include "base/android/jni_android.h"
 #include "base/android/jni_int_wrapper.h"
 #include "base/android/scoped_java_ref.h"
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
 #include "base/logging.h"
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
@@ -51,6 +53,78 @@
   base::android::CheckException(env);
 }
 
+// A 32 bit number could be an address on stack. Random 64 bit marker on the
+// stack is much less likely to be present on stack.
+constexpr uint64_t kJniStackMarkerValue = 0xbdbdef1bebcade1b;
+
+// Context about the JNI call with exception checked to be stored in stack.
+struct BASE_EXPORT JniJavaCallContextUnchecked {
+  ALWAYS_INLINE JniJavaCallContextUnchecked() {
+// TODO(ssid): Implement for other architectures.
+#if defined(__arm__) || defined(__aarch64__)
+    // This assumes that this method does not increment the stack pointer.
+    asm volatile("mov %0, sp" : "=r"(sp));
+#else
+    sp = 0;
+#endif
+  }
+
+  // Force no inline to reduce code size.
+  template <base::android::MethodID::Type type>
+  NOINLINE void Init(JNIEnv* env,
+                     jclass clazz,
+                     const char* method_name,
+                     const char* jni_signature,
+                     std::atomic<jmethodID>* atomic_method_id) {
+    env1 = env;
+
+    // Make sure compiler doesn't optimize out the assignment.
+    memcpy(&marker, &kJniStackMarkerValue, sizeof(kJniStackMarkerValue));
+    // Gets PC of the calling function.
+    pc = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
+
+    method_id = base::android::MethodID::LazyGet<type>(
+        env, clazz, method_name, jni_signature, atomic_method_id);
+  }
+
+  NOINLINE ~JniJavaCallContextUnchecked() {
+    // Reset so that spurious marker finds are avoided.
+    memset(&marker, 0, sizeof(marker));
+  }
+
+  uint64_t marker;
+  uintptr_t sp;
+  uintptr_t pc;
+
+  JNIEnv* env1;
+  jmethodID method_id;
+};
+
+// Context about the JNI call with exception unchecked to be stored in stack.
+struct BASE_EXPORT JniJavaCallContextChecked {
+  // Force no inline to reduce code size.
+  template <base::android::MethodID::Type type>
+  NOINLINE void Init(JNIEnv* env,
+                     jclass clazz,
+                     const char* method_name,
+                     const char* jni_signature,
+                     std::atomic<jmethodID>* atomic_method_id) {
+    base.Init<type>(env, clazz, method_name, jni_signature, atomic_method_id);
+    // Reset |pc| to correct caller.
+    base.pc = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
+  }
+
+  NOINLINE ~JniJavaCallContextChecked() {
+    jni_generator::CheckException(base.env1);
+  }
+
+  JniJavaCallContextUnchecked base;
+};
+
+static_assert(sizeof(JniJavaCallContextChecked) ==
+                  sizeof(JniJavaCallContextUnchecked),
+              "Stack unwinder cannot work with structs of different sizes.");
+
 }  // namespace jni_generator
 
 #endif  // BASE_ANDROID_JNI_GENERATOR_JNI_GENERATOR_HELPER_H_
diff --git a/base/android/jni_generator/testCalledByNatives.golden b/base/android/jni_generator/testCalledByNatives.golden
index 09ecb6c..6249bd6 100644
--- a/base/android/jni_generator/testCalledByNatives.golden
+++ b/base/android/jni_generator/testCalledByNatives.golden
@@ -55,20 +55,23 @@
     const base::android::JavaRef<jstring>& buttonCancel,
     const base::android::JavaRef<jstring>& title,
     const base::android::JavaRef<jobject>& icon) {
+  jclass clazz = org_chromium_TestJni_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       org_chromium_TestJni_clazz(env), NULL);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, org_chromium_TestJni_clazz(env),
+          env,
+          clazz,
           "showConfirmInfoBar",
 "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Landroid/graphics/Bitmap;)Lorg/chromium/Foo$InnerClass;",
           &g_org_chromium_TestJni_showConfirmInfoBar);
 
   jobject ret =
       env->CallObjectMethod(obj.obj(),
-          method_id, as_jint(nativeInfoBar), buttonOk.obj(), buttonCancel.obj(), title.obj(),
-              icon.obj());
-  jni_generator::CheckException(env);
+          call_context.base.method_id, as_jint(nativeInfoBar), buttonOk.obj(), buttonCancel.obj(),
+              title.obj(), icon.obj());
   return base::android::ScopedJavaLocalRef<jobject>(env, ret);
 }
 
@@ -78,36 +81,43 @@
     const base::android::JavaRef<jstring>& realm,
     const base::android::JavaRef<jstring>& account,
     const base::android::JavaRef<jstring>& args) {
+  jclass clazz = org_chromium_TestJni_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       org_chromium_TestJni_clazz(env), NULL);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, org_chromium_TestJni_clazz(env),
+          env,
+          clazz,
           "showAutoLoginInfoBar",
           "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lorg/chromium/Foo$InnerClass;",
           &g_org_chromium_TestJni_showAutoLoginInfoBar);
 
   jobject ret =
       env->CallObjectMethod(obj.obj(),
-          method_id, as_jint(nativeInfoBar), realm.obj(), account.obj(), args.obj());
-  jni_generator::CheckException(env);
+          call_context.base.method_id, as_jint(nativeInfoBar), realm.obj(), account.obj(),
+              args.obj());
   return base::android::ScopedJavaLocalRef<jobject>(env, ret);
 }
 
 static std::atomic<jmethodID> g_org_chromium_TestJni_00024InfoBar_dismiss(nullptr);
 static void Java_InfoBar_dismiss(JNIEnv* env, const base::android::JavaRef<jobject>& obj) {
+  jclass clazz = org_chromium_TestJni_00024InfoBar_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       org_chromium_TestJni_00024InfoBar_clazz(env));
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, org_chromium_TestJni_00024InfoBar_clazz(env),
+          env,
+          clazz,
           "dismiss",
           "()V",
           &g_org_chromium_TestJni_00024InfoBar_dismiss);
 
      env->CallVoidMethod(obj.obj(),
-          method_id);
-  jni_generator::CheckException(env);
+          call_context.base.method_id);
 }
 
 static std::atomic<jmethodID> g_org_chromium_TestJni_shouldShowAutoLogin(nullptr);
@@ -116,38 +126,44 @@
     const base::android::JavaRef<jstring>& realm,
     const base::android::JavaRef<jstring>& account,
     const base::android::JavaRef<jstring>& args) {
-  CHECK_CLAZZ(env, org_chromium_TestJni_clazz(env),
+  jclass clazz = org_chromium_TestJni_clazz(env);
+  CHECK_CLAZZ(env, clazz,
       org_chromium_TestJni_clazz(env), false);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_STATIC>(
-          env, org_chromium_TestJni_clazz(env),
+          env,
+          clazz,
           "shouldShowAutoLogin",
           "(Landroid/view/View;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z",
           &g_org_chromium_TestJni_shouldShowAutoLogin);
 
   jboolean ret =
-      env->CallStaticBooleanMethod(org_chromium_TestJni_clazz(env),
-          method_id, view.obj(), realm.obj(), account.obj(), args.obj());
-  jni_generator::CheckException(env);
+      env->CallStaticBooleanMethod(clazz,
+          call_context.base.method_id, view.obj(), realm.obj(), account.obj(), args.obj());
   return ret;
 }
 
 static std::atomic<jmethodID> g_org_chromium_TestJni_openUrl(nullptr);
 static base::android::ScopedJavaLocalRef<jobject> Java_TestJni_openUrl(JNIEnv* env, const
     base::android::JavaRef<jstring>& url) {
-  CHECK_CLAZZ(env, org_chromium_TestJni_clazz(env),
+  jclass clazz = org_chromium_TestJni_clazz(env);
+  CHECK_CLAZZ(env, clazz,
       org_chromium_TestJni_clazz(env), NULL);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_STATIC>(
-          env, org_chromium_TestJni_clazz(env),
+          env,
+          clazz,
           "openUrl",
           "(Ljava/lang/String;)Ljava/io/InputStream;",
           &g_org_chromium_TestJni_openUrl);
 
   jobject ret =
-      env->CallStaticObjectMethod(org_chromium_TestJni_clazz(env),
-          method_id, url.obj());
-  jni_generator::CheckException(env);
+      env->CallStaticObjectMethod(clazz,
+          call_context.base.method_id, url.obj());
   return base::android::ScopedJavaLocalRef<jobject>(env, ret);
 }
 
@@ -158,261 +174,304 @@
     JniIntWrapper iType,
     JniIntWrapper iPrimaryID,
     JniIntWrapper iSecondaryID) {
+  jclass clazz = org_chromium_TestJni_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       org_chromium_TestJni_clazz(env));
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, org_chromium_TestJni_clazz(env),
+          env,
+          clazz,
           "activateHardwareAcceleration",
           "(ZIIII)V",
           &g_org_chromium_TestJni_activateHardwareAcceleration);
 
      env->CallVoidMethod(obj.obj(),
-          method_id, activated, as_jint(iPid), as_jint(iType), as_jint(iPrimaryID),
-              as_jint(iSecondaryID));
-  jni_generator::CheckException(env);
+          call_context.base.method_id, activated, as_jint(iPid), as_jint(iType),
+              as_jint(iPrimaryID), as_jint(iSecondaryID));
 }
 
 static std::atomic<jmethodID> g_org_chromium_TestJni_updateStatus(nullptr);
 static jint Java_TestJni_updateStatus(JNIEnv* env, JniIntWrapper status) {
-  CHECK_CLAZZ(env, org_chromium_TestJni_clazz(env),
+  jclass clazz = org_chromium_TestJni_clazz(env);
+  CHECK_CLAZZ(env, clazz,
       org_chromium_TestJni_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_STATIC>(
-          env, org_chromium_TestJni_clazz(env),
+          env,
+          clazz,
           "updateStatus",
           "(I)I",
           &g_org_chromium_TestJni_updateStatus);
 
   jint ret =
-      env->CallStaticIntMethod(org_chromium_TestJni_clazz(env),
-          method_id, as_jint(status));
-  jni_generator::CheckException(env);
+      env->CallStaticIntMethod(clazz,
+          call_context.base.method_id, as_jint(status));
   return ret;
 }
 
 static std::atomic<jmethodID> g_org_chromium_TestJni_uncheckedCall(nullptr);
 static void Java_TestJni_uncheckedCall(JNIEnv* env, const base::android::JavaRef<jobject>& obj,
     JniIntWrapper iParam) {
+  jclass clazz = org_chromium_TestJni_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       org_chromium_TestJni_clazz(env));
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextUnchecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, org_chromium_TestJni_clazz(env),
+          env,
+          clazz,
           "uncheckedCall",
           "(I)V",
           &g_org_chromium_TestJni_uncheckedCall);
 
      env->CallVoidMethod(obj.obj(),
-          method_id, as_jint(iParam));
+          call_context.method_id, as_jint(iParam));
 }
 
 static std::atomic<jmethodID> g_org_chromium_TestJni_returnByteArray(nullptr);
 static base::android::ScopedJavaLocalRef<jbyteArray> Java_TestJni_returnByteArray(JNIEnv* env, const
     base::android::JavaRef<jobject>& obj) {
+  jclass clazz = org_chromium_TestJni_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       org_chromium_TestJni_clazz(env), NULL);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, org_chromium_TestJni_clazz(env),
+          env,
+          clazz,
           "returnByteArray",
           "()[B",
           &g_org_chromium_TestJni_returnByteArray);
 
   jbyteArray ret =
       static_cast<jbyteArray>(env->CallObjectMethod(obj.obj(),
-          method_id));
-  jni_generator::CheckException(env);
+          call_context.base.method_id));
   return base::android::ScopedJavaLocalRef<jbyteArray>(env, ret);
 }
 
 static std::atomic<jmethodID> g_org_chromium_TestJni_returnBooleanArray(nullptr);
 static base::android::ScopedJavaLocalRef<jbooleanArray> Java_TestJni_returnBooleanArray(JNIEnv* env,
     const base::android::JavaRef<jobject>& obj) {
+  jclass clazz = org_chromium_TestJni_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       org_chromium_TestJni_clazz(env), NULL);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, org_chromium_TestJni_clazz(env),
+          env,
+          clazz,
           "returnBooleanArray",
           "()[Z",
           &g_org_chromium_TestJni_returnBooleanArray);
 
   jbooleanArray ret =
       static_cast<jbooleanArray>(env->CallObjectMethod(obj.obj(),
-          method_id));
-  jni_generator::CheckException(env);
+          call_context.base.method_id));
   return base::android::ScopedJavaLocalRef<jbooleanArray>(env, ret);
 }
 
 static std::atomic<jmethodID> g_org_chromium_TestJni_returnCharArray(nullptr);
 static base::android::ScopedJavaLocalRef<jcharArray> Java_TestJni_returnCharArray(JNIEnv* env, const
     base::android::JavaRef<jobject>& obj) {
+  jclass clazz = org_chromium_TestJni_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       org_chromium_TestJni_clazz(env), NULL);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, org_chromium_TestJni_clazz(env),
+          env,
+          clazz,
           "returnCharArray",
           "()[C",
           &g_org_chromium_TestJni_returnCharArray);
 
   jcharArray ret =
       static_cast<jcharArray>(env->CallObjectMethod(obj.obj(),
-          method_id));
-  jni_generator::CheckException(env);
+          call_context.base.method_id));
   return base::android::ScopedJavaLocalRef<jcharArray>(env, ret);
 }
 
 static std::atomic<jmethodID> g_org_chromium_TestJni_returnShortArray(nullptr);
 static base::android::ScopedJavaLocalRef<jshortArray> Java_TestJni_returnShortArray(JNIEnv* env,
     const base::android::JavaRef<jobject>& obj) {
+  jclass clazz = org_chromium_TestJni_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       org_chromium_TestJni_clazz(env), NULL);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, org_chromium_TestJni_clazz(env),
+          env,
+          clazz,
           "returnShortArray",
           "()[S",
           &g_org_chromium_TestJni_returnShortArray);
 
   jshortArray ret =
       static_cast<jshortArray>(env->CallObjectMethod(obj.obj(),
-          method_id));
-  jni_generator::CheckException(env);
+          call_context.base.method_id));
   return base::android::ScopedJavaLocalRef<jshortArray>(env, ret);
 }
 
 static std::atomic<jmethodID> g_org_chromium_TestJni_returnIntArray(nullptr);
 static base::android::ScopedJavaLocalRef<jintArray> Java_TestJni_returnIntArray(JNIEnv* env, const
     base::android::JavaRef<jobject>& obj) {
+  jclass clazz = org_chromium_TestJni_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       org_chromium_TestJni_clazz(env), NULL);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, org_chromium_TestJni_clazz(env),
+          env,
+          clazz,
           "returnIntArray",
           "()[I",
           &g_org_chromium_TestJni_returnIntArray);
 
   jintArray ret =
       static_cast<jintArray>(env->CallObjectMethod(obj.obj(),
-          method_id));
-  jni_generator::CheckException(env);
+          call_context.base.method_id));
   return base::android::ScopedJavaLocalRef<jintArray>(env, ret);
 }
 
 static std::atomic<jmethodID> g_org_chromium_TestJni_returnLongArray(nullptr);
 static base::android::ScopedJavaLocalRef<jlongArray> Java_TestJni_returnLongArray(JNIEnv* env, const
     base::android::JavaRef<jobject>& obj) {
+  jclass clazz = org_chromium_TestJni_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       org_chromium_TestJni_clazz(env), NULL);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, org_chromium_TestJni_clazz(env),
+          env,
+          clazz,
           "returnLongArray",
           "()[J",
           &g_org_chromium_TestJni_returnLongArray);
 
   jlongArray ret =
       static_cast<jlongArray>(env->CallObjectMethod(obj.obj(),
-          method_id));
-  jni_generator::CheckException(env);
+          call_context.base.method_id));
   return base::android::ScopedJavaLocalRef<jlongArray>(env, ret);
 }
 
 static std::atomic<jmethodID> g_org_chromium_TestJni_returnDoubleArray(nullptr);
 static base::android::ScopedJavaLocalRef<jdoubleArray> Java_TestJni_returnDoubleArray(JNIEnv* env,
     const base::android::JavaRef<jobject>& obj) {
+  jclass clazz = org_chromium_TestJni_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       org_chromium_TestJni_clazz(env), NULL);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, org_chromium_TestJni_clazz(env),
+          env,
+          clazz,
           "returnDoubleArray",
           "()[D",
           &g_org_chromium_TestJni_returnDoubleArray);
 
   jdoubleArray ret =
       static_cast<jdoubleArray>(env->CallObjectMethod(obj.obj(),
-          method_id));
-  jni_generator::CheckException(env);
+          call_context.base.method_id));
   return base::android::ScopedJavaLocalRef<jdoubleArray>(env, ret);
 }
 
 static std::atomic<jmethodID> g_org_chromium_TestJni_returnObjectArray(nullptr);
 static base::android::ScopedJavaLocalRef<jobjectArray> Java_TestJni_returnObjectArray(JNIEnv* env,
     const base::android::JavaRef<jobject>& obj) {
+  jclass clazz = org_chromium_TestJni_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       org_chromium_TestJni_clazz(env), NULL);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, org_chromium_TestJni_clazz(env),
+          env,
+          clazz,
           "returnObjectArray",
           "()[Ljava/lang/Object;",
           &g_org_chromium_TestJni_returnObjectArray);
 
   jobjectArray ret =
       static_cast<jobjectArray>(env->CallObjectMethod(obj.obj(),
-          method_id));
-  jni_generator::CheckException(env);
+          call_context.base.method_id));
   return base::android::ScopedJavaLocalRef<jobjectArray>(env, ret);
 }
 
 static std::atomic<jmethodID> g_org_chromium_TestJni_returnArrayOfByteArray(nullptr);
 static base::android::ScopedJavaLocalRef<jobjectArray> Java_TestJni_returnArrayOfByteArray(JNIEnv*
     env, const base::android::JavaRef<jobject>& obj) {
+  jclass clazz = org_chromium_TestJni_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       org_chromium_TestJni_clazz(env), NULL);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, org_chromium_TestJni_clazz(env),
+          env,
+          clazz,
           "returnArrayOfByteArray",
           "()[[B",
           &g_org_chromium_TestJni_returnArrayOfByteArray);
 
   jobjectArray ret =
       static_cast<jobjectArray>(env->CallObjectMethod(obj.obj(),
-          method_id));
-  jni_generator::CheckException(env);
+          call_context.base.method_id));
   return base::android::ScopedJavaLocalRef<jobjectArray>(env, ret);
 }
 
 static std::atomic<jmethodID> g_org_chromium_TestJni_getCompressFormat(nullptr);
 static base::android::ScopedJavaLocalRef<jobject> Java_TestJni_getCompressFormat(JNIEnv* env, const
     base::android::JavaRef<jobject>& obj) {
+  jclass clazz = org_chromium_TestJni_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       org_chromium_TestJni_clazz(env), NULL);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, org_chromium_TestJni_clazz(env),
+          env,
+          clazz,
           "getCompressFormat",
           "()Landroid/graphics/Bitmap$CompressFormat;",
           &g_org_chromium_TestJni_getCompressFormat);
 
   jobject ret =
       env->CallObjectMethod(obj.obj(),
-          method_id);
-  jni_generator::CheckException(env);
+          call_context.base.method_id);
   return base::android::ScopedJavaLocalRef<jobject>(env, ret);
 }
 
 static std::atomic<jmethodID> g_org_chromium_TestJni_getCompressFormatList(nullptr);
 static base::android::ScopedJavaLocalRef<jobject> Java_TestJni_getCompressFormatList(JNIEnv* env,
     const base::android::JavaRef<jobject>& obj) {
+  jclass clazz = org_chromium_TestJni_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       org_chromium_TestJni_clazz(env), NULL);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, org_chromium_TestJni_clazz(env),
+          env,
+          clazz,
           "getCompressFormatList",
           "()Ljava/util/List;",
           &g_org_chromium_TestJni_getCompressFormatList);
 
   jobject ret =
       env->CallObjectMethod(obj.obj(),
-          method_id);
-  jni_generator::CheckException(env);
+          call_context.base.method_id);
   return base::android::ScopedJavaLocalRef<jobject>(env, ret);
 }
 
diff --git a/base/android/jni_generator/testConstantsFromJavaP.golden b/base/android/jni_generator/testConstantsFromJavaP.golden
index 043685f..b0364515 100644
--- a/base/android/jni_generator/testConstantsFromJavaP.golden
+++ b/base/android/jni_generator/testConstantsFromJavaP.golden
@@ -128,18 +128,21 @@
 static void Java_MotionEvent_finalize(JNIEnv* env, const base::android::JavaRef<jobject>& obj)
     __attribute__ ((unused));
 static void Java_MotionEvent_finalize(JNIEnv* env, const base::android::JavaRef<jobject>& obj) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env));
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "finalize",
           "()V",
           &g_android_view_MotionEvent_finalize);
 
      env->CallVoidMethod(obj.obj(),
-          method_id);
-  jni_generator::CheckException(env);
+          call_context.base.method_id);
 }
 
 static std::atomic<jmethodID>
@@ -174,20 +177,24 @@
     JniIntWrapper p11,
     JniIntWrapper p12,
     JniIntWrapper p13) {
-  CHECK_CLAZZ(env, android_view_MotionEvent_clazz(env),
+  jclass clazz = android_view_MotionEvent_clazz(env);
+  CHECK_CLAZZ(env, clazz,
       android_view_MotionEvent_clazz(env), NULL);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_STATIC>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "obtain",
 "(JJII[Landroid/view/MotionEvent$PointerProperties;[Landroid/view/MotionEvent$PointerCoords;IIFFIIII)Landroid/view/MotionEvent;",
           &g_android_view_MotionEvent_obtainAVME_J_J_I_I_LAVMEPP_LAVMEPC_I_I_F_F_I_I_I_I);
 
   jobject ret =
-      env->CallStaticObjectMethod(android_view_MotionEvent_clazz(env),
-          method_id, p0, p1, as_jint(p2), as_jint(p3), p4.obj(), p5.obj(), as_jint(p6), as_jint(p7),
-              p8, p9, as_jint(p10), as_jint(p11), as_jint(p12), as_jint(p13));
-  jni_generator::CheckException(env);
+      env->CallStaticObjectMethod(clazz,
+          call_context.base.method_id, p0, p1, as_jint(p2), as_jint(p3), p4.obj(), p5.obj(),
+              as_jint(p6), as_jint(p7), p8, p9, as_jint(p10), as_jint(p11), as_jint(p12),
+              as_jint(p13));
   return base::android::ScopedJavaLocalRef<jobject>(env, ret);
 }
 
@@ -221,20 +228,23 @@
     JniIntWrapper p10,
     JniIntWrapper p11,
     JniIntWrapper p12) {
-  CHECK_CLAZZ(env, android_view_MotionEvent_clazz(env),
+  jclass clazz = android_view_MotionEvent_clazz(env);
+  CHECK_CLAZZ(env, clazz,
       android_view_MotionEvent_clazz(env), NULL);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_STATIC>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "obtain",
           "(JJII[I[Landroid/view/MotionEvent$PointerCoords;IFFIIII)Landroid/view/MotionEvent;",
           &g_android_view_MotionEvent_obtainAVME_J_J_I_I_AI_LAVMEPC_I_F_F_I_I_I_I);
 
   jobject ret =
-      env->CallStaticObjectMethod(android_view_MotionEvent_clazz(env),
-          method_id, p0, p1, as_jint(p2), as_jint(p3), p4.obj(), p5.obj(), as_jint(p6), p7, p8,
-              as_jint(p9), as_jint(p10), as_jint(p11), as_jint(p12));
-  jni_generator::CheckException(env);
+      env->CallStaticObjectMethod(clazz,
+          call_context.base.method_id, p0, p1, as_jint(p2), as_jint(p3), p4.obj(), p5.obj(),
+              as_jint(p6), p7, p8, as_jint(p9), as_jint(p10), as_jint(p11), as_jint(p12));
   return base::android::ScopedJavaLocalRef<jobject>(env, ret);
 }
 
@@ -266,20 +276,23 @@
     jfloat p9,
     JniIntWrapper p10,
     JniIntWrapper p11) {
-  CHECK_CLAZZ(env, android_view_MotionEvent_clazz(env),
+  jclass clazz = android_view_MotionEvent_clazz(env);
+  CHECK_CLAZZ(env, clazz,
       android_view_MotionEvent_clazz(env), NULL);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_STATIC>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "obtain",
           "(JJIFFFFIFFII)Landroid/view/MotionEvent;",
           &g_android_view_MotionEvent_obtainAVME_J_J_I_F_F_F_F_I_F_F_I_I);
 
   jobject ret =
-      env->CallStaticObjectMethod(android_view_MotionEvent_clazz(env),
-          method_id, p0, p1, as_jint(p2), p3, p4, p5, p6, as_jint(p7), p8, p9, as_jint(p10),
-              as_jint(p11));
-  jni_generator::CheckException(env);
+      env->CallStaticObjectMethod(clazz,
+          call_context.base.method_id, p0, p1, as_jint(p2), p3, p4, p5, p6, as_jint(p7), p8, p9,
+              as_jint(p10), as_jint(p11));
   return base::android::ScopedJavaLocalRef<jobject>(env, ret);
 }
 
@@ -313,20 +326,23 @@
     jfloat p10,
     JniIntWrapper p11,
     JniIntWrapper p12) {
-  CHECK_CLAZZ(env, android_view_MotionEvent_clazz(env),
+  jclass clazz = android_view_MotionEvent_clazz(env);
+  CHECK_CLAZZ(env, clazz,
       android_view_MotionEvent_clazz(env), NULL);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_STATIC>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "obtain",
           "(JJIIFFFFIFFII)Landroid/view/MotionEvent;",
           &g_android_view_MotionEvent_obtainAVME_J_J_I_I_F_F_F_F_I_F_F_I_I);
 
   jobject ret =
-      env->CallStaticObjectMethod(android_view_MotionEvent_clazz(env),
-          method_id, p0, p1, as_jint(p2), as_jint(p3), p4, p5, p6, p7, as_jint(p8), p9, p10,
-              as_jint(p11), as_jint(p12));
-  jni_generator::CheckException(env);
+      env->CallStaticObjectMethod(clazz,
+          call_context.base.method_id, p0, p1, as_jint(p2), as_jint(p3), p4, p5, p6, p7,
+              as_jint(p8), p9, p10, as_jint(p11), as_jint(p12));
   return base::android::ScopedJavaLocalRef<jobject>(env, ret);
 }
 
@@ -345,19 +361,22 @@
     jfloat p3,
     jfloat p4,
     JniIntWrapper p5) {
-  CHECK_CLAZZ(env, android_view_MotionEvent_clazz(env),
+  jclass clazz = android_view_MotionEvent_clazz(env);
+  CHECK_CLAZZ(env, clazz,
       android_view_MotionEvent_clazz(env), NULL);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_STATIC>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "obtain",
           "(JJIFFI)Landroid/view/MotionEvent;",
           &g_android_view_MotionEvent_obtainAVME_J_J_I_F_F_I);
 
   jobject ret =
-      env->CallStaticObjectMethod(android_view_MotionEvent_clazz(env),
-          method_id, p0, p1, as_jint(p2), p3, p4, as_jint(p5));
-  jni_generator::CheckException(env);
+      env->CallStaticObjectMethod(clazz,
+          call_context.base.method_id, p0, p1, as_jint(p2), p3, p4, as_jint(p5));
   return base::android::ScopedJavaLocalRef<jobject>(env, ret);
 }
 
@@ -366,19 +385,22 @@
     const base::android::JavaRef<jobject>& p0) __attribute__ ((unused));
 static base::android::ScopedJavaLocalRef<jobject> Java_MotionEvent_obtainAVME_AVME(JNIEnv* env,
     const base::android::JavaRef<jobject>& p0) {
-  CHECK_CLAZZ(env, android_view_MotionEvent_clazz(env),
+  jclass clazz = android_view_MotionEvent_clazz(env);
+  CHECK_CLAZZ(env, clazz,
       android_view_MotionEvent_clazz(env), NULL);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_STATIC>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "obtain",
           "(Landroid/view/MotionEvent;)Landroid/view/MotionEvent;",
           &g_android_view_MotionEvent_obtainAVME_AVME);
 
   jobject ret =
-      env->CallStaticObjectMethod(android_view_MotionEvent_clazz(env),
-          method_id, p0.obj());
-  jni_generator::CheckException(env);
+      env->CallStaticObjectMethod(clazz,
+          call_context.base.method_id, p0.obj());
   return base::android::ScopedJavaLocalRef<jobject>(env, ret);
 }
 
@@ -387,19 +409,22 @@
     const base::android::JavaRef<jobject>& p0) __attribute__ ((unused));
 static base::android::ScopedJavaLocalRef<jobject> Java_MotionEvent_obtainNoHistory(JNIEnv* env,
     const base::android::JavaRef<jobject>& p0) {
-  CHECK_CLAZZ(env, android_view_MotionEvent_clazz(env),
+  jclass clazz = android_view_MotionEvent_clazz(env);
+  CHECK_CLAZZ(env, clazz,
       android_view_MotionEvent_clazz(env), NULL);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_STATIC>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "obtainNoHistory",
           "(Landroid/view/MotionEvent;)Landroid/view/MotionEvent;",
           &g_android_view_MotionEvent_obtainNoHistory);
 
   jobject ret =
-      env->CallStaticObjectMethod(android_view_MotionEvent_clazz(env),
-          method_id, p0.obj());
-  jni_generator::CheckException(env);
+      env->CallStaticObjectMethod(clazz,
+          call_context.base.method_id, p0.obj());
   return base::android::ScopedJavaLocalRef<jobject>(env, ret);
 }
 
@@ -407,37 +432,43 @@
 static void Java_MotionEvent_recycle(JNIEnv* env, const base::android::JavaRef<jobject>& obj)
     __attribute__ ((unused));
 static void Java_MotionEvent_recycle(JNIEnv* env, const base::android::JavaRef<jobject>& obj) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env));
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "recycle",
           "()V",
           &g_android_view_MotionEvent_recycle);
 
      env->CallVoidMethod(obj.obj(),
-          method_id);
-  jni_generator::CheckException(env);
+          call_context.base.method_id);
 }
 
 static std::atomic<jmethodID> g_android_view_MotionEvent_getDeviceId(nullptr);
 static jint Java_MotionEvent_getDeviceId(JNIEnv* env, const base::android::JavaRef<jobject>& obj)
     __attribute__ ((unused));
 static jint Java_MotionEvent_getDeviceId(JNIEnv* env, const base::android::JavaRef<jobject>& obj) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "getDeviceId",
           "()I",
           &g_android_view_MotionEvent_getDeviceId);
 
   jint ret =
       env->CallIntMethod(obj.obj(),
-          method_id);
-  jni_generator::CheckException(env);
+          call_context.base.method_id);
   return ret;
 }
 
@@ -445,19 +476,22 @@
 static jint Java_MotionEvent_getSource(JNIEnv* env, const base::android::JavaRef<jobject>& obj)
     __attribute__ ((unused));
 static jint Java_MotionEvent_getSource(JNIEnv* env, const base::android::JavaRef<jobject>& obj) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "getSource",
           "()I",
           &g_android_view_MotionEvent_getSource);
 
   jint ret =
       env->CallIntMethod(obj.obj(),
-          method_id);
-  jni_generator::CheckException(env);
+          call_context.base.method_id);
   return ret;
 }
 
@@ -466,37 +500,43 @@
     JniIntWrapper p0) __attribute__ ((unused));
 static void Java_MotionEvent_setSource(JNIEnv* env, const base::android::JavaRef<jobject>& obj,
     JniIntWrapper p0) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env));
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "setSource",
           "(I)V",
           &g_android_view_MotionEvent_setSource);
 
      env->CallVoidMethod(obj.obj(),
-          method_id, as_jint(p0));
-  jni_generator::CheckException(env);
+          call_context.base.method_id, as_jint(p0));
 }
 
 static std::atomic<jmethodID> g_android_view_MotionEvent_getAction(nullptr);
 static jint Java_MotionEvent_getAction(JNIEnv* env, const base::android::JavaRef<jobject>& obj)
     __attribute__ ((unused));
 static jint Java_MotionEvent_getAction(JNIEnv* env, const base::android::JavaRef<jobject>& obj) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "getAction",
           "()I",
           &g_android_view_MotionEvent_getAction);
 
   jint ret =
       env->CallIntMethod(obj.obj(),
-          method_id);
-  jni_generator::CheckException(env);
+          call_context.base.method_id);
   return ret;
 }
 
@@ -505,19 +545,22 @@
     obj) __attribute__ ((unused));
 static jint Java_MotionEvent_getActionMasked(JNIEnv* env, const base::android::JavaRef<jobject>&
     obj) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "getActionMasked",
           "()I",
           &g_android_view_MotionEvent_getActionMasked);
 
   jint ret =
       env->CallIntMethod(obj.obj(),
-          method_id);
-  jni_generator::CheckException(env);
+          call_context.base.method_id);
   return ret;
 }
 
@@ -526,19 +569,22 @@
     __attribute__ ((unused));
 static jint Java_MotionEvent_getActionIndex(JNIEnv* env, const base::android::JavaRef<jobject>& obj)
     {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "getActionIndex",
           "()I",
           &g_android_view_MotionEvent_getActionIndex);
 
   jint ret =
       env->CallIntMethod(obj.obj(),
-          method_id);
-  jni_generator::CheckException(env);
+          call_context.base.method_id);
   return ret;
 }
 
@@ -546,19 +592,22 @@
 static jint Java_MotionEvent_getFlags(JNIEnv* env, const base::android::JavaRef<jobject>& obj)
     __attribute__ ((unused));
 static jint Java_MotionEvent_getFlags(JNIEnv* env, const base::android::JavaRef<jobject>& obj) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "getFlags",
           "()I",
           &g_android_view_MotionEvent_getFlags);
 
   jint ret =
       env->CallIntMethod(obj.obj(),
-          method_id);
-  jni_generator::CheckException(env);
+          call_context.base.method_id);
   return ret;
 }
 
@@ -566,19 +615,22 @@
 static jlong Java_MotionEvent_getDownTime(JNIEnv* env, const base::android::JavaRef<jobject>& obj)
     __attribute__ ((unused));
 static jlong Java_MotionEvent_getDownTime(JNIEnv* env, const base::android::JavaRef<jobject>& obj) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "getDownTime",
           "()J",
           &g_android_view_MotionEvent_getDownTime);
 
   jlong ret =
       env->CallLongMethod(obj.obj(),
-          method_id);
-  jni_generator::CheckException(env);
+          call_context.base.method_id);
   return ret;
 }
 
@@ -587,19 +639,22 @@
     __attribute__ ((unused));
 static jlong Java_MotionEvent_getEventTime(JNIEnv* env, const base::android::JavaRef<jobject>& obj)
     {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "getEventTime",
           "()J",
           &g_android_view_MotionEvent_getEventTime);
 
   jlong ret =
       env->CallLongMethod(obj.obj(),
-          method_id);
-  jni_generator::CheckException(env);
+          call_context.base.method_id);
   return ret;
 }
 
@@ -607,19 +662,22 @@
 static jfloat Java_MotionEvent_getXF(JNIEnv* env, const base::android::JavaRef<jobject>& obj)
     __attribute__ ((unused));
 static jfloat Java_MotionEvent_getXF(JNIEnv* env, const base::android::JavaRef<jobject>& obj) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "getX",
           "()F",
           &g_android_view_MotionEvent_getXF);
 
   jfloat ret =
       env->CallFloatMethod(obj.obj(),
-          method_id);
-  jni_generator::CheckException(env);
+          call_context.base.method_id);
   return ret;
 }
 
@@ -627,19 +685,22 @@
 static jfloat Java_MotionEvent_getYF(JNIEnv* env, const base::android::JavaRef<jobject>& obj)
     __attribute__ ((unused));
 static jfloat Java_MotionEvent_getYF(JNIEnv* env, const base::android::JavaRef<jobject>& obj) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "getY",
           "()F",
           &g_android_view_MotionEvent_getYF);
 
   jfloat ret =
       env->CallFloatMethod(obj.obj(),
-          method_id);
-  jni_generator::CheckException(env);
+          call_context.base.method_id);
   return ret;
 }
 
@@ -648,19 +709,22 @@
     __attribute__ ((unused));
 static jfloat Java_MotionEvent_getPressureF(JNIEnv* env, const base::android::JavaRef<jobject>& obj)
     {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "getPressure",
           "()F",
           &g_android_view_MotionEvent_getPressureF);
 
   jfloat ret =
       env->CallFloatMethod(obj.obj(),
-          method_id);
-  jni_generator::CheckException(env);
+          call_context.base.method_id);
   return ret;
 }
 
@@ -668,19 +732,22 @@
 static jfloat Java_MotionEvent_getSizeF(JNIEnv* env, const base::android::JavaRef<jobject>& obj)
     __attribute__ ((unused));
 static jfloat Java_MotionEvent_getSizeF(JNIEnv* env, const base::android::JavaRef<jobject>& obj) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "getSize",
           "()F",
           &g_android_view_MotionEvent_getSizeF);
 
   jfloat ret =
       env->CallFloatMethod(obj.obj(),
-          method_id);
-  jni_generator::CheckException(env);
+          call_context.base.method_id);
   return ret;
 }
 
@@ -689,19 +756,22 @@
     obj) __attribute__ ((unused));
 static jfloat Java_MotionEvent_getTouchMajorF(JNIEnv* env, const base::android::JavaRef<jobject>&
     obj) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "getTouchMajor",
           "()F",
           &g_android_view_MotionEvent_getTouchMajorF);
 
   jfloat ret =
       env->CallFloatMethod(obj.obj(),
-          method_id);
-  jni_generator::CheckException(env);
+          call_context.base.method_id);
   return ret;
 }
 
@@ -710,19 +780,22 @@
     obj) __attribute__ ((unused));
 static jfloat Java_MotionEvent_getTouchMinorF(JNIEnv* env, const base::android::JavaRef<jobject>&
     obj) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "getTouchMinor",
           "()F",
           &g_android_view_MotionEvent_getTouchMinorF);
 
   jfloat ret =
       env->CallFloatMethod(obj.obj(),
-          method_id);
-  jni_generator::CheckException(env);
+          call_context.base.method_id);
   return ret;
 }
 
@@ -731,19 +804,22 @@
     obj) __attribute__ ((unused));
 static jfloat Java_MotionEvent_getToolMajorF(JNIEnv* env, const base::android::JavaRef<jobject>&
     obj) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "getToolMajor",
           "()F",
           &g_android_view_MotionEvent_getToolMajorF);
 
   jfloat ret =
       env->CallFloatMethod(obj.obj(),
-          method_id);
-  jni_generator::CheckException(env);
+          call_context.base.method_id);
   return ret;
 }
 
@@ -752,19 +828,22 @@
     obj) __attribute__ ((unused));
 static jfloat Java_MotionEvent_getToolMinorF(JNIEnv* env, const base::android::JavaRef<jobject>&
     obj) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "getToolMinor",
           "()F",
           &g_android_view_MotionEvent_getToolMinorF);
 
   jfloat ret =
       env->CallFloatMethod(obj.obj(),
-          method_id);
-  jni_generator::CheckException(env);
+          call_context.base.method_id);
   return ret;
 }
 
@@ -773,19 +852,22 @@
     obj) __attribute__ ((unused));
 static jfloat Java_MotionEvent_getOrientationF(JNIEnv* env, const base::android::JavaRef<jobject>&
     obj) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "getOrientation",
           "()F",
           &g_android_view_MotionEvent_getOrientationF);
 
   jfloat ret =
       env->CallFloatMethod(obj.obj(),
-          method_id);
-  jni_generator::CheckException(env);
+          call_context.base.method_id);
   return ret;
 }
 
@@ -794,19 +876,22 @@
     obj, JniIntWrapper p0) __attribute__ ((unused));
 static jfloat Java_MotionEvent_getAxisValueF_I(JNIEnv* env, const base::android::JavaRef<jobject>&
     obj, JniIntWrapper p0) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "getAxisValue",
           "(I)F",
           &g_android_view_MotionEvent_getAxisValueF_I);
 
   jfloat ret =
       env->CallFloatMethod(obj.obj(),
-          method_id, as_jint(p0));
-  jni_generator::CheckException(env);
+          call_context.base.method_id, as_jint(p0));
   return ret;
 }
 
@@ -815,19 +900,22 @@
     obj) __attribute__ ((unused));
 static jint Java_MotionEvent_getPointerCount(JNIEnv* env, const base::android::JavaRef<jobject>&
     obj) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "getPointerCount",
           "()I",
           &g_android_view_MotionEvent_getPointerCount);
 
   jint ret =
       env->CallIntMethod(obj.obj(),
-          method_id);
-  jni_generator::CheckException(env);
+          call_context.base.method_id);
   return ret;
 }
 
@@ -836,19 +924,22 @@
     JniIntWrapper p0) __attribute__ ((unused));
 static jint Java_MotionEvent_getPointerId(JNIEnv* env, const base::android::JavaRef<jobject>& obj,
     JniIntWrapper p0) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "getPointerId",
           "(I)I",
           &g_android_view_MotionEvent_getPointerId);
 
   jint ret =
       env->CallIntMethod(obj.obj(),
-          method_id, as_jint(p0));
-  jni_generator::CheckException(env);
+          call_context.base.method_id, as_jint(p0));
   return ret;
 }
 
@@ -857,19 +948,22 @@
     JniIntWrapper p0) __attribute__ ((unused));
 static jint Java_MotionEvent_getToolType(JNIEnv* env, const base::android::JavaRef<jobject>& obj,
     JniIntWrapper p0) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "getToolType",
           "(I)I",
           &g_android_view_MotionEvent_getToolType);
 
   jint ret =
       env->CallIntMethod(obj.obj(),
-          method_id, as_jint(p0));
-  jni_generator::CheckException(env);
+          call_context.base.method_id, as_jint(p0));
   return ret;
 }
 
@@ -878,19 +972,22 @@
     obj, JniIntWrapper p0) __attribute__ ((unused));
 static jint Java_MotionEvent_findPointerIndex(JNIEnv* env, const base::android::JavaRef<jobject>&
     obj, JniIntWrapper p0) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "findPointerIndex",
           "(I)I",
           &g_android_view_MotionEvent_findPointerIndex);
 
   jint ret =
       env->CallIntMethod(obj.obj(),
-          method_id, as_jint(p0));
-  jni_generator::CheckException(env);
+          call_context.base.method_id, as_jint(p0));
   return ret;
 }
 
@@ -899,19 +996,22 @@
     JniIntWrapper p0) __attribute__ ((unused));
 static jfloat Java_MotionEvent_getXF_I(JNIEnv* env, const base::android::JavaRef<jobject>& obj,
     JniIntWrapper p0) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "getX",
           "(I)F",
           &g_android_view_MotionEvent_getXF_I);
 
   jfloat ret =
       env->CallFloatMethod(obj.obj(),
-          method_id, as_jint(p0));
-  jni_generator::CheckException(env);
+          call_context.base.method_id, as_jint(p0));
   return ret;
 }
 
@@ -920,19 +1020,22 @@
     JniIntWrapper p0) __attribute__ ((unused));
 static jfloat Java_MotionEvent_getYF_I(JNIEnv* env, const base::android::JavaRef<jobject>& obj,
     JniIntWrapper p0) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "getY",
           "(I)F",
           &g_android_view_MotionEvent_getYF_I);
 
   jfloat ret =
       env->CallFloatMethod(obj.obj(),
-          method_id, as_jint(p0));
-  jni_generator::CheckException(env);
+          call_context.base.method_id, as_jint(p0));
   return ret;
 }
 
@@ -941,19 +1044,22 @@
     obj, JniIntWrapper p0) __attribute__ ((unused));
 static jfloat Java_MotionEvent_getPressureF_I(JNIEnv* env, const base::android::JavaRef<jobject>&
     obj, JniIntWrapper p0) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "getPressure",
           "(I)F",
           &g_android_view_MotionEvent_getPressureF_I);
 
   jfloat ret =
       env->CallFloatMethod(obj.obj(),
-          method_id, as_jint(p0));
-  jni_generator::CheckException(env);
+          call_context.base.method_id, as_jint(p0));
   return ret;
 }
 
@@ -962,19 +1068,22 @@
     JniIntWrapper p0) __attribute__ ((unused));
 static jfloat Java_MotionEvent_getSizeF_I(JNIEnv* env, const base::android::JavaRef<jobject>& obj,
     JniIntWrapper p0) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "getSize",
           "(I)F",
           &g_android_view_MotionEvent_getSizeF_I);
 
   jfloat ret =
       env->CallFloatMethod(obj.obj(),
-          method_id, as_jint(p0));
-  jni_generator::CheckException(env);
+          call_context.base.method_id, as_jint(p0));
   return ret;
 }
 
@@ -983,19 +1092,22 @@
     obj, JniIntWrapper p0) __attribute__ ((unused));
 static jfloat Java_MotionEvent_getTouchMajorF_I(JNIEnv* env, const base::android::JavaRef<jobject>&
     obj, JniIntWrapper p0) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "getTouchMajor",
           "(I)F",
           &g_android_view_MotionEvent_getTouchMajorF_I);
 
   jfloat ret =
       env->CallFloatMethod(obj.obj(),
-          method_id, as_jint(p0));
-  jni_generator::CheckException(env);
+          call_context.base.method_id, as_jint(p0));
   return ret;
 }
 
@@ -1004,19 +1116,22 @@
     obj, JniIntWrapper p0) __attribute__ ((unused));
 static jfloat Java_MotionEvent_getTouchMinorF_I(JNIEnv* env, const base::android::JavaRef<jobject>&
     obj, JniIntWrapper p0) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "getTouchMinor",
           "(I)F",
           &g_android_view_MotionEvent_getTouchMinorF_I);
 
   jfloat ret =
       env->CallFloatMethod(obj.obj(),
-          method_id, as_jint(p0));
-  jni_generator::CheckException(env);
+          call_context.base.method_id, as_jint(p0));
   return ret;
 }
 
@@ -1025,19 +1140,22 @@
     obj, JniIntWrapper p0) __attribute__ ((unused));
 static jfloat Java_MotionEvent_getToolMajorF_I(JNIEnv* env, const base::android::JavaRef<jobject>&
     obj, JniIntWrapper p0) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "getToolMajor",
           "(I)F",
           &g_android_view_MotionEvent_getToolMajorF_I);
 
   jfloat ret =
       env->CallFloatMethod(obj.obj(),
-          method_id, as_jint(p0));
-  jni_generator::CheckException(env);
+          call_context.base.method_id, as_jint(p0));
   return ret;
 }
 
@@ -1046,19 +1164,22 @@
     obj, JniIntWrapper p0) __attribute__ ((unused));
 static jfloat Java_MotionEvent_getToolMinorF_I(JNIEnv* env, const base::android::JavaRef<jobject>&
     obj, JniIntWrapper p0) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "getToolMinor",
           "(I)F",
           &g_android_view_MotionEvent_getToolMinorF_I);
 
   jfloat ret =
       env->CallFloatMethod(obj.obj(),
-          method_id, as_jint(p0));
-  jni_generator::CheckException(env);
+          call_context.base.method_id, as_jint(p0));
   return ret;
 }
 
@@ -1067,19 +1188,22 @@
     obj, JniIntWrapper p0) __attribute__ ((unused));
 static jfloat Java_MotionEvent_getOrientationF_I(JNIEnv* env, const base::android::JavaRef<jobject>&
     obj, JniIntWrapper p0) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "getOrientation",
           "(I)F",
           &g_android_view_MotionEvent_getOrientationF_I);
 
   jfloat ret =
       env->CallFloatMethod(obj.obj(),
-          method_id, as_jint(p0));
-  jni_generator::CheckException(env);
+          call_context.base.method_id, as_jint(p0));
   return ret;
 }
 
@@ -1090,19 +1214,22 @@
 static jfloat Java_MotionEvent_getAxisValueF_I_I(JNIEnv* env, const base::android::JavaRef<jobject>&
     obj, JniIntWrapper p0,
     JniIntWrapper p1) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "getAxisValue",
           "(II)F",
           &g_android_view_MotionEvent_getAxisValueF_I_I);
 
   jfloat ret =
       env->CallFloatMethod(obj.obj(),
-          method_id, as_jint(p0), as_jint(p1));
-  jni_generator::CheckException(env);
+          call_context.base.method_id, as_jint(p0), as_jint(p1));
   return ret;
 }
 
@@ -1113,18 +1240,21 @@
 static void Java_MotionEvent_getPointerCoords(JNIEnv* env, const base::android::JavaRef<jobject>&
     obj, JniIntWrapper p0,
     const base::android::JavaRef<jobject>& p1) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env));
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "getPointerCoords",
           "(ILandroid/view/MotionEvent$PointerCoords;)V",
           &g_android_view_MotionEvent_getPointerCoords);
 
      env->CallVoidMethod(obj.obj(),
-          method_id, as_jint(p0), p1.obj());
-  jni_generator::CheckException(env);
+          call_context.base.method_id, as_jint(p0), p1.obj());
 }
 
 static std::atomic<jmethodID> g_android_view_MotionEvent_getPointerProperties(nullptr);
@@ -1134,37 +1264,43 @@
 static void Java_MotionEvent_getPointerProperties(JNIEnv* env, const
     base::android::JavaRef<jobject>& obj, JniIntWrapper p0,
     const base::android::JavaRef<jobject>& p1) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env));
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "getPointerProperties",
           "(ILandroid/view/MotionEvent$PointerProperties;)V",
           &g_android_view_MotionEvent_getPointerProperties);
 
      env->CallVoidMethod(obj.obj(),
-          method_id, as_jint(p0), p1.obj());
-  jni_generator::CheckException(env);
+          call_context.base.method_id, as_jint(p0), p1.obj());
 }
 
 static std::atomic<jmethodID> g_android_view_MotionEvent_getMetaState(nullptr);
 static jint Java_MotionEvent_getMetaState(JNIEnv* env, const base::android::JavaRef<jobject>& obj)
     __attribute__ ((unused));
 static jint Java_MotionEvent_getMetaState(JNIEnv* env, const base::android::JavaRef<jobject>& obj) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "getMetaState",
           "()I",
           &g_android_view_MotionEvent_getMetaState);
 
   jint ret =
       env->CallIntMethod(obj.obj(),
-          method_id);
-  jni_generator::CheckException(env);
+          call_context.base.method_id);
   return ret;
 }
 
@@ -1173,19 +1309,22 @@
     __attribute__ ((unused));
 static jint Java_MotionEvent_getButtonState(JNIEnv* env, const base::android::JavaRef<jobject>& obj)
     {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "getButtonState",
           "()I",
           &g_android_view_MotionEvent_getButtonState);
 
   jint ret =
       env->CallIntMethod(obj.obj(),
-          method_id);
-  jni_generator::CheckException(env);
+          call_context.base.method_id);
   return ret;
 }
 
@@ -1193,19 +1332,22 @@
 static jfloat Java_MotionEvent_getRawX(JNIEnv* env, const base::android::JavaRef<jobject>& obj)
     __attribute__ ((unused));
 static jfloat Java_MotionEvent_getRawX(JNIEnv* env, const base::android::JavaRef<jobject>& obj) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "getRawX",
           "()F",
           &g_android_view_MotionEvent_getRawX);
 
   jfloat ret =
       env->CallFloatMethod(obj.obj(),
-          method_id);
-  jni_generator::CheckException(env);
+          call_context.base.method_id);
   return ret;
 }
 
@@ -1213,19 +1355,22 @@
 static jfloat Java_MotionEvent_getRawY(JNIEnv* env, const base::android::JavaRef<jobject>& obj)
     __attribute__ ((unused));
 static jfloat Java_MotionEvent_getRawY(JNIEnv* env, const base::android::JavaRef<jobject>& obj) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "getRawY",
           "()F",
           &g_android_view_MotionEvent_getRawY);
 
   jfloat ret =
       env->CallFloatMethod(obj.obj(),
-          method_id);
-  jni_generator::CheckException(env);
+          call_context.base.method_id);
   return ret;
 }
 
@@ -1234,19 +1379,22 @@
     obj) __attribute__ ((unused));
 static jfloat Java_MotionEvent_getXPrecision(JNIEnv* env, const base::android::JavaRef<jobject>&
     obj) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "getXPrecision",
           "()F",
           &g_android_view_MotionEvent_getXPrecision);
 
   jfloat ret =
       env->CallFloatMethod(obj.obj(),
-          method_id);
-  jni_generator::CheckException(env);
+          call_context.base.method_id);
   return ret;
 }
 
@@ -1255,19 +1403,22 @@
     obj) __attribute__ ((unused));
 static jfloat Java_MotionEvent_getYPrecision(JNIEnv* env, const base::android::JavaRef<jobject>&
     obj) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "getYPrecision",
           "()F",
           &g_android_view_MotionEvent_getYPrecision);
 
   jfloat ret =
       env->CallFloatMethod(obj.obj(),
-          method_id);
-  jni_generator::CheckException(env);
+          call_context.base.method_id);
   return ret;
 }
 
@@ -1276,19 +1427,22 @@
     __attribute__ ((unused));
 static jint Java_MotionEvent_getHistorySize(JNIEnv* env, const base::android::JavaRef<jobject>& obj)
     {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "getHistorySize",
           "()I",
           &g_android_view_MotionEvent_getHistorySize);
 
   jint ret =
       env->CallIntMethod(obj.obj(),
-          method_id);
-  jni_generator::CheckException(env);
+          call_context.base.method_id);
   return ret;
 }
 
@@ -1297,19 +1451,22 @@
     base::android::JavaRef<jobject>& obj, JniIntWrapper p0) __attribute__ ((unused));
 static jlong Java_MotionEvent_getHistoricalEventTime(JNIEnv* env, const
     base::android::JavaRef<jobject>& obj, JniIntWrapper p0) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "getHistoricalEventTime",
           "(I)J",
           &g_android_view_MotionEvent_getHistoricalEventTime);
 
   jlong ret =
       env->CallLongMethod(obj.obj(),
-          method_id, as_jint(p0));
-  jni_generator::CheckException(env);
+          call_context.base.method_id, as_jint(p0));
   return ret;
 }
 
@@ -1318,19 +1475,22 @@
     obj, JniIntWrapper p0) __attribute__ ((unused));
 static jfloat Java_MotionEvent_getHistoricalXF_I(JNIEnv* env, const base::android::JavaRef<jobject>&
     obj, JniIntWrapper p0) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "getHistoricalX",
           "(I)F",
           &g_android_view_MotionEvent_getHistoricalXF_I);
 
   jfloat ret =
       env->CallFloatMethod(obj.obj(),
-          method_id, as_jint(p0));
-  jni_generator::CheckException(env);
+          call_context.base.method_id, as_jint(p0));
   return ret;
 }
 
@@ -1339,19 +1499,22 @@
     obj, JniIntWrapper p0) __attribute__ ((unused));
 static jfloat Java_MotionEvent_getHistoricalYF_I(JNIEnv* env, const base::android::JavaRef<jobject>&
     obj, JniIntWrapper p0) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "getHistoricalY",
           "(I)F",
           &g_android_view_MotionEvent_getHistoricalYF_I);
 
   jfloat ret =
       env->CallFloatMethod(obj.obj(),
-          method_id, as_jint(p0));
-  jni_generator::CheckException(env);
+          call_context.base.method_id, as_jint(p0));
   return ret;
 }
 
@@ -1360,19 +1523,22 @@
     base::android::JavaRef<jobject>& obj, JniIntWrapper p0) __attribute__ ((unused));
 static jfloat Java_MotionEvent_getHistoricalPressureF_I(JNIEnv* env, const
     base::android::JavaRef<jobject>& obj, JniIntWrapper p0) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "getHistoricalPressure",
           "(I)F",
           &g_android_view_MotionEvent_getHistoricalPressureF_I);
 
   jfloat ret =
       env->CallFloatMethod(obj.obj(),
-          method_id, as_jint(p0));
-  jni_generator::CheckException(env);
+          call_context.base.method_id, as_jint(p0));
   return ret;
 }
 
@@ -1381,19 +1547,22 @@
     base::android::JavaRef<jobject>& obj, JniIntWrapper p0) __attribute__ ((unused));
 static jfloat Java_MotionEvent_getHistoricalSizeF_I(JNIEnv* env, const
     base::android::JavaRef<jobject>& obj, JniIntWrapper p0) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "getHistoricalSize",
           "(I)F",
           &g_android_view_MotionEvent_getHistoricalSizeF_I);
 
   jfloat ret =
       env->CallFloatMethod(obj.obj(),
-          method_id, as_jint(p0));
-  jni_generator::CheckException(env);
+          call_context.base.method_id, as_jint(p0));
   return ret;
 }
 
@@ -1402,19 +1571,22 @@
     base::android::JavaRef<jobject>& obj, JniIntWrapper p0) __attribute__ ((unused));
 static jfloat Java_MotionEvent_getHistoricalTouchMajorF_I(JNIEnv* env, const
     base::android::JavaRef<jobject>& obj, JniIntWrapper p0) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "getHistoricalTouchMajor",
           "(I)F",
           &g_android_view_MotionEvent_getHistoricalTouchMajorF_I);
 
   jfloat ret =
       env->CallFloatMethod(obj.obj(),
-          method_id, as_jint(p0));
-  jni_generator::CheckException(env);
+          call_context.base.method_id, as_jint(p0));
   return ret;
 }
 
@@ -1423,19 +1595,22 @@
     base::android::JavaRef<jobject>& obj, JniIntWrapper p0) __attribute__ ((unused));
 static jfloat Java_MotionEvent_getHistoricalTouchMinorF_I(JNIEnv* env, const
     base::android::JavaRef<jobject>& obj, JniIntWrapper p0) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "getHistoricalTouchMinor",
           "(I)F",
           &g_android_view_MotionEvent_getHistoricalTouchMinorF_I);
 
   jfloat ret =
       env->CallFloatMethod(obj.obj(),
-          method_id, as_jint(p0));
-  jni_generator::CheckException(env);
+          call_context.base.method_id, as_jint(p0));
   return ret;
 }
 
@@ -1444,19 +1619,22 @@
     base::android::JavaRef<jobject>& obj, JniIntWrapper p0) __attribute__ ((unused));
 static jfloat Java_MotionEvent_getHistoricalToolMajorF_I(JNIEnv* env, const
     base::android::JavaRef<jobject>& obj, JniIntWrapper p0) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "getHistoricalToolMajor",
           "(I)F",
           &g_android_view_MotionEvent_getHistoricalToolMajorF_I);
 
   jfloat ret =
       env->CallFloatMethod(obj.obj(),
-          method_id, as_jint(p0));
-  jni_generator::CheckException(env);
+          call_context.base.method_id, as_jint(p0));
   return ret;
 }
 
@@ -1465,19 +1643,22 @@
     base::android::JavaRef<jobject>& obj, JniIntWrapper p0) __attribute__ ((unused));
 static jfloat Java_MotionEvent_getHistoricalToolMinorF_I(JNIEnv* env, const
     base::android::JavaRef<jobject>& obj, JniIntWrapper p0) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "getHistoricalToolMinor",
           "(I)F",
           &g_android_view_MotionEvent_getHistoricalToolMinorF_I);
 
   jfloat ret =
       env->CallFloatMethod(obj.obj(),
-          method_id, as_jint(p0));
-  jni_generator::CheckException(env);
+          call_context.base.method_id, as_jint(p0));
   return ret;
 }
 
@@ -1486,19 +1667,22 @@
     base::android::JavaRef<jobject>& obj, JniIntWrapper p0) __attribute__ ((unused));
 static jfloat Java_MotionEvent_getHistoricalOrientationF_I(JNIEnv* env, const
     base::android::JavaRef<jobject>& obj, JniIntWrapper p0) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "getHistoricalOrientation",
           "(I)F",
           &g_android_view_MotionEvent_getHistoricalOrientationF_I);
 
   jfloat ret =
       env->CallFloatMethod(obj.obj(),
-          method_id, as_jint(p0));
-  jni_generator::CheckException(env);
+          call_context.base.method_id, as_jint(p0));
   return ret;
 }
 
@@ -1509,19 +1693,22 @@
 static jfloat Java_MotionEvent_getHistoricalAxisValueF_I_I(JNIEnv* env, const
     base::android::JavaRef<jobject>& obj, JniIntWrapper p0,
     JniIntWrapper p1) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "getHistoricalAxisValue",
           "(II)F",
           &g_android_view_MotionEvent_getHistoricalAxisValueF_I_I);
 
   jfloat ret =
       env->CallFloatMethod(obj.obj(),
-          method_id, as_jint(p0), as_jint(p1));
-  jni_generator::CheckException(env);
+          call_context.base.method_id, as_jint(p0), as_jint(p1));
   return ret;
 }
 
@@ -1532,19 +1719,22 @@
 static jfloat Java_MotionEvent_getHistoricalXF_I_I(JNIEnv* env, const
     base::android::JavaRef<jobject>& obj, JniIntWrapper p0,
     JniIntWrapper p1) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "getHistoricalX",
           "(II)F",
           &g_android_view_MotionEvent_getHistoricalXF_I_I);
 
   jfloat ret =
       env->CallFloatMethod(obj.obj(),
-          method_id, as_jint(p0), as_jint(p1));
-  jni_generator::CheckException(env);
+          call_context.base.method_id, as_jint(p0), as_jint(p1));
   return ret;
 }
 
@@ -1555,19 +1745,22 @@
 static jfloat Java_MotionEvent_getHistoricalYF_I_I(JNIEnv* env, const
     base::android::JavaRef<jobject>& obj, JniIntWrapper p0,
     JniIntWrapper p1) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "getHistoricalY",
           "(II)F",
           &g_android_view_MotionEvent_getHistoricalYF_I_I);
 
   jfloat ret =
       env->CallFloatMethod(obj.obj(),
-          method_id, as_jint(p0), as_jint(p1));
-  jni_generator::CheckException(env);
+          call_context.base.method_id, as_jint(p0), as_jint(p1));
   return ret;
 }
 
@@ -1578,19 +1771,22 @@
 static jfloat Java_MotionEvent_getHistoricalPressureF_I_I(JNIEnv* env, const
     base::android::JavaRef<jobject>& obj, JniIntWrapper p0,
     JniIntWrapper p1) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "getHistoricalPressure",
           "(II)F",
           &g_android_view_MotionEvent_getHistoricalPressureF_I_I);
 
   jfloat ret =
       env->CallFloatMethod(obj.obj(),
-          method_id, as_jint(p0), as_jint(p1));
-  jni_generator::CheckException(env);
+          call_context.base.method_id, as_jint(p0), as_jint(p1));
   return ret;
 }
 
@@ -1601,19 +1797,22 @@
 static jfloat Java_MotionEvent_getHistoricalSizeF_I_I(JNIEnv* env, const
     base::android::JavaRef<jobject>& obj, JniIntWrapper p0,
     JniIntWrapper p1) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "getHistoricalSize",
           "(II)F",
           &g_android_view_MotionEvent_getHistoricalSizeF_I_I);
 
   jfloat ret =
       env->CallFloatMethod(obj.obj(),
-          method_id, as_jint(p0), as_jint(p1));
-  jni_generator::CheckException(env);
+          call_context.base.method_id, as_jint(p0), as_jint(p1));
   return ret;
 }
 
@@ -1624,19 +1823,22 @@
 static jfloat Java_MotionEvent_getHistoricalTouchMajorF_I_I(JNIEnv* env, const
     base::android::JavaRef<jobject>& obj, JniIntWrapper p0,
     JniIntWrapper p1) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "getHistoricalTouchMajor",
           "(II)F",
           &g_android_view_MotionEvent_getHistoricalTouchMajorF_I_I);
 
   jfloat ret =
       env->CallFloatMethod(obj.obj(),
-          method_id, as_jint(p0), as_jint(p1));
-  jni_generator::CheckException(env);
+          call_context.base.method_id, as_jint(p0), as_jint(p1));
   return ret;
 }
 
@@ -1647,19 +1849,22 @@
 static jfloat Java_MotionEvent_getHistoricalTouchMinorF_I_I(JNIEnv* env, const
     base::android::JavaRef<jobject>& obj, JniIntWrapper p0,
     JniIntWrapper p1) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "getHistoricalTouchMinor",
           "(II)F",
           &g_android_view_MotionEvent_getHistoricalTouchMinorF_I_I);
 
   jfloat ret =
       env->CallFloatMethod(obj.obj(),
-          method_id, as_jint(p0), as_jint(p1));
-  jni_generator::CheckException(env);
+          call_context.base.method_id, as_jint(p0), as_jint(p1));
   return ret;
 }
 
@@ -1670,19 +1875,22 @@
 static jfloat Java_MotionEvent_getHistoricalToolMajorF_I_I(JNIEnv* env, const
     base::android::JavaRef<jobject>& obj, JniIntWrapper p0,
     JniIntWrapper p1) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "getHistoricalToolMajor",
           "(II)F",
           &g_android_view_MotionEvent_getHistoricalToolMajorF_I_I);
 
   jfloat ret =
       env->CallFloatMethod(obj.obj(),
-          method_id, as_jint(p0), as_jint(p1));
-  jni_generator::CheckException(env);
+          call_context.base.method_id, as_jint(p0), as_jint(p1));
   return ret;
 }
 
@@ -1693,19 +1901,22 @@
 static jfloat Java_MotionEvent_getHistoricalToolMinorF_I_I(JNIEnv* env, const
     base::android::JavaRef<jobject>& obj, JniIntWrapper p0,
     JniIntWrapper p1) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "getHistoricalToolMinor",
           "(II)F",
           &g_android_view_MotionEvent_getHistoricalToolMinorF_I_I);
 
   jfloat ret =
       env->CallFloatMethod(obj.obj(),
-          method_id, as_jint(p0), as_jint(p1));
-  jni_generator::CheckException(env);
+          call_context.base.method_id, as_jint(p0), as_jint(p1));
   return ret;
 }
 
@@ -1716,19 +1927,22 @@
 static jfloat Java_MotionEvent_getHistoricalOrientationF_I_I(JNIEnv* env, const
     base::android::JavaRef<jobject>& obj, JniIntWrapper p0,
     JniIntWrapper p1) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "getHistoricalOrientation",
           "(II)F",
           &g_android_view_MotionEvent_getHistoricalOrientationF_I_I);
 
   jfloat ret =
       env->CallFloatMethod(obj.obj(),
-          method_id, as_jint(p0), as_jint(p1));
-  jni_generator::CheckException(env);
+          call_context.base.method_id, as_jint(p0), as_jint(p1));
   return ret;
 }
 
@@ -1741,19 +1955,22 @@
     base::android::JavaRef<jobject>& obj, JniIntWrapper p0,
     JniIntWrapper p1,
     JniIntWrapper p2) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "getHistoricalAxisValue",
           "(III)F",
           &g_android_view_MotionEvent_getHistoricalAxisValueF_I_I_I);
 
   jfloat ret =
       env->CallFloatMethod(obj.obj(),
-          method_id, as_jint(p0), as_jint(p1), as_jint(p2));
-  jni_generator::CheckException(env);
+          call_context.base.method_id, as_jint(p0), as_jint(p1), as_jint(p2));
   return ret;
 }
 
@@ -1766,37 +1983,43 @@
     base::android::JavaRef<jobject>& obj, JniIntWrapper p0,
     JniIntWrapper p1,
     const base::android::JavaRef<jobject>& p2) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env));
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "getHistoricalPointerCoords",
           "(IILandroid/view/MotionEvent$PointerCoords;)V",
           &g_android_view_MotionEvent_getHistoricalPointerCoords);
 
      env->CallVoidMethod(obj.obj(),
-          method_id, as_jint(p0), as_jint(p1), p2.obj());
-  jni_generator::CheckException(env);
+          call_context.base.method_id, as_jint(p0), as_jint(p1), p2.obj());
 }
 
 static std::atomic<jmethodID> g_android_view_MotionEvent_getEdgeFlags(nullptr);
 static jint Java_MotionEvent_getEdgeFlags(JNIEnv* env, const base::android::JavaRef<jobject>& obj)
     __attribute__ ((unused));
 static jint Java_MotionEvent_getEdgeFlags(JNIEnv* env, const base::android::JavaRef<jobject>& obj) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "getEdgeFlags",
           "()I",
           &g_android_view_MotionEvent_getEdgeFlags);
 
   jint ret =
       env->CallIntMethod(obj.obj(),
-          method_id);
-  jni_generator::CheckException(env);
+          call_context.base.method_id);
   return ret;
 }
 
@@ -1805,18 +2028,21 @@
     JniIntWrapper p0) __attribute__ ((unused));
 static void Java_MotionEvent_setEdgeFlags(JNIEnv* env, const base::android::JavaRef<jobject>& obj,
     JniIntWrapper p0) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env));
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "setEdgeFlags",
           "(I)V",
           &g_android_view_MotionEvent_setEdgeFlags);
 
      env->CallVoidMethod(obj.obj(),
-          method_id, as_jint(p0));
-  jni_generator::CheckException(env);
+          call_context.base.method_id, as_jint(p0));
 }
 
 static std::atomic<jmethodID> g_android_view_MotionEvent_setAction(nullptr);
@@ -1824,18 +2050,21 @@
     JniIntWrapper p0) __attribute__ ((unused));
 static void Java_MotionEvent_setAction(JNIEnv* env, const base::android::JavaRef<jobject>& obj,
     JniIntWrapper p0) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env));
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "setAction",
           "(I)V",
           &g_android_view_MotionEvent_setAction);
 
      env->CallVoidMethod(obj.obj(),
-          method_id, as_jint(p0));
-  jni_generator::CheckException(env);
+          call_context.base.method_id, as_jint(p0));
 }
 
 static std::atomic<jmethodID> g_android_view_MotionEvent_offsetLocation(nullptr);
@@ -1845,18 +2074,21 @@
 static void Java_MotionEvent_offsetLocation(JNIEnv* env, const base::android::JavaRef<jobject>& obj,
     jfloat p0,
     jfloat p1) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env));
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "offsetLocation",
           "(FF)V",
           &g_android_view_MotionEvent_offsetLocation);
 
      env->CallVoidMethod(obj.obj(),
-          method_id, p0, p1);
-  jni_generator::CheckException(env);
+          call_context.base.method_id, p0, p1);
 }
 
 static std::atomic<jmethodID> g_android_view_MotionEvent_setLocation(nullptr);
@@ -1866,18 +2098,21 @@
 static void Java_MotionEvent_setLocation(JNIEnv* env, const base::android::JavaRef<jobject>& obj,
     jfloat p0,
     jfloat p1) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env));
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "setLocation",
           "(FF)V",
           &g_android_view_MotionEvent_setLocation);
 
      env->CallVoidMethod(obj.obj(),
-          method_id, p0, p1);
-  jni_generator::CheckException(env);
+          call_context.base.method_id, p0, p1);
 }
 
 static std::atomic<jmethodID> g_android_view_MotionEvent_transform(nullptr);
@@ -1885,18 +2120,21 @@
     const base::android::JavaRef<jobject>& p0) __attribute__ ((unused));
 static void Java_MotionEvent_transform(JNIEnv* env, const base::android::JavaRef<jobject>& obj,
     const base::android::JavaRef<jobject>& p0) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env));
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "transform",
           "(Landroid/graphics/Matrix;)V",
           &g_android_view_MotionEvent_transform);
 
      env->CallVoidMethod(obj.obj(),
-          method_id, p0.obj());
-  jni_generator::CheckException(env);
+          call_context.base.method_id, p0.obj());
 }
 
 static std::atomic<jmethodID> g_android_view_MotionEvent_addBatchV_J_F_F_F_F_I(nullptr);
@@ -1914,18 +2152,21 @@
     jfloat p3,
     jfloat p4,
     JniIntWrapper p5) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env));
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "addBatch",
           "(JFFFFI)V",
           &g_android_view_MotionEvent_addBatchV_J_F_F_F_F_I);
 
      env->CallVoidMethod(obj.obj(),
-          method_id, p0, p1, p2, p3, p4, as_jint(p5));
-  jni_generator::CheckException(env);
+          call_context.base.method_id, p0, p1, p2, p3, p4, as_jint(p5));
 }
 
 static std::atomic<jmethodID> g_android_view_MotionEvent_addBatchV_J_LAVMEPC_I(nullptr);
@@ -1937,18 +2178,21 @@
     base::android::JavaRef<jobject>& obj, jlong p0,
     const base::android::JavaRef<jobjectArray>& p1,
     JniIntWrapper p2) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env));
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "addBatch",
           "(J[Landroid/view/MotionEvent$PointerCoords;I)V",
           &g_android_view_MotionEvent_addBatchV_J_LAVMEPC_I);
 
      env->CallVoidMethod(obj.obj(),
-          method_id, p0, p1.obj(), as_jint(p2));
-  jni_generator::CheckException(env);
+          call_context.base.method_id, p0, p1.obj(), as_jint(p2));
 }
 
 static std::atomic<jmethodID> g_android_view_MotionEvent_toString(nullptr);
@@ -1956,19 +2200,22 @@
     base::android::JavaRef<jobject>& obj) __attribute__ ((unused));
 static base::android::ScopedJavaLocalRef<jstring> Java_MotionEvent_toString(JNIEnv* env, const
     base::android::JavaRef<jobject>& obj) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env), NULL);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "toString",
           "()Ljava/lang/String;",
           &g_android_view_MotionEvent_toString);
 
   jstring ret =
       static_cast<jstring>(env->CallObjectMethod(obj.obj(),
-          method_id));
-  jni_generator::CheckException(env);
+          call_context.base.method_id));
   return base::android::ScopedJavaLocalRef<jstring>(env, ret);
 }
 
@@ -1977,19 +2224,22 @@
     JniIntWrapper p0) __attribute__ ((unused));
 static base::android::ScopedJavaLocalRef<jstring> Java_MotionEvent_actionToString(JNIEnv* env,
     JniIntWrapper p0) {
-  CHECK_CLAZZ(env, android_view_MotionEvent_clazz(env),
+  jclass clazz = android_view_MotionEvent_clazz(env);
+  CHECK_CLAZZ(env, clazz,
       android_view_MotionEvent_clazz(env), NULL);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_STATIC>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "actionToString",
           "(I)Ljava/lang/String;",
           &g_android_view_MotionEvent_actionToString);
 
   jstring ret =
-      static_cast<jstring>(env->CallStaticObjectMethod(android_view_MotionEvent_clazz(env),
-          method_id, as_jint(p0)));
-  jni_generator::CheckException(env);
+      static_cast<jstring>(env->CallStaticObjectMethod(clazz,
+          call_context.base.method_id, as_jint(p0)));
   return base::android::ScopedJavaLocalRef<jstring>(env, ret);
 }
 
@@ -1998,19 +2248,22 @@
     JniIntWrapper p0) __attribute__ ((unused));
 static base::android::ScopedJavaLocalRef<jstring> Java_MotionEvent_axisToString(JNIEnv* env,
     JniIntWrapper p0) {
-  CHECK_CLAZZ(env, android_view_MotionEvent_clazz(env),
+  jclass clazz = android_view_MotionEvent_clazz(env);
+  CHECK_CLAZZ(env, clazz,
       android_view_MotionEvent_clazz(env), NULL);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_STATIC>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "axisToString",
           "(I)Ljava/lang/String;",
           &g_android_view_MotionEvent_axisToString);
 
   jstring ret =
-      static_cast<jstring>(env->CallStaticObjectMethod(android_view_MotionEvent_clazz(env),
-          method_id, as_jint(p0)));
-  jni_generator::CheckException(env);
+      static_cast<jstring>(env->CallStaticObjectMethod(clazz,
+          call_context.base.method_id, as_jint(p0)));
   return base::android::ScopedJavaLocalRef<jstring>(env, ret);
 }
 
@@ -2019,19 +2272,22 @@
     __attribute__ ((unused));
 static jint Java_MotionEvent_axisFromString(JNIEnv* env, const base::android::JavaRef<jstring>& p0)
     {
-  CHECK_CLAZZ(env, android_view_MotionEvent_clazz(env),
+  jclass clazz = android_view_MotionEvent_clazz(env);
+  CHECK_CLAZZ(env, clazz,
       android_view_MotionEvent_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_STATIC>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "axisFromString",
           "(Ljava/lang/String;)I",
           &g_android_view_MotionEvent_axisFromString);
 
   jint ret =
-      env->CallStaticIntMethod(android_view_MotionEvent_clazz(env),
-          method_id, p0.obj());
-  jni_generator::CheckException(env);
+      env->CallStaticIntMethod(clazz,
+          call_context.base.method_id, p0.obj());
   return ret;
 }
 
@@ -2042,18 +2298,21 @@
 static void Java_MotionEvent_writeToParcel(JNIEnv* env, const base::android::JavaRef<jobject>& obj,
     const base::android::JavaRef<jobject>& p0,
     JniIntWrapper p1) {
+  jclass clazz = android_view_MotionEvent_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       android_view_MotionEvent_clazz(env));
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, android_view_MotionEvent_clazz(env),
+          env,
+          clazz,
           "writeToParcel",
           "(Landroid/os/Parcel;I)V",
           &g_android_view_MotionEvent_writeToParcel);
 
      env->CallVoidMethod(obj.obj(),
-          method_id, p0.obj(), as_jint(p1));
-  jni_generator::CheckException(env);
+          call_context.base.method_id, p0.obj(), as_jint(p1));
 }
 
 }  // namespace JNI_MotionEvent
diff --git a/base/android/jni_generator/testFromJavaP.golden b/base/android/jni_generator/testFromJavaP.golden
index 9225f6e..e5f9467 100644
--- a/base/android/jni_generator/testFromJavaP.golden
+++ b/base/android/jni_generator/testFromJavaP.golden
@@ -42,19 +42,22 @@
 static jint Java_InputStream_available(JNIEnv* env, const base::android::JavaRef<jobject>& obj)
     __attribute__ ((unused));
 static jint Java_InputStream_available(JNIEnv* env, const base::android::JavaRef<jobject>& obj) {
+  jclass clazz = java_io_InputStream_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       java_io_InputStream_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, java_io_InputStream_clazz(env),
+          env,
+          clazz,
           "available",
           "()I",
           &g_java_io_InputStream_available);
 
   jint ret =
       env->CallIntMethod(obj.obj(),
-          method_id);
-  jni_generator::CheckException(env);
+          call_context.base.method_id);
   return ret;
 }
 
@@ -62,18 +65,21 @@
 static void Java_InputStream_close(JNIEnv* env, const base::android::JavaRef<jobject>& obj)
     __attribute__ ((unused));
 static void Java_InputStream_close(JNIEnv* env, const base::android::JavaRef<jobject>& obj) {
+  jclass clazz = java_io_InputStream_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       java_io_InputStream_clazz(env));
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, java_io_InputStream_clazz(env),
+          env,
+          clazz,
           "close",
           "()V",
           &g_java_io_InputStream_close);
 
      env->CallVoidMethod(obj.obj(),
-          method_id);
-  jni_generator::CheckException(env);
+          call_context.base.method_id);
 }
 
 static std::atomic<jmethodID> g_java_io_InputStream_mark(nullptr);
@@ -81,18 +87,21 @@
     JniIntWrapper p0) __attribute__ ((unused));
 static void Java_InputStream_mark(JNIEnv* env, const base::android::JavaRef<jobject>& obj,
     JniIntWrapper p0) {
+  jclass clazz = java_io_InputStream_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       java_io_InputStream_clazz(env));
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, java_io_InputStream_clazz(env),
+          env,
+          clazz,
           "mark",
           "(I)V",
           &g_java_io_InputStream_mark);
 
      env->CallVoidMethod(obj.obj(),
-          method_id, as_jint(p0));
-  jni_generator::CheckException(env);
+          call_context.base.method_id, as_jint(p0));
 }
 
 static std::atomic<jmethodID> g_java_io_InputStream_markSupported(nullptr);
@@ -100,19 +109,22 @@
     obj) __attribute__ ((unused));
 static jboolean Java_InputStream_markSupported(JNIEnv* env, const base::android::JavaRef<jobject>&
     obj) {
+  jclass clazz = java_io_InputStream_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       java_io_InputStream_clazz(env), false);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, java_io_InputStream_clazz(env),
+          env,
+          clazz,
           "markSupported",
           "()Z",
           &g_java_io_InputStream_markSupported);
 
   jboolean ret =
       env->CallBooleanMethod(obj.obj(),
-          method_id);
-  jni_generator::CheckException(env);
+          call_context.base.method_id);
   return ret;
 }
 
@@ -120,19 +132,22 @@
 static jint Java_InputStream_readI(JNIEnv* env, const base::android::JavaRef<jobject>& obj)
     __attribute__ ((unused));
 static jint Java_InputStream_readI(JNIEnv* env, const base::android::JavaRef<jobject>& obj) {
+  jclass clazz = java_io_InputStream_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       java_io_InputStream_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, java_io_InputStream_clazz(env),
+          env,
+          clazz,
           "read",
           "()I",
           &g_java_io_InputStream_readI);
 
   jint ret =
       env->CallIntMethod(obj.obj(),
-          method_id);
-  jni_generator::CheckException(env);
+          call_context.base.method_id);
   return ret;
 }
 
@@ -141,19 +156,22 @@
     base::android::JavaRef<jbyteArray>& p0) __attribute__ ((unused));
 static jint Java_InputStream_readI_AB(JNIEnv* env, const base::android::JavaRef<jobject>& obj, const
     base::android::JavaRef<jbyteArray>& p0) {
+  jclass clazz = java_io_InputStream_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       java_io_InputStream_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, java_io_InputStream_clazz(env),
+          env,
+          clazz,
           "read",
           "([B)I",
           &g_java_io_InputStream_readI_AB);
 
   jint ret =
       env->CallIntMethod(obj.obj(),
-          method_id, p0.obj());
-  jni_generator::CheckException(env);
+          call_context.base.method_id, p0.obj());
   return ret;
 }
 
@@ -166,19 +184,22 @@
     const base::android::JavaRef<jbyteArray>& p0,
     JniIntWrapper p1,
     JniIntWrapper p2) {
+  jclass clazz = java_io_InputStream_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       java_io_InputStream_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, java_io_InputStream_clazz(env),
+          env,
+          clazz,
           "read",
           "([BII)I",
           &g_java_io_InputStream_readI_AB_I_I);
 
   jint ret =
       env->CallIntMethod(obj.obj(),
-          method_id, p0.obj(), as_jint(p1), as_jint(p2));
-  jni_generator::CheckException(env);
+          call_context.base.method_id, p0.obj(), as_jint(p1), as_jint(p2));
   return ret;
 }
 
@@ -186,18 +207,21 @@
 static void Java_InputStream_reset(JNIEnv* env, const base::android::JavaRef<jobject>& obj)
     __attribute__ ((unused));
 static void Java_InputStream_reset(JNIEnv* env, const base::android::JavaRef<jobject>& obj) {
+  jclass clazz = java_io_InputStream_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       java_io_InputStream_clazz(env));
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, java_io_InputStream_clazz(env),
+          env,
+          clazz,
           "reset",
           "()V",
           &g_java_io_InputStream_reset);
 
      env->CallVoidMethod(obj.obj(),
-          method_id);
-  jni_generator::CheckException(env);
+          call_context.base.method_id);
 }
 
 static std::atomic<jmethodID> g_java_io_InputStream_skip(nullptr);
@@ -205,19 +229,22 @@
     p0) __attribute__ ((unused));
 static jlong Java_InputStream_skip(JNIEnv* env, const base::android::JavaRef<jobject>& obj, jlong
     p0) {
+  jclass clazz = java_io_InputStream_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       java_io_InputStream_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, java_io_InputStream_clazz(env),
+          env,
+          clazz,
           "skip",
           "(J)J",
           &g_java_io_InputStream_skip);
 
   jlong ret =
       env->CallLongMethod(obj.obj(),
-          method_id, p0);
-  jni_generator::CheckException(env);
+          call_context.base.method_id, p0);
   return ret;
 }
 
@@ -225,19 +252,22 @@
 static base::android::ScopedJavaLocalRef<jobject> Java_InputStream_Constructor(JNIEnv* env)
     __attribute__ ((unused));
 static base::android::ScopedJavaLocalRef<jobject> Java_InputStream_Constructor(JNIEnv* env) {
-  CHECK_CLAZZ(env, java_io_InputStream_clazz(env),
+  jclass clazz = java_io_InputStream_clazz(env);
+  CHECK_CLAZZ(env, clazz,
       java_io_InputStream_clazz(env), NULL);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, java_io_InputStream_clazz(env),
+          env,
+          clazz,
           "<init>",
           "()V",
           &g_java_io_InputStream_Constructor);
 
   jobject ret =
-      env->NewObject(java_io_InputStream_clazz(env),
-          method_id);
-  jni_generator::CheckException(env);
+      env->NewObject(clazz,
+          call_context.base.method_id);
   return base::android::ScopedJavaLocalRef<jobject>(env, ret);
 }
 
diff --git a/base/android/jni_generator/testFromJavaPGenerics.golden b/base/android/jni_generator/testFromJavaPGenerics.golden
index cf2646f..9c34dfc 100644
--- a/base/android/jni_generator/testFromJavaPGenerics.golden
+++ b/base/android/jni_generator/testFromJavaPGenerics.golden
@@ -41,18 +41,21 @@
 static void Java_HashSet_dummy(JNIEnv* env, const base::android::JavaRef<jobject>& obj)
     __attribute__ ((unused));
 static void Java_HashSet_dummy(JNIEnv* env, const base::android::JavaRef<jobject>& obj) {
+  jclass clazz = java_util_HashSet_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       java_util_HashSet_clazz(env));
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, java_util_HashSet_clazz(env),
+          env,
+          clazz,
           "dummy",
           "()V",
           &g_java_util_HashSet_dummy);
 
      env->CallVoidMethod(obj.obj(),
-          method_id);
-  jni_generator::CheckException(env);
+          call_context.base.method_id);
 }
 
 static std::atomic<jmethodID> g_java_util_HashSet_getClass(nullptr);
@@ -60,19 +63,22 @@
     base::android::JavaRef<jobject>& obj) __attribute__ ((unused));
 static base::android::ScopedJavaLocalRef<jclass> Java_HashSet_getClass(JNIEnv* env, const
     base::android::JavaRef<jobject>& obj) {
+  jclass clazz = java_util_HashSet_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       java_util_HashSet_clazz(env), NULL);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, java_util_HashSet_clazz(env),
+          env,
+          clazz,
           "getClass",
           "()Ljava/lang/Class<*>;",
           &g_java_util_HashSet_getClass);
 
   jclass ret =
       static_cast<jclass>(env->CallObjectMethod(obj.obj(),
-          method_id));
-  jni_generator::CheckException(env);
+          call_context.base.method_id));
   return base::android::ScopedJavaLocalRef<jclass>(env, ret);
 }
 
diff --git a/base/android/jni_generator/testMultipleJNIAdditionalImport.golden b/base/android/jni_generator/testMultipleJNIAdditionalImport.golden
index ab2496ca..2bbcfd9 100644
--- a/base/android/jni_generator/testMultipleJNIAdditionalImport.golden
+++ b/base/android/jni_generator/testMultipleJNIAdditionalImport.golden
@@ -53,18 +53,21 @@
 static std::atomic<jmethodID> g_org_chromium_foo_Foo_calledByNative(nullptr);
 static void Java_Foo_calledByNative(JNIEnv* env, const base::android::JavaRef<jobject>& callback1,
     const base::android::JavaRef<jobject>& callback2) {
-  CHECK_CLAZZ(env, org_chromium_foo_Foo_clazz(env),
+  jclass clazz = org_chromium_foo_Foo_clazz(env);
+  CHECK_CLAZZ(env, clazz,
       org_chromium_foo_Foo_clazz(env));
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_STATIC>(
-          env, org_chromium_foo_Foo_clazz(env),
+          env,
+          clazz,
           "calledByNative",
           "(Lorg/chromium/foo/Bar1$Callback;Lorg/chromium/foo/Bar2$Callback;)V",
           &g_org_chromium_foo_Foo_calledByNative);
 
-     env->CallStaticVoidMethod(org_chromium_foo_Foo_clazz(env),
-          method_id, callback1.obj(), callback2.obj());
-  jni_generator::CheckException(env);
+     env->CallStaticVoidMethod(clazz,
+          call_context.base.method_id, callback1.obj(), callback2.obj());
 }
 
 #endif  // org_chromium_foo_Foo_JNI
diff --git a/base/android/jni_generator/testNativeExportsOnlyOption.golden b/base/android/jni_generator/testNativeExportsOnlyOption.golden
index 7553007..bde7d5f 100644
--- a/base/android/jni_generator/testNativeExportsOnlyOption.golden
+++ b/base/android/jni_generator/testNativeExportsOnlyOption.golden
@@ -118,18 +118,21 @@
     g_org_chromium_example_jni_1generator_SampleForTests_testMethodWithParam(nullptr);
 static void Java_SampleForTests_testMethodWithParam(JNIEnv* env, const
     base::android::JavaRef<jobject>& obj, JniIntWrapper iParam) {
+  jclass clazz = org_chromium_example_jni_1generator_SampleForTests_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       org_chromium_example_jni_1generator_SampleForTests_clazz(env));
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, org_chromium_example_jni_1generator_SampleForTests_clazz(env),
+          env,
+          clazz,
           "testMethodWithParam",
           "(I)V",
           &g_org_chromium_example_jni_1generator_SampleForTests_testMethodWithParam);
 
      env->CallVoidMethod(obj.obj(),
-          method_id, as_jint(iParam));
-  jni_generator::CheckException(env);
+          call_context.base.method_id, as_jint(iParam));
 }
 
 static std::atomic<jmethodID>
@@ -137,57 +140,66 @@
 static base::android::ScopedJavaLocalRef<jstring>
     Java_SampleForTests_testMethodWithParamAndReturn(JNIEnv* env, const
     base::android::JavaRef<jobject>& obj, JniIntWrapper iParam) {
+  jclass clazz = org_chromium_example_jni_1generator_SampleForTests_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       org_chromium_example_jni_1generator_SampleForTests_clazz(env), NULL);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, org_chromium_example_jni_1generator_SampleForTests_clazz(env),
+          env,
+          clazz,
           "testMethodWithParamAndReturn",
           "(I)Ljava/lang/String;",
           &g_org_chromium_example_jni_1generator_SampleForTests_testMethodWithParamAndReturn);
 
   jstring ret =
       static_cast<jstring>(env->CallObjectMethod(obj.obj(),
-          method_id, as_jint(iParam)));
-  jni_generator::CheckException(env);
+          call_context.base.method_id, as_jint(iParam)));
   return base::android::ScopedJavaLocalRef<jstring>(env, ret);
 }
 
 static std::atomic<jmethodID>
     g_org_chromium_example_jni_1generator_SampleForTests_testStaticMethodWithParam(nullptr);
 static jint Java_SampleForTests_testStaticMethodWithParam(JNIEnv* env, JniIntWrapper iParam) {
-  CHECK_CLAZZ(env, org_chromium_example_jni_1generator_SampleForTests_clazz(env),
+  jclass clazz = org_chromium_example_jni_1generator_SampleForTests_clazz(env);
+  CHECK_CLAZZ(env, clazz,
       org_chromium_example_jni_1generator_SampleForTests_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_STATIC>(
-          env, org_chromium_example_jni_1generator_SampleForTests_clazz(env),
+          env,
+          clazz,
           "testStaticMethodWithParam",
           "(I)I",
           &g_org_chromium_example_jni_1generator_SampleForTests_testStaticMethodWithParam);
 
   jint ret =
-      env->CallStaticIntMethod(org_chromium_example_jni_1generator_SampleForTests_clazz(env),
-          method_id, as_jint(iParam));
-  jni_generator::CheckException(env);
+      env->CallStaticIntMethod(clazz,
+          call_context.base.method_id, as_jint(iParam));
   return ret;
 }
 
 static std::atomic<jmethodID>
     g_org_chromium_example_jni_1generator_SampleForTests_testMethodWithNoParam(nullptr);
 static jdouble Java_SampleForTests_testMethodWithNoParam(JNIEnv* env) {
-  CHECK_CLAZZ(env, org_chromium_example_jni_1generator_SampleForTests_clazz(env),
+  jclass clazz = org_chromium_example_jni_1generator_SampleForTests_clazz(env);
+  CHECK_CLAZZ(env, clazz,
       org_chromium_example_jni_1generator_SampleForTests_clazz(env), 0);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_STATIC>(
-          env, org_chromium_example_jni_1generator_SampleForTests_clazz(env),
+          env,
+          clazz,
           "testMethodWithNoParam",
           "()D",
           &g_org_chromium_example_jni_1generator_SampleForTests_testMethodWithNoParam);
 
   jdouble ret =
-      env->CallStaticDoubleMethod(org_chromium_example_jni_1generator_SampleForTests_clazz(env),
-          method_id);
-  jni_generator::CheckException(env);
+      env->CallStaticDoubleMethod(clazz,
+          call_context.base.method_id);
   return ret;
 }
 
@@ -195,19 +207,22 @@
     g_org_chromium_example_jni_1generator_SampleForTests_testStaticMethodWithNoParam(nullptr);
 static base::android::ScopedJavaLocalRef<jstring>
     Java_SampleForTests_testStaticMethodWithNoParam(JNIEnv* env) {
-  CHECK_CLAZZ(env, org_chromium_example_jni_1generator_SampleForTests_clazz(env),
+  jclass clazz = org_chromium_example_jni_1generator_SampleForTests_clazz(env);
+  CHECK_CLAZZ(env, clazz,
       org_chromium_example_jni_1generator_SampleForTests_clazz(env), NULL);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_STATIC>(
-          env, org_chromium_example_jni_1generator_SampleForTests_clazz(env),
+          env,
+          clazz,
           "testStaticMethodWithNoParam",
           "()Ljava/lang/String;",
           &g_org_chromium_example_jni_1generator_SampleForTests_testStaticMethodWithNoParam);
 
   jstring ret =
-static_cast<jstring>(env->CallStaticObjectMethod(org_chromium_example_jni_1generator_SampleForTests_clazz(env),
-          method_id));
-  jni_generator::CheckException(env);
+      static_cast<jstring>(env->CallStaticObjectMethod(clazz,
+          call_context.base.method_id));
   return base::android::ScopedJavaLocalRef<jstring>(env, ret);
 }
 
diff --git a/base/android/jni_generator/testSingleJNIAdditionalImport.golden b/base/android/jni_generator/testSingleJNIAdditionalImport.golden
index 7164c0b..17d9cf3 100644
--- a/base/android/jni_generator/testSingleJNIAdditionalImport.golden
+++ b/base/android/jni_generator/testSingleJNIAdditionalImport.golden
@@ -49,18 +49,21 @@
 
 static std::atomic<jmethodID> g_org_chromium_foo_Foo_calledByNative(nullptr);
 static void Java_Foo_calledByNative(JNIEnv* env, const base::android::JavaRef<jobject>& callback) {
-  CHECK_CLAZZ(env, org_chromium_foo_Foo_clazz(env),
+  jclass clazz = org_chromium_foo_Foo_clazz(env);
+  CHECK_CLAZZ(env, clazz,
       org_chromium_foo_Foo_clazz(env));
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_STATIC>(
-          env, org_chromium_foo_Foo_clazz(env),
+          env,
+          clazz,
           "calledByNative",
           "(Lorg/chromium/foo/Bar$Callback;)V",
           &g_org_chromium_foo_Foo_calledByNative);
 
-     env->CallStaticVoidMethod(org_chromium_foo_Foo_clazz(env),
-          method_id, callback.obj());
-  jni_generator::CheckException(env);
+     env->CallStaticVoidMethod(clazz,
+          call_context.base.method_id, callback.obj());
 }
 
 #endif  // org_chromium_foo_Foo_JNI
diff --git a/base/android/jni_generator/testTracing.golden b/base/android/jni_generator/testTracing.golden
index 88dbec9..fa8bdb2 100644
--- a/base/android/jni_generator/testTracing.golden
+++ b/base/android/jni_generator/testTracing.golden
@@ -42,8 +42,8 @@
     JNIEnv* env,
     jobject jcaller,
     jlong nativeInstance) {
-  TRACE_EVENT0("jni", "org::chromium_foo::Instance::InstanceMethod");  Instance* native =
-      reinterpret_cast<Instance*>(nativeInstance);
+  TRACE_EVENT0("jni", "org::chromium_foo::Instance::InstanceMethod");
+  Instance* native = reinterpret_cast<Instance*>(nativeInstance);
   CHECK_NATIVE_PTR(env, jcaller, native, "InstanceMethod");
   return native->InstanceMethod(env, base::android::JavaParamRef<jobject>(env, jcaller));
 }
@@ -53,44 +53,51 @@
 JNI_GENERATOR_EXPORT void Java_org_chromium_foo_Foo_nativeStaticMethod(
     JNIEnv* env,
     jclass jcaller) {
-  TRACE_EVENT0("jni", "org::chromium_foo::JNI_Foo_StaticMethod");  return JNI_Foo_StaticMethod(env,
-      base::android::JavaParamRef<jclass>(env, jcaller));
+  TRACE_EVENT0("jni", "org::chromium_foo::JNI_Foo_StaticMethod");
+  return JNI_Foo_StaticMethod(env, base::android::JavaParamRef<jclass>(env, jcaller));
 }
 
 
 static std::atomic<jmethodID> g_org_chromium_foo_Foo_Constructor(nullptr);
 static base::android::ScopedJavaLocalRef<jobject> Java_Foo_Constructor(JNIEnv* env) {
-  CHECK_CLAZZ(env, org_chromium_foo_Foo_clazz(env),
+  jclass clazz = org_chromium_foo_Foo_clazz(env);
+  CHECK_CLAZZ(env, clazz,
       org_chromium_foo_Foo_clazz(env), NULL);
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, org_chromium_foo_Foo_clazz(env),
+          env,
+          clazz,
           "<init>",
           "()V",
           &g_org_chromium_foo_Foo_Constructor);
 
-  TRACE_EVENT0("jni", "org.chromium.foo.Foo.<init>");  jobject ret =
-      env->NewObject(org_chromium_foo_Foo_clazz(env),
-          method_id);
-  jni_generator::CheckException(env);
+  TRACE_EVENT0("jni", "org.chromium.foo.Foo.<init>");
+  jobject ret =
+      env->NewObject(clazz,
+          call_context.base.method_id);
   return base::android::ScopedJavaLocalRef<jobject>(env, ret);
 }
 
 static std::atomic<jmethodID> g_org_chromium_foo_Foo_callbackFromNative(nullptr);
 static void Java_Foo_callbackFromNative(JNIEnv* env, const base::android::JavaRef<jobject>& obj) {
+  jclass clazz = org_chromium_foo_Foo_clazz(env);
   CHECK_CLAZZ(env, obj.obj(),
       org_chromium_foo_Foo_clazz(env));
-  jmethodID method_id = base::android::MethodID::LazyGet<
+
+  jni_generator::JniJavaCallContextChecked call_context;
+  call_context.Init<
       base::android::MethodID::TYPE_INSTANCE>(
-          env, org_chromium_foo_Foo_clazz(env),
+          env,
+          clazz,
           "callbackFromNative",
           "()V",
           &g_org_chromium_foo_Foo_callbackFromNative);
 
-  TRACE_EVENT0("jni", "org.chromium.foo.Foo.callbackFromNative");  
+  TRACE_EVENT0("jni", "org.chromium.foo.Foo.callbackFromNative");
      env->CallVoidMethod(obj.obj(),
-          method_id);
-  jni_generator::CheckException(env);
+          call_context.base.method_id);
 }
 
 }  // namespace chromium_foo
diff --git a/base/files/file_descriptor_watcher_posix.cc b/base/files/file_descriptor_watcher_posix.cc
index b26bf6c..94f746f7 100644
--- a/base/files/file_descriptor_watcher_posix.cc
+++ b/base/files/file_descriptor_watcher_posix.cc
@@ -22,21 +22,21 @@
 
 // MessageLoopForIO used to watch file descriptors for which callbacks are
 // registered from a given thread.
-LazyInstance<ThreadLocalPointer<MessageLoopForIO>>::Leaky
-    tls_message_loop_for_io = LAZY_INSTANCE_INITIALIZER;
+LazyInstance<ThreadLocalPointer<FileDescriptorWatcher>>::Leaky tls_fd_watcher =
+    LAZY_INSTANCE_INITIALIZER;
 
 }  // namespace
 
 FileDescriptorWatcher::Controller::~Controller() {
   DCHECK(sequence_checker_.CalledOnValidSequence());
 
-  // Delete |watcher_| on the MessageLoopForIO.
+  // Delete |watcher_| on the IO thread task runner.
   //
   // If the MessageLoopForIO is deleted before Watcher::StartWatching() runs,
   // |watcher_| is leaked. If the MessageLoopForIO is deleted after
   // Watcher::StartWatching() runs but before the DeleteSoon task runs,
   // |watcher_| is deleted from Watcher::WillDestroyCurrentMessageLoop().
-  message_loop_for_io_task_runner_->DeleteSoon(FROM_HERE, watcher_.release());
+  io_thread_task_runner_->DeleteSoon(FROM_HERE, watcher_.release());
 
   // Since WeakPtrs are invalidated by the destructor, RunCallback() won't be
   // invoked after this returns.
@@ -109,6 +109,7 @@
 
 void FileDescriptorWatcher::Controller::Watcher::StartWatching() {
   DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK(MessageLoopCurrentForIO::IsSet());
 
   if (!MessageLoopCurrentForIO::Get()->WatchFileDescriptor(
           fd_, false, mode_, &fd_watch_controller_, this)) {
@@ -161,11 +162,11 @@
                                               int fd,
                                               const Closure& callback)
     : callback_(callback),
-      message_loop_for_io_task_runner_(
-          tls_message_loop_for_io.Get().Get()->task_runner()),
+      io_thread_task_runner_(
+          tls_fd_watcher.Get().Get()->io_thread_task_runner()),
       weak_factory_(this) {
   DCHECK(!callback_.is_null());
-  DCHECK(message_loop_for_io_task_runner_);
+  DCHECK(io_thread_task_runner_);
   watcher_ = std::make_unique<Watcher>(weak_factory_.GetWeakPtr(), mode, fd);
   StartWatching();
 }
@@ -173,10 +174,10 @@
 void FileDescriptorWatcher::Controller::StartWatching() {
   DCHECK(sequence_checker_.CalledOnValidSequence());
   // It is safe to use Unretained() below because |watcher_| can only be deleted
-  // by a delete task posted to |message_loop_for_io_task_runner_| by this
+  // by a delete task posted to |io_thread_task_runner_| by this
   // Controller's destructor. Since this delete task hasn't been posted yet, it
   // can't run before the task posted below.
-  message_loop_for_io_task_runner_->PostTask(
+  io_thread_task_runner_->PostTask(
       FROM_HERE, BindOnce(&Watcher::StartWatching, Unretained(watcher_.get())));
 }
 
@@ -193,14 +194,14 @@
 }
 
 FileDescriptorWatcher::FileDescriptorWatcher(
-    MessageLoopForIO* message_loop_for_io) {
-  DCHECK(message_loop_for_io);
-  DCHECK(!tls_message_loop_for_io.Get().Get());
-  tls_message_loop_for_io.Get().Set(message_loop_for_io);
+    scoped_refptr<SingleThreadTaskRunner> io_thread_task_runner)
+    : io_thread_task_runner_(std::move(io_thread_task_runner)) {
+  DCHECK(!tls_fd_watcher.Get().Get());
+  tls_fd_watcher.Get().Set(this);
 }
 
 FileDescriptorWatcher::~FileDescriptorWatcher() {
-  tls_message_loop_for_io.Get().Set(nullptr);
+  tls_fd_watcher.Get().Set(nullptr);
 }
 
 std::unique_ptr<FileDescriptorWatcher::Controller>
diff --git a/base/files/file_descriptor_watcher_posix.h b/base/files/file_descriptor_watcher_posix.h
index aa445790..3a7c5ed 100644
--- a/base/files/file_descriptor_watcher_posix.h
+++ b/base/files/file_descriptor_watcher_posix.h
@@ -12,9 +12,9 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop.h"
 #include "base/message_loop/message_pump_for_io.h"
 #include "base/sequence_checker.h"
+#include "base/single_thread_task_runner.h"
 
 namespace base {
 
@@ -61,11 +61,10 @@
 
     // TaskRunner associated with the MessageLoopForIO that watches the file
     // descriptor.
-    const scoped_refptr<SingleThreadTaskRunner>
-        message_loop_for_io_task_runner_;
+    const scoped_refptr<SingleThreadTaskRunner> io_thread_task_runner_;
 
     // Notified by the MessageLoopForIO associated with
-    // |message_loop_for_io_task_runner_| when the watched file descriptor is
+    // |io_thread_task_runner_| when the watched file descriptor is
     // readable or writable without blocking. Posts a task to run RunCallback()
     // on the sequence on which the Controller was instantiated. When the
     // Controller is deleted, ownership of |watcher_| is transfered to a delete
@@ -82,11 +81,13 @@
     DISALLOW_COPY_AND_ASSIGN(Controller);
   };
 
-  // Registers |message_loop_for_io| to watch file descriptors for which
+  // Registers |io_thread_task_runner| to watch file descriptors for which
   // callbacks are registered from the current thread via WatchReadable() or
-  // WatchWritable(). |message_loop_for_io| may run on another thread. The
-  // constructed FileDescriptorWatcher must not outlive |message_loop_for_io|.
-  FileDescriptorWatcher(MessageLoopForIO* message_loop_for_io);
+  // WatchWritable(). |io_thread_task_runner| may run on another thread.
+  // |io_thread_task_runner| must post tasks to a thread which runs
+  // a MessagePumpForIO.
+  explicit FileDescriptorWatcher(
+      scoped_refptr<SingleThreadTaskRunner> io_thread_task_runner);
   ~FileDescriptorWatcher();
 
   // Registers |callback| to be posted on the current sequence when |fd| is
@@ -102,6 +103,12 @@
                                                    const Closure& callback);
 
  private:
+  scoped_refptr<SingleThreadTaskRunner> io_thread_task_runner() const {
+    return io_thread_task_runner_;
+  }
+
+  const scoped_refptr<SingleThreadTaskRunner> io_thread_task_runner_;
+
   DISALLOW_COPY_AND_ASSIGN(FileDescriptorWatcher);
 };
 
diff --git a/base/files/file_descriptor_watcher_posix_unittest.cc b/base/files/file_descriptor_watcher_posix_unittest.cc
index 4ed044b..8e6dd2be 100644
--- a/base/files/file_descriptor_watcher_posix_unittest.cc
+++ b/base/files/file_descriptor_watcher_posix_unittest.cc
@@ -70,7 +70,7 @@
 
     ASSERT_TRUE(message_loop_for_io->IsType(MessageLoop::TYPE_IO));
     file_descriptor_watcher_ = std::make_unique<FileDescriptorWatcher>(
-        static_cast<MessageLoopForIO*>(message_loop_for_io));
+        message_loop_for_io->task_runner());
   }
 
   void TearDown() override {
diff --git a/base/files/file_path_watcher_unittest.cc b/base/files/file_path_watcher_unittest.cc
index 2530b27..42121389 100644
--- a/base/files/file_path_watcher_unittest.cc
+++ b/base/files/file_path_watcher_unittest.cc
@@ -143,7 +143,7 @@
  public:
   FilePathWatcherTest()
 #if defined(OS_POSIX)
-      : file_descriptor_watcher_(&loop_)
+      : file_descriptor_watcher_(loop_.task_runner())
 #endif
   {
   }
diff --git a/base/json/json_writer.cc b/base/json/json_writer.cc
index e4f1e3c..e4cbd28 100644
--- a/base/json/json_writer.cc
+++ b/base/json/json_writer.cc
@@ -57,47 +57,34 @@
 
 bool JSONWriter::BuildJSONString(const Value& node, size_t depth) {
   switch (node.type()) {
-    case Value::Type::NONE: {
+    case Value::Type::NONE:
       json_string_->append("null");
       return true;
-    }
 
-    case Value::Type::BOOLEAN: {
-      bool value;
-      bool result = node.GetAsBoolean(&value);
-      DCHECK(result);
-      json_string_->append(value ? "true" : "false");
-      return result;
-    }
+    case Value::Type::BOOLEAN:
+      json_string_->append(node.GetBool() ? "true" : "false");
+      return true;
 
-    case Value::Type::INTEGER: {
-      int value;
-      bool result = node.GetAsInteger(&value);
-      DCHECK(result);
-      json_string_->append(IntToString(value));
-      return result;
-    }
+    case Value::Type::INTEGER:
+      json_string_->append(IntToString(node.GetInt()));
+      return true;
 
     case Value::Type::DOUBLE: {
-      double value;
-      bool result = node.GetAsDouble(&value);
-      DCHECK(result);
+      double value = node.GetDouble();
       if (omit_double_type_preservation_ &&
           value <= std::numeric_limits<int64_t>::max() &&
           value >= std::numeric_limits<int64_t>::min() &&
           std::floor(value) == value) {
         json_string_->append(Int64ToString(static_cast<int64_t>(value)));
-        return result;
+        return true;
       }
       std::string real = NumberToString(value);
       // Ensure that the number has a .0 if there's no decimal or 'e'.  This
       // makes sure that when we read the JSON back, it's interpreted as a
       // real rather than an int.
-      if (real.find('.') == std::string::npos &&
-          real.find('e') == std::string::npos &&
-          real.find('E') == std::string::npos) {
+      if (real.find_first_of(".eE") == std::string::npos)
         real.append(".0");
-      }
+
       // The JSON spec requires that non-integer values in the range (-1,1)
       // have a zero before the decimal point - ".52" is not valid, "0.52" is.
       if (real[0] == '.') {
@@ -107,27 +94,21 @@
         real.insert(static_cast<size_t>(1), static_cast<size_t>(1), '0');
       }
       json_string_->append(real);
-      return result;
+      return true;
     }
 
-    case Value::Type::STRING: {
-      std::string value;
-      bool result = node.GetAsString(&value);
-      DCHECK(result);
-      EscapeJSONString(value, true, json_string_);
-      return result;
-    }
+    case Value::Type::STRING:
+      EscapeJSONString(node.GetString(), true, json_string_);
+      return true;
 
     case Value::Type::LIST: {
       json_string_->push_back('[');
       if (pretty_print_)
         json_string_->push_back(' ');
 
-      const ListValue* list = nullptr;
       bool first_value_has_been_output = false;
-      bool result = node.GetAsList(&list);
-      DCHECK(result);
-      for (const auto& value : *list) {
+      bool result = true;
+      for (const auto& value : node.GetList()) {
         if (omit_binary_values_ && value.type() == Value::Type::BINARY)
           continue;
 
@@ -154,15 +135,13 @@
       if (pretty_print_)
         json_string_->append(kPrettyPrintLineEnding);
 
-      const DictionaryValue* dict = nullptr;
       bool first_value_has_been_output = false;
-      bool result = node.GetAsDictionary(&dict);
-      DCHECK(result);
-      for (DictionaryValue::Iterator itr(*dict); !itr.IsAtEnd();
-           itr.Advance()) {
-        if (omit_binary_values_ && itr.value().type() == Value::Type::BINARY) {
+      bool result = true;
+      for (const auto& pair : node.DictItems()) {
+        const auto& key = pair.first;
+        const auto& value = pair.second;
+        if (omit_binary_values_ && value.type() == Value::Type::BINARY)
           continue;
-        }
 
         if (first_value_has_been_output) {
           json_string_->push_back(',');
@@ -173,12 +152,12 @@
         if (pretty_print_)
           IndentLine(depth + 1U);
 
-        EscapeJSONString(itr.key(), true, json_string_);
+        EscapeJSONString(key, true, json_string_);
         json_string_->push_back(':');
         if (pretty_print_)
           json_string_->push_back(' ');
 
-        if (!BuildJSONString(itr.value(), depth + 1U))
+        if (!BuildJSONString(value, depth + 1U))
           result = false;
 
         first_value_has_been_output = true;
@@ -198,7 +177,9 @@
       DLOG_IF(ERROR, !omit_binary_values_) << "Cannot serialize binary value.";
       return omit_binary_values_;
   }
-  NOTREACHED();
+
+  // TODO(crbug.com/859477): Revert to NOTREACHED() after root cause is found.
+  CHECK(false);
   return false;
 }
 
diff --git a/base/mac/scoped_mach_msg_destroy.h b/base/mac/scoped_mach_msg_destroy.h
new file mode 100644
index 0000000..19e90d4
--- /dev/null
+++ b/base/mac/scoped_mach_msg_destroy.h
@@ -0,0 +1,37 @@
+// 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 BASE_MAC_SCOPED_MACH_MSG_DESTROY_H_
+#define BASE_MAC_SCOPED_MACH_MSG_DESTROY_H_
+
+#include <mach/message.h>
+
+#include "base/macros.h"
+
+namespace base {
+
+// Calls mach_msg_destroy on the specified message when the object goes out
+// of scope.
+class ScopedMachMsgDestroy {
+ public:
+  explicit ScopedMachMsgDestroy(mach_msg_header_t* header) : header_(header) {}
+
+  ~ScopedMachMsgDestroy() {
+    if (header_) {
+      mach_msg_destroy(header_);
+    }
+  }
+
+  // Prevents the message from being destroyed when it goes out of scope.
+  void Disarm() { header_ = nullptr; }
+
+ private:
+  mach_msg_header_t* header_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedMachMsgDestroy);
+};
+
+}  // namespace base
+
+#endif  // BASE_MAC_SCOPED_MACH_MSG_DESTROY_H_
diff --git a/base/metrics/OWNERS b/base/metrics/OWNERS
index 4cc69ff..5ed8a4a 100644
--- a/base/metrics/OWNERS
+++ b/base/metrics/OWNERS
@@ -1,10 +1,11 @@
 asvitkine@chromium.org
 bcwhite@chromium.org
-gayane@chromium.org
 holte@chromium.org
 isherman@chromium.org
 jwd@chromium.org
 mpearson@chromium.org
 rkaplow@chromium.org
 
+per-file field_trial_memory_mac*=rsesek@chromium.org
+
 # COMPONENT: Internals>Metrics
diff --git a/base/metrics/field_trial.cc b/base/metrics/field_trial.cc
index ffb4744..aca642b 100644
--- a/base/metrics/field_trial.cc
+++ b/base/metrics/field_trial.cc
@@ -26,7 +26,9 @@
 #include "base/unguessable_token.h"
 
 // On POSIX, the fd is shared using the mapping in GlobalDescriptors.
-#if defined(OS_POSIX) && !defined(OS_NACL)
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+#include "base/metrics/field_trial_memory_mac.h"
+#elif defined(OS_POSIX) && !defined(OS_NACL)
 #include "base/posix/global_descriptors.h"
 #endif
 
@@ -829,7 +831,8 @@
     int fd_key) {
   global_->create_trials_from_command_line_called_ = true;
 
-#if defined(OS_WIN) || defined(OS_FUCHSIA)
+#if defined(OS_WIN) || defined(OS_FUCHSIA) || \
+    (defined(OS_MACOSX) && !defined(OS_IOS))
   if (cmd_line.HasSwitch(field_trial_handle_switch)) {
     std::string switch_value =
         cmd_line.GetSwitchValueASCII(field_trial_handle_switch);
@@ -894,6 +897,15 @@
 }
 #elif defined(OS_FUCHSIA)
 // TODO(fuchsia): Implement shared-memory configuration (crbug.com/752368).
+#elif defined(OS_MACOSX) && !defined(OS_IOS)
+// static
+FieldTrialMemoryServer* FieldTrialList::GetFieldTrialMemoryServer() {
+  if (global_ && kUseSharedMemoryForFieldTrials) {
+    InstantiateFieldTrialAllocatorIfNeeded();
+    return global_->field_trial_server_.get();
+  }
+  return nullptr;
+}
 #elif defined(OS_POSIX) && !defined(OS_NACL)
 // static
 SharedMemoryHandle FieldTrialList::GetFieldTrialHandle() {
@@ -1215,6 +1227,10 @@
   ss << uintptr_handle << ",";
 #elif defined(OS_FUCHSIA)
   ss << shm.GetHandle() << ",";
+#elif defined(OS_MACOSX) && !defined(OS_IOS)
+  // The handle on Mac is looked up directly by the child, rather than being
+  // transferred to the child over the command line.
+  ss << "0,";
 #elif !defined(OS_POSIX)
 #error Unsupported OS
 #endif
@@ -1225,7 +1241,8 @@
   return ss.str();
 }
 
-#if defined(OS_WIN) || defined(OS_FUCHSIA)
+#if defined(OS_WIN) || defined(OS_FUCHSIA) || \
+    (defined(OS_MACOSX) && !defined(OS_IOS))
 
 // static
 SharedMemoryHandle FieldTrialList::DeserializeSharedMemoryHandleMetadata(
@@ -1252,6 +1269,11 @@
                     FALSE, DUPLICATE_SAME_ACCESS);
     CloseHandle(parent_handle);
   }
+#elif defined(OS_MACOSX) && !defined(OS_IOS)
+  mac::ScopedMachSendRight scoped_handle =
+      FieldTrialMemoryClient::AcquireMemoryObject();
+  if (scoped_handle == MACH_PORT_NULL)
+    return SharedMemoryHandle();
 #endif  // defined(OS_WIN)
 
   base::UnguessableToken guid;
@@ -1262,6 +1284,11 @@
   if (!base::StringToInt(tokens[3], &size))
     return SharedMemoryHandle();
 
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+  // Transfer ownership to SharedMemoryHandle.
+  mach_port_t handle = scoped_handle.release();
+#endif
+
   return SharedMemoryHandle(handle, static_cast<size_t>(size), guid);
 }
 
@@ -1291,7 +1318,8 @@
 
 #endif
 
-#if defined(OS_WIN) || defined(OS_FUCHSIA)
+#if defined(OS_WIN) || defined(OS_FUCHSIA) || \
+    (defined(OS_MACOSX) && !defined(OS_IOS))
 // static
 bool FieldTrialList::CreateTrialsFromSwitchValue(
     const std::string& switch_value) {
@@ -1382,9 +1410,6 @@
   SharedMemoryCreateOptions options;
   options.size = kFieldTrialAllocationSize;
   options.share_read_only = true;
-#if defined(OS_MACOSX) && !defined(OS_IOS)
-  options.type = SharedMemoryHandle::POSIX;
-#endif
 
   std::unique_ptr<SharedMemory> shm(new SharedMemory());
   if (!shm->Create(options))
@@ -1411,6 +1436,13 @@
   global_->readonly_allocator_handle_ = GetSharedMemoryReadOnlyHandle(
       global_->field_trial_allocator_->shared_memory());
 #endif
+
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+  global_->field_trial_server_ = std::make_unique<FieldTrialMemoryServer>(
+      global_->readonly_allocator_handle_.GetMemoryObject());
+  bool ok = global_->field_trial_server_->Start();
+  DCHECK(ok);
+#endif
 }
 
 // static
diff --git a/base/metrics/field_trial.h b/base/metrics/field_trial.h
index d439fcce..95f646f 100644
--- a/base/metrics/field_trial.h
+++ b/base/metrics/field_trial.h
@@ -85,6 +85,7 @@
 namespace base {
 
 class FieldTrialList;
+class FieldTrialMemoryServer;
 
 class BASE_EXPORT FieldTrial : public RefCounted<FieldTrial> {
  public:
@@ -588,6 +589,10 @@
       base::HandlesToInheritVector* handles);
 #elif defined(OS_FUCHSIA)
   // TODO(fuchsia): Implement shared-memory configuration (crbug.com/752368).
+#elif defined(OS_MACOSX) && !defined(OS_IOS)
+  // On Mac, the field trial shared memory is accessed via a Mach server, which
+  // the child looks up directly.
+  static FieldTrialMemoryServer* GetFieldTrialMemoryServer();
 #elif defined(OS_POSIX) && !defined(OS_NACL)
   // On POSIX, we also need to explicitly pass down this file descriptor that
   // should be shared with the child process. Returns an invalid handle if it
@@ -682,6 +687,7 @@
   FRIEND_TEST_ALL_PREFIXES(FieldTrialListTest, ClearParamsFromSharedMemory);
   FRIEND_TEST_ALL_PREFIXES(FieldTrialListTest,
                            SerializeSharedMemoryHandleMetadata);
+  friend int SerializeSharedMemoryHandleMetadata(void);
   FRIEND_TEST_ALL_PREFIXES(FieldTrialListTest, CheckReadOnlySharedMemoryHandle);
 
   // Serialization is used to pass information about the handle to child
@@ -690,7 +696,8 @@
   // underlying OS resource - that must be done by the Process launcher.
   static std::string SerializeSharedMemoryHandleMetadata(
       const SharedMemoryHandle& shm);
-#if defined(OS_WIN) || defined(OS_FUCHSIA)
+#if defined(OS_WIN) || defined(OS_FUCHSIA) || \
+    (defined(OS_MACOSX) && !defined(OS_IOS))
   static SharedMemoryHandle DeserializeSharedMemoryHandleMetadata(
       const std::string& switch_value);
 #elif defined(OS_POSIX) && !defined(OS_NACL)
@@ -699,7 +706,8 @@
       const std::string& switch_value);
 #endif
 
-#if defined(OS_WIN) || defined(OS_FUCHSIA)
+#if defined(OS_WIN) || defined(OS_FUCHSIA) || \
+    (defined(OS_MACOSX) && !defined(OS_IOS))
   // Takes in |handle_switch| from the command line which represents the shared
   // memory handle for field trials, parses it, and creates the field trials.
   // Returns true on success, false on failure.
@@ -793,6 +801,12 @@
   // AppendFieldTrialHandleIfNeeded().
   base::SharedMemoryHandle readonly_allocator_handle_;
 
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+  // Mach message server that handles requests to acquire the shared memory
+  // object.
+  std::unique_ptr<FieldTrialMemoryServer> field_trial_server_;
+#endif
+
   // Tracks whether CreateTrialsFromCommandLine() has been called.
   bool create_trials_from_command_line_called_ = false;
 
diff --git a/base/metrics/field_trial_memory_mac.cc b/base/metrics/field_trial_memory_mac.cc
new file mode 100644
index 0000000..bc3d2fb
--- /dev/null
+++ b/base/metrics/field_trial_memory_mac.cc
@@ -0,0 +1,205 @@
+// 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 "base/metrics/field_trial_memory_mac.h"
+
+#include <bsm/libbsm.h>
+#include <libproc.h>
+#include <mach/mig.h>
+#include <servers/bootstrap.h>
+#include <unistd.h>
+
+#include "base/logging.h"
+#include "base/mac/foundation_util.h"
+#include "base/mac/mach_logging.h"
+#include "base/mac/scoped_mach_msg_destroy.h"
+#include "base/strings/stringprintf.h"
+
+namespace base {
+
+namespace {
+
+// The name to use in the bootstrap server, formatted with the BaseBundleID and
+// PID of the server.
+const char kBootstrapNameFormat[] = "%s.FieldTrialMemoryServer.%d";
+
+enum FieldTrialMsgId : mach_msg_id_t {
+  kFieldTrialMsgIdRequest = 'FTrq',
+  kFieldTrialMsgIdResponse = 'FTsp',
+};
+
+// Message received by the server for handling lookup lookup requests.
+struct FieldTrialMemoryRequestMessage : public mach_msg_base_t {
+  // The size of the message excluding the trailer, used for msgh_size.
+  static const mach_msg_size_t kSendSize;
+
+  mach_msg_audit_trailer_t trailer;
+};
+
+const mach_msg_size_t FieldTrialMemoryRequestMessage::kSendSize =
+    sizeof(FieldTrialMemoryRequestMessage) - sizeof(trailer);
+
+// Message used for sending and receiving the memory object handle.
+struct FieldTrialMemoryResponseMessage : public mach_msg_base_t {
+  // The size of the message excluding the trailer, used for msgh_size.
+  static const mach_msg_size_t kSendSize;
+
+  mach_msg_port_descriptor_t port;
+  mach_msg_trailer_t trailer;
+};
+
+const mach_msg_size_t FieldTrialMemoryResponseMessage::kSendSize =
+    sizeof(FieldTrialMemoryResponseMessage) - sizeof(trailer);
+
+}  // namespace
+
+FieldTrialMemoryServer::FieldTrialMemoryServer(mach_port_t memory_object)
+    : memory_object_(memory_object), server_pid_(getpid()) {
+  DCHECK(memory_object != MACH_PORT_NULL);
+}
+
+FieldTrialMemoryServer::~FieldTrialMemoryServer() {}
+
+bool FieldTrialMemoryServer::Start() {
+  std::string bootstrap_name = GetBootstrapName();
+  kern_return_t kr = bootstrap_check_in(bootstrap_port, bootstrap_name.c_str(),
+                                        server_port_.receive());
+  if (kr != KERN_SUCCESS) {
+    BOOTSTRAP_LOG(ERROR, kr) << "bootstrap_check_in " << bootstrap_name;
+    return false;
+  }
+
+  dispatch_source_ = std::make_unique<DispatchSourceMach>(
+      "org.chromium.base.FieldTrialMemoryServer", server_port_.get(), ^{
+        HandleRequest();
+      });
+  dispatch_source_->Resume();
+  return true;
+}
+
+// static
+std::string FieldTrialMemoryServer::GetBootstrapName() {
+  return StringPrintf(kBootstrapNameFormat, mac::BaseBundleID(), getpid());
+}
+
+void FieldTrialMemoryServer::HandleRequest() {
+  // Receive the request message, using the kernel audit token to ascertain the
+  // PID of the sender.
+  FieldTrialMemoryRequestMessage request{};
+  request.header.msgh_size = sizeof(request);
+  request.header.msgh_local_port = server_port_.get();
+
+  const mach_msg_option_t options =
+      MACH_RCV_MSG | MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0) |
+      MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT);
+
+  kern_return_t kr =
+      mach_msg(&request.header, options, 0, sizeof(request), server_port_.get(),
+               MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
+  if (kr != KERN_SUCCESS) {
+    MACH_LOG(ERROR, kr) << "mach_msg receive";
+    return;
+  }
+
+  // Destroy the message in case of an early return, which will release
+  // any rights from a bad message. In the case of a disallowed sender,
+  // the destruction of the reply port will break them out of a mach_msg.
+  ScopedMachMsgDestroy scoped_message(&request.header);
+
+  if (request.header.msgh_id != kFieldTrialMsgIdRequest ||
+      request.header.msgh_size != request.kSendSize) {
+    // Do not reply to messages that are unexpected.
+    return;
+  }
+
+  // A client is allowed to look up the object if the sending process is a
+  // direct child of this server's process.
+  pid_t sender_pid = audit_token_to_pid(request.trailer.msgh_audit);
+  proc_bsdshortinfo sender{};
+  int rv = proc_pidinfo(sender_pid, PROC_PIDT_SHORTBSDINFO, 0, &sender,
+                        PROC_PIDT_SHORTBSDINFO_SIZE);
+  if (rv != PROC_PIDT_SHORTBSDINFO_SIZE ||
+      sender.pbsi_ppid != static_cast<uint32_t>(server_pid_)) {
+    return;
+  }
+
+  FieldTrialMemoryResponseMessage response{};
+  response.header.msgh_bits =
+      MACH_MSGH_BITS_REMOTE(MACH_MSG_TYPE_MOVE_SEND_ONCE) |
+      MACH_MSGH_BITS_COMPLEX;
+  response.header.msgh_size = response.kSendSize;
+  response.header.msgh_remote_port = request.header.msgh_remote_port;
+  response.header.msgh_id = kFieldTrialMsgIdResponse;
+  response.body.msgh_descriptor_count = 1;
+  response.port.name = memory_object_;
+  response.port.disposition = MACH_MSG_TYPE_COPY_SEND;
+  response.port.type = MACH_MSG_PORT_DESCRIPTOR;
+
+  scoped_message.Disarm();
+
+  kr = mach_msg(&response.header, MACH_SEND_MSG, response.header.msgh_size, 0,
+                MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
+  MACH_LOG_IF(ERROR, kr != KERN_SUCCESS, kr) << "mach_msg send";
+}
+
+// static
+mac::ScopedMachSendRight FieldTrialMemoryClient::AcquireMemoryObject() {
+  mac::ScopedMachSendRight server_port;
+  std::string bootstrap_name = GetBootstrapName();
+  kern_return_t kr = bootstrap_look_up(
+      bootstrap_port, const_cast<char*>(bootstrap_name.c_str()),
+      server_port.receive());
+  if (kr != KERN_SUCCESS) {
+    BOOTSTRAP_LOG(ERROR, kr) << "bootstrap_look_up " << bootstrap_name;
+    return mac::ScopedMachSendRight();
+  }
+
+  return ChildSendRequest(std::move(server_port));
+}
+
+// static
+std::string FieldTrialMemoryClient::GetBootstrapName() {
+  return StringPrintf(kBootstrapNameFormat, mac::BaseBundleID(), getppid());
+}
+
+// static
+mac::ScopedMachSendRight FieldTrialMemoryClient::ChildSendRequest(
+    mac::ScopedMachSendRight server_port) {
+  // Perform a send and receive mach_msg.
+  union {
+    FieldTrialMemoryRequestMessage request;
+    FieldTrialMemoryResponseMessage response;
+  } msg{};
+  msg.request.header.msgh_bits =
+      MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE);
+  // The size of |msg| is used for receiving since it includes space for the
+  // trailer, but for the request being sent, the size is just the base message.
+  msg.request.header.msgh_size = msg.request.kSendSize;
+  msg.request.header.msgh_remote_port = server_port.release();
+  msg.request.header.msgh_local_port = mig_get_reply_port();
+  msg.request.header.msgh_id = kFieldTrialMsgIdRequest;
+
+  kern_return_t kr =
+      mach_msg(&msg.request.header, MACH_SEND_MSG | MACH_RCV_MSG,
+               msg.request.header.msgh_size, sizeof(msg.response),
+               msg.request.header.msgh_local_port, MACH_MSG_TIMEOUT_NONE,
+               MACH_PORT_NULL);
+  if (kr != KERN_SUCCESS) {
+    MACH_LOG(ERROR, kr) << "mach_msg";
+    return mac::ScopedMachSendRight();
+  }
+
+  if (msg.response.header.msgh_id != kFieldTrialMsgIdResponse ||
+      msg.response.header.msgh_size != msg.response.kSendSize) {
+    return mac::ScopedMachSendRight();
+  }
+
+  return mac::ScopedMachSendRight(msg.response.port.name);
+}
+
+FieldTrialMemoryClient::FieldTrialMemoryClient() = default;
+
+FieldTrialMemoryClient::~FieldTrialMemoryClient() = default;
+
+}  // namespace base
diff --git a/base/metrics/field_trial_memory_mac.h b/base/metrics/field_trial_memory_mac.h
new file mode 100644
index 0000000..3a323760
--- /dev/null
+++ b/base/metrics/field_trial_memory_mac.h
@@ -0,0 +1,85 @@
+// 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 BASE_METRICS_FIELD_TRIAL_MEMORY_MAC_H_
+#define BASE_METRICS_FIELD_TRIAL_MEMORY_MAC_H_
+
+#include <mach/port.h>
+#include <sys/types.h>
+
+#include <memory>
+#include <string>
+
+#include "base/base_export.h"
+#include "base/mac/dispatch_source_mach.h"
+#include "base/mac/scoped_mach_port.h"
+#include "base/macros.h"
+
+namespace base {
+
+// FieldTrialMemoryServer services requests for the FieldTrial shared memory
+// region on Mac. Shared memory on Mac uses Mach ports, which cannot be
+// transferred across process creation. Instead, this class publishes an
+// endpoint in the bootstrap server. Child processes look up the server and then
+// send requests to acquire the shared memory object. Only processes that are
+// direct children of the process that is running this server are allowed to
+// acquire the memory object send right.
+class BASE_EXPORT FieldTrialMemoryServer {
+ public:
+  // Creates a server that will vend access to the passed |memory_object|.
+  // This does not change the user refcount of the object. Start() must be
+  // called before requests will be processed.
+  explicit FieldTrialMemoryServer(mach_port_t memory_object);
+  ~FieldTrialMemoryServer();
+
+  // Starts processing requests for the server. Returns false if the server
+  // could not be started and true on success.
+  bool Start();
+
+ private:
+  friend class FieldTrialMemoryServerTest;
+
+  // Exposed for testing.
+  void set_server_pid(pid_t pid) { server_pid_ = pid; }
+
+  // Returns the name of the server to publish in the bootstrap namespace.
+  static std::string GetBootstrapName();
+
+  // The server-side Mach message handler.
+  void HandleRequest();
+
+  mach_port_t memory_object_;  // weak
+  pid_t server_pid_;           // PPID used for access control checks.
+  mac::ScopedMachReceiveRight server_port_;
+  std::unique_ptr<DispatchSourceMach> dispatch_source_;
+
+  DISALLOW_COPY_AND_ASSIGN(FieldTrialMemoryServer);
+};
+
+// Client class for accessing the memory object exposed by the
+// FieldTrialMemoryServer.
+class BASE_EXPORT FieldTrialMemoryClient {
+ public:
+  // Called by children of the process running the FieldTrialMemoryServer, this
+  // attempts to acquire the port for the |memory_object_|. Returns the port
+  // on success or MACH_PORT_NULL on error or failure.
+  static mac::ScopedMachSendRight AcquireMemoryObject();
+
+  // Returns the name of the server to look up in the bootstrap namespace.
+  static std::string GetBootstrapName();
+
+ private:
+  // Sends the Mach message to |server_port| to acquire the memory object.
+  static mac::ScopedMachSendRight ChildSendRequest(
+      mac::ScopedMachSendRight server_port);
+
+  FieldTrialMemoryClient();
+  ~FieldTrialMemoryClient();
+
+  DISALLOW_COPY_AND_ASSIGN(FieldTrialMemoryClient);
+};
+
+}  // namespace base
+
+#endif  // BASE_METRICS_FIELD_TRIAL_MEMORY_MAC_H_
diff --git a/base/metrics/field_trial_memory_mac_unittest.cc b/base/metrics/field_trial_memory_mac_unittest.cc
new file mode 100644
index 0000000..33b9815
--- /dev/null
+++ b/base/metrics/field_trial_memory_mac_unittest.cc
@@ -0,0 +1,117 @@
+// 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 "base/metrics/field_trial_memory_mac.h"
+
+#include <mach/mach.h>
+#include <mach/mach_vm.h>
+
+#include "base/mac/mach_logging.h"
+#include "base/mac/scoped_mach_vm.h"
+#include "base/test/multiprocess_test.h"
+#include "base/test/test_timeouts.h"
+#include "testing/multiprocess_func_list.h"
+
+namespace base {
+
+namespace {
+
+enum ChildExitCode {
+  kChildExitInvalid,
+  kChildExitNoPort,
+  kChildExitMapFailed,
+  kChildExitBadPattern,
+  kChildExitSuccess,
+};
+
+constexpr char kMemoryTestPattern[] = "Hello there, bear";
+
+constexpr mach_vm_size_t kMemoryAllocationSize = 1024;
+
+}  // namespace
+
+class FieldTrialMemoryServerTest : public MultiProcessTest {
+ public:
+  void SetUp() override {
+    mach_vm_address_t address = 0;
+    mach_vm_size_t size = mach_vm_round_page(kMemoryAllocationSize);
+    kern_return_t kr =
+        mach_vm_allocate(mach_task_self(), &address, size, VM_FLAGS_ANYWHERE);
+    ASSERT_EQ(kr, KERN_SUCCESS) << "mach_vm_allocate";
+    memory_.reset(address, size);
+
+    kr = mach_make_memory_entry_64(mach_task_self(), &size, address,
+                                   VM_PROT_READ, memory_object_.receive(),
+                                   MACH_PORT_NULL);
+    ASSERT_EQ(kr, KERN_SUCCESS) << "mach_make_memory_entry_64";
+
+    memcpy(reinterpret_cast<void*>(address), kMemoryTestPattern,
+           sizeof(kMemoryTestPattern));
+  }
+
+  void SetServerPid(FieldTrialMemoryServer* server, pid_t server_pid) {
+    server->set_server_pid(server_pid);
+  }
+
+  mach_port_t memory_object() { return memory_object_.get(); }
+
+ private:
+  mac::ScopedMachVM memory_;
+  mac::ScopedMachSendRight memory_object_;
+};
+
+MULTIPROCESS_TEST_MAIN(AcquireMemoryObjectAndMap) {
+  mac::ScopedMachSendRight memory_object =
+      FieldTrialMemoryClient::AcquireMemoryObject();
+  if (memory_object == MACH_PORT_NULL)
+    return kChildExitNoPort;
+
+  mach_vm_address_t address = 0;
+  kern_return_t kr =
+      mach_vm_map(mach_task_self(), &address, kMemoryAllocationSize, 0,
+                  VM_FLAGS_ANYWHERE, memory_object.get(), 0, false,
+                  VM_PROT_READ, VM_PROT_READ, VM_INHERIT_NONE);
+  if (kr != KERN_SUCCESS) {
+    MACH_LOG(ERROR, kr) << "mach_vm_map";
+    return kChildExitMapFailed;
+  }
+
+  if (memcmp(kMemoryTestPattern, reinterpret_cast<void*>(address),
+             sizeof(kMemoryTestPattern)) != 0) {
+    return kChildExitBadPattern;
+  }
+
+  return kChildExitSuccess;
+}
+
+TEST_F(FieldTrialMemoryServerTest, AllowedPid) {
+  FieldTrialMemoryServer server(memory_object());
+  ASSERT_TRUE(server.Start());
+
+  Process child = SpawnChild("AcquireMemoryObjectAndMap");
+
+  int exit_code;
+  ASSERT_TRUE(WaitForMultiprocessTestChildExit(
+      child, TestTimeouts::action_timeout(), &exit_code));
+
+  EXPECT_EQ(kChildExitSuccess, exit_code);
+}
+
+TEST_F(FieldTrialMemoryServerTest, BlockedPid) {
+  FieldTrialMemoryServer server(memory_object());
+  // Override the server's PID so that the request does not look like it is
+  // coming from a process that is the child of the server.
+  SetServerPid(&server, 1);
+  ASSERT_TRUE(server.Start());
+
+  Process child = SpawnChild("AcquireMemoryObjectAndMap");
+
+  int exit_code;
+  ASSERT_TRUE(WaitForMultiprocessTestChildExit(
+      child, TestTimeouts::action_timeout(), &exit_code));
+
+  EXPECT_EQ(kChildExitNoPort, exit_code);
+}
+
+}  // namespace base
diff --git a/base/metrics/field_trial_unittest.cc b/base/metrics/field_trial_unittest.cc
index 7dbe737d..0b861bb 100644
--- a/base/metrics/field_trial_unittest.cc
+++ b/base/metrics/field_trial_unittest.cc
@@ -19,10 +19,17 @@
 #include "base/strings/stringprintf.h"
 #include "base/test/gtest_util.h"
 #include "base/test/mock_entropy_provider.h"
+#include "base/test/multiprocess_test.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/test_shared_memory_util.h"
+#include "base/test/test_timeouts.h"
 #include "build/build_config.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "testing/multiprocess_func_list.h"
+
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+#include "base/metrics/field_trial_memory_mac.h"
+#endif
 
 namespace base {
 
@@ -1426,33 +1433,66 @@
   EXPECT_EQ("value2", shm_params["key2"]);
 }
 
-#if !defined(OS_NACL)
+#if !defined(OS_NACL) && !defined(OS_IOS)
+MULTIPROCESS_TEST_MAIN(SerializeSharedMemoryHandleMetadata) {
+  std::string serialized =
+      CommandLine::ForCurrentProcess()->GetSwitchValueASCII("field_trials");
+  std::string guid_string =
+      CommandLine::ForCurrentProcess()->GetSwitchValueASCII("guid");
+
+#if defined(OS_WIN) || defined(OS_FUCHSIA) || \
+    (defined(OS_MACOSX) && !defined(OS_IOS))
+  SharedMemoryHandle deserialized =
+      FieldTrialList::DeserializeSharedMemoryHandleMetadata(serialized);
+#else
+  // Use the arbitrary value selected below.
+  SharedMemoryHandle deserialized =
+      FieldTrialList::DeserializeSharedMemoryHandleMetadata(42, serialized);
+#endif
+  CHECK_EQ(deserialized.GetGUID().ToString(), guid_string);
+  CHECK(!deserialized.GetGUID().is_empty());
+
+  return 0;
+}
+
 TEST(FieldTrialListTest, SerializeSharedMemoryHandleMetadata) {
   std::unique_ptr<SharedMemory> shm(new SharedMemory());
   shm->CreateAndMapAnonymous(4 << 10);
 
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+  FieldTrialMemoryServer mach_server(shm->handle().GetMemoryObject());
+  ASSERT_TRUE(mach_server.Start());
+#endif
+
   std::string serialized =
       FieldTrialList::SerializeSharedMemoryHandleMetadata(shm->handle());
-#if defined(OS_WIN) || defined(OS_FUCHSIA)
-  SharedMemoryHandle deserialized =
-      FieldTrialList::DeserializeSharedMemoryHandleMetadata(serialized);
-#else
-  // Use a valid-looking arbitrary number for the file descriptor. It's not
-  // being used in this unittest, but needs to pass sanity checks in the
-  // handle's constructor.
-  SharedMemoryHandle deserialized =
-      FieldTrialList::DeserializeSharedMemoryHandleMetadata(42, serialized);
+
+  LaunchOptions options;
+#if defined(OS_POSIX) && (!defined(OS_MACOSX) && !defined(OS_IOS))
+  // Pick an arbitrary FD number to use for the shmem FD in the child.
+  options.fds_to_remap.emplace_back(
+      std::make_pair(shm->handle().GetHandle(), 42));
 #endif
-  EXPECT_EQ(deserialized.GetGUID(), shm->handle().GetGUID());
-  EXPECT_FALSE(deserialized.GetGUID().is_empty());
+  CommandLine cmd_line = GetMultiProcessTestChildBaseCommandLine();
+  cmd_line.AppendSwitchASCII("field_trials", serialized);
+  cmd_line.AppendSwitchASCII("guid", shm->handle().GetGUID().ToString());
+
+  Process process = SpawnMultiProcessTestChild(
+      "SerializeSharedMemoryHandleMetadata", cmd_line, options);
+
+  int exit_code;
+  EXPECT_TRUE(WaitForMultiprocessTestChildExit(
+      process, TestTimeouts::action_timeout(), &exit_code));
+  EXPECT_EQ(0, exit_code);
 }
 #endif  // !defined(OS_NACL)
 
 // Verify that the field trial shared memory handle is really read-only, and
-// does not allow writable mappings. Test disabled on NaCl, Windows and Fuchsia
-// which don't support/implement GetFieldTrialHandle(). For Fuchsia, see
-// crbug.com/752368
-#if !defined(OS_NACL) && !defined(OS_WIN) && !defined(OS_FUCHSIA)
+// does not allow writable mappings. Test disabled on NaCl, Windows, Fuchsia,
+// and Mac, which don't support/implement GetFieldTrialHandle(). For Fuchsia,
+// see crbug.com/752368
+#if !defined(OS_NACL) && !defined(OS_WIN) && !defined(OS_FUCHSIA) && \
+    (!defined(OS_MACOSX) && !defined(OS_IOS))
 TEST(FieldTrialListTest, CheckReadOnlySharedMemoryHandle) {
   FieldTrialList field_trial_list(nullptr);
   FieldTrialList::CreateFieldTrial("Trial1", "Group1");
diff --git a/base/metrics/histogram.cc b/base/metrics/histogram.cc
index 094dea7..bddc75a 100644
--- a/base/metrics/histogram.cc
+++ b/base/metrics/histogram.cc
@@ -194,6 +194,16 @@
 // Temporary check for https://crbug.com/836238
 #if defined(OS_WIN)  // Only Windows has a debugger that makes this useful.
     std::unique_ptr<const BucketRanges> recreated_ranges(CreateRanges());
+    // Most histograms have 50 buckets plus underflow and overflow.
+    const size_t capture_boundaries = 52;
+    Sample created_boundaries[capture_boundaries];
+    Sample recreated_boundaries[capture_boundaries];
+    for (uint32_t i = 0; i < bucket_count_ && i < capture_boundaries; ++i) {
+      created_boundaries[i] = created_ranges->range(i);
+      recreated_boundaries[i] = recreated_ranges->range(i);
+    }
+    debug::Alias(created_boundaries);
+    debug::Alias(recreated_boundaries);
     for (uint32_t i = 0; i < bucket_count_; ++i) {
       uint32_t created_range = created_ranges->range(i);
       uint32_t recreated_range = recreated_ranges->range(i);
diff --git a/base/metrics/histogram_functions.cc b/base/metrics/histogram_functions.cc
index 31bf219..e0d7b2dd 100644
--- a/base/metrics/histogram_functions.cc
+++ b/base/metrics/histogram_functions.cc
@@ -89,6 +89,22 @@
                           TimeDelta::FromHours(1), 50);
 }
 
+void UmaHistogramCustomMicrosecondsTimes(const std::string& name,
+                                         TimeDelta sample,
+                                         TimeDelta min,
+                                         TimeDelta max,
+                                         int buckets) {
+  HistogramBase* histogram = Histogram::FactoryTimeGet(
+      name, min, max, buckets, HistogramBase::kUmaTargetedHistogramFlag);
+  histogram->AddTimeMicrosecondsGranularity(sample);
+}
+
+void UmaHistogramMicrosecondsTimes(const std::string& name, TimeDelta sample) {
+  UmaHistogramCustomMicrosecondsTimes(name, sample,
+                                      TimeDelta::FromMicroseconds(1),
+                                      TimeDelta::FromSeconds(10), 50);
+}
+
 void UmaHistogramMemoryKB(const std::string& name, int sample) {
   UmaHistogramCustomCounts(name, sample, 1000, 500000, 50);
 }
diff --git a/base/metrics/histogram_functions.h b/base/metrics/histogram_functions.h
index 60c0057..3d95464f 100644
--- a/base/metrics/histogram_functions.h
+++ b/base/metrics/histogram_functions.h
@@ -101,7 +101,7 @@
 BASE_EXPORT void UmaHistogramCounts1M(const std::string& name, int sample);
 BASE_EXPORT void UmaHistogramCounts10M(const std::string& name, int sample);
 
-// For histograms storing times.
+// For histograms storing times. It uses milliseconds granularity.
 BASE_EXPORT void UmaHistogramCustomTimes(const std::string& name,
                                          TimeDelta sample,
                                          TimeDelta min,
@@ -116,6 +116,17 @@
 BASE_EXPORT void UmaHistogramLongTimes(const std::string& name,
                                        TimeDelta sample);
 
+// For histograms storing times with microseconds granularity.
+BASE_EXPORT void UmaHistogramCustomMicrosecondsTimes(const std::string& name,
+                                                     TimeDelta sample,
+                                                     TimeDelta min,
+                                                     TimeDelta max,
+                                                     int buckets);
+
+// For microseconds timings from 1 microsecond up to 10 seconds (50 buckets).
+BASE_EXPORT void UmaHistogramMicrosecondsTimes(const std::string& name,
+                                               TimeDelta sample);
+
 // For recording memory related histograms.
 // Used to measure common KB-granularity memory stats. Range is up to 500M.
 BASE_EXPORT void UmaHistogramMemoryKB(const std::string& name, int sample);
diff --git a/base/profiler/stack_sampling_profiler.cc b/base/profiler/stack_sampling_profiler.cc
index a35895c..a686652 100644
--- a/base/profiler/stack_sampling_profiler.cc
+++ b/base/profiler/stack_sampling_profiler.cc
@@ -24,6 +24,7 @@
 #include "base/threading/thread_restrictions.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/timer/elapsed_timer.h"
+#include "base/trace_event/trace_event.h"
 
 namespace base {
 
@@ -443,6 +444,9 @@
   if (!active_collections_.empty())
     return;
 
+  TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cpu_profiler"),
+               "StackSamplingProfiler::SamplingThread::ScheduleShutdownIfIdle");
+
   int add_events;
   {
     AutoLock lock(thread_execution_state_lock_);
@@ -559,6 +563,9 @@
   if (thread_execution_state_add_events_ != add_events)
     return;
 
+  TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cpu_profiler"),
+               "StackSamplingProfiler::SamplingThread::ShutdownTask");
+
   // There can be no new AddCollectionTasks at this point because creating
   // those always increments "add events". There may be other requests, like
   // Remove, but it's okay to schedule the thread to stop once they've been
@@ -650,10 +657,15 @@
       profiling_inactive_(kResetPolicy, WaitableEvent::InitialState::SIGNALED),
       profiler_id_(kNullProfilerId),
       test_delegate_(test_delegate) {
+  TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cpu_profiler"),
+               "StackSamplingProfiler::StackSamplingProfiler");
   DCHECK(profile_builder_);
 }
 
 StackSamplingProfiler::~StackSamplingProfiler() {
+  TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cpu_profiler"),
+               "StackSamplingProfiler::~StackSamplingProfiler");
+
   // Stop returns immediately but the shutdown runs asynchronously. There is a
   // non-zero probability that one more sample will be taken after this call
   // returns.
@@ -673,6 +685,9 @@
 }
 
 void StackSamplingProfiler::Start() {
+  TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cpu_profiler"),
+               "StackSamplingProfiler::Start");
+
   // Multiple calls to Start() for a single StackSamplingProfiler object is not
   // allowed. If profile_builder_ is nullptr, then Start() has been called
   // already.
@@ -702,9 +717,15 @@
           thread_id_, params_, &profiling_inactive_, std::move(native_sampler_),
           std::move(profile_builder_)));
   DCHECK_NE(kNullProfilerId, profiler_id_);
+
+  TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cpu_profiler"),
+               "StackSamplingProfiler::Started", "profiler_id", profiler_id_);
 }
 
 void StackSamplingProfiler::Stop() {
+  TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cpu_profiler"),
+               "StackSamplingProfiler::Stop", "profiler_id", profiler_id_);
+
   SamplingThread::GetInstance()->Remove(profiler_id_);
   profiler_id_ = kNullProfilerId;
 }
diff --git a/base/strings/string_piece_unittest.cc b/base/strings/string_piece_unittest.cc
index 17d0897..5b7d1811 100644
--- a/base/strings/string_piece_unittest.cc
+++ b/base/strings/string_piece_unittest.cc
@@ -723,6 +723,33 @@
   }
 }
 
+TEST(StringPieceTest, OutOfBoundsDeath) {
+  {
+    constexpr StringPiece piece;
+    ASSERT_DEATH_IF_SUPPORTED(piece[0], "");
+  }
+
+  {
+    constexpr StringPiece piece;
+    ASSERT_DEATH_IF_SUPPORTED(piece.front(), "");
+  }
+
+  {
+    constexpr StringPiece piece;
+    ASSERT_DEATH_IF_SUPPORTED(piece.back(), "");
+  }
+
+  {
+    StringPiece piece;
+    ASSERT_DEATH_IF_SUPPORTED(piece.remove_suffix(1), "");
+  }
+
+  {
+    StringPiece piece;
+    ASSERT_DEATH_IF_SUPPORTED(piece.remove_prefix(1), "");
+  }
+}
+
 TEST(StringPieceTest, ConstexprData) {
   {
     constexpr StringPiece piece;
diff --git a/base/task/task_scheduler/priority_queue.cc b/base/task/task_scheduler/priority_queue.cc
index 9643c87b..01a00ea7 100644
--- a/base/task/task_scheduler/priority_queue.cc
+++ b/base/task/task_scheduler/priority_queue.cc
@@ -18,6 +18,7 @@
 // call.
 class PriorityQueue::SequenceAndSortKey {
  public:
+  SequenceAndSortKey() = default;
   SequenceAndSortKey(scoped_refptr<Sequence> sequence,
                      const SequenceSortKey& sort_key)
       : sequence_(std::move(sequence)), sort_key_(sort_key) {
@@ -25,10 +26,10 @@
   }
 
   // Note: while |sequence_| should always be non-null post-move (i.e. we
-  // shouldn't be moving an invalid SequenceAndSortKey around), there can't be a
-  // DCHECK(sequence_) on moves as the Windows STL moves elements on pop instead
-  // of overwriting them: resulting in the move of a SequenceAndSortKey with a
-  // null |sequence_| in Transaction::Pop()'s implementation.
+  // shouldn't be moving an invalid SequenceAndSortKey around), there can't be
+  // a DCHECK(sequence_) on moves as IntrusiveHeap moves elements on pop
+  // instead of overwriting them: resulting in the move of a SequenceAndSortKey
+  // with a null |sequence_| in Transaction::Pop()'s implementation.
   SequenceAndSortKey(SequenceAndSortKey&& other) = default;
   SequenceAndSortKey& operator=(SequenceAndSortKey&& other) = default;
 
@@ -40,14 +41,16 @@
   }
 
   // Compares this SequenceAndSortKey to |other| based on their respective
-  // |sort_key_|.
-  bool operator<(const SequenceAndSortKey& other) const {
-    return sort_key_ < other.sort_key_;
+  // |sort_key_|. Required by IntrusiveHeap.
+  bool operator<=(const SequenceAndSortKey& other) const {
+    return sort_key_ <= other.sort_key_;
   }
-  // Style-guide dictates to define operator> when defining operator< but it's
-  // unused in this case and this isn't a public API. Explicitly delete it so
-  // any errors point here if that ever changes.
-  bool operator>(const SequenceAndSortKey& other) const = delete;
+
+  // Required by IntrusiveHeap.
+  void SetHeapHandle(const HeapHandle& handle) {}
+
+  // Required by IntrusiveHeap.
+  void ClearHeapHandle() {}
 
   const SequenceSortKey& sort_key() const { return sort_key_; }
 
@@ -66,12 +69,13 @@
 void PriorityQueue::Transaction::Push(
     scoped_refptr<Sequence> sequence,
     const SequenceSortKey& sequence_sort_key) {
-  outer_queue_->container_.emplace(std::move(sequence), sequence_sort_key);
+  outer_queue_->container_.insert(
+      SequenceAndSortKey(std::move(sequence), sequence_sort_key));
 }
 
 const SequenceSortKey& PriorityQueue::Transaction::PeekSortKey() const {
   DCHECK(!IsEmpty());
-  return outer_queue_->container_.top().sort_key();
+  return outer_queue_->container_.Min().sort_key();
 }
 
 scoped_refptr<Sequence> PriorityQueue::Transaction::PopSequence() {
@@ -79,13 +83,12 @@
 
   // The const_cast on top() is okay since the SequenceAndSortKey is
   // transactionally being popped from |container_| right after and taking its
-  // Sequence does not alter its sort order (a requirement for the Windows STL's
-  // consistency debug-checks for std::priority_queue::top()).
+  // Sequence does not alter its sort order.
   scoped_refptr<Sequence> sequence =
       const_cast<PriorityQueue::SequenceAndSortKey&>(
-          outer_queue_->container_.top())
+          outer_queue_->container_.Min())
           .take_sequence();
-  outer_queue_->container_.pop();
+  outer_queue_->container_.Pop();
   return sequence;
 }
 
diff --git a/base/task/task_scheduler/priority_queue.h b/base/task/task_scheduler/priority_queue.h
index ca9ac13..265660d9 100644
--- a/base/task/task_scheduler/priority_queue.h
+++ b/base/task/task_scheduler/priority_queue.h
@@ -6,12 +6,11 @@
 #define BASE_TASK_TASK_SCHEDULER_PRIORITY_QUEUE_H_
 
 #include <memory>
-#include <queue>
-#include <vector>
 
 #include "base/base_export.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
+#include "base/task/common/intrusive_heap.h"
 #include "base/task/task_scheduler/scheduler_lock.h"
 #include "base/task/task_scheduler/sequence.h"
 #include "base/task/task_scheduler/sequence_sort_key.h"
@@ -88,7 +87,7 @@
   // position in a PriorityQueue.
   class SequenceAndSortKey;
 
-  using ContainerType = std::priority_queue<SequenceAndSortKey>;
+  using ContainerType = IntrusiveHeap<SequenceAndSortKey>;
 
   // Synchronizes access to |container_|.
   SchedulerLock container_lock_;
diff --git a/base/task/task_scheduler/sequence_sort_key.cc b/base/task/task_scheduler/sequence_sort_key.cc
index 497507c..98be8699 100644
--- a/base/task/task_scheduler/sequence_sort_key.cc
+++ b/base/task/task_scheduler/sequence_sort_key.cc
@@ -12,17 +12,17 @@
     : priority_(priority),
       next_task_sequenced_time_(next_task_sequenced_time) {}
 
-bool SequenceSortKey::operator<(const SequenceSortKey& other) const {
-  // This SequenceSortKey is considered less important than |other| if it has a
-  // lower priority or if it has the same priority but its next task was posted
-  // later than |other|'s.
+bool SequenceSortKey::operator<=(const SequenceSortKey& other) const {
+  // This SequenceSortKey is considered more important than |other| if it has a
+  // higher priority or if it has the same priority but its next task was
+  // posted sooner than |other|'s.
   const int priority_diff =
       static_cast<int>(priority_) - static_cast<int>(other.priority_);
-  if (priority_diff < 0)
-    return true;
   if (priority_diff > 0)
+    return true;
+  if (priority_diff < 0)
     return false;
-  return next_task_sequenced_time_ > other.next_task_sequenced_time_;
+  return next_task_sequenced_time_ <= other.next_task_sequenced_time_;
 }
 
 }  // namespace internal
diff --git a/base/task/task_scheduler/sequence_sort_key.h b/base/task/task_scheduler/sequence_sort_key.h
index 95406027..ed1497d6 100644
--- a/base/task/task_scheduler/sequence_sort_key.h
+++ b/base/task/task_scheduler/sequence_sort_key.h
@@ -15,6 +15,7 @@
 // An immutable but assignable representation of the priority of a Sequence.
 class BASE_EXPORT SequenceSortKey final {
  public:
+  SequenceSortKey() = default;
   SequenceSortKey(TaskPriority priority, TimeTicks next_task_sequenced_time);
 
   TaskPriority priority() const { return priority_; }
@@ -22,8 +23,8 @@
     return next_task_sequenced_time_;
   }
 
-  bool operator<(const SequenceSortKey& other) const;
-  bool operator>(const SequenceSortKey& other) const { return other < *this; }
+  // Lower sort key means more important.
+  bool operator<=(const SequenceSortKey& other) const;
 
   bool operator==(const SequenceSortKey& other) const {
     return priority_ == other.priority_ &&
diff --git a/base/task/task_scheduler/sequence_sort_key_unittest.cc b/base/task/task_scheduler/sequence_sort_key_unittest.cc
index 024fc2b..93704a9 100644
--- a/base/task/task_scheduler/sequence_sort_key_unittest.cc
+++ b/base/task/task_scheduler/sequence_sort_key_unittest.cc
@@ -11,7 +11,7 @@
 namespace base {
 namespace internal {
 
-TEST(TaskSchedulerSequenceSortKeyTest, OperatorLessThan) {
+TEST(TaskSchedulerSequenceSortKeyTest, OperatorLessThanOrEqual) {
   SequenceSortKey key_a(TaskPriority::USER_BLOCKING,
                         TimeTicks::FromInternalValue(1000));
   SequenceSortKey key_b(TaskPriority::USER_BLOCKING,
@@ -25,104 +25,47 @@
   SequenceSortKey key_f(TaskPriority::BEST_EFFORT,
                         TimeTicks::FromInternalValue(2000));
 
-  EXPECT_FALSE(key_a < key_a);
-  EXPECT_LT(key_b, key_a);
-  EXPECT_LT(key_c, key_a);
-  EXPECT_LT(key_d, key_a);
-  EXPECT_LT(key_e, key_a);
-  EXPECT_LT(key_f, key_a);
+  EXPECT_LE(key_a, key_a);
+  EXPECT_FALSE(key_b <= key_a);
+  EXPECT_FALSE(key_c <= key_a);
+  EXPECT_FALSE(key_d <= key_a);
+  EXPECT_FALSE(key_e <= key_a);
+  EXPECT_FALSE(key_f <= key_a);
 
-  EXPECT_FALSE(key_a < key_b);
-  EXPECT_FALSE(key_b < key_b);
-  EXPECT_LT(key_c, key_b);
-  EXPECT_LT(key_d, key_b);
-  EXPECT_LT(key_e, key_b);
-  EXPECT_LT(key_f, key_b);
+  EXPECT_LE(key_a, key_b);
+  EXPECT_LE(key_b, key_b);
+  EXPECT_FALSE(key_c <= key_b);
+  EXPECT_FALSE(key_d <= key_b);
+  EXPECT_FALSE(key_e <= key_b);
+  EXPECT_FALSE(key_f <= key_b);
 
-  EXPECT_FALSE(key_a < key_c);
-  EXPECT_FALSE(key_b < key_c);
-  EXPECT_FALSE(key_c < key_c);
-  EXPECT_LT(key_d, key_c);
-  EXPECT_LT(key_e, key_c);
-  EXPECT_LT(key_f, key_c);
+  EXPECT_LE(key_a, key_c);
+  EXPECT_LE(key_b, key_c);
+  EXPECT_LE(key_c, key_c);
+  EXPECT_FALSE(key_d <= key_c);
+  EXPECT_FALSE(key_e <= key_c);
+  EXPECT_FALSE(key_f <= key_c);
 
-  EXPECT_FALSE(key_a < key_d);
-  EXPECT_FALSE(key_b < key_d);
-  EXPECT_FALSE(key_c < key_d);
-  EXPECT_FALSE(key_d < key_d);
-  EXPECT_LT(key_e, key_d);
-  EXPECT_LT(key_f, key_d);
+  EXPECT_LE(key_a, key_d);
+  EXPECT_LE(key_b, key_d);
+  EXPECT_LE(key_c, key_d);
+  EXPECT_LE(key_d, key_d);
+  EXPECT_FALSE(key_e <= key_d);
+  EXPECT_FALSE(key_f <= key_d);
 
-  EXPECT_FALSE(key_a < key_e);
-  EXPECT_FALSE(key_b < key_e);
-  EXPECT_FALSE(key_c < key_e);
-  EXPECT_FALSE(key_d < key_e);
-  EXPECT_FALSE(key_e < key_e);
-  EXPECT_LT(key_f, key_e);
+  EXPECT_LE(key_a, key_e);
+  EXPECT_LE(key_b, key_e);
+  EXPECT_LE(key_c, key_e);
+  EXPECT_LE(key_d, key_e);
+  EXPECT_LE(key_e, key_e);
+  EXPECT_FALSE(key_f <= key_e);
 
-  EXPECT_FALSE(key_a < key_f);
-  EXPECT_FALSE(key_b < key_f);
-  EXPECT_FALSE(key_c < key_f);
-  EXPECT_FALSE(key_d < key_f);
-  EXPECT_FALSE(key_e < key_f);
-  EXPECT_FALSE(key_f < key_f);
-}
-
-TEST(TaskSchedulerSequenceSortKeyTest, OperatorGreaterThan) {
-  SequenceSortKey key_a(TaskPriority::USER_BLOCKING,
-                        TimeTicks::FromInternalValue(1000));
-  SequenceSortKey key_b(TaskPriority::USER_BLOCKING,
-                        TimeTicks::FromInternalValue(2000));
-  SequenceSortKey key_c(TaskPriority::USER_VISIBLE,
-                        TimeTicks::FromInternalValue(1000));
-  SequenceSortKey key_d(TaskPriority::USER_VISIBLE,
-                        TimeTicks::FromInternalValue(2000));
-  SequenceSortKey key_e(TaskPriority::BEST_EFFORT,
-                        TimeTicks::FromInternalValue(1000));
-  SequenceSortKey key_f(TaskPriority::BEST_EFFORT,
-                        TimeTicks::FromInternalValue(2000));
-
-  EXPECT_FALSE(key_a > key_a);
-  EXPECT_FALSE(key_b > key_a);
-  EXPECT_FALSE(key_c > key_a);
-  EXPECT_FALSE(key_d > key_a);
-  EXPECT_FALSE(key_e > key_a);
-  EXPECT_FALSE(key_f > key_a);
-
-  EXPECT_GT(key_a, key_b);
-  EXPECT_FALSE(key_b > key_b);
-  EXPECT_FALSE(key_c > key_b);
-  EXPECT_FALSE(key_d > key_b);
-  EXPECT_FALSE(key_e > key_b);
-  EXPECT_FALSE(key_f > key_b);
-
-  EXPECT_GT(key_a, key_c);
-  EXPECT_GT(key_b, key_c);
-  EXPECT_FALSE(key_c > key_c);
-  EXPECT_FALSE(key_d > key_c);
-  EXPECT_FALSE(key_e > key_c);
-  EXPECT_FALSE(key_f > key_c);
-
-  EXPECT_GT(key_a, key_d);
-  EXPECT_GT(key_b, key_d);
-  EXPECT_GT(key_c, key_d);
-  EXPECT_FALSE(key_d > key_d);
-  EXPECT_FALSE(key_e > key_d);
-  EXPECT_FALSE(key_f > key_d);
-
-  EXPECT_GT(key_a, key_e);
-  EXPECT_GT(key_b, key_e);
-  EXPECT_GT(key_c, key_e);
-  EXPECT_GT(key_d, key_e);
-  EXPECT_FALSE(key_e > key_e);
-  EXPECT_FALSE(key_f > key_e);
-
-  EXPECT_GT(key_a, key_f);
-  EXPECT_GT(key_b, key_f);
-  EXPECT_GT(key_c, key_f);
-  EXPECT_GT(key_d, key_f);
-  EXPECT_GT(key_e, key_f);
-  EXPECT_FALSE(key_f > key_f);
+  EXPECT_LE(key_a, key_f);
+  EXPECT_LE(key_b, key_f);
+  EXPECT_LE(key_c, key_f);
+  EXPECT_LE(key_d, key_f);
+  EXPECT_LE(key_e, key_f);
+  EXPECT_LE(key_f, key_f);
 }
 
 TEST(TaskSchedulerSequenceSortKeyTest, OperatorEqual) {
diff --git a/base/task/task_scheduler/task_tracker_posix.cc b/base/task/task_scheduler/task_tracker_posix.cc
index 9c64fc2..6cd6185 100644
--- a/base/task/task_scheduler/task_tracker_posix.cc
+++ b/base/task/task_scheduler/task_tracker_posix.cc
@@ -7,6 +7,7 @@
 #include <utility>
 
 #include "base/files/file_descriptor_watcher_posix.h"
+#include "base/message_loop/message_loop.h"
 
 namespace base {
 namespace internal {
@@ -19,7 +20,7 @@
                                      bool can_run_task) {
   DCHECK(watch_file_descriptor_message_loop_);
   FileDescriptorWatcher file_descriptor_watcher(
-      watch_file_descriptor_message_loop_);
+      watch_file_descriptor_message_loop_->task_runner());
   TaskTracker::RunOrSkipTask(std::move(task), sequence, can_run_task);
 }
 
diff --git a/base/test/launcher/test_launcher_nacl_nonsfi.cc b/base/test/launcher/test_launcher_nacl_nonsfi.cc
index bdc4f67..304cc78 100644
--- a/base/test/launcher/test_launcher_nacl_nonsfi.cc
+++ b/base/test/launcher/test_launcher_nacl_nonsfi.cc
@@ -147,7 +147,7 @@
 
   base::MessageLoopForIO message_loop;
 #if defined(OS_POSIX)
-  FileDescriptorWatcher file_descriptor_watcher(&message_loop);
+  FileDescriptorWatcher file_descriptor_watcher(message_loop.task_runner());
 #endif
 
   NonSfiUnitTestPlatformDelegate platform_delegate;
diff --git a/base/test/launcher/unit_test_launcher.cc b/base/test/launcher/unit_test_launcher.cc
index 789d42ecb..51ab94ef 100644
--- a/base/test/launcher/unit_test_launcher.cc
+++ b/base/test/launcher/unit_test_launcher.cc
@@ -249,7 +249,7 @@
 
   MessageLoopForIO message_loop;
 #if defined(OS_POSIX)
-  FileDescriptorWatcher file_descriptor_watcher(&message_loop);
+  FileDescriptorWatcher file_descriptor_watcher(message_loop.task_runner());
 #endif
 
   DefaultUnitTestPlatformDelegate platform_delegate;
diff --git a/base/test/scoped_task_environment.cc b/base/test/scoped_task_environment.cc
index 32265ee..cf8e5cad 100644
--- a/base/test/scoped_task_environment.cc
+++ b/base/test/scoped_task_environment.cc
@@ -117,11 +117,10 @@
                     slsm_for_mock_time_.get())
               : nullptr),
 #if defined(OS_POSIX)
-      file_descriptor_watcher_(
-          main_thread_type == MainThreadType::IO
-              ? std::make_unique<FileDescriptorWatcher>(
-                    static_cast<MessageLoopForIO*>(message_loop_.get()))
-              : nullptr),
+      file_descriptor_watcher_(main_thread_type == MainThreadType::IO
+                                   ? std::make_unique<FileDescriptorWatcher>(
+                                         message_loop_->task_runner())
+                                   : nullptr),
 #endif  // defined(OS_POSIX)
       task_tracker_(new TestTaskTracker()) {
   CHECK(!TaskScheduler::GetInstance())
diff --git a/base/test/scoped_task_environment_unittest.cc b/base/test/scoped_task_environment_unittest.cc
index d8e76c5..d918b45 100644
--- a/base/test/scoped_task_environment_unittest.cc
+++ b/base/test/scoped_task_environment_unittest.cc
@@ -9,6 +9,7 @@
 #include "base/atomicops.h"
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "base/run_loop.h"
 #include "base/synchronization/atomic_flag.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/task/post_task.h"
diff --git a/base/threading/platform_thread.h b/base/threading/platform_thread.h
index 029cca5..a2761cf 100644
--- a/base/threading/platform_thread.h
+++ b/base/threading/platform_thread.h
@@ -231,6 +231,10 @@
                                 ThreadPriority priority);
 #endif
 
+  // Returns the default thread stack size set by chrome. If we do not
+  // explicitly set default size then returns 0.
+  static size_t GetDefaultThreadStackSize();
+
  private:
   DISALLOW_IMPLICIT_CONSTRUCTORS(PlatformThread);
 };
diff --git a/base/threading/platform_thread_posix.cc b/base/threading/platform_thread_posix.cc
index c904f38..3de9ed8 100644
--- a/base/threading/platform_thread_posix.cc
+++ b/base/threading/platform_thread_posix.cc
@@ -342,4 +342,11 @@
 
 #endif  // !defined(OS_MACOSX) && !defined(OS_FUCHSIA)
 
+// static
+size_t PlatformThread::GetDefaultThreadStackSize() {
+  pthread_attr_t attributes;
+  pthread_attr_init(&attributes);
+  return base::GetDefaultThreadStackSize(attributes);
+}
+
 }  // namespace base
diff --git a/base/threading/platform_thread_unittest.cc b/base/threading/platform_thread_unittest.cc
index bd0c4d88..d7a9890 100644
--- a/base/threading/platform_thread_unittest.cc
+++ b/base/threading/platform_thread_unittest.cc
@@ -395,4 +395,16 @@
   PlatformThread::SetName(long_name);
 }
 
+TEST(PlatformThreadTest, GetDefaultThreadStackSize) {
+  size_t stack_size = PlatformThread::GetDefaultThreadStackSize();
+#if defined(OS_WIN) || defined(OS_IOS) || defined(OS_FUCHSIA) || \
+    (defined(OS_LINUX) && !defined(THREAD_SANITIZER)) ||         \
+    (defined(OS_ANDROID) && !defined(ADDRESS_SANITIZER))
+  EXPECT_EQ(0u, stack_size);
+#else
+  EXPECT_GT(stack_size, 0u);
+  EXPECT_LT(stack_size, 20u * (1 << 20));
+#endif
+}
+
 }  // namespace base
diff --git a/base/threading/platform_thread_win.cc b/base/threading/platform_thread_win.cc
index c21de9f..b645f202 100644
--- a/base/threading/platform_thread_win.cc
+++ b/base/threading/platform_thread_win.cc
@@ -359,4 +359,9 @@
   return ThreadPriority::NORMAL;
 }
 
+// static
+size_t PlatformThread::GetDefaultThreadStackSize() {
+  return 0;
+}
+
 }  // namespace base
diff --git a/base/threading/thread.cc b/base/threading/thread.cc
index fce6a794..4d3390d 100644
--- a/base/threading/thread.cc
+++ b/base/threading/thread.cc
@@ -323,8 +323,8 @@
   // Allow threads running a MessageLoopForIO to use FileDescriptorWatcher API.
   std::unique_ptr<FileDescriptorWatcher> file_descriptor_watcher;
   if (MessageLoopForIO::IsCurrent()) {
-    file_descriptor_watcher.reset(new FileDescriptorWatcher(
-        static_cast<MessageLoopForIO*>(message_loop_)));
+    file_descriptor_watcher.reset(
+        new FileDescriptorWatcher(message_loop_->task_runner()));
   }
 #endif
 
diff --git a/base/trace_event/blame_context.cc b/base/trace_event/blame_context.cc
index 0ed9aa7..b46412c 100644
--- a/base/trace_event/blame_context.cc
+++ b/base/trace_event/blame_context.cc
@@ -33,9 +33,9 @@
 BlameContext::~BlameContext() {
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(WasInitialized());
-  TRACE_EVENT_API_ADD_TRACE_EVENT(
-      TRACE_EVENT_PHASE_DELETE_OBJECT, category_group_enabled_, type_, scope_,
-      id_, 0, nullptr, nullptr, nullptr, nullptr, TRACE_EVENT_FLAG_HAS_ID);
+  TRACE_EVENT_API_ADD_TRACE_EVENT(TRACE_EVENT_PHASE_DELETE_OBJECT,
+                                  category_group_enabled_, type_, scope_, id_,
+                                  nullptr, TRACE_EVENT_FLAG_HAS_ID);
   trace_event::TraceLog::GetInstance()->RemoveAsyncEnabledStateObserver(this);
 }
 
@@ -43,7 +43,6 @@
   DCHECK(WasInitialized());
   TRACE_EVENT_API_ADD_TRACE_EVENT(TRACE_EVENT_PHASE_ENTER_CONTEXT,
                                   category_group_enabled_, name_, scope_, id_,
-                                  0 /* num_args */, nullptr, nullptr, nullptr,
                                   nullptr, TRACE_EVENT_FLAG_HAS_ID);
 }
 
@@ -51,7 +50,6 @@
   DCHECK(WasInitialized());
   TRACE_EVENT_API_ADD_TRACE_EVENT(TRACE_EVENT_PHASE_LEAVE_CONTEXT,
                                   category_group_enabled_, name_, scope_, id_,
-                                  0 /* num_args */, nullptr, nullptr, nullptr,
                                   nullptr, TRACE_EVENT_FLAG_HAS_ID);
 }
 
@@ -63,15 +61,10 @@
   std::unique_ptr<trace_event::TracedValue> snapshot(
       new trace_event::TracedValue);
   AsValueInto(snapshot.get());
-  static const char* const kArgName = "snapshot";
-  const int kNumArgs = 1;
-  unsigned char arg_types[1] = {TRACE_VALUE_TYPE_CONVERTABLE};
-  std::unique_ptr<trace_event::ConvertableToTraceFormat> arg_values[1] = {
-      std::move(snapshot)};
+  TraceArguments args("snapshot", std::move(snapshot));
   TRACE_EVENT_API_ADD_TRACE_EVENT(TRACE_EVENT_PHASE_SNAPSHOT_OBJECT,
                                   category_group_enabled_, type_, scope_, id_,
-                                  kNumArgs, &kArgName, arg_types, nullptr,
-                                  arg_values, TRACE_EVENT_FLAG_HAS_ID);
+                                  &args, TRACE_EVENT_FLAG_HAS_ID);
 }
 
 void BlameContext::OnTraceLogEnabled() {
@@ -95,9 +88,9 @@
   DCHECK(thread_checker_.CalledOnValidThread());
   category_group_enabled_ =
       TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(category_);
-  TRACE_EVENT_API_ADD_TRACE_EVENT(
-      TRACE_EVENT_PHASE_CREATE_OBJECT, category_group_enabled_, type_, scope_,
-      id_, 0, nullptr, nullptr, nullptr, nullptr, TRACE_EVENT_FLAG_HAS_ID);
+  TRACE_EVENT_API_ADD_TRACE_EVENT(TRACE_EVENT_PHASE_CREATE_OBJECT,
+                                  category_group_enabled_, type_, scope_, id_,
+                                  nullptr, TRACE_EVENT_FLAG_HAS_ID);
   trace_event::TraceLog::GetInstance()->AddAsyncEnabledStateObserver(
       weak_factory_.GetWeakPtr());
   TakeSnapshot();
diff --git a/base/trace_event/event_name_filter_unittest.cc b/base/trace_event/event_name_filter_unittest.cc
index 134be0d..d5bd057 100644
--- a/base/trace_event/event_name_filter_unittest.cc
+++ b/base/trace_event/event_name_filter_unittest.cc
@@ -12,11 +12,10 @@
 namespace trace_event {
 
 const TraceEvent& MakeTraceEvent(const char* name) {
-  static TraceEvent event;
-  event.Reset();
-  event.Initialize(0, TimeTicks(), ThreadTicks(), 'b', nullptr, name, "", 0, 0,
-                   0, nullptr, nullptr, nullptr, nullptr, 0);
-  return event;
+  static TraceEvent trace_event;
+  trace_event = TraceEvent(0, TimeTicks(), ThreadTicks(), 'b', nullptr, name,
+                           "", 0, 0, nullptr, 0);
+  return trace_event;
 }
 
 TEST(TraceEventNameFilterTest, Whitelist) {
diff --git a/base/trace_event/process_memory_dump.cc b/base/trace_event/process_memory_dump.cc
index 8f851f4..5a049cc 100644
--- a/base/trace_event/process_memory_dump.cc
+++ b/base/trace_event/process_memory_dump.cc
@@ -13,6 +13,7 @@
 #include "base/process/process_metrics.h"
 #include "base/strings/stringprintf.h"
 #include "base/trace_event/memory_infra_background_whitelist.h"
+#include "base/trace_event/trace_event_impl.h"
 #include "base/trace_event/traced_value.h"
 #include "base/unguessable_token.h"
 #include "build/build_config.h"
diff --git a/base/trace_event/trace_arguments.cc b/base/trace_event/trace_arguments.cc
new file mode 100644
index 0000000..002720f
--- /dev/null
+++ b/base/trace_event/trace_arguments.cc
@@ -0,0 +1,270 @@
+// 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 "base/trace_event/trace_arguments.h"
+
+#include <inttypes.h>
+#include <stddef.h>
+#include <string.h>
+
+#include <stdio.h>
+
+#include "base/json/string_escape.h"
+#include "base/logging.h"
+#include "base/stl_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+
+namespace base {
+namespace trace_event {
+
+namespace {
+
+size_t GetAllocLength(const char* str) {
+  return str ? strlen(str) + 1 : 0;
+}
+
+// Copies |*member| into |*buffer|, sets |*member| to point to this new
+// location, and then advances |*buffer| by the amount written.
+void CopyTraceEventParameter(char** buffer,
+                             const char** member,
+                             const char* end) {
+  if (*member) {
+    size_t written = strlcpy(*buffer, *member, end - *buffer) + 1;
+    DCHECK_LE(static_cast<int>(written), end - *buffer);
+    *member = *buffer;
+    *buffer += written;
+  }
+}
+
+// Append |val| as a JSON output value to |*out|.
+void AppendDoubleAsJSON(double val, std::string* out) {
+  // FIXME: base/json/json_writer.cc is using the same code,
+  //        should be made into a common method.
+  std::string real;
+  if (std::isfinite(val)) {
+    real = NumberToString(val);
+    // Ensure that the number has a .0 if there's no decimal or 'e'.  This
+    // makes sure that when we read the JSON back, it's interpreted as a
+    // real rather than an int.
+    if (real.find('.') == std::string::npos &&
+        real.find('e') == std::string::npos &&
+        real.find('E') == std::string::npos) {
+      real.append(".0");
+    }
+    // The JSON spec requires that non-integer values in the range (-1,1)
+    // have a zero before the decimal point - ".52" is not valid, "0.52" is.
+    if (real[0] == '.') {
+      real.insert(0, "0");
+    } else if (real.length() > 1 && real[0] == '-' && real[1] == '.') {
+      // "-.1" bad "-0.1" good
+      real.insert(1, "0");
+    }
+  } else if (std::isnan(val)) {
+    // The JSON spec doesn't allow NaN and Infinity (since these are
+    // objects in EcmaScript).  Use strings instead.
+    real = "\"NaN\"";
+  } else if (val < 0) {
+    real = "\"-Infinity\"";
+  } else {
+    real = "\"Infinity\"";
+  }
+  StringAppendF(out, "%s", real.c_str());
+}
+
+const char* TypeToString(char arg_type) {
+  switch (arg_type) {
+    case TRACE_VALUE_TYPE_INT:
+      return "int";
+    case TRACE_VALUE_TYPE_UINT:
+      return "uint";
+    case TRACE_VALUE_TYPE_DOUBLE:
+      return "double";
+    case TRACE_VALUE_TYPE_BOOL:
+      return "bool";
+    case TRACE_VALUE_TYPE_POINTER:
+      return "pointer";
+    case TRACE_VALUE_TYPE_STRING:
+      return "string";
+    case TRACE_VALUE_TYPE_COPY_STRING:
+      return "copy_string";
+    case TRACE_VALUE_TYPE_CONVERTABLE:
+      return "convertable";
+    default:
+      NOTREACHED();
+      return "UNKNOWN_TYPE";
+  }
+}
+
+void AppendValueDebugString(const TraceArguments& args,
+                            size_t idx,
+                            std::string* out) {
+  *out += (args.names()[idx] ? args.names()[idx] : "NULL_NAME");
+  *out += "=";
+  *out += TypeToString(args.types()[idx]);
+  *out += "(";
+  args.values()[idx].AppendAsJSON(args.types()[idx], out);
+  *out += ")";
+}
+
+}  // namespace
+
+void StringStorage::Reset(size_t alloc_size) {
+  if (!alloc_size) {
+    if (data_)
+      ::free(data_);
+    data_ = nullptr;
+  } else if (!data_ || alloc_size != data_->size) {
+    data_ = static_cast<Data*>(::realloc(data_, sizeof(size_t) + alloc_size));
+    data_->size = alloc_size;
+  }
+}
+
+bool StringStorage::Contains(const TraceArguments& args) const {
+  for (size_t n = 0; n < args.size(); ++n) {
+    if (args.types()[n] == TRACE_VALUE_TYPE_COPY_STRING &&
+        !Contains(args.values()[n].as_string)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+static_assert(
+    std::is_pod<TraceValue>::value,
+    "TraceValue must be plain-old-data type for performance reasons!");
+
+void TraceValue::AppendAsJSON(unsigned char type, std::string* out) const {
+  switch (type) {
+    case TRACE_VALUE_TYPE_BOOL:
+      *out += this->as_bool ? "true" : "false";
+      break;
+    case TRACE_VALUE_TYPE_UINT:
+      StringAppendF(out, "%" PRIu64, static_cast<uint64_t>(this->as_uint));
+      break;
+    case TRACE_VALUE_TYPE_INT:
+      StringAppendF(out, "%" PRId64, static_cast<int64_t>(this->as_int));
+      break;
+    case TRACE_VALUE_TYPE_DOUBLE:
+      AppendDoubleAsJSON(this->as_double, out);
+      break;
+    case TRACE_VALUE_TYPE_POINTER:
+      // JSON only supports double and int numbers.
+      // So as not to lose bits from a 64-bit pointer, output as a hex string.
+      StringAppendF(
+          out, "\"0x%" PRIx64 "\"",
+          static_cast<uint64_t>(reinterpret_cast<uintptr_t>(this->as_pointer)));
+      break;
+    case TRACE_VALUE_TYPE_STRING:
+    case TRACE_VALUE_TYPE_COPY_STRING:
+      EscapeJSONString(this->as_string ? this->as_string : "NULL", true, out);
+      break;
+    case TRACE_VALUE_TYPE_CONVERTABLE:
+      this->as_convertable->AppendAsTraceFormat(out);
+      break;
+    default:
+      NOTREACHED() << "Don't know how to print this value";
+      break;
+  }
+}
+
+TraceArguments& TraceArguments::operator=(TraceArguments&& other) noexcept {
+  if (this != &other) {
+    this->~TraceArguments();
+    new (this) TraceArguments(std::move(other));
+  }
+  return *this;
+}
+
+TraceArguments::TraceArguments(int num_args,
+                               const char* const* arg_names,
+                               const unsigned char* arg_types,
+                               const unsigned long long* arg_values) {
+  if (num_args > static_cast<int>(kMaxSize))
+    num_args = static_cast<int>(kMaxSize);
+
+  size_ = static_cast<unsigned char>(num_args);
+  for (size_t n = 0; n < size_; ++n) {
+    types_[n] = arg_types[n];
+    names_[n] = arg_names[n];
+    values_[n].as_uint = arg_values[n];
+  }
+}
+
+void TraceArguments::Reset() {
+  for (size_t n = 0; n < size_; ++n) {
+    if (types_[n] == TRACE_VALUE_TYPE_CONVERTABLE)
+      delete values_[n].as_convertable;
+  }
+  size_ = 0;
+}
+
+void TraceArguments::CopyStringsTo(StringStorage* storage,
+                                   bool copy_all_strings,
+                                   const char** extra_string1,
+                                   const char** extra_string2) {
+  // First, compute total allocation size.
+  size_t alloc_size = 0;
+
+  if (copy_all_strings) {
+    alloc_size +=
+        GetAllocLength(*extra_string1) + GetAllocLength(*extra_string2);
+    for (size_t n = 0; n < size_; ++n)
+      alloc_size += GetAllocLength(names_[n]);
+  }
+  for (size_t n = 0; n < size_; ++n) {
+    if (copy_all_strings && types_[n] == TRACE_VALUE_TYPE_STRING)
+      types_[n] = TRACE_VALUE_TYPE_COPY_STRING;
+    if (types_[n] == TRACE_VALUE_TYPE_COPY_STRING)
+      alloc_size += GetAllocLength(values_[n].as_string);
+  }
+
+  if (alloc_size) {
+    storage->Reset(alloc_size);
+    char* ptr = storage->data();
+    const char* end = ptr + alloc_size;
+    if (copy_all_strings) {
+      CopyTraceEventParameter(&ptr, extra_string1, end);
+      CopyTraceEventParameter(&ptr, extra_string2, end);
+      for (size_t n = 0; n < size_; ++n)
+        CopyTraceEventParameter(&ptr, &names_[n], end);
+    }
+    for (size_t n = 0; n < size_; ++n) {
+      if (types_[n] == TRACE_VALUE_TYPE_COPY_STRING)
+        CopyTraceEventParameter(&ptr, &values_[n].as_string, end);
+    }
+#if DCHECK_IS_ON()
+    DCHECK_EQ(end, ptr) << "Overrun by " << ptr - end;
+    if (copy_all_strings) {
+      if (extra_string1 && *extra_string1)
+        DCHECK(storage->Contains(*extra_string1));
+      if (extra_string2 && *extra_string2)
+        DCHECK(storage->Contains(*extra_string2));
+      for (size_t n = 0; n < size_; ++n)
+        DCHECK(storage->Contains(names_[n]));
+    }
+    for (size_t n = 0; n < size_; ++n) {
+      if (types_[n] == TRACE_VALUE_TYPE_COPY_STRING)
+        DCHECK(storage->Contains(values_[n].as_string));
+    }
+#endif  // DCHECK_IS_ON()
+  } else {
+    storage->Reset();
+  }
+}
+
+void TraceArguments::AppendDebugString(std::string* out) {
+  *out += "TraceArguments(";
+  for (size_t n = 0; n < size_; ++n) {
+    if (n > 0)
+      *out += ", ";
+    AppendValueDebugString(*this, n, out);
+  }
+  *out += ")";
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/trace_arguments.h b/base/trace_event/trace_arguments.h
new file mode 100644
index 0000000..31d5bdff
--- /dev/null
+++ b/base/trace_event/trace_arguments.h
@@ -0,0 +1,653 @@
+// 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 BASE_TRACE_EVENT_TRACE_ARGUMENTS_H_
+#define BASE_TRACE_EVENT_TRACE_ARGUMENTS_H_
+
+#include <stdlib.h>
+
+#include <algorithm>
+#include <memory>
+#include <string>
+
+#include "base/base_export.h"
+#include "base/macros.h"
+#include "base/trace_event/common/trace_event_common.h"
+
+// Trace macro can have one or two optional arguments, each one of them
+// identified by a name (a C string literal) and a value, which can be an
+// integer, enum, floating point, boolean, string pointer or reference, or
+// std::unique_ptr<ConvertableToTraceFormat> compatible values. Additionally,
+// custom data types need to be supported, like time values or WTF::CString.
+//
+// TraceArguments is a helper class used to store 0 to 2 named arguments
+// corresponding to an individual trace macro call. As efficiently as possible,
+// and with the minimal amount of generated machine code (since this affects
+// any TRACE macro call). Each argument has:
+//
+//  - A name (C string literal, e.g "dumps")
+//  - An 8-bit type value, corresponding to the TRACE_VALUE_TYPE_XXX macros.
+//  - A value, stored in a TraceValue union
+//
+// IMPORTANT: For a TRACE_VALUE_TYPE_CONVERTABLE types, the TraceArguments
+// instance owns the pointed ConvertableToTraceFormat object, i.e. it will
+// delete it automatically on destruction.
+//
+// TraceArguments instances should be built using one of specialized
+// constructors declared below. One cannot modify an instance once it has
+// been built, except for move operations, Reset() and destruction. Examples:
+//
+//    TraceArguments args;    // No arguments.
+//    // args.size() == 0
+//
+//    TraceArguments("foo", 100);
+//    // args.size() == 1
+//    // args.types()[0] == TRACE_VALUE_TYPE_INT
+//    // args.names()[0] == "foo"
+//    // args.values()[0].as_int == 100
+//
+//    TraceArguments("bar", 1ULL);
+//    // args.size() == 1
+//    // args.types()[0] == TRACE_VALUE_TYPE_UINT
+//    // args.names()[0] == "bar"
+//    // args.values()[0].as_uint == 100
+//
+//    TraceArguments("foo", "Hello", "bar", "World");
+//    // args.size() == 2
+//    // args.types()[0] == TRACE_VALUE_TYPE_STRING
+//    // args.types()[1] == TRACE_VALUE_TYPE_STRING
+//    // args.names()[0] == "foo"
+//    // args.names()[1] == "bar"
+//    // args.values()[0].as_string == "Hello"
+//    // args.values()[1].as_string == "World"
+//
+//    std::string some_string = ...;
+//    TraceArguments("str1", some_string);
+//    // args.size() == 1
+//    // args.types()[0] == TRACE_VALUE_TYPE_COPY_STRING
+//    // args.names()[0] == "str1"
+//    // args.values()[0].as_string == some_string.c_str()
+//
+// Note that TRACE_VALUE_TYPE_COPY_STRING corresponds to string pointers
+// that point to temporary values that may disappear soon. The
+// TraceArguments::CopyStringTo() method can be used to copy their content
+// into a StringStorage memory block, and update the |as_string| value pointers
+// to it to avoid keeping any dangling pointers. This is used by TraceEvent
+// to keep copies of such strings in the log after their initialization values
+// have disappeared.
+//
+// The TraceStringWithCopy helper class can be used to initialize a value
+// from a regular string pointer with TRACE_VALUE_TYPE_COPY_STRING too, as in:
+//
+//     const char str[] = "....";
+//     TraceArguments("foo", str, "bar", TraceStringWithCopy(str));
+//     // args.size() == 2
+//     // args.types()[0] == TRACE_VALUE_TYPE_STRING
+//     // args.types()[1] == TRACE_VALUE_TYPE_COPY_STRING
+//     // args.names()[0] == "foo"
+//     // args.names()[1] == "bar"
+//     // args.values()[0].as_string == str
+//     // args.values()[1].as_string == str
+//
+//     StringStorage storage;
+//     args.CopyStringTo(&storage, false, nullptr, nullptr);
+//     // args.size() == 2
+//     // args.types()[0] == TRACE_VALUE_TYPE_STRING
+//     // args.types()[1] == TRACE_VALUE_TYPE_COPY_STRING
+//     // args.names()[0] == "foo"
+//     // args.names()[1] == "bar"
+//     // args.values()[0].as_string == str
+//     // args.values()[1].as_string == Address inside |storage|.
+//
+// Initialization from a std::unique_ptr<ConvertableToTraceFormat>
+// is supported but will move ownership of the pointer objects to the
+// TraceArguments instance:
+//
+//     class MyConvertableType :
+//         public base::trace_event::AsConvertableToTraceFormat {
+//        ...
+//     };
+//
+//     {
+//       TraceArguments args("foo" , std::make_unique<MyConvertableType>(...));
+//       // args.size() == 1
+//       // args.values()[0].as_convertable == address of MyConvertable object.
+//     } // Calls |args| destructor, which will delete the object too.
+//
+// Finally, it is possible to support initialization from custom values by
+// specializing the TraceValue::Helper<> template struct as described below.
+//
+// This is how values of custom types like WTF::CString can be passed directly
+// to trace macros.
+
+namespace base {
+
+class Time;
+class TimeTicks;
+class ThreadTicks;
+
+namespace trace_event {
+
+class TraceEventMemoryOverhead;
+
+// For any argument of type TRACE_VALUE_TYPE_CONVERTABLE the provided
+// class must implement this interface. Note that unlike other values,
+// these objects will be owned by the TraceArguments instance that points
+// to them.
+class BASE_EXPORT ConvertableToTraceFormat {
+ public:
+  ConvertableToTraceFormat() = default;
+  virtual ~ConvertableToTraceFormat() = default;
+
+  // Append the class info to the provided |out| string. The appended
+  // data must be a valid JSON object. Strings must be properly quoted, and
+  // escaped. There is no processing applied to the content after it is
+  // appended.
+  virtual void AppendAsTraceFormat(std::string* out) const = 0;
+
+  virtual void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead* overhead);
+
+  std::string ToString() const {
+    std::string result;
+    AppendAsTraceFormat(&result);
+    return result;
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ConvertableToTraceFormat);
+};
+
+// A union used to hold the values of individual trace arguments.
+//
+// This is a POD union for performance reason. Initialization from an
+// explicit C++ trace argument should be performed with the Init()
+// templated method described below.
+//
+// Initialization from custom types is possible by implementing a custom
+// TraceValue::Helper<> instantiation as described below.
+//
+// IMPORTANT: Pointer storage inside a TraceUnion follows specific rules:
+//
+//   - |as_pointer| is for raw pointers that should be treated as a simple
+//     address and will never be dereferenced. Associated with the
+//     TRACE_VALUE_TYPE_POINTER type.
+//
+//   - |as_string| is for C-string pointers, associated with both
+//     TRACE_VALUE_TYPE_STRING and TRACE_VALUE_TYPE_COPY_STRING. The former
+//     indicates that the string pointer is persistent (e.g. a C string
+//     literal), while the second indicates that the pointer belongs to a
+//     temporary variable that may disappear soon. The TraceArguments class
+//     provides a CopyStringTo() method to copy these strings into a
+//     StringStorage instance, which is useful if the instance needs to
+//     survive longer than the temporaries.
+//
+//   - |as_convertable| is equivalent to
+//     std::unique_ptr<ConvertableToTraceFormat>, except that it is a pointer
+//     to keep this union POD and avoid un-necessary declarations and potential
+//     code generation. This means that its ownership is passed to the
+//     TraceValue instance when Init(std::unique_ptr<ConvertableToTraceFormat>)
+//     is called, and that it will be deleted by the containing TraceArguments
+//     destructor, or Reset() method.
+//
+union BASE_EXPORT TraceValue {
+  bool as_bool;
+  unsigned long long as_uint;
+  long long as_int;
+  double as_double;
+  const void* as_pointer;
+  const char* as_string;
+  ConvertableToTraceFormat* as_convertable;
+
+  // There is no constructor to keep this structure POD intentionally.
+  // This avoids un-needed initialization when only 0 or 1 arguments are
+  // used to construct a TraceArguments instance. Use Init() instead to
+  // perform explicit initialization from a given C++ value.
+
+  // Initialize TraceValue instance from a C++ trace value.
+  // This relies on the proper specialization of TraceValue::Helper<>
+  // described below. Usage is simply:
+  //
+  //  TraceValue v;
+  //  v.Init(<value>);
+  //
+  // NOTE: For ConvertableToTraceFormat values, see the note above and
+  // the one for TraceValue::Helper for CONVERTABLE_TYPE below.
+  template <typename T>
+  void Init(T&& value) {
+    using ValueType = typename InnerType<T>::type;
+    Helper<ValueType>::SetValue(this, std::forward<T>(value));
+  }
+
+  // Static method to create a new TraceValue instance from a given
+  // initialization value. Note that this deduces the TRACE_VALUE_TYPE_XXX
+  // type but doesn't return it, use ForType<T>::value for this.
+  //
+  // Usage example:
+  //     auto v = TraceValue::Make(100);
+  //     auto v2 = TraceValue::Make("Some text string");
+  //
+  // IMPORTANT: Experience shows that the compiler generates worse code when
+  // using this method rather than calling Init() directly on an existing
+  // TraceValue union :-(
+  //
+  template <typename T>
+  static TraceValue Make(T&& value) {
+    TraceValue ret;
+    ret.Init(std::forward<T>(value));
+    return ret;
+  }
+
+  // Output current value as a JSON string. |type| must be a valid
+  // TRACE_VALUE_TYPE_XXX value.
+  void AppendAsJSON(unsigned char type, std::string* out) const;
+
+ private:
+  // InnerType<T>::type removes reference, cv-qualifications and decays
+  // function and arrays into pointers. Only used internally.
+  template <typename T>
+  struct InnerType {
+    using type = typename std::remove_cv<typename std::remove_reference<
+        typename std::decay<T>::type>::type>::type;
+  };
+
+ public:
+  // TraceValue::Helper is used to provide information about initialization
+  // value types and an initialization function. It is a struct that should
+  // provide the following for supported initialization value types:
+  //
+  //    - kType: is a static TRACE_VALUE_TYPE_XXX constant.
+  //
+  //    - SetValue(TraceValue*, T): is a static inline method that sets
+  //        TraceValue value from a given T value. Second parameter type
+  //        can also be const T& or T&& to restrict uses.
+  //
+  // IMPORTANT: The type T must be InnerType<Q>, where Q is the real C++
+  // argument type. I.e. you should not have to deal with reference types
+  // in your specialization.
+  //
+  // Specializations are defined for integers, enums, floating point, pointers,
+  // constant C string literals and pointers, std::string, time values below.
+  //
+  // Specializations for custom types are possible provided that there exists
+  // a corresponding Helper specialization, for example:
+  //
+  //    template <>
+  //    struct base::trace_event::TraceValue::Helper<Foo> {
+  //      static constexpr unsigned char kTypes = TRACE_VALUE_TYPE_COPY_STRING;
+  //      static inline void SetValue(TraceValue* v, const Foo& value) {
+  //        v->as_string = value.c_str();
+  //      }
+  //    };
+  //
+  // Will allow code like:
+  //
+  //    Foo foo = ...;
+  //    auto v = TraceValue::Make(foo);
+  //
+  // Or even:
+  //    Foo foo = ...;
+  //    TraceArguments args("foo_arg1", foo);
+  //
+  template <typename T, class = void>
+  struct Helper {};
+
+  // TraceValue::TypeFor<T>::value returns the TRACE_VALUE_TYPE_XXX
+  // corresponding to initialization values of type T.
+  template <typename T>
+  struct TypeFor {
+    using ValueType = typename InnerType<T>::type;
+    static const unsigned char value = Helper<ValueType>::kType;
+  };
+
+  // TraceValue::TypeCheck<T>::value is only defined iff T can be used to
+  // initialize a TraceValue instance. This is useful to restrict template
+  // instantiation to only the appropriate type (see TraceArguments
+  // constructors below).
+  template <typename T,
+            class = decltype(TraceValue::Helper<
+                             typename TraceValue::InnerType<T>::type>::kType)>
+  struct TypeCheck {
+    static const bool value = true;
+  };
+};
+
+// TraceValue::Helper for integers and enums.
+template <typename T>
+struct TraceValue::Helper<
+    T,
+    typename std::enable_if<std::is_integral<T>::value ||
+                            std::is_enum<T>::value>::type> {
+  static constexpr unsigned char kType =
+      std::is_signed<T>::value ? TRACE_VALUE_TYPE_INT : TRACE_VALUE_TYPE_UINT;
+  static inline void SetValue(TraceValue* v, T value) {
+    v->as_uint = static_cast<unsigned long long>(value);
+  }
+};
+
+// TraceValue::Helper for floating-point types
+template <typename T>
+struct TraceValue::
+    Helper<T, typename std::enable_if<std::is_floating_point<T>::value>::type> {
+  static constexpr unsigned char kType = TRACE_VALUE_TYPE_DOUBLE;
+  static inline void SetValue(TraceValue* v, T value) { v->as_double = value; }
+};
+
+// TraceValue::Helper for bool.
+template <>
+struct TraceValue::Helper<bool> {
+  static constexpr unsigned char kType = TRACE_VALUE_TYPE_BOOL;
+  static inline void SetValue(TraceValue* v, bool value) { v->as_bool = value; }
+};
+
+//  TraceValue::Helper for generic pointer types.
+template <typename T>
+struct TraceValue::Helper<T*> {
+  static constexpr unsigned char kType = TRACE_VALUE_TYPE_POINTER;
+  static inline void SetValue(TraceValue* v,
+                              const typename std::decay<T>::type* value) {
+    v->as_pointer = value;
+  }
+};
+
+// TraceValue::Helper for raw persistent C strings.
+template <>
+struct TraceValue::Helper<const char*> {
+  static constexpr unsigned char kType = TRACE_VALUE_TYPE_STRING;
+  static inline void SetValue(TraceValue* v, const char* value) {
+    v->as_string = value;
+  }
+};
+
+// TraceValue::Helper for std::string values.
+template <>
+struct TraceValue::Helper<std::string> {
+  static constexpr unsigned char kType = TRACE_VALUE_TYPE_COPY_STRING;
+  static inline void SetValue(TraceValue* v, const std::string& value) {
+    v->as_string = value.c_str();
+  }
+};
+
+// Special case for scoped pointers to convertables to trace format.
+// |CONVERTABLE_TYPE| must be a type whose pointers can be converted to a
+// ConvertableToTraceFormat* pointer as well (e.g. a derived class).
+// IMPORTANT: This takes an std::unique_ptr<CONVERTABLE_TYPE> value, and takes
+// ownership of the pointed object!
+template <typename CONVERTABLE_TYPE>
+struct TraceValue::Helper<std::unique_ptr<CONVERTABLE_TYPE>,
+                          typename std::enable_if<std::is_convertible<
+                              CONVERTABLE_TYPE*,
+                              ConvertableToTraceFormat*>::value>::type> {
+  static constexpr unsigned char kType = TRACE_VALUE_TYPE_CONVERTABLE;
+  static inline void SetValue(TraceValue* v,
+                              std::unique_ptr<CONVERTABLE_TYPE> value) {
+    v->as_convertable = value.release();
+  }
+};
+
+// Specialization for time-based values like base::Time, which provide a
+// a ToInternalValue() method.
+template <typename T>
+struct TraceValue::Helper<
+    T,
+    typename std::enable_if<std::is_same<T, base::Time>::value ||
+                            std::is_same<T, base::TimeTicks>::value ||
+                            std::is_same<T, base::ThreadTicks>::value>::type> {
+  static constexpr unsigned char kType = TRACE_VALUE_TYPE_INT;
+  static inline void SetValue(TraceValue* v, const T& value) {
+    v->as_int = value.ToInternalValue();
+  }
+};
+
+// Simple container for const char* that should be copied instead of retained.
+// The goal is to indicate that the C string is copyable, unlike the default
+// Init(const char*) implementation. Usage is:
+//
+//    const char* str = ...;
+//    v.Init(TraceStringWithCopy(str));
+//
+// Which will mark the string as TRACE_VALUE_TYPE_COPY_STRING, instead of
+// TRACE_VALUE_TYPE_STRING.
+//
+class TraceStringWithCopy {
+ public:
+  explicit TraceStringWithCopy(const char* str) : str_(str) {}
+  const char* str() const { return str_; }
+
+ private:
+  const char* str_;
+};
+
+template <>
+struct TraceValue::Helper<TraceStringWithCopy> {
+  static constexpr unsigned char kType = TRACE_VALUE_TYPE_COPY_STRING;
+  static inline void SetValue(TraceValue* v, const TraceStringWithCopy& value) {
+    v->as_string = value.str();
+  }
+};
+
+class TraceArguments;
+
+// A small class used to store a copy of all strings from a given
+// TraceArguments instance (see below). When empty, this should only
+// take the size of a pointer. Otherwise, this will point to a heap
+// allocated block containing a size_t value followed by all characters
+// in the storage area. For most cases, this is more efficient
+// than using a std::unique_ptr<std::string> or an std::vector<char>.
+class BASE_EXPORT StringStorage {
+ public:
+  constexpr StringStorage() = default;
+
+  explicit StringStorage(size_t alloc_size) { Reset(alloc_size); }
+
+  ~StringStorage() {
+    if (data_)
+      ::free(data_);
+  }
+
+  StringStorage(StringStorage&& other) : data_(other.data_) {
+    other.data_ = nullptr;
+  }
+
+  StringStorage& operator=(StringStorage&& other) {
+    if (this != &other) {
+      if (data_)
+        ::free(data_);
+      data_ = other.data_;
+      other.data_ = nullptr;
+    }
+    return *this;
+  }
+
+  // Reset storage area to new allocation size. Existing content might not
+  // be preserved. If |alloc_size| is 0, this will free the storage area
+  // as well.
+  void Reset(size_t alloc_size = 0);
+
+  // Accessors.
+  constexpr size_t size() const { return data_ ? data_->size : 0u; }
+  constexpr const char* data() const { return data_ ? data_->chars : nullptr; }
+  constexpr char* data() { return data_ ? data_->chars : nullptr; }
+
+  constexpr const char* begin() const { return data(); }
+  constexpr const char* end() const { return data() + size(); }
+  inline char* begin() { return data(); }
+  inline char* end() { return data() + size(); }
+
+  // True iff storage is empty.
+  constexpr bool empty() const { return size() == 0; }
+
+  // Returns true if |ptr| is inside the storage area, false otherwise.
+  // Used during unit-testing.
+  constexpr bool Contains(const void* ptr) const {
+    const char* char_ptr = static_cast<const char*>(ptr);
+    return (char_ptr >= begin() && char_ptr < end());
+  }
+
+  // Returns true if all string pointers in |args| are contained in this
+  // storage area.
+  bool Contains(const TraceArguments& args) const;
+
+  // Return an estimate of the memory overhead of this instance. This doesn't
+  // count the size of |data_| itself.
+  constexpr size_t EstimateTraceMemoryOverhead() const {
+    return data_ ? 0 : sizeof(size_t) + data_->size;
+  }
+
+ private:
+  // Heap allocated data block (variable size), made of:
+  //
+  //   - size: a size_t field, giving the size of the following |chars| array.
+  //   - chars: an array of |size| characters, holding all zero-terminated
+  //     strings referenced from a TraceArguments instance.
+  struct Data {
+    size_t size = 0;
+    char chars[1];  // really |size| character items in storage.
+  };
+
+  // This is an owning pointer. Normally, using a std::unique_ptr<> would be
+  // enough, but the compiler will then complaing about inlined constructors
+  // and destructors being too complex (!), resulting in larger code for no
+  // good reason.
+  Data* data_ = nullptr;
+};
+
+// TraceArguments models an array of kMaxSize trace-related items,
+// each one of them having:
+//   - a name, which is a constant char array literal.
+//   - a type, as described by TRACE_VALUE_TYPE_XXX macros.
+//   - a value, stored in a TraceValue union.
+//
+// IMPORTANT: For TRACE_VALUE_TYPE_CONVERTABLE, the value holds an owning
+//            pointer to an AsConvertableToTraceFormat instance, which will
+//            be destroyed with the array (or moved out of it when passed
+//            to a TraceEvent instance).
+//
+// For TRACE_VALUE_TYPE_COPY_STRING, the value holds a const char* pointer
+// whose content will be copied when creating a TraceEvent instance.
+//
+// IMPORTANT: The constructor, destructor and SetArgument() methods are all
+// inlined intentionally, in order to let the compiler remove un-necessary
+// operations and reduce machine code.
+//
+class BASE_EXPORT TraceArguments {
+ public:
+  // Maximum number of arguments held by this structure.
+  static constexpr size_t kMaxSize = 2;
+
+  // Default constructor, no arguments.
+  TraceArguments() : size_(0) {}
+
+  // Constructor for a single argument.
+  template <typename T, class = decltype(TraceValue::TypeCheck<T>::value)>
+  TraceArguments(const char* arg1_name, T&& arg1_value) : size_(1) {
+    types_[0] = TraceValue::TypeFor<T>::value;
+    names_[0] = arg1_name;
+    values_[0].Init(std::forward<T>(arg1_value));
+  }
+
+  // Constructor for two arguments.
+  template <typename T1,
+            typename T2,
+            class = decltype(TraceValue::TypeCheck<T1>::value &&
+                             TraceValue::TypeCheck<T2>::value)>
+  TraceArguments(const char* arg1_name,
+                 T1&& arg1_value,
+                 const char* arg2_name,
+                 T2&& arg2_value)
+      : size_(2) {
+    types_[0] = TraceValue::TypeFor<T1>::value;
+    types_[1] = TraceValue::TypeFor<T2>::value;
+    names_[0] = arg1_name;
+    names_[1] = arg2_name;
+    values_[0].Init(std::forward<T1>(arg1_value));
+    values_[1].Init(std::forward<T2>(arg2_value));
+  }
+
+  // Constructor used to convert a legacy set of arguments when there
+  // are no convertable values at all.
+  TraceArguments(int num_args,
+                 const char* const* arg_names,
+                 const unsigned char* arg_types,
+                 const unsigned long long* arg_values);
+
+  // Constructor used to convert legacy set of arguments, where the
+  // convertable values are also provided by an array of CONVERTABLE_TYPE.
+  template <typename CONVERTABLE_TYPE>
+  TraceArguments(int num_args,
+                 const char* const* arg_names,
+                 const unsigned char* arg_types,
+                 const unsigned long long* arg_values,
+                 CONVERTABLE_TYPE* arg_convertables) {
+    static int max_args = static_cast<int>(kMaxSize);
+    if (num_args > max_args)
+      num_args = max_args;
+    size_ = static_cast<unsigned char>(num_args);
+    for (size_t n = 0; n < size_; ++n) {
+      types_[n] = arg_types[n];
+      names_[n] = arg_names[n];
+      if (arg_types[n] == TRACE_VALUE_TYPE_CONVERTABLE) {
+        values_[n].Init(
+            std::forward<CONVERTABLE_TYPE>(std::move(arg_convertables[n])));
+      } else {
+        values_[n].as_uint = arg_values[n];
+      }
+    }
+  }
+
+  // Destructor. NOTE: Intentionally inlined (see note above).
+  ~TraceArguments() {
+    for (size_t n = 0; n < size_; ++n) {
+      if (types_[n] == TRACE_VALUE_TYPE_CONVERTABLE)
+        delete values_[n].as_convertable;
+    }
+  }
+
+  // Disallow copy operations.
+  TraceArguments(const TraceArguments&) = delete;
+  TraceArguments& operator=(const TraceArguments&) = delete;
+
+  // Allow move operations.
+  TraceArguments(TraceArguments&& other) noexcept {
+    ::memcpy(this, &other, sizeof(*this));
+    // All owning pointers were copied to |this|. Setting |other.size_| will
+    // mask the pointer values still in |other|.
+    other.size_ = 0;
+  }
+
+  TraceArguments& operator=(TraceArguments&&) noexcept;
+
+  // Accessors
+  size_t size() const { return size_; }
+  const unsigned char* types() const { return types_; }
+  const char* const* names() const { return names_; }
+  const TraceValue* values() const { return values_; }
+
+  // Reset to empty arguments list.
+  void Reset();
+
+  // Use |storage| to copy all copyable strings.
+  // If |copy_all_strings| is false, then only the TRACE_VALUE_TYPE_COPY_STRING
+  // values will be copied into storage. If it is true, then argument names are
+  // also copied to storage, as well as the strings pointed to by
+  // |*extra_string1| and |*extra_string2|.
+  // NOTE: If there are no strings to copy, |*storage| is left untouched.
+  void CopyStringsTo(StringStorage* storage,
+                     bool copy_all_strings,
+                     const char** extra_string1,
+                     const char** extra_string2);
+
+  // Append debug string representation to |*out|.
+  void AppendDebugString(std::string* out);
+
+ private:
+  unsigned char size_;
+  unsigned char types_[kMaxSize];
+  const char* names_[kMaxSize];
+  TraceValue values_[kMaxSize];
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_TRACE_ARGUMENTS_H_
diff --git a/base/trace_event/trace_arguments_unittest.cc b/base/trace_event/trace_arguments_unittest.cc
new file mode 100644
index 0000000..f7be83e0f
--- /dev/null
+++ b/base/trace_event/trace_arguments_unittest.cc
@@ -0,0 +1,459 @@
+// 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 "base/trace_event/trace_arguments.h"
+
+#include <gtest/gtest.h>
+#include <string>
+
+namespace base {
+namespace trace_event {
+
+namespace {
+
+// Simple convertable that holds a string to append to the trace,
+// and can also write to a boolean flag on destruction.
+class MyConvertable : public ConvertableToTraceFormat {
+ public:
+  MyConvertable(const char* text, bool* destroy_flag = nullptr)
+      : text_(text), destroy_flag_(destroy_flag) {}
+  ~MyConvertable() override {
+    if (destroy_flag_)
+      *destroy_flag_ = true;
+  }
+  void AppendAsTraceFormat(std::string* out) const override { *out += text_; }
+  const char* text() const { return text_; }
+
+ private:
+  const char* text_;
+  bool* destroy_flag_;
+};
+
+}  // namespace
+
+TEST(TraceArguments, StringStorageDefaultConstruction) {
+  StringStorage storage;
+  EXPECT_TRUE(storage.empty());
+  EXPECT_FALSE(storage.data());
+  EXPECT_EQ(0U, storage.size());
+}
+
+TEST(TraceArguments, StringStorageConstructionWithSize) {
+  const size_t kSize = 128;
+  StringStorage storage(kSize);
+  EXPECT_FALSE(storage.empty());
+  EXPECT_TRUE(storage.data());
+  EXPECT_EQ(kSize, storage.size());
+  EXPECT_EQ(storage.data(), storage.begin());
+  EXPECT_EQ(storage.data() + kSize, storage.end());
+}
+
+TEST(TraceArguments, StringStorageReset) {
+  StringStorage storage(128);
+  EXPECT_FALSE(storage.empty());
+
+  storage.Reset();
+  EXPECT_TRUE(storage.empty());
+  EXPECT_FALSE(storage.data());
+  EXPECT_EQ(0u, storage.size());
+}
+
+TEST(TraceArguments, StringStorageResetWithSize) {
+  StringStorage storage;
+  EXPECT_TRUE(storage.empty());
+
+  const size_t kSize = 128;
+  storage.Reset(kSize);
+  EXPECT_FALSE(storage.empty());
+  EXPECT_TRUE(storage.data());
+  EXPECT_EQ(kSize, storage.size());
+  EXPECT_EQ(storage.data(), storage.begin());
+  EXPECT_EQ(storage.data() + kSize, storage.end());
+}
+
+static void CheckJSONFor(TraceValue v, char type, const char* expected) {
+  std::string out;
+  v.AppendAsJSON(type, &out);
+  EXPECT_STREQ(expected, out.c_str());
+}
+
+TEST(TraceArguments, TraceValueAppendAsJSON) {
+  TraceValue v;
+
+  v.Init(-1024);
+  CheckJSONFor(v, TRACE_VALUE_TYPE_INT, "-1024");
+  v.Init(1024ULL);
+  CheckJSONFor(v, TRACE_VALUE_TYPE_UINT, "1024");
+  v.Init(3.1415926535);
+  CheckJSONFor(v, TRACE_VALUE_TYPE_DOUBLE, "3.1415926535");
+  v.Init(true);
+  CheckJSONFor(v, TRACE_VALUE_TYPE_BOOL, "true");
+  v.Init(false);
+  CheckJSONFor(v, TRACE_VALUE_TYPE_BOOL, "false");
+  v.Init("Some \"nice\" String");
+  CheckJSONFor(v, TRACE_VALUE_TYPE_STRING, "\"Some \\\"nice\\\" String\"");
+  CheckJSONFor(v, TRACE_VALUE_TYPE_COPY_STRING, "\"Some \\\"nice\\\" String\"");
+}
+
+TEST(TraceArguments, DefaultConstruction) {
+  TraceArguments args;
+  EXPECT_EQ(0U, args.size());
+}
+
+TEST(TraceArguments, ConstructorSingleInteger) {
+  TraceArguments args("foo_int", int(10));
+  EXPECT_EQ(1U, args.size());
+  EXPECT_EQ(TRACE_VALUE_TYPE_INT, args.types()[0]);
+  EXPECT_STREQ("foo_int", args.names()[0]);
+  EXPECT_EQ(10, args.values()[0].as_int);
+}
+
+TEST(TraceArguments, ConstructorSingleFloat) {
+  TraceArguments args("foo_pi", float(3.1415));
+  double expected = float(3.1415);
+  EXPECT_EQ(1U, args.size());
+  EXPECT_EQ(TRACE_VALUE_TYPE_DOUBLE, args.types()[0]);
+  EXPECT_STREQ("foo_pi", args.names()[0]);
+  EXPECT_EQ(expected, args.values()[0].as_double);
+}
+
+TEST(TraceArguments, ConstructorSingleNoCopyString) {
+  const char kText[] = "Persistent string";
+  TraceArguments args("foo_cstring", kText);
+  EXPECT_EQ(1U, args.size());
+  EXPECT_EQ(TRACE_VALUE_TYPE_STRING, args.types()[0]);
+  EXPECT_STREQ("foo_cstring", args.names()[0]);
+  EXPECT_EQ(kText, args.values()[0].as_string);
+}
+
+TEST(TraceArguments, ConstructorSingleStdString) {
+  std::string text = "Non-persistent string";
+  TraceArguments args("foo_stdstring", text);
+  EXPECT_EQ(1U, args.size());
+  EXPECT_EQ(TRACE_VALUE_TYPE_COPY_STRING, args.types()[0]);
+  EXPECT_STREQ("foo_stdstring", args.names()[0]);
+  EXPECT_EQ(text.c_str(), args.values()[0].as_string);
+}
+
+TEST(TraceArguments, ConstructorSingleTraceStringWithCopy) {
+  const char kText[] = "Persistent string #2";
+  TraceArguments args("foo_tracestring", TraceStringWithCopy(kText));
+  EXPECT_EQ(1U, args.size());
+  EXPECT_EQ(TRACE_VALUE_TYPE_COPY_STRING, args.types()[0]);
+  EXPECT_STREQ("foo_tracestring", args.names()[0]);
+  EXPECT_EQ(kText, args.values()[0].as_string);
+}
+
+TEST(TraceArguments, ConstructorSinglePointer) {
+  bool destroy_flag = false;
+  {
+    // Simple class that can set a boolean flag on destruction.
+    class Foo {
+     public:
+      Foo(bool* destroy_flag) : destroy_flag_(destroy_flag) {}
+      ~Foo() {
+        if (destroy_flag_)
+          *destroy_flag_ = true;
+      }
+
+     private:
+      bool* destroy_flag_;
+    };
+    auto foo = std::make_unique<Foo>(&destroy_flag);
+    EXPECT_FALSE(destroy_flag);
+    // This test also verifies that the object is not destroyed by the
+    // TraceArguments destructor. This should only be possible for
+    // TRACE_VALUE_TYPE_CONVERTABLE instances.
+    {
+      TraceArguments args("foo_pointer", foo.get());
+      EXPECT_EQ(1U, args.size());
+      EXPECT_EQ(TRACE_VALUE_TYPE_POINTER, args.types()[0]);
+      EXPECT_STREQ("foo_pointer", args.names()[0]);
+      EXPECT_EQ(foo.get(), args.values()[0].as_pointer);
+      EXPECT_FALSE(destroy_flag);
+    }  // Calls TraceArguments destructor.
+    EXPECT_FALSE(destroy_flag);
+  }  // Calls Foo destructor.
+  EXPECT_TRUE(destroy_flag);
+}
+
+TEST(TraceArguments, ConstructorSingleConvertable) {
+  bool destroy_flag = false;
+  const char kText[] = "Text for MyConvertable instance";
+  MyConvertable* ptr = new MyConvertable(kText, &destroy_flag);
+
+  // This test also verifies that the MyConvertable instance is properly
+  // destroyed when the TraceArguments destructor is called.
+  EXPECT_FALSE(destroy_flag);
+  {
+    TraceArguments args("foo_convertable", std::unique_ptr<MyConvertable>(ptr));
+    EXPECT_EQ(1U, args.size());
+    EXPECT_EQ(TRACE_VALUE_TYPE_CONVERTABLE, args.types()[0]);
+    EXPECT_STREQ("foo_convertable", args.names()[0]);
+    EXPECT_EQ(ptr, args.values()[0].as_convertable);
+    EXPECT_FALSE(destroy_flag);
+  }  // Calls TraceArguments destructor.
+  EXPECT_TRUE(destroy_flag);
+}
+
+TEST(TraceArguments, ConstructorWithTwoArguments) {
+  const char kText1[] = "First argument";
+  const char kText2[] = "Second argument";
+  bool destroy_flag = false;
+
+  {
+    MyConvertable* ptr = new MyConvertable(kText2, &destroy_flag);
+    TraceArguments args1("foo_arg1_cstring", kText1, "foo_arg2_convertable",
+                         std::unique_ptr<MyConvertable>(ptr));
+    EXPECT_EQ(2U, args1.size());
+    EXPECT_STREQ("foo_arg1_cstring", args1.names()[0]);
+    EXPECT_STREQ("foo_arg2_convertable", args1.names()[1]);
+    EXPECT_EQ(TRACE_VALUE_TYPE_STRING, args1.types()[0]);
+    EXPECT_EQ(TRACE_VALUE_TYPE_CONVERTABLE, args1.types()[1]);
+    EXPECT_EQ(kText1, args1.values()[0].as_string);
+    EXPECT_EQ(ptr, args1.values()[1].as_convertable);
+    EXPECT_FALSE(destroy_flag);
+  }  // calls |args1| destructor. Should delete |ptr|.
+  EXPECT_TRUE(destroy_flag);
+}
+
+TEST(TraceArguments, ConstructorLegacyNoConvertables) {
+  const char* const kNames[3] = {"legacy_arg1", "legacy_arg2", "legacy_arg3"};
+  const unsigned char kTypes[3] = {
+      TRACE_VALUE_TYPE_INT, TRACE_VALUE_TYPE_STRING, TRACE_VALUE_TYPE_POINTER,
+  };
+  static const char kText[] = "Some text";
+  const unsigned long long kValues[3] = {
+      1000042ULL, reinterpret_cast<unsigned long long>(kText),
+      reinterpret_cast<unsigned long long>(kText + 2),
+  };
+  TraceArguments args(3, kNames, kTypes, kValues);
+  // Check that only the first kMaxSize arguments are taken!
+  EXPECT_EQ(2U, args.size());
+  EXPECT_STREQ(kNames[0], args.names()[0]);
+  EXPECT_STREQ(kNames[1], args.names()[1]);
+  EXPECT_EQ(TRACE_VALUE_TYPE_INT, args.types()[0]);
+  EXPECT_EQ(TRACE_VALUE_TYPE_STRING, args.types()[1]);
+  EXPECT_EQ(kValues[0], args.values()[0].as_uint);
+  EXPECT_EQ(kText, args.values()[1].as_string);
+};
+
+TEST(TraceArguments, ConstructorLegacyWithConvertables) {
+  const char* const kNames[3] = {"legacy_arg1", "legacy_arg2", "legacy_arg3"};
+  const unsigned char kTypes[3] = {
+      TRACE_VALUE_TYPE_CONVERTABLE, TRACE_VALUE_TYPE_CONVERTABLE,
+      TRACE_VALUE_TYPE_CONVERTABLE,
+  };
+  std::unique_ptr<MyConvertable> convertables[3] = {
+      std::make_unique<MyConvertable>("First one"),
+      std::make_unique<MyConvertable>("Second one"),
+      std::make_unique<MyConvertable>("Third one"),
+  };
+  TraceArguments args(3, kNames, kTypes, nullptr, convertables);
+  // Check that only the first kMaxSize arguments are taken!
+  EXPECT_EQ(2U, args.size());
+  EXPECT_STREQ(kNames[0], args.names()[0]);
+  EXPECT_STREQ(kNames[1], args.names()[1]);
+  EXPECT_EQ(TRACE_VALUE_TYPE_CONVERTABLE, args.types()[0]);
+  EXPECT_EQ(TRACE_VALUE_TYPE_CONVERTABLE, args.types()[1]);
+  // Check that only the first two items were moved to |args|.
+  EXPECT_FALSE(convertables[0].get());
+  EXPECT_FALSE(convertables[1].get());
+  EXPECT_TRUE(convertables[2].get());
+}
+
+TEST(TraceArguments, MoveConstruction) {
+  const char kText1[] = "First argument";
+  const char kText2[] = "Second argument";
+  bool destroy_flag = false;
+
+  {
+    MyConvertable* ptr = new MyConvertable(kText2, &destroy_flag);
+    TraceArguments args1("foo_arg1_cstring", kText1, "foo_arg2_convertable",
+                         std::unique_ptr<MyConvertable>(ptr));
+    EXPECT_EQ(2U, args1.size());
+    EXPECT_STREQ("foo_arg1_cstring", args1.names()[0]);
+    EXPECT_STREQ("foo_arg2_convertable", args1.names()[1]);
+    EXPECT_EQ(TRACE_VALUE_TYPE_STRING, args1.types()[0]);
+    EXPECT_EQ(TRACE_VALUE_TYPE_CONVERTABLE, args1.types()[1]);
+    EXPECT_EQ(kText1, args1.values()[0].as_string);
+    EXPECT_EQ(ptr, args1.values()[1].as_convertable);
+
+    {
+      TraceArguments args2(std::move(args1));
+      EXPECT_FALSE(destroy_flag);
+
+      // |args1| is now empty.
+      EXPECT_EQ(0U, args1.size());
+
+      // Check that everything was transferred to |args2|.
+      EXPECT_EQ(2U, args2.size());
+      EXPECT_STREQ("foo_arg1_cstring", args2.names()[0]);
+      EXPECT_STREQ("foo_arg2_convertable", args2.names()[1]);
+      EXPECT_EQ(TRACE_VALUE_TYPE_STRING, args2.types()[0]);
+      EXPECT_EQ(TRACE_VALUE_TYPE_CONVERTABLE, args2.types()[1]);
+      EXPECT_EQ(kText1, args2.values()[0].as_string);
+      EXPECT_EQ(ptr, args2.values()[1].as_convertable);
+    }  // Calls |args2| destructor. Should delete |ptr|.
+    EXPECT_TRUE(destroy_flag);
+    destroy_flag = false;
+  }  // Calls |args1| destructor. Should not delete |ptr|.
+  EXPECT_FALSE(destroy_flag);
+}
+
+TEST(TraceArguments, MoveAssignment) {
+  const char kText1[] = "First argument";
+  const char kText2[] = "Second argument";
+  bool destroy_flag = false;
+
+  {
+    MyConvertable* ptr = new MyConvertable(kText2, &destroy_flag);
+    TraceArguments args1("foo_arg1_cstring", kText1, "foo_arg2_convertable",
+                         std::unique_ptr<MyConvertable>(ptr));
+    EXPECT_EQ(2U, args1.size());
+    EXPECT_STREQ("foo_arg1_cstring", args1.names()[0]);
+    EXPECT_STREQ("foo_arg2_convertable", args1.names()[1]);
+    EXPECT_EQ(TRACE_VALUE_TYPE_STRING, args1.types()[0]);
+    EXPECT_EQ(TRACE_VALUE_TYPE_CONVERTABLE, args1.types()[1]);
+    EXPECT_EQ(kText1, args1.values()[0].as_string);
+    EXPECT_EQ(ptr, args1.values()[1].as_convertable);
+
+    {
+      TraceArguments args2;
+
+      args2 = std::move(args1);
+      EXPECT_FALSE(destroy_flag);
+
+      // |args1| is now empty.
+      EXPECT_EQ(0U, args1.size());
+
+      // Check that everything was transferred to |args2|.
+      EXPECT_EQ(2U, args2.size());
+      EXPECT_STREQ("foo_arg1_cstring", args2.names()[0]);
+      EXPECT_STREQ("foo_arg2_convertable", args2.names()[1]);
+      EXPECT_EQ(TRACE_VALUE_TYPE_STRING, args2.types()[0]);
+      EXPECT_EQ(TRACE_VALUE_TYPE_CONVERTABLE, args2.types()[1]);
+      EXPECT_EQ(kText1, args2.values()[0].as_string);
+      EXPECT_EQ(ptr, args2.values()[1].as_convertable);
+    }  // Calls |args2| destructor. Should delete |ptr|.
+    EXPECT_TRUE(destroy_flag);
+    destroy_flag = false;
+  }  // Calls |args1| destructor. Should not delete |ptr|.
+  EXPECT_FALSE(destroy_flag);
+}
+
+TEST(TraceArguments, Reset) {
+  bool destroy_flag = false;
+  {
+    TraceArguments args(
+        "foo_arg1", "Hello", "foo_arg2",
+        std::make_unique<MyConvertable>("World", &destroy_flag));
+
+    EXPECT_EQ(2U, args.size());
+    EXPECT_FALSE(destroy_flag);
+    args.Reset();
+    EXPECT_EQ(0U, args.size());
+    EXPECT_TRUE(destroy_flag);
+    destroy_flag = false;
+  }  // Calls |args| destructor. Should not delete twice.
+  EXPECT_FALSE(destroy_flag);
+}
+
+TEST(TraceArguments, CopyStringsTo_NoStrings) {
+  StringStorage storage;
+
+  TraceArguments args("arg1", 10, "arg2", 42);
+  args.CopyStringsTo(&storage, false, nullptr, nullptr);
+  EXPECT_TRUE(storage.empty());
+  EXPECT_EQ(0U, storage.size());
+}
+
+TEST(TraceArguments, CopyStringsTo_OnlyArgs) {
+  StringStorage storage;
+
+  TraceArguments args("arg1", TraceStringWithCopy("Hello"), "arg2",
+                      TraceStringWithCopy("World"));
+
+  const char kExtra1[] = "extra1";
+  const char kExtra2[] = "extra2";
+  const char* extra1 = kExtra1;
+  const char* extra2 = kExtra2;
+
+  // Types should be copyable strings.
+  EXPECT_EQ(TRACE_VALUE_TYPE_COPY_STRING, args.types()[0]);
+  EXPECT_EQ(TRACE_VALUE_TYPE_COPY_STRING, args.types()[1]);
+
+  args.CopyStringsTo(&storage, false, &extra1, &extra2);
+
+  // Storage should be allocated.
+  EXPECT_TRUE(storage.data());
+  EXPECT_NE(0U, storage.size());
+
+  // Types should not be changed.
+  EXPECT_EQ(TRACE_VALUE_TYPE_COPY_STRING, args.types()[0]);
+  EXPECT_EQ(TRACE_VALUE_TYPE_COPY_STRING, args.types()[1]);
+
+  // names should not be copied.
+  EXPECT_FALSE(storage.Contains(args.names()[0]));
+  EXPECT_FALSE(storage.Contains(args.names()[1]));
+  EXPECT_STREQ("arg1", args.names()[0]);
+  EXPECT_STREQ("arg2", args.names()[1]);
+
+  // strings should be copied.
+  EXPECT_TRUE(storage.Contains(args.values()[0].as_string));
+  EXPECT_TRUE(storage.Contains(args.values()[1].as_string));
+  EXPECT_STREQ("Hello", args.values()[0].as_string);
+  EXPECT_STREQ("World", args.values()[1].as_string);
+
+  // |extra1| and |extra2| should not be copied.
+  EXPECT_EQ(kExtra1, extra1);
+  EXPECT_EQ(kExtra2, extra2);
+}
+
+TEST(TraceArguments, CopyStringsTo_Everything) {
+  StringStorage storage;
+
+  TraceArguments args("arg1", "Hello", "arg2", "World");
+  const char kExtra1[] = "extra1";
+  const char kExtra2[] = "extra2";
+  const char* extra1 = kExtra1;
+  const char* extra2 = kExtra2;
+
+  // Types should be normal strings.
+  EXPECT_EQ(TRACE_VALUE_TYPE_STRING, args.types()[0]);
+  EXPECT_EQ(TRACE_VALUE_TYPE_STRING, args.types()[1]);
+
+  args.CopyStringsTo(&storage, true, &extra1, &extra2);
+
+  // Storage should be allocated.
+  EXPECT_TRUE(storage.data());
+  EXPECT_NE(0U, storage.size());
+
+  // Types should be changed to copyable strings.
+  EXPECT_EQ(TRACE_VALUE_TYPE_COPY_STRING, args.types()[0]);
+  EXPECT_EQ(TRACE_VALUE_TYPE_COPY_STRING, args.types()[1]);
+
+  // names should be copied.
+  EXPECT_TRUE(storage.Contains(args.names()[0]));
+  EXPECT_TRUE(storage.Contains(args.names()[1]));
+  EXPECT_STREQ("arg1", args.names()[0]);
+  EXPECT_STREQ("arg2", args.names()[1]);
+
+  // strings should be copied.
+  EXPECT_TRUE(storage.Contains(args.values()[0].as_string));
+  EXPECT_TRUE(storage.Contains(args.values()[1].as_string));
+  EXPECT_STREQ("Hello", args.values()[0].as_string);
+  EXPECT_STREQ("World", args.values()[1].as_string);
+
+  // |extra1| and |extra2| should be copied.
+  EXPECT_NE(kExtra1, extra1);
+  EXPECT_NE(kExtra2, extra2);
+  EXPECT_TRUE(storage.Contains(extra1));
+  EXPECT_TRUE(storage.Contains(extra2));
+  EXPECT_STREQ(kExtra1, extra1);
+  EXPECT_STREQ(kExtra2, extra2);
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/trace_event.h b/base/trace_event/trace_event.h
index 271022e..b6b71d7 100644
--- a/base/trace_event/trace_event.h
+++ b/base/trace_event/trace_event.h
@@ -21,6 +21,7 @@
 #include "base/time/time_override.h"
 #include "base/trace_event/common/trace_event_common.h"
 #include "base/trace_event/heap_profiler.h"
+#include "base/trace_event/trace_arguments.h"
 #include "base/trace_event/trace_category.h"
 #include "base/trace_event/trace_event_system_stats_monitor.h"
 #include "base/trace_event/trace_log.h"
@@ -28,8 +29,7 @@
 
 // By default, const char* argument values are assumed to have long-lived scope
 // and will not be copied. Use this macro to force a const char* to be copied.
-#define TRACE_STR_COPY(str) \
-    trace_event_internal::TraceStringWithCopy(str)
+#define TRACE_STR_COPY(str) ::base::trace_event::TraceStringWithCopy(str)
 
 // DEPRECATED: do not use: Consider using TRACE_ID_{GLOBAL, LOCAL} macros,
 // instead. By default, uint64_t ID argument values are not mangled with the
@@ -642,115 +642,13 @@
   unsigned int id_flags_ = TRACE_EVENT_FLAG_HAS_ID;
 };
 
-// Simple union to store various types as unsigned long long.
-union TraceValueUnion {
-  bool as_bool;
-  unsigned long long as_uint;
-  long long as_int;
-  double as_double;
-  const void* as_pointer;
-  const char* as_string;
-};
-
-// Simple container for const char* that should be copied instead of retained.
-class TraceStringWithCopy {
- public:
-  explicit TraceStringWithCopy(const char* str) : str_(str) {}
-  const char* str() const { return str_; }
- private:
-  const char* str_;
-};
-
-// Define SetTraceValue for each allowed type. It stores the type and
-// value in the return arguments. This allows this API to avoid declaring any
-// structures so that it is portable to third_party libraries.
-#define INTERNAL_DECLARE_SET_TRACE_VALUE(actual_type, \
-                                         arg_expression, \
-                                         union_member, \
-                                         value_type_id) \
-    static inline void SetTraceValue( \
-        actual_type arg, \
-        unsigned char* type, \
-        unsigned long long* value) { \
-      TraceValueUnion type_value; \
-      type_value.union_member = arg_expression; \
-      *type = value_type_id; \
-      *value = type_value.as_uint; \
-    }
-// Simpler form for int types that can be safely casted.
-#define INTERNAL_DECLARE_SET_TRACE_VALUE_INT(actual_type, \
-                                             value_type_id) \
-    static inline void SetTraceValue( \
-        actual_type arg, \
-        unsigned char* type, \
-        unsigned long long* value) { \
-      *type = value_type_id; \
-      *value = static_cast<unsigned long long>(arg); \
-    }
-
-INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned long long, TRACE_VALUE_TYPE_UINT)
-INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned long, TRACE_VALUE_TYPE_UINT)
-INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned int, TRACE_VALUE_TYPE_UINT)
-INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned short, TRACE_VALUE_TYPE_UINT)
-INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned char, TRACE_VALUE_TYPE_UINT)
-INTERNAL_DECLARE_SET_TRACE_VALUE_INT(long long, TRACE_VALUE_TYPE_INT)
-INTERNAL_DECLARE_SET_TRACE_VALUE_INT(long, TRACE_VALUE_TYPE_INT)
-INTERNAL_DECLARE_SET_TRACE_VALUE_INT(int, TRACE_VALUE_TYPE_INT)
-INTERNAL_DECLARE_SET_TRACE_VALUE_INT(short, TRACE_VALUE_TYPE_INT)
-INTERNAL_DECLARE_SET_TRACE_VALUE_INT(signed char, TRACE_VALUE_TYPE_INT)
-INTERNAL_DECLARE_SET_TRACE_VALUE(bool, arg, as_bool, TRACE_VALUE_TYPE_BOOL)
-INTERNAL_DECLARE_SET_TRACE_VALUE(double, arg, as_double,
-                                 TRACE_VALUE_TYPE_DOUBLE)
-INTERNAL_DECLARE_SET_TRACE_VALUE(const void*, arg, as_pointer,
-                                 TRACE_VALUE_TYPE_POINTER)
-INTERNAL_DECLARE_SET_TRACE_VALUE(const char*, arg, as_string,
-                                 TRACE_VALUE_TYPE_STRING)
-INTERNAL_DECLARE_SET_TRACE_VALUE(const TraceStringWithCopy&, arg.str(),
-                                 as_string, TRACE_VALUE_TYPE_COPY_STRING)
-
-#undef INTERNAL_DECLARE_SET_TRACE_VALUE
-#undef INTERNAL_DECLARE_SET_TRACE_VALUE_INT
-
-// std::string version of SetTraceValue so that trace arguments can be strings.
-static inline void SetTraceValue(const std::string& arg,
-                                 unsigned char* type,
-                                 unsigned long long* value) {
-  TraceValueUnion type_value;
-  type_value.as_string = arg.c_str();
-  *type = TRACE_VALUE_TYPE_COPY_STRING;
-  *value = type_value.as_uint;
-}
-
-// base::Time, base::TimeTicks, etc. versions of SetTraceValue to make it easier
-// to trace these types.
-static inline void SetTraceValue(const base::Time arg,
-                                 unsigned char* type,
-                                 unsigned long long* value) {
-  *type = TRACE_VALUE_TYPE_INT;
-  *value = arg.ToInternalValue();
-}
-
-static inline void SetTraceValue(const base::TimeTicks arg,
-                                 unsigned char* type,
-                                 unsigned long long* value) {
-  *type = TRACE_VALUE_TYPE_INT;
-  *value = arg.ToInternalValue();
-}
-
-static inline void SetTraceValue(const base::ThreadTicks arg,
-                                 unsigned char* type,
-                                 unsigned long long* value) {
-  *type = TRACE_VALUE_TYPE_INT;
-  *value = arg.ToInternalValue();
-}
-
 // These AddTraceEvent and AddTraceEventWithThreadIdAndTimestamp template
 // functions are defined here instead of in the macro, because the arg_values
 // could be temporary objects, such as std::string. In order to store
 // pointers to the internal c_str and pass through to the tracing API,
 // the arg_values must live throughout these procedures.
 
-template <class ARG1_CONVERTABLE_TYPE>
+template <class ARG1_TYPE>
 static inline base::trace_event::TraceEventHandle
 AddTraceEventWithThreadIdAndTimestamp(
     char phase,
@@ -763,18 +661,15 @@
     unsigned int flags,
     unsigned long long bind_id,
     const char* arg1_name,
-    std::unique_ptr<ARG1_CONVERTABLE_TYPE> arg1_val) {
-  const int num_args = 1;
-  unsigned char arg_types[1] = { TRACE_VALUE_TYPE_CONVERTABLE };
-  std::unique_ptr<base::trace_event::ConvertableToTraceFormat>
-      convertable_values[1] = {std::move(arg1_val)};
+    ARG1_TYPE&& arg1_val) {
+  base::trace_event::TraceArguments args(arg1_name,
+                                         std::forward<ARG1_TYPE>(arg1_val));
   return TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(
       phase, category_group_enabled, name, scope, id, bind_id, thread_id,
-      timestamp, num_args, &arg1_name, arg_types, NULL, convertable_values,
-      flags);
+      timestamp, &args, flags);
 }
 
-template <class ARG1_TYPE, class ARG2_CONVERTABLE_TYPE>
+template <class ARG1_TYPE, class ARG2_TYPE>
 static inline base::trace_event::TraceEventHandle
 AddTraceEventWithThreadIdAndTimestamp(
     char phase,
@@ -787,82 +682,15 @@
     unsigned int flags,
     unsigned long long bind_id,
     const char* arg1_name,
-    const ARG1_TYPE& arg1_val,
+    ARG1_TYPE&& arg1_val,
     const char* arg2_name,
-    std::unique_ptr<ARG2_CONVERTABLE_TYPE> arg2_val) {
-  const int num_args = 2;
-  const char* arg_names[2] = { arg1_name, arg2_name };
-
-  unsigned char arg_types[2];
-  unsigned long long arg_values[2];
-  SetTraceValue(arg1_val, &arg_types[0], &arg_values[0]);
-  arg_types[1] = TRACE_VALUE_TYPE_CONVERTABLE;
-  std::unique_ptr<base::trace_event::ConvertableToTraceFormat>
-      convertable_values[2] = {nullptr, std::move(arg2_val)};
+    ARG2_TYPE&& arg2_val) {
+  base::trace_event::TraceArguments args(
+      arg1_name, std::forward<ARG1_TYPE>(arg1_val), arg2_name,
+      std::forward<ARG2_TYPE>(arg2_val));
   return TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(
       phase, category_group_enabled, name, scope, id, bind_id, thread_id,
-      timestamp, num_args, arg_names, arg_types, arg_values, convertable_values,
-      flags);
-}
-
-template <class ARG1_CONVERTABLE_TYPE, class ARG2_TYPE>
-static inline base::trace_event::TraceEventHandle
-AddTraceEventWithThreadIdAndTimestamp(
-    char phase,
-    const unsigned char* category_group_enabled,
-    const char* name,
-    const char* scope,
-    unsigned long long id,
-    int thread_id,
-    const base::TimeTicks& timestamp,
-    unsigned int flags,
-    unsigned long long bind_id,
-    const char* arg1_name,
-    std::unique_ptr<ARG1_CONVERTABLE_TYPE> arg1_val,
-    const char* arg2_name,
-    const ARG2_TYPE& arg2_val) {
-  const int num_args = 2;
-  const char* arg_names[2] = { arg1_name, arg2_name };
-
-  unsigned char arg_types[2];
-  unsigned long long arg_values[2];
-  arg_types[0] = TRACE_VALUE_TYPE_CONVERTABLE;
-  arg_values[0] = 0;
-  SetTraceValue(arg2_val, &arg_types[1], &arg_values[1]);
-  std::unique_ptr<base::trace_event::ConvertableToTraceFormat>
-      convertable_values[2] = {std::move(arg1_val), nullptr};
-  return TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(
-      phase, category_group_enabled, name, scope, id, bind_id, thread_id,
-      timestamp, num_args, arg_names, arg_types, arg_values, convertable_values,
-      flags);
-}
-
-template <class ARG1_CONVERTABLE_TYPE, class ARG2_CONVERTABLE_TYPE>
-static inline base::trace_event::TraceEventHandle
-AddTraceEventWithThreadIdAndTimestamp(
-    char phase,
-    const unsigned char* category_group_enabled,
-    const char* name,
-    const char* scope,
-    unsigned long long id,
-    int thread_id,
-    const base::TimeTicks& timestamp,
-    unsigned int flags,
-    unsigned long long bind_id,
-    const char* arg1_name,
-    std::unique_ptr<ARG1_CONVERTABLE_TYPE> arg1_val,
-    const char* arg2_name,
-    std::unique_ptr<ARG2_CONVERTABLE_TYPE> arg2_val) {
-  const int num_args = 2;
-  const char* arg_names[2] = { arg1_name, arg2_name };
-  unsigned char arg_types[2] =
-      { TRACE_VALUE_TYPE_CONVERTABLE, TRACE_VALUE_TYPE_CONVERTABLE };
-  std::unique_ptr<base::trace_event::ConvertableToTraceFormat>
-      convertable_values[2] = {std::move(arg1_val), std::move(arg2_val)};
-  return TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(
-      phase, category_group_enabled, name, scope, id, bind_id, thread_id,
-      timestamp, num_args, arg_names, arg_types, NULL, convertable_values,
-      flags);
+      timestamp, &args, flags);
 }
 
 static inline base::trace_event::TraceEventHandle
@@ -878,7 +706,7 @@
     unsigned long long bind_id) {
   return TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(
       phase, category_group_enabled, name, scope, id, bind_id, thread_id,
-      timestamp, kZeroNumArgs, NULL, NULL, NULL, NULL, flags);
+      timestamp, nullptr, flags);
 }
 
 static inline base::trace_event::TraceEventHandle AddTraceEvent(
@@ -896,30 +724,7 @@
       bind_id);
 }
 
-template<class ARG1_TYPE>
-static inline base::trace_event::TraceEventHandle
-AddTraceEventWithThreadIdAndTimestamp(
-    char phase,
-    const unsigned char* category_group_enabled,
-    const char* name,
-    const char* scope,
-    unsigned long long id,
-    int thread_id,
-    const base::TimeTicks& timestamp,
-    unsigned int flags,
-    unsigned long long bind_id,
-    const char* arg1_name,
-    const ARG1_TYPE& arg1_val) {
-  const int num_args = 1;
-  unsigned char arg_types[1];
-  unsigned long long arg_values[1];
-  SetTraceValue(arg1_val, &arg_types[0], &arg_values[0]);
-  return TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(
-      phase, category_group_enabled, name, scope, id, bind_id, thread_id,
-      timestamp, num_args, &arg1_name, arg_types, arg_values, NULL, flags);
-}
-
-template<class ARG1_TYPE>
+template <class ARG1_TYPE>
 static inline base::trace_event::TraceEventHandle AddTraceEvent(
     char phase,
     const unsigned char* category_group_enabled,
@@ -929,15 +734,15 @@
     unsigned int flags,
     unsigned long long bind_id,
     const char* arg1_name,
-    const ARG1_TYPE& arg1_val) {
+    ARG1_TYPE&& arg1_val) {
   int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
   base::TimeTicks now = TRACE_TIME_TICKS_NOW();
   return AddTraceEventWithThreadIdAndTimestamp(
       phase, category_group_enabled, name, scope, id, thread_id, now, flags,
-      bind_id, arg1_name, arg1_val);
+      bind_id, arg1_name, std::forward<ARG1_TYPE>(arg1_val));
 }
 
-template <class ARG1_CONVERTABLE_TYPE>
+template <class ARG1_TYPE, class ARG2_TYPE>
 static inline base::trace_event::TraceEventHandle AddTraceEvent(
     char phase,
     const unsigned char* category_group_enabled,
@@ -947,153 +752,26 @@
     unsigned int flags,
     unsigned long long bind_id,
     const char* arg1_name,
-    std::unique_ptr<ARG1_CONVERTABLE_TYPE> arg1_val) {
-  int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
-  base::TimeTicks now = TRACE_TIME_TICKS_NOW();
-  return AddTraceEventWithThreadIdAndTimestamp(
-      phase, category_group_enabled, name, scope, id, thread_id, now, flags,
-      bind_id, arg1_name, std::move(arg1_val));
-}
-
-template<class ARG1_TYPE, class ARG2_TYPE>
-static inline base::trace_event::TraceEventHandle
-AddTraceEventWithThreadIdAndTimestamp(
-    char phase,
-    const unsigned char* category_group_enabled,
-    const char* name,
-    const char* scope,
-    unsigned long long id,
-    int thread_id,
-    const base::TimeTicks& timestamp,
-    unsigned int flags,
-    unsigned long long bind_id,
-    const char* arg1_name,
-    const ARG1_TYPE& arg1_val,
+    ARG1_TYPE&& arg1_val,
     const char* arg2_name,
-    const ARG2_TYPE& arg2_val) {
-  const int num_args = 2;
-  const char* arg_names[2] = { arg1_name, arg2_name };
-  unsigned char arg_types[2];
-  unsigned long long arg_values[2];
-  SetTraceValue(arg1_val, &arg_types[0], &arg_values[0]);
-  SetTraceValue(arg2_val, &arg_types[1], &arg_values[1]);
-  return TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(
-      phase, category_group_enabled, name, scope, id, bind_id, thread_id,
-      timestamp, num_args, arg_names, arg_types, arg_values, NULL, flags);
-}
-
-template <class ARG1_CONVERTABLE_TYPE, class ARG2_TYPE>
-static inline base::trace_event::TraceEventHandle AddTraceEvent(
-    char phase,
-    const unsigned char* category_group_enabled,
-    const char* name,
-    const char* scope,
-    unsigned long long id,
-    unsigned int flags,
-    unsigned long long bind_id,
-    const char* arg1_name,
-    std::unique_ptr<ARG1_CONVERTABLE_TYPE> arg1_val,
-    const char* arg2_name,
-    const ARG2_TYPE& arg2_val) {
+    ARG2_TYPE&& arg2_val) {
   int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
   base::TimeTicks now = TRACE_TIME_TICKS_NOW();
   return AddTraceEventWithThreadIdAndTimestamp(
       phase, category_group_enabled, name, scope, id, thread_id, now, flags,
-      bind_id, arg1_name, std::move(arg1_val), arg2_name, arg2_val);
-}
-
-template <class ARG1_TYPE, class ARG2_CONVERTABLE_TYPE>
-static inline base::trace_event::TraceEventHandle AddTraceEvent(
-    char phase,
-    const unsigned char* category_group_enabled,
-    const char* name,
-    const char* scope,
-    unsigned long long id,
-    unsigned int flags,
-    unsigned long long bind_id,
-    const char* arg1_name,
-    const ARG1_TYPE& arg1_val,
-    const char* arg2_name,
-    std::unique_ptr<ARG2_CONVERTABLE_TYPE> arg2_val) {
-  int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
-  base::TimeTicks now = TRACE_TIME_TICKS_NOW();
-  return AddTraceEventWithThreadIdAndTimestamp(
-      phase, category_group_enabled, name, scope, id, thread_id, now, flags,
-      bind_id, arg1_name, arg1_val, arg2_name, std::move(arg2_val));
-}
-
-template <class ARG1_CONVERTABLE_TYPE, class ARG2_CONVERTABLE_TYPE>
-static inline base::trace_event::TraceEventHandle AddTraceEvent(
-    char phase,
-    const unsigned char* category_group_enabled,
-    const char* name,
-    const char* scope,
-    unsigned long long id,
-    unsigned int flags,
-    unsigned long long bind_id,
-    const char* arg1_name,
-    std::unique_ptr<ARG1_CONVERTABLE_TYPE> arg1_val,
-    const char* arg2_name,
-    std::unique_ptr<ARG2_CONVERTABLE_TYPE> arg2_val) {
-  int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
-  base::TimeTicks now = TRACE_TIME_TICKS_NOW();
-  return AddTraceEventWithThreadIdAndTimestamp(
-      phase, category_group_enabled, name, scope, id, thread_id, now, flags,
-      bind_id, arg1_name, std::move(arg1_val), arg2_name, std::move(arg2_val));
-}
-
-template<class ARG1_TYPE, class ARG2_TYPE>
-static inline base::trace_event::TraceEventHandle AddTraceEvent(
-    char phase,
-    const unsigned char* category_group_enabled,
-    const char* name,
-    const char* scope,
-    unsigned long long id,
-    unsigned int flags,
-    unsigned long long bind_id,
-    const char* arg1_name,
-    const ARG1_TYPE& arg1_val,
-    const char* arg2_name,
-    const ARG2_TYPE& arg2_val) {
-  int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
-  base::TimeTicks now = TRACE_TIME_TICKS_NOW();
-  return AddTraceEventWithThreadIdAndTimestamp(
-      phase, category_group_enabled, name, scope, id, thread_id, now, flags,
-      bind_id, arg1_name, arg1_val, arg2_name, arg2_val);
-}
-
-template <class ARG1_CONVERTABLE_TYPE>
-static inline void AddMetadataEvent(
-    const unsigned char* category_group_enabled,
-    const char* event_name,
-    const char* arg_name,
-    std::unique_ptr<ARG1_CONVERTABLE_TYPE> arg_value) {
-  const char* arg_names[1] = {arg_name};
-  unsigned char arg_types[1] = {TRACE_VALUE_TYPE_CONVERTABLE};
-  std::unique_ptr<base::trace_event::ConvertableToTraceFormat>
-      convertable_values[1] = {std::move(arg_value)};
-  base::trace_event::TraceLog::GetInstance()->AddMetadataEvent(
-      category_group_enabled, event_name,
-      1,  // num_args
-      arg_names, arg_types,
-      nullptr,  // arg_values
-      convertable_values, TRACE_EVENT_FLAG_NONE);
+      bind_id, arg1_name, std::forward<ARG1_TYPE>(arg1_val), arg2_name,
+      std::forward<ARG2_TYPE>(arg2_val));
 }
 
 template <class ARG1_TYPE>
 static void AddMetadataEvent(const unsigned char* category_group_enabled,
                              const char* event_name,
                              const char* arg_name,
-                             const ARG1_TYPE& arg_val) {
-  const int num_args = 1;
-  const char* arg_names[1] = {arg_name};
-  unsigned char arg_types[1];
-  unsigned long long arg_values[1];
-  SetTraceValue(arg_val, &arg_types[0], &arg_values[0]);
-
+                             ARG1_TYPE&& arg_val) {
+  base::trace_event::TraceArguments args(arg_name,
+                                         std::forward<ARG1_TYPE>(arg_val));
   base::trace_event::TraceLog::GetInstance()->AddMetadataEvent(
-      category_group_enabled, event_name, num_args, arg_names, arg_types,
-      arg_values, nullptr, TRACE_EVENT_FLAG_NONE);
+      category_group_enabled, event_name, &args, TRACE_EVENT_FLAG_NONE);
 }
 
 // Used by TRACE_EVENTx macros. Do not use directly.
diff --git a/base/trace_event/trace_event_android.cc b/base/trace_event/trace_event_android.cc
index 30d9c74..a1e51e8 100644
--- a/base/trace_event/trace_event_android.cc
+++ b/base/trace_event/trace_event_android.cc
@@ -39,32 +39,25 @@
   }
 }
 
-void WriteEvent(
-    char phase,
-    const char* category_group,
-    const char* name,
-    unsigned long long id,
-    const char** arg_names,
-    const unsigned char* arg_types,
-    const TraceEvent::TraceValue* arg_values,
-    const std::unique_ptr<ConvertableToTraceFormat>* convertable_values,
-    unsigned int flags) {
+void WriteEvent(char phase,
+                const char* category_group,
+                const char* name,
+                unsigned long long id,
+                const TraceArguments& args,
+                unsigned int flags) {
   std::string out = StringPrintf("%c|%d|%s", phase, getpid(), name);
   if (flags & TRACE_EVENT_FLAG_HAS_ID)
     StringAppendF(&out, "-%" PRIx64, static_cast<uint64_t>(id));
   out += '|';
 
-  for (int i = 0; i < kTraceMaxNumArgs && arg_names[i];
-       ++i) {
+  const char* const* arg_names = args.names();
+  for (size_t i = 0; i < args.size() && arg_names[i]; ++i) {
     if (i)
       out += ';';
     out += arg_names[i];
     out += '=';
     std::string::size_type value_start = out.length();
-    if (arg_types[i] == TRACE_VALUE_TYPE_CONVERTABLE)
-      convertable_values[i]->AppendAsTraceFormat(&out);
-    else
-      TraceEvent::AppendValueAsJSON(arg_types[i], arg_values[i], &out);
+    args.values()[i].AppendAsJSON(args.types()[i], &out);
 
     // Remove the quotes which may confuse the atrace script.
     ReplaceSubstringsAfterOffset(&out, value_start, "\\\"", "'");
@@ -147,43 +140,35 @@
 
   switch (phase_) {
     case TRACE_EVENT_PHASE_BEGIN:
-      WriteEvent('B', category_group, name_, id_,
-                 arg_names_, arg_types_, arg_values_, convertable_values_,
-                 flags_);
+      WriteEvent('B', category_group, name_, id_, args_, flags_);
       break;
 
     case TRACE_EVENT_PHASE_COMPLETE:
-      WriteEvent(duration_.ToInternalValue() == -1 ? 'B' : 'E',
-                 category_group, name_, id_,
-                 arg_names_, arg_types_, arg_values_, convertable_values_,
-                 flags_);
+      WriteEvent(duration_.ToInternalValue() == -1 ? 'B' : 'E', category_group,
+                 name_, id_, args_, flags_);
       break;
 
     case TRACE_EVENT_PHASE_END:
       // Though a single 'E' is enough, here append pid, name and
       // category_group etc. So that unpaired events can be found easily.
-      WriteEvent('E', category_group, name_, id_,
-                 arg_names_, arg_types_, arg_values_, convertable_values_,
-                 flags_);
+      WriteEvent('E', category_group, name_, id_, args_, flags_);
       break;
 
     case TRACE_EVENT_PHASE_INSTANT:
       // Simulate an instance event with a pair of begin/end events.
-      WriteEvent('B', category_group, name_, id_,
-                 arg_names_, arg_types_, arg_values_, convertable_values_,
-                 flags_);
+      WriteEvent('B', category_group, name_, id_, args_, flags_);
       WriteToATrace(g_atrace_fd, "E", 1);
       break;
 
     case TRACE_EVENT_PHASE_COUNTER:
-      for (int i = 0; i < kTraceMaxNumArgs && arg_names_[i]; ++i) {
-        DCHECK(arg_types_[i] == TRACE_VALUE_TYPE_INT);
-        std::string out = base::StringPrintf(
-            "C|%d|%s-%s", getpid(), name_, arg_names_[i]);
+      for (size_t i = 0; i < arg_size() && arg_name(i); ++i) {
+        DCHECK(arg_type(i) == TRACE_VALUE_TYPE_INT);
+        std::string out =
+            base::StringPrintf("C|%d|%s-%s", getpid(), name_, arg_name(i));
         if (flags_ & TRACE_EVENT_FLAG_HAS_ID)
           StringAppendF(&out, "-%" PRIx64, static_cast<uint64_t>(id_));
-        StringAppendF(&out, "|%d|%s",
-                      static_cast<int>(arg_values_[i].as_int), category_group);
+        StringAppendF(&out, "|%d|%s", static_cast<int>(arg_value(i).as_int),
+                      category_group);
         WriteToATrace(g_atrace_fd, out.c_str(), out.size());
       }
       break;
diff --git a/base/trace_event/trace_event_argument.h b/base/trace_event/trace_event_argument.h
index 2d2eb54..7860abf 100644
--- a/base/trace_event/trace_event_argument.h
+++ b/base/trace_event/trace_event_argument.h
@@ -1,4 +1,4 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
diff --git a/base/trace_event/trace_event_etw_export_win.cc b/base/trace_event/trace_event_etw_export_win.cc
index e6d8107..65ce7d7e 100644
--- a/base/trace_event/trace_event_etw_export_win.cc
+++ b/base/trace_event/trace_event_etw_export_win.cc
@@ -172,16 +172,11 @@
 }
 
 // static
-void TraceEventETWExport::AddEvent(
-    char phase,
-    const unsigned char* category_group_enabled,
-    const char* name,
-    unsigned long long id,
-    int num_args,
-    const char* const* arg_names,
-    const unsigned char* arg_types,
-    const unsigned long long* arg_values,
-    const std::unique_ptr<ConvertableToTraceFormat>* convertable_values) {
+void TraceEventETWExport::AddEvent(char phase,
+                                   const unsigned char* category_group_enabled,
+                                   const char* name,
+                                   unsigned long long id,
+                                   const TraceArguments* args) {
   // We bail early in case exporting is disabled or no consumer is listening.
   auto* instance = GetInstance();
   if (!instance || !instance->etw_export_enabled_ || !EventEnabledChromeEvent())
@@ -259,26 +254,22 @@
   }
 
   std::string arg_values_string[3];
-  for (int i = 0; i < num_args; i++) {
-    if (arg_types[i] == TRACE_VALUE_TYPE_CONVERTABLE) {
+  size_t num_args = args ? args->size() : 0;
+  for (size_t i = 0; i < num_args; i++) {
+    if (args->types()[i] == TRACE_VALUE_TYPE_CONVERTABLE) {
       // Temporarily do nothing here. This function consumes 1/3 to 1/2 of
       // *total* process CPU time when ETW tracing, and many of the strings
       // created exceed WPA's 4094 byte limit and are shown as:
       // "Unable to parse data". See crbug.com/488257
-      // convertable_values[i]->AppendAsTraceFormat(arg_values_string + i);
     } else {
-      TraceEvent::TraceValue trace_event;
-      trace_event.as_uint = arg_values[i];
-      TraceEvent::AppendValueAsJSON(arg_types[i], trace_event,
-                                    arg_values_string + i);
+      args->values()[i].AppendAsJSON(args->types()[i], arg_values_string + i);
     }
   }
 
   EventWriteChromeEvent(
-      name, phase_string, num_args > 0 ? arg_names[0] : "",
-      arg_values_string[0].c_str(), num_args > 1 ? arg_names[1] : "",
-      arg_values_string[1].c_str(), num_args > 2 ? arg_names[2] : "",
-      arg_values_string[2].c_str());
+      name, phase_string, num_args > 0 ? args->names()[0] : "",
+      arg_values_string[0].c_str(), num_args > 1 ? args->names()[1] : "",
+      arg_values_string[1].c_str(), "", "");
 }
 
 // static
diff --git a/base/trace_event/trace_event_etw_export_win.h b/base/trace_event/trace_event_etw_export_win.h
index 8a85b221..edcaef9a 100644
--- a/base/trace_event/trace_event_etw_export_win.h
+++ b/base/trace_event/trace_event_etw_export_win.h
@@ -41,16 +41,11 @@
 
   // Exports an event to ETW. This is mainly used in
   // TraceLog::AddTraceEventWithThreadIdAndTimestamp to export internal events.
-  static void AddEvent(
-      char phase,
-      const unsigned char* category_group_enabled,
-      const char* name,
-      unsigned long long id,
-      int num_args,
-      const char* const* arg_names,
-      const unsigned char* arg_types,
-      const unsigned long long* arg_values,
-      const std::unique_ptr<ConvertableToTraceFormat>* convertable_values);
+  static void AddEvent(char phase,
+                       const unsigned char* category_group_enabled,
+                       const char* name,
+                       unsigned long long id,
+                       const TraceArguments* args);
 
   // Exports an ETW event that marks the end of a complete event.
   static void AddCompleteEndEvent(const char* name);
diff --git a/base/trace_event/trace_event_impl.cc b/base/trace_event/trace_event_impl.cc
index 3458115..cc423006 100644
--- a/base/trace_event/trace_event_impl.cc
+++ b/base/trace_event/trace_event_impl.cc
@@ -19,169 +19,61 @@
 #include "base/trace_event/trace_log.h"
 #include "base/trace_event/traced_value.h"
 
+#include <algorithm>
+
 namespace base {
 namespace trace_event {
 
-namespace {
-
-size_t GetAllocLength(const char* str) { return str ? strlen(str) + 1 : 0; }
-
-// Copies |*member| into |*buffer|, sets |*member| to point to this new
-// location, and then advances |*buffer| by the amount written.
-void CopyTraceEventParameter(char** buffer,
-                             const char** member,
-                             const char* end) {
-  if (*member) {
-    size_t written = strlcpy(*buffer, *member, end - *buffer) + 1;
-    DCHECK_LE(static_cast<int>(written), end - *buffer);
-    *member = *buffer;
-    *buffer += written;
-  }
-}
-
-}  // namespace
-
 TraceEvent::TraceEvent()
     : duration_(TimeDelta::FromInternalValue(-1)),
       scope_(trace_event_internal::kGlobalScope),
-      id_(0u),
+      id_(0),
       category_group_enabled_(nullptr),
       name_(nullptr),
-      thread_id_(0),
+      thread_id_(-1),
       flags_(0),
-      phase_(TRACE_EVENT_PHASE_BEGIN) {
-  for (int i = 0; i < kTraceMaxNumArgs; ++i)
-    arg_names_[i] = nullptr;
-  memset(arg_values_, 0, sizeof(arg_values_));
+      phase_(TRACE_EVENT_PHASE_BEGIN) {}
+
+TraceEvent::TraceEvent(int thread_id,
+                       TimeTicks timestamp,
+                       ThreadTicks thread_timestamp,
+                       char phase,
+                       const unsigned char* category_group_enabled,
+                       const char* name,
+                       const char* scope,
+                       unsigned long long id,
+                       unsigned long long bind_id,
+                       TraceArguments* args,
+                       unsigned int flags)
+    : timestamp_(timestamp),
+      thread_timestamp_(thread_timestamp),
+      duration_(TimeDelta::FromInternalValue(-1)),
+      thread_duration_(TimeDelta::FromInternalValue(-1)),
+      scope_(scope),
+      id_(id),
+      category_group_enabled_(category_group_enabled),
+      name_(name),
+      thread_id_(thread_id),
+      flags_(flags),
+      bind_id_(bind_id),
+      phase_(phase) {
+  if (args)
+    args_ = std::move(*args);
+  args_.CopyStringsTo(&parameter_copy_storage_,
+                      !!(flags_ & TRACE_EVENT_FLAG_COPY), &name_, &scope_);
 }
 
 TraceEvent::~TraceEvent() = default;
 
-void TraceEvent::MoveFrom(std::unique_ptr<TraceEvent> other) {
-  timestamp_ = other->timestamp_;
-  thread_timestamp_ = other->thread_timestamp_;
-  duration_ = other->duration_;
-  scope_ = other->scope_;
-  id_ = other->id_;
-  category_group_enabled_ = other->category_group_enabled_;
-  name_ = other->name_;
-  if (other->flags_ & TRACE_EVENT_FLAG_HAS_PROCESS_ID)
-    process_id_ = other->process_id_;
-  else
-    thread_id_ = other->thread_id_;
-  phase_ = other->phase_;
-  flags_ = other->flags_;
-  parameter_copy_storage_ = std::move(other->parameter_copy_storage_);
-
-  for (int i = 0; i < kTraceMaxNumArgs; ++i) {
-    arg_names_[i] = other->arg_names_[i];
-    arg_types_[i] = other->arg_types_[i];
-    arg_values_[i] = other->arg_values_[i];
-    convertable_values_[i] = std::move(other->convertable_values_[i]);
-  }
-}
-
-void TraceEvent::Initialize(
-    int thread_id,
-    TimeTicks timestamp,
-    ThreadTicks thread_timestamp,
-    char phase,
-    const unsigned char* category_group_enabled,
-    const char* name,
-    const char* scope,
-    unsigned long long id,
-    unsigned long long bind_id,
-    int num_args,
-    const char* const* arg_names,
-    const unsigned char* arg_types,
-    const unsigned long long* arg_values,
-    std::unique_ptr<ConvertableToTraceFormat>* convertable_values,
-    unsigned int flags) {
-  timestamp_ = timestamp;
-  thread_timestamp_ = thread_timestamp;
-  duration_ = TimeDelta::FromInternalValue(-1);
-  scope_ = scope;
-  id_ = id;
-  category_group_enabled_ = category_group_enabled;
-  name_ = name;
-  thread_id_ = thread_id;
-  phase_ = phase;
-  flags_ = flags;
-  bind_id_ = bind_id;
-
-  // Clamp num_args since it may have been set by a third_party library.
-  num_args = (num_args > kTraceMaxNumArgs) ? kTraceMaxNumArgs : num_args;
-  int i = 0;
-  for (; i < num_args; ++i) {
-    arg_names_[i] = arg_names[i];
-    arg_types_[i] = arg_types[i];
-
-    if (arg_types[i] == TRACE_VALUE_TYPE_CONVERTABLE) {
-      convertable_values_[i] = std::move(convertable_values[i]);
-    } else {
-      arg_values_[i].as_uint = arg_values[i];
-      convertable_values_[i].reset();
-    }
-  }
-  for (; i < kTraceMaxNumArgs; ++i) {
-    arg_names_[i] = nullptr;
-    arg_values_[i].as_uint = 0u;
-    convertable_values_[i].reset();
-    arg_types_[i] = TRACE_VALUE_TYPE_UINT;
-  }
-
-  bool copy = !!(flags & TRACE_EVENT_FLAG_COPY);
-  size_t alloc_size = 0;
-  if (copy) {
-    alloc_size += GetAllocLength(name) + GetAllocLength(scope);
-    for (i = 0; i < num_args; ++i) {
-      alloc_size += GetAllocLength(arg_names_[i]);
-      if (arg_types_[i] == TRACE_VALUE_TYPE_STRING)
-        arg_types_[i] = TRACE_VALUE_TYPE_COPY_STRING;
-    }
-  }
-
-  bool arg_is_copy[kTraceMaxNumArgs];
-  for (i = 0; i < num_args; ++i) {
-    // No copying of convertable types, we retain ownership.
-    if (arg_types_[i] == TRACE_VALUE_TYPE_CONVERTABLE)
-      continue;
-
-    // We only take a copy of arg_vals if they are of type COPY_STRING.
-    arg_is_copy[i] = (arg_types_[i] == TRACE_VALUE_TYPE_COPY_STRING);
-    if (arg_is_copy[i])
-      alloc_size += GetAllocLength(arg_values_[i].as_string);
-  }
-
-  if (alloc_size) {
-    parameter_copy_storage_.reset(new std::string);
-    parameter_copy_storage_->resize(alloc_size);
-    char* ptr = base::data(*parameter_copy_storage_);
-    const char* end = ptr + alloc_size;
-    if (copy) {
-      CopyTraceEventParameter(&ptr, &name_, end);
-      CopyTraceEventParameter(&ptr, &scope_, end);
-      for (i = 0; i < num_args; ++i) {
-        CopyTraceEventParameter(&ptr, &arg_names_[i], end);
-      }
-    }
-    for (i = 0; i < num_args; ++i) {
-      if (arg_types_[i] == TRACE_VALUE_TYPE_CONVERTABLE)
-        continue;
-      if (arg_is_copy[i])
-        CopyTraceEventParameter(&ptr, &arg_values_[i].as_string, end);
-    }
-    DCHECK_EQ(end, ptr) << "Overrun by " << ptr - end;
-  }
-}
+TraceEvent::TraceEvent(TraceEvent&& other) noexcept = default;
+TraceEvent& TraceEvent::operator=(TraceEvent&& other) noexcept = default;
 
 void TraceEvent::Reset() {
-  // Only reset fields that won't be initialized in Initialize(), or that may
+  // Only reset fields that won't be initialized in constructor, or that may
   // hold references to other objects.
   duration_ = TimeDelta::FromInternalValue(-1);
-  parameter_copy_storage_.reset();
-  for (int i = 0; i < kTraceMaxNumArgs; ++i)
-    convertable_values_[i].reset();
+  args_.Reset();
+  parameter_copy_storage_.Reset();
 }
 
 void TraceEvent::UpdateDuration(const TimeTicks& now,
@@ -197,80 +89,12 @@
 
 void TraceEvent::EstimateTraceMemoryOverhead(
     TraceEventMemoryOverhead* overhead) {
-  overhead->Add(TraceEventMemoryOverhead::kTraceEvent, sizeof(*this));
+  overhead->Add(TraceEventMemoryOverhead::kTraceEvent,
+                parameter_copy_storage_.EstimateTraceMemoryOverhead());
 
-  if (parameter_copy_storage_)
-    overhead->AddString(*parameter_copy_storage_);
-
-  for (size_t i = 0; i < kTraceMaxNumArgs; ++i) {
-    if (arg_types_[i] == TRACE_VALUE_TYPE_CONVERTABLE)
-      convertable_values_[i]->EstimateTraceMemoryOverhead(overhead);
-  }
-}
-
-// static
-void TraceEvent::AppendValueAsJSON(unsigned char type,
-                                   TraceEvent::TraceValue value,
-                                   std::string* out) {
-  switch (type) {
-    case TRACE_VALUE_TYPE_BOOL:
-      *out += value.as_bool ? "true" : "false";
-      break;
-    case TRACE_VALUE_TYPE_UINT:
-      StringAppendF(out, "%" PRIu64, static_cast<uint64_t>(value.as_uint));
-      break;
-    case TRACE_VALUE_TYPE_INT:
-      StringAppendF(out, "%" PRId64, static_cast<int64_t>(value.as_int));
-      break;
-    case TRACE_VALUE_TYPE_DOUBLE: {
-      // FIXME: base/json/json_writer.cc is using the same code,
-      //        should be made into a common method.
-      std::string real;
-      double val = value.as_double;
-      if (std::isfinite(val)) {
-        real = NumberToString(val);
-        // Ensure that the number has a .0 if there's no decimal or 'e'.  This
-        // makes sure that when we read the JSON back, it's interpreted as a
-        // real rather than an int.
-        if (real.find('.') == std::string::npos &&
-            real.find('e') == std::string::npos &&
-            real.find('E') == std::string::npos) {
-          real.append(".0");
-        }
-        // The JSON spec requires that non-integer values in the range (-1,1)
-        // have a zero before the decimal point - ".52" is not valid, "0.52" is.
-        if (real[0] == '.') {
-          real.insert(0, "0");
-        } else if (real.length() > 1 && real[0] == '-' && real[1] == '.') {
-          // "-.1" bad "-0.1" good
-          real.insert(1, "0");
-        }
-      } else if (std::isnan(val)){
-        // The JSON spec doesn't allow NaN and Infinity (since these are
-        // objects in EcmaScript).  Use strings instead.
-        real = "\"NaN\"";
-      } else if (val < 0) {
-        real = "\"-Infinity\"";
-      } else {
-        real = "\"Infinity\"";
-      }
-      StringAppendF(out, "%s", real.c_str());
-      break;
-    }
-    case TRACE_VALUE_TYPE_POINTER:
-      // JSON only supports double and int numbers.
-      // So as not to lose bits from a 64-bit pointer, output as a hex string.
-      StringAppendF(
-          out, "\"0x%" PRIx64 "\"",
-          static_cast<uint64_t>(reinterpret_cast<uintptr_t>(value.as_pointer)));
-      break;
-    case TRACE_VALUE_TYPE_STRING:
-    case TRACE_VALUE_TYPE_COPY_STRING:
-      EscapeJSONString(value.as_string ? value.as_string : "NULL", true, out);
-      break;
-    default:
-      NOTREACHED() << "Don't know how to print this value";
-      break;
+  for (size_t i = 0; i < arg_size(); ++i) {
+    if (arg_type(i) == TRACE_VALUE_TYPE_CONVERTABLE)
+      arg_value(i).as_convertable->EstimateTraceMemoryOverhead(overhead);
   }
 }
 
@@ -305,7 +129,7 @@
   // approach
   ArgumentNameFilterPredicate argument_name_filter_predicate;
   bool strip_args =
-      arg_names_[0] && !argument_filter_predicate.is_null() &&
+      arg_size() > 0 && arg_name(0) && !argument_filter_predicate.is_null() &&
       !argument_filter_predicate.Run(category_group_name, name_,
                                      &argument_name_filter_predicate);
 
@@ -314,19 +138,16 @@
   } else {
     *out += "{";
 
-    for (int i = 0; i < kTraceMaxNumArgs && arg_names_[i]; ++i) {
+    for (size_t i = 0; i < arg_size() && arg_name(i); ++i) {
       if (i > 0)
         *out += ",";
       *out += "\"";
-      *out += arg_names_[i];
+      *out += arg_name(i);
       *out += "\":";
 
       if (argument_name_filter_predicate.is_null() ||
-          argument_name_filter_predicate.Run(arg_names_[i])) {
-        if (arg_types_[i] == TRACE_VALUE_TYPE_CONVERTABLE)
-          convertable_values_[i]->AppendAsTraceFormat(out);
-        else
-          AppendValueAsJSON(arg_types_[i], arg_values_[i], out);
+          argument_name_filter_predicate.Run(arg_name(i))) {
+        arg_value(i).AppendAsJSON(arg_type(i), out);
       } else {
         *out += "\"__stripped__\"";
       }
@@ -427,19 +248,14 @@
   *out << name_ << "[";
   *out << TraceLog::GetCategoryGroupName(category_group_enabled_);
   *out << "]";
-  if (arg_names_[0]) {
+  if (arg_size() > 0 && arg_name(0)) {
     *out << ", {";
-    for (int i = 0; i < kTraceMaxNumArgs && arg_names_[i]; ++i) {
+    for (size_t i = 0; i < arg_size() && arg_name(i); ++i) {
       if (i > 0)
         *out << ", ";
-      *out << arg_names_[i] << ":";
+      *out << arg_name(i) << ":";
       std::string value_as_text;
-
-      if (arg_types_[i] == TRACE_VALUE_TYPE_CONVERTABLE)
-        convertable_values_[i]->AppendAsTraceFormat(&value_as_text);
-      else
-        AppendValueAsJSON(arg_types_[i], arg_values_[i], &value_as_text);
-
+      arg_value(i).AppendAsJSON(arg_type(i), &value_as_text);
       *out << value_as_text;
     }
     *out << "}";
diff --git a/base/trace_event/trace_event_impl.h b/base/trace_event/trace_event_impl.h
index 4b4b88f5..9c88afe 100644
--- a/base/trace_event/trace_event_impl.h
+++ b/base/trace_event/trace_event_impl.h
@@ -23,6 +23,8 @@
 #include "base/synchronization/condition_variable.h"
 #include "base/synchronization/lock.h"
 #include "base/threading/thread_local.h"
+#include "base/trace_event/common/trace_event_common.h"
+#include "base/trace_event/trace_arguments.h"
 #include "base/trace_event/trace_event_memory_overhead.h"
 #include "build/build_config.h"
 
@@ -36,33 +38,6 @@
                             ArgumentNameFilterPredicate*)>
     ArgumentFilterPredicate;
 
-// For any argument of type TRACE_VALUE_TYPE_CONVERTABLE the provided
-// class must implement this interface.
-class BASE_EXPORT ConvertableToTraceFormat {
- public:
-  ConvertableToTraceFormat() = default;
-  virtual ~ConvertableToTraceFormat() = default;
-
-  // Append the class info to the provided |out| string. The appended
-  // data must be a valid JSON object. Strings must be properly quoted, and
-  // escaped. There is no processing applied to the content after it is
-  // appended.
-  virtual void AppendAsTraceFormat(std::string* out) const = 0;
-
-  virtual void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead* overhead);
-
-  std::string ToString() const {
-    std::string result;
-    AppendAsTraceFormat(&result);
-    return result;
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(ConvertableToTraceFormat);
-};
-
-const int kTraceMaxNumArgs = 2;
-
 struct TraceEventHandle {
   uint32_t chunk_seq;
   // These numbers of bits must be kept consistent with
@@ -74,35 +49,27 @@
 
 class BASE_EXPORT TraceEvent {
  public:
-  union TraceValue {
-    bool as_bool;
-    unsigned long long as_uint;
-    long long as_int;
-    double as_double;
-    const void* as_pointer;
-    const char* as_string;
-  };
+  // TODO(898794): Remove once all users have been updated.
+  using TraceValue = base::trace_event::TraceValue;
 
   TraceEvent();
   ~TraceEvent();
 
-  void MoveFrom(std::unique_ptr<TraceEvent> other);
+  // Allow move operations.
+  TraceEvent(TraceEvent&&) noexcept;
+  TraceEvent& operator=(TraceEvent&&) noexcept;
 
-  void Initialize(int thread_id,
-                  TimeTicks timestamp,
-                  ThreadTicks thread_timestamp,
-                  char phase,
-                  const unsigned char* category_group_enabled,
-                  const char* name,
-                  const char* scope,
-                  unsigned long long id,
-                  unsigned long long bind_id,
-                  int num_args,
-                  const char* const* arg_names,
-                  const unsigned char* arg_types,
-                  const unsigned long long* arg_values,
-                  std::unique_ptr<ConvertableToTraceFormat>* convertable_values,
-                  unsigned int flags);
+  TraceEvent(int thread_id,
+             TimeTicks timestamp,
+             ThreadTicks thread_timestamp,
+             char phase,
+             const unsigned char* category_group_enabled,
+             const char* name,
+             const char* scope,
+             unsigned long long id,
+             unsigned long long bind_id,
+             TraceArguments* args,
+             unsigned int flags);
 
   void Reset();
 
@@ -116,9 +83,12 @@
       const ArgumentFilterPredicate& argument_filter_predicate) const;
   void AppendPrettyPrinted(std::ostringstream* out) const;
 
+  // TODO(898794): Remove once caller has been updated.
   static void AppendValueAsJSON(unsigned char type,
                                 TraceValue value,
-                                std::string* out);
+                                std::string* out) {
+    value.AppendAsJSON(type, out);
+  }
 
   TimeTicks timestamp() const { return timestamp_; }
   ThreadTicks thread_timestamp() const { return thread_timestamp_; }
@@ -132,8 +102,8 @@
   unsigned long long bind_id() const { return bind_id_; }
   // Exposed for unittesting:
 
-  const std::string* parameter_copy_storage() const {
-    return parameter_copy_storage_.get();
+  const StringStorage& parameter_copy_storage() const {
+    return parameter_copy_storage_;
   }
 
   const unsigned char* category_group_enabled() const {
@@ -142,12 +112,17 @@
 
   const char* name() const { return name_; }
 
-  unsigned char arg_type(size_t index) const { return arg_types_[index]; }
-  const char* arg_name(size_t index) const { return arg_names_[index]; }
-  const TraceValue& arg_value(size_t index) const { return arg_values_[index]; }
+  size_t arg_size() const { return args_.size(); }
+  unsigned char arg_type(size_t index) const { return args_.types()[index]; }
+  const char* arg_name(size_t index) const { return args_.names()[index]; }
+  const TraceValue& arg_value(size_t index) const {
+    return args_.values()[index];
+  }
 
   const ConvertableToTraceFormat* arg_convertible_value(size_t index) const {
-    return convertable_values_[index].get();
+    return (arg_type(index) == TRACE_VALUE_TYPE_CONVERTABLE)
+               ? arg_value(index).as_convertable
+               : nullptr;
   }
 
 #if defined(OS_ANDROID)
@@ -163,13 +138,10 @@
   // scope_ and id_ can be used to store phase-specific data.
   const char* scope_;
   unsigned long long id_;
-  TraceValue arg_values_[kTraceMaxNumArgs];
-  const char* arg_names_[kTraceMaxNumArgs];
-  std::unique_ptr<ConvertableToTraceFormat>
-      convertable_values_[kTraceMaxNumArgs];
   const unsigned char* category_group_enabled_;
   const char* name_;
-  std::unique_ptr<std::string> parameter_copy_storage_;
+  StringStorage parameter_copy_storage_;
+  TraceArguments args_;
   // Depending on TRACE_EVENT_FLAG_HAS_PROCESS_ID the event will have either:
   //  tid: thread_id_, pid: current_process_id (default case).
   //  tid: -1, pid: process_id_ (when flags_ & TRACE_EVENT_FLAG_HAS_PROCESS_ID).
@@ -179,7 +151,6 @@
   };
   unsigned int flags_;
   unsigned long long bind_id_;
-  unsigned char arg_types_[kTraceMaxNumArgs];
   char phase_;
 
   DISALLOW_COPY_AND_ASSIGN(TraceEvent);
diff --git a/base/trace_event/trace_event_unittest.cc b/base/trace_event/trace_event_unittest.cc
index 4f51f97..c5928ec 100644
--- a/base/trace_event/trace_event_unittest.cc
+++ b/base/trace_event/trace_event_unittest.cc
@@ -1697,10 +1697,10 @@
     ASSERT_TRUE(event2);
     EXPECT_STREQ("name1", event1->name());
     EXPECT_STREQ("name2", event2->name());
-    EXPECT_TRUE(event1->parameter_copy_storage() != nullptr);
-    EXPECT_TRUE(event2->parameter_copy_storage() != nullptr);
-    EXPECT_GT(event1->parameter_copy_storage()->size(), 0u);
-    EXPECT_GT(event2->parameter_copy_storage()->size(), 0u);
+    EXPECT_FALSE(event1->parameter_copy_storage().empty());
+    EXPECT_FALSE(event2->parameter_copy_storage().empty());
+    EXPECT_GT(event1->parameter_copy_storage().size(), 0u);
+    EXPECT_GT(event2->parameter_copy_storage().size(), 0u);
     EndTraceAndFlush();
   }
 
@@ -1730,8 +1730,8 @@
     ASSERT_TRUE(event2);
     EXPECT_STREQ("name1", event1->name());
     EXPECT_STREQ("name2", event2->name());
-    EXPECT_TRUE(event1->parameter_copy_storage() == nullptr);
-    EXPECT_TRUE(event2->parameter_copy_storage() == nullptr);
+    EXPECT_TRUE(event1->parameter_copy_storage().empty());
+    EXPECT_TRUE(event2->parameter_copy_storage().empty());
     EndTraceAndFlush();
   }
 }
diff --git a/base/trace_event/trace_log.cc b/base/trace_event/trace_log.cc
index 82474dd7..1f539f9 100644
--- a/base/trace_event/trace_log.cc
+++ b/base/trace_event/trace_log.cc
@@ -109,26 +109,14 @@
   if (!trace_event)
     return;
 
-  int num_args = 1;
-  unsigned char arg_type;
-  unsigned long long arg_value;
-  ::trace_event_internal::SetTraceValue(value, &arg_type, &arg_value);
-  trace_event->Initialize(
-      thread_id,
-      TimeTicks(),
-      ThreadTicks(),
-      TRACE_EVENT_PHASE_METADATA,
-      CategoryRegistry::kCategoryMetadata->state_ptr(),
-      metadata_name,
+  TraceArguments args(arg_name, value);
+  *trace_event = TraceEvent(
+      thread_id, TimeTicks(), ThreadTicks(), TRACE_EVENT_PHASE_METADATA,
+      CategoryRegistry::kCategoryMetadata->state_ptr(), metadata_name,
       trace_event_internal::kGlobalScope,  // scope
-      trace_event_internal::kNoId,  // id
-      trace_event_internal::kNoId,  // bind_id
-      num_args,
-      &arg_name,
-      &arg_type,
-      &arg_value,
-      nullptr,
-      TRACE_EVENT_FLAG_NONE);
+      trace_event_internal::kNoId,         // id
+      trace_event_internal::kNoId,         // bind_id
+      &args, TRACE_EVENT_FLAG_NONE);
 }
 
 class AutoThreadLocalBoolean {
@@ -1081,21 +1069,12 @@
     unsigned int flags) {
   int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
   base::TimeTicks now = TRACE_TIME_TICKS_NOW();
+  TraceArguments args(num_args, arg_names, arg_types, arg_values,
+                      convertable_values);
   return AddTraceEventWithThreadIdAndTimestamp(
-      phase,
-      category_group_enabled,
-      name,
-      scope,
-      id,
+      phase, category_group_enabled, name, scope, id,
       trace_event_internal::kNoId,  // bind_id
-      thread_id,
-      now,
-      num_args,
-      arg_names,
-      arg_types,
-      arg_values,
-      convertable_values,
-      flags);
+      thread_id, now, &args, flags);
 }
 
 TraceEventHandle TraceLog::AddTraceEventWithBindId(
@@ -1113,21 +1092,11 @@
     unsigned int flags) {
   int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
   base::TimeTicks now = TRACE_TIME_TICKS_NOW();
+  TraceArguments args(num_args, arg_names, arg_types, arg_values,
+                      convertable_values);
   return AddTraceEventWithThreadIdAndTimestamp(
-      phase,
-      category_group_enabled,
-      name,
-      scope,
-      id,
-      bind_id,
-      thread_id,
-      now,
-      num_args,
-      arg_names,
-      arg_types,
-      arg_values,
-      convertable_values,
-      flags | TRACE_EVENT_FLAG_HAS_CONTEXT_ID);
+      phase, category_group_enabled, name, scope, id, bind_id, thread_id, now,
+      &args, flags | TRACE_EVENT_FLAG_HAS_CONTEXT_ID);
 }
 
 TraceEventHandle TraceLog::AddTraceEventWithProcessId(
@@ -1144,21 +1113,12 @@
     std::unique_ptr<ConvertableToTraceFormat>* convertable_values,
     unsigned int flags) {
   base::TimeTicks now = TRACE_TIME_TICKS_NOW();
+  TraceArguments args(num_args, arg_names, arg_types, arg_values,
+                      convertable_values);
   return AddTraceEventWithThreadIdAndTimestamp(
-      phase,
-      category_group_enabled,
-      name,
-      scope,
-      id,
+      phase, category_group_enabled, name, scope, id,
       trace_event_internal::kNoId,  // bind_id
-      process_id,
-      now,
-      num_args,
-      arg_names,
-      arg_types,
-      arg_values,
-      convertable_values,
-      flags | TRACE_EVENT_FLAG_HAS_PROCESS_ID);
+      process_id, now, &args, flags | TRACE_EVENT_FLAG_HAS_PROCESS_ID);
 }
 
 // Handle legacy calls to AddTraceEventWithThreadIdAndTimestamp
@@ -1177,21 +1137,78 @@
     const unsigned long long* arg_values,
     std::unique_ptr<ConvertableToTraceFormat>* convertable_values,
     unsigned int flags) {
+  TraceArguments args(num_args, arg_names, arg_types, arg_values,
+                      convertable_values);
   return AddTraceEventWithThreadIdAndTimestamp(
-      phase,
-      category_group_enabled,
-      name,
-      scope,
-      id,
+      phase, category_group_enabled, name, scope, id,
       trace_event_internal::kNoId,  // bind_id
-      thread_id,
-      timestamp,
-      num_args,
-      arg_names,
-      arg_types,
-      arg_values,
-      convertable_values,
-      flags);
+      thread_id, timestamp, &args, flags);
+}
+
+TraceEventHandle TraceLog::AddTraceEvent(
+    char phase,
+    const unsigned char* category_group_enabled,
+    const char* name,
+    const char* scope,
+    unsigned long long id,
+    TraceArguments* args,
+    unsigned int flags) {
+  int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
+  base::TimeTicks now = TRACE_TIME_TICKS_NOW();
+  return AddTraceEventWithThreadIdAndTimestamp(
+      phase, category_group_enabled, name, scope, id,
+      trace_event_internal::kNoId,  // bind_id
+      thread_id, now, args, flags);
+}
+
+TraceEventHandle TraceLog::AddTraceEventWithBindId(
+    char phase,
+    const unsigned char* category_group_enabled,
+    const char* name,
+    const char* scope,
+    unsigned long long id,
+    unsigned long long bind_id,
+    TraceArguments* args,
+    unsigned int flags) {
+  int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
+  base::TimeTicks now = TRACE_TIME_TICKS_NOW();
+  return AddTraceEventWithThreadIdAndTimestamp(
+      phase, category_group_enabled, name, scope, id, bind_id, thread_id, now,
+      args, flags | TRACE_EVENT_FLAG_HAS_CONTEXT_ID);
+}
+
+TraceEventHandle TraceLog::AddTraceEventWithProcessId(
+    char phase,
+    const unsigned char* category_group_enabled,
+    const char* name,
+    const char* scope,
+    unsigned long long id,
+    int process_id,
+    TraceArguments* args,
+    unsigned int flags) {
+  base::TimeTicks now = TRACE_TIME_TICKS_NOW();
+  return AddTraceEventWithThreadIdAndTimestamp(
+      phase, category_group_enabled, name, scope, id,
+      trace_event_internal::kNoId,  // bind_id
+      process_id, now, args, flags | TRACE_EVENT_FLAG_HAS_PROCESS_ID);
+}
+
+// Handle legacy calls to AddTraceEventWithThreadIdAndTimestamp
+// with kNoId as bind_id
+TraceEventHandle TraceLog::AddTraceEventWithThreadIdAndTimestamp(
+    char phase,
+    const unsigned char* category_group_enabled,
+    const char* name,
+    const char* scope,
+    unsigned long long id,
+    int thread_id,
+    const TimeTicks& timestamp,
+    TraceArguments* args,
+    unsigned int flags) {
+  return AddTraceEventWithThreadIdAndTimestamp(
+      phase, category_group_enabled, name, scope, id,
+      trace_event_internal::kNoId,  // bind_id
+      thread_id, timestamp, args, flags);
 }
 
 TraceEventHandle TraceLog::AddTraceEventWithThreadIdAndTimestamp(
@@ -1209,6 +1226,24 @@
     const unsigned long long* arg_values,
     std::unique_ptr<ConvertableToTraceFormat>* convertable_values,
     unsigned int flags) {
+  TraceArguments args(num_args, arg_names, arg_types, arg_values,
+                      convertable_values);
+  return AddTraceEventWithThreadIdAndTimestamp(
+      phase, category_group_enabled, name, scope, id, bind_id, thread_id,
+      timestamp, &args, flags);
+}
+
+TraceEventHandle TraceLog::AddTraceEventWithThreadIdAndTimestamp(
+    char phase,
+    const unsigned char* category_group_enabled,
+    const char* name,
+    const char* scope,
+    unsigned long long id,
+    unsigned long long bind_id,
+    int thread_id,
+    const TimeTicks& timestamp,
+    TraceArguments* args,
+    unsigned int flags) {
   TraceEventHandle handle = {0, 0, 0};
   if (!*category_group_enabled)
     return handle;
@@ -1281,15 +1316,13 @@
   // acquiring the lock, which is not needed for ETW as it's already threadsafe.
   if (*category_group_enabled & TraceCategory::ENABLED_FOR_ETW_EXPORT)
     TraceEventETWExport::AddEvent(phase, category_group_enabled, name, id,
-                                  num_args, arg_names, arg_types, arg_values,
-                                  convertable_values);
+                                  args);
 #endif  // OS_WIN
 
   AddTraceEventOverrideCallback trace_event_override =
       reinterpret_cast<AddTraceEventOverrideCallback>(
           subtle::NoBarrier_Load(&trace_event_override_));
   if (trace_event_override) {
-    TraceEvent new_trace_event;
     // If we have an override in place for events, rather than sending
     // them to the tracelog, we don't have a way of going back and updating
     // the duration of _COMPLETE events. Instead, we emit separate _BEGIN
@@ -1297,10 +1330,9 @@
     if (phase == TRACE_EVENT_PHASE_COMPLETE)
       phase = TRACE_EVENT_PHASE_BEGIN;
 
-    new_trace_event.Initialize(thread_id, offset_event_timestamp, thread_now,
+    TraceEvent new_trace_event(thread_id, offset_event_timestamp, thread_now,
                                phase, category_group_enabled, name, scope, id,
-                               bind_id, num_args, arg_names, arg_types,
-                               arg_values, convertable_values, flags);
+                               bind_id, args, flags);
 
     trace_event_override(new_trace_event);
     return handle;
@@ -1310,11 +1342,9 @@
   std::unique_ptr<TraceEvent> filtered_trace_event;
   bool disabled_by_filters = false;
   if (*category_group_enabled & TraceCategory::ENABLED_FOR_FILTERING) {
-    std::unique_ptr<TraceEvent> new_trace_event(new TraceEvent);
-    new_trace_event->Initialize(thread_id, offset_event_timestamp, thread_now,
-                                phase, category_group_enabled, name, scope, id,
-                                bind_id, num_args, arg_names, arg_types,
-                                arg_values, convertable_values, flags);
+    auto new_trace_event = std::make_unique<TraceEvent>(
+        thread_id, offset_event_timestamp, thread_now, phase,
+        category_group_enabled, name, scope, id, bind_id, args, flags);
 
     disabled_by_filters = true;
     ForEachCategoryFilter(
@@ -1343,12 +1373,11 @@
 
     if (trace_event) {
       if (filtered_trace_event) {
-        trace_event->MoveFrom(std::move(filtered_trace_event));
+        *trace_event = std::move(*filtered_trace_event);
       } else {
-        trace_event->Initialize(thread_id, offset_event_timestamp, thread_now,
-                                phase, category_group_enabled, name, scope, id,
-                                bind_id, num_args, arg_names, arg_types,
-                                arg_values, convertable_values, flags);
+        *trace_event = TraceEvent(thread_id, offset_event_timestamp, thread_now,
+                                  phase, category_group_enabled, name, scope,
+                                  id, bind_id, args, flags);
       }
 
 #if defined(OS_ANDROID)
@@ -1378,19 +1407,27 @@
     const unsigned long long* arg_values,
     std::unique_ptr<ConvertableToTraceFormat>* convertable_values,
     unsigned int flags) {
+  TraceArguments args(num_args, arg_names, arg_types, arg_values,
+                      convertable_values);
+  return AddMetadataEvent(category_group_enabled, name, &args, flags);
+}
+
+void TraceLog::AddMetadataEvent(const unsigned char* category_group_enabled,
+                                const char* name,
+                                TraceArguments* args,
+                                unsigned int flags) {
   HEAP_PROFILER_SCOPED_IGNORE;
-  std::unique_ptr<TraceEvent> trace_event(new TraceEvent);
   int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
   ThreadTicks thread_now = ThreadNow();
   TimeTicks now = OffsetNow();
   AutoLock lock(lock_);
-  trace_event->Initialize(
+  auto trace_event = std::make_unique<TraceEvent>(
       thread_id, now, thread_now, TRACE_EVENT_PHASE_METADATA,
       category_group_enabled, name,
       trace_event_internal::kGlobalScope,  // scope
       trace_event_internal::kNoId,         // id
       trace_event_internal::kNoId,         // bind_id
-      num_args, arg_names, arg_types, arg_values, convertable_values, flags);
+      args, flags);
   metadata_events_.push_back(std::move(trace_event));
 }
 
@@ -1500,14 +1537,13 @@
     // we don't have way of updating the prior event so we'll emit a
     // separate _END event instead.
     if (trace_event_override) {
-      TraceEvent new_trace_event;
-      new_trace_event.Initialize(
+      TraceEvent new_trace_event(
           static_cast<int>(base::PlatformThread::CurrentId()), now, thread_now,
           TRACE_EVENT_PHASE_END, category_group_enabled, name,
           trace_event_internal::kGlobalScope,
           trace_event_internal::kNoId /* id */,
-          trace_event_internal::kNoId /* bind_id */, 0, nullptr, nullptr,
-          nullptr, nullptr, TRACE_EVENT_FLAG_NONE);
+          trace_event_internal::kNoId /* bind_id */, nullptr,
+          TRACE_EVENT_FLAG_NONE);
       trace_event_override(new_trace_event);
 
 #if defined(OS_ANDROID)
@@ -1584,7 +1620,7 @@
     while (!metadata_events_.empty()) {
       TraceEvent* event =
           AddEventToThreadSharedChunkWhileLocked(nullptr, false);
-      event->MoveFrom(std::move(metadata_events_.back()));
+      *event = std::move(*metadata_events_.back());
       metadata_events_.pop_back();
     }
   }
diff --git a/base/trace_event/trace_log.h b/base/trace_event/trace_log.h
index e1d233a..89b423b 100644
--- a/base/trace_event/trace_log.h
+++ b/base/trace_event/trace_log.h
@@ -203,6 +203,58 @@
   // Called by TRACE_EVENT* macros, don't call this directly.
   // If |copy| is set, |name|, |arg_name1| and |arg_name2| will be deep copied
   // into the event; see "Memory scoping note" and TRACE_EVENT_COPY_XXX above.
+  TraceEventHandle AddTraceEvent(char phase,
+                                 const unsigned char* category_group_enabled,
+                                 const char* name,
+                                 const char* scope,
+                                 unsigned long long id,
+                                 TraceArguments* args,
+                                 unsigned int flags);
+  TraceEventHandle AddTraceEventWithBindId(
+      char phase,
+      const unsigned char* category_group_enabled,
+      const char* name,
+      const char* scope,
+      unsigned long long id,
+      unsigned long long bind_id,
+      TraceArguments* args,
+      unsigned int flags);
+  TraceEventHandle AddTraceEventWithProcessId(
+      char phase,
+      const unsigned char* category_group_enabled,
+      const char* name,
+      const char* scope,
+      unsigned long long id,
+      int process_id,
+      TraceArguments* args,
+      unsigned int flags);
+  TraceEventHandle AddTraceEventWithThreadIdAndTimestamp(
+      char phase,
+      const unsigned char* category_group_enabled,
+      const char* name,
+      const char* scope,
+      unsigned long long id,
+      int thread_id,
+      const TimeTicks& timestamp,
+      TraceArguments* args,
+      unsigned int flags);
+  TraceEventHandle AddTraceEventWithThreadIdAndTimestamp(
+      char phase,
+      const unsigned char* category_group_enabled,
+      const char* name,
+      const char* scope,
+      unsigned long long id,
+      unsigned long long bind_id,
+      int thread_id,
+      const TimeTicks& timestamp,
+      TraceArguments* args,
+      unsigned int flags);
+
+  // Adds a metadata event that will be written when the trace log is flushed.
+  void AddMetadataEvent(const unsigned char* category_group_enabled,
+                        const char* name,
+                        TraceArguments* args,
+                        unsigned int flags);
   TraceEventHandle AddTraceEvent(
       char phase,
       const unsigned char* category_group_enabled,
@@ -215,6 +267,8 @@
       const unsigned long long* arg_values,
       std::unique_ptr<ConvertableToTraceFormat>* convertable_values,
       unsigned int flags);
+
+  // TODO(898794): Remove methods below when all callers have been updated.
   TraceEventHandle AddTraceEventWithBindId(
       char phase,
       const unsigned char* category_group_enabled,
diff --git a/base/trace_event/traced_value.cc b/base/trace_event/traced_value.cc
index 3f4c743..a159928 100644
--- a/base/trace_event/traced_value.cc
+++ b/base/trace_event/traced_value.cc
@@ -521,10 +521,10 @@
       }
 
       case kTypeBool: {
-        TraceEvent::TraceValue json_value;
+        TraceValue json_value;
         CHECK(it.ReadBool(&json_value.as_bool));
         maybe_append_key_name(state_stack[current_state_index], &it, out);
-        TraceEvent::AppendValueAsJSON(TRACE_VALUE_TYPE_BOOL, json_value, out);
+        json_value.AppendAsJSON(TRACE_VALUE_TYPE_BOOL, out);
         break;
       }
 
@@ -532,17 +532,17 @@
         int value;
         CHECK(it.ReadInt(&value));
         maybe_append_key_name(state_stack[current_state_index], &it, out);
-        TraceEvent::TraceValue json_value;
+        TraceValue json_value;
         json_value.as_int = value;
-        TraceEvent::AppendValueAsJSON(TRACE_VALUE_TYPE_INT, json_value, out);
+        json_value.AppendAsJSON(TRACE_VALUE_TYPE_INT, out);
         break;
       }
 
       case kTypeDouble: {
-        TraceEvent::TraceValue json_value;
+        TraceValue json_value;
         CHECK(it.ReadDouble(&json_value.as_double));
         maybe_append_key_name(state_stack[current_state_index], &it, out);
-        TraceEvent::AppendValueAsJSON(TRACE_VALUE_TYPE_DOUBLE, json_value, out);
+        json_value.AppendAsJSON(TRACE_VALUE_TYPE_DOUBLE, out);
         break;
       }
 
@@ -550,9 +550,9 @@
         std::string value;
         CHECK(it.ReadString(&value));
         maybe_append_key_name(state_stack[current_state_index], &it, out);
-        TraceEvent::TraceValue json_value;
+        TraceValue json_value;
         json_value.as_string = value.c_str();
-        TraceEvent::AppendValueAsJSON(TRACE_VALUE_TYPE_STRING, json_value, out);
+        json_value.AppendAsJSON(TRACE_VALUE_TYPE_STRING, out);
         break;
       }
 
diff --git a/build/android/gyp/apkbuilder.py b/build/android/gyp/apkbuilder.py
index ce61e756..39c06d5 100755
--- a/build/android/gyp/apkbuilder.py
+++ b/build/android/gyp/apkbuilder.py
@@ -327,8 +327,9 @@
         resource_infos = resource_apk.infolist()
 
         # 1. AndroidManifest.xml
-        assert resource_infos[0].filename == 'AndroidManifest.xml'
-        copy_resource(resource_infos[0], out_dir=apk_manifest_dir)
+        copy_resource(
+            resource_apk.getinfo('AndroidManifest.xml'),
+            out_dir=apk_manifest_dir)
 
         # 2. Assets
         if options.write_asset_list:
@@ -376,8 +377,9 @@
           build_utils.AddToZipHermetic(out_apk, apk_path, data='')
 
         # 5. Resources
-        for info in resource_infos[1:]:
-          copy_resource(info)
+        for info in resource_infos:
+          if info.filename != 'AndroidManifest.xml':
+            copy_resource(info)
 
         # 6. Java resources that should be accessible via
         # Class.getResourceAsStream(), in particular parts of Emma jar.
diff --git a/build/android/gyp/compile_resources.py b/build/android/gyp/compile_resources.py
index cbc2930..2876e20 100755
--- a/build/android/gyp/compile_resources.py
+++ b/build/android/gyp/compile_resources.py
@@ -141,6 +141,17 @@
                           action='store_true',
                           help='Whether to strip xml namespaces from processed '
                                'xml resources')
+  input_opts.add_argument(
+      '--resources-config-path', help='Path to aapt2 resources config file.')
+  input_opts.add_argument(
+      '--optimize-resources',
+      default=False,
+      action='store_true',
+      help='Whether to run the `aapt2 optimize` step on the resources.')
+  input_opts.add_argument(
+      '--unoptimized-resources-path',
+      help='Path to output the intermediate apk before running '
+      '`aapt2 optimize`.')
 
   input_opts.add_argument(
       '--check-resources-pkg-id', type=_PackageIdArgument,
@@ -306,7 +317,6 @@
     '--version-name', options.version_name,
     '--auto-add-overlay',
     '--no-version-vectors',
-    '-o', options.apk_path,
   ]
 
   for j in options.include_resources:
@@ -481,7 +491,11 @@
     partial_path = os.path.join(partials_dir, dirname + '.zip')
     compile_command = (partial_compile_command +
                        ['--dir', directory, '-o', partial_path])
-    build_utils.CheckOutput(compile_command)
+    build_utils.CheckOutput(
+        compile_command,
+        stderr_filter=lambda output:
+            build_utils.FilterLines(
+                output, r'ignoring configuration .* for styleable'))
 
     # Sorting the files in the partial ensures deterministic output from the
     # aapt2 link step which uses order of files in the partial.
@@ -541,7 +555,15 @@
   for directory in dep_subdirs:
     renamed_paths.update(_MoveImagesToNonMdpiFolders(directory))
 
+  if options.optimize_resources:
+    if options.unoptimized_resources_path:
+      unoptimized_apk_path = options.unoptimized_resources_path
+    else:
+      unoptimized_apk_path = os.path.join(gen_dir, 'intermediate.ap_')
+  else:
+    unoptimized_apk_path = options.apk_path
   link_command = _CreateLinkApkArgs(options)
+  link_command += ['-o', unoptimized_apk_path]
   link_command += ['--output-text-symbols', r_txt_path]
   # TODO(digit): Is this below actually required for R.txt generation?
   link_command += ['--java', gen_dir]
@@ -557,6 +579,26 @@
   # Also creates R.txt
   build_utils.CheckOutput(
       link_command, print_stdout=False, print_stderr=False)
+
+  if options.optimize_resources:
+    # Optimize the resources.arsc file by obfuscating resource names and only
+    # allow usage via R.java constant.
+    optimize_command = [
+        options.aapt2_path,
+        'optimize',
+        '--enable-resource-obfuscation',
+        '-o',
+        options.apk_path,
+        unoptimized_apk_path,
+    ]
+    if options.resources_config_path:
+      optimize_command += [
+          '--resources-config-path',
+          options.resources_config_path,
+      ]
+    build_utils.CheckOutput(
+        optimize_command, print_stdout=False, print_stderr=False)
+
   _CreateResourceInfoFile(
       renamed_paths, options.apk_info_path, options.dependencies_res_zips)
 
@@ -639,25 +681,27 @@
   # Order of these must match order specified in GN so that the correct one
   # appears first in the depfile.
   possible_output_paths = [
-    options.apk_path,
-    options.apk_path + '.info',
-    options.r_text_out,
-    options.srcjar_out,
-    options.proguard_file,
-    options.proguard_file_main_dex,
+      options.apk_path,
+      options.apk_path + '.info',
+      options.r_text_out,
+      options.srcjar_out,
+      options.proguard_file,
+      options.proguard_file_main_dex,
+      options.unoptimized_resources_path,
   ]
   output_paths = [x for x in possible_output_paths if x]
 
   # List python deps in input_strings rather than input_paths since the contents
   # of them does not change what gets written to the depsfile.
   input_strings = options.extra_res_packages + [
-    options.shared_resources,
-    options.resource_blacklist_regex,
-    options.resource_blacklist_exceptions,
-    str(options.debuggable),
-    str(options.png_to_webp),
-    str(options.support_zh_hk),
-    str(options.no_xml_namespaces),
+      options.shared_resources,
+      options.resource_blacklist_regex,
+      options.resource_blacklist_exceptions,
+      str(options.debuggable),
+      str(options.png_to_webp),
+      str(options.support_zh_hk),
+      str(options.no_xml_namespaces),
+      str(options.optimize_resources),
   ]
 
   input_strings.extend(_CreateLinkApkArgs(options))
@@ -669,11 +713,12 @@
 
 
   possible_input_paths = [
-    options.aapt_path,
-    options.aapt2_path,
-    options.android_manifest,
-    debug_temp_resources_dir,
-    options.shared_resources_whitelist,
+      options.aapt_path,
+      options.aapt2_path,
+      options.android_manifest,
+      debug_temp_resources_dir,
+      options.shared_resources_whitelist,
+      options.resources_config_path,
   ]
   possible_input_paths += options.include_resources
   input_paths = [x for x in possible_input_paths if x]
diff --git a/build/android/gyp/create_app_bundle.py b/build/android/gyp/create_app_bundle.py
index d58bf30..8f24717 100755
--- a/build/android/gyp/create_app_bundle.py
+++ b/build/android/gyp/create_app_bundle.py
@@ -50,6 +50,10 @@
                       help='Output bundle zip archive.')
   parser.add_argument('--module-zips', required=True,
                       help='GN-list of module zip archives.')
+  parser.add_argument(
+      '--rtxt-in-paths', action='append', help='GN-list of module R.txt files.')
+  parser.add_argument(
+      '--rtxt-out-path', help='Path to combined R.txt file for bundle.')
   parser.add_argument('--uncompressed-assets', action='append',
                       help='GN-list of uncompressed assets.')
   parser.add_argument('--uncompress-shared-libraries', action='append',
@@ -63,6 +67,7 @@
 
   options = parser.parse_args(args)
   options.module_zips = build_utils.ParseGnList(options.module_zips)
+  options.rtxt_in_paths = build_utils.ExpandFileArgs(options.rtxt_in_paths)
 
   if len(options.module_zips) == 0:
     raise Exception('The module zip list cannot be empty.')
@@ -285,6 +290,14 @@
 
     shutil.move(tmp_bundle, options.out_bundle)
 
+  if options.rtxt_out_path:
+    with open(options.rtxt_out_path, 'w') as rtxt_out:
+      for rtxt_in_path in options.rtxt_in_paths:
+        with open(rtxt_in_path, 'r') as rtxt_in:
+          rtxt_out.write('-- Contents of {}\n'.format(
+              os.path.basename(rtxt_in_path)))
+          rtxt_out.write(rtxt_in.read())
+
 
 if __name__ == '__main__':
   main(sys.argv[1:])
diff --git a/build/android/gyp/write_build_config.py b/build/android/gyp/write_build_config.py
index f4d25bf..b87e551c 100755
--- a/build/android/gyp/write_build_config.py
+++ b/build/android/gyp/write_build_config.py
@@ -348,6 +348,10 @@
 The path of an zip archive containing the APK's resources compiled to the
 protocol buffer format (instead of regular binary xml + resources.arsc).
 
+* `deps_info['module_rtxt_path']`:
+The path of the R.txt file generated when compiling the resources for the bundle
+module.
+
 * `native['libraries']`
 List of native libraries for the primary ABI to be embedded in this APK.
 E.g. [ "libchrome.so" ] (i.e. this doesn't include any ABI sub-directory
@@ -871,6 +875,9 @@
   parser.add_option('--apk-proto-resources',
                     help='Path to resources compiled in protocol buffer format '
                          ' for this apk.')
+  parser.add_option(
+      '--module-rtxt-path',
+      help='Path to R.txt file for resources in a bundle module.')
 
   parser.add_option('--generate-markdown-format-doc', action='store_true',
                     help='Dump the Markdown .build_config format documentation '
@@ -884,7 +891,7 @@
   if options.generate_markdown_format_doc:
     doc_lines = _ExtractMarkdownDocumentation(__doc__)
     for line in doc_lines:
-        print(line)
+      print(line)
     return 0
 
   if options.fail:
@@ -919,6 +926,10 @@
     if options.type != 'android_app_bundle_module':
       raise Exception('--apk-proto-resources can only be used with '
                       '--type=android_app_bundle_module')
+  if options.module_rtxt_path:
+    if options.type != 'android_app_bundle_module':
+      raise Exception('--module-rxt-path can only be used with '
+                      '--type=android_app_bundle_module')
 
   is_apk_or_module_target = options.type in ('android_apk',
       'android_app_bundle_module')
@@ -1028,6 +1039,9 @@
     if options.apk_proto_resources:
       deps_info['proto_resources_path'] = options.apk_proto_resources
 
+    if options.module_rtxt_path:
+      deps_info['module_rtxt_path'] = options.module_rtxt_path
+
   if is_java_target:
     deps_info['requires_android'] = bool(options.requires_android)
     deps_info['supports_android'] = bool(options.supports_android)
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni
index 1250e05..41dd23c 100644
--- a/build/config/android/internal_rules.gni
+++ b/build/config/android/internal_rules.gni
@@ -320,6 +320,11 @@
       args += [ "--apk-proto-resources=$_rebased_proto_resources" ]
     }
 
+    if (defined(invoker.module_rtxt_path)) {
+      _rebased_rtxt_path = rebase_path(invoker.module_rtxt_path, root_build_dir)
+      args += [ "--module-rtxt-path=$_rebased_rtxt_path" ]
+    }
+
     if (defined(invoker.shared_libraries_runtime_deps_file)) {
       # Don't list shared_libraries_runtime_deps_file as an input in order to
       # avoid having to depend on the runtime_deps target. See comment in
@@ -1976,14 +1981,15 @@
       outputs = []
 
       _android_aapt_path = android_default_aapt_path
+      _android_aapt2_path = android_sdk_tools_bundle_aapt2
       if (_proto_format) {
-        _android_aapt2_path = android_sdk_tools_bundle_aapt2
         depfile = "$target_gen_dir/${invoker.target_name}_3.d"
       }
 
       inputs = [
         invoker.build_config,
         _android_aapt_path,
+        _android_aapt2_path,
       ]
 
       _rebased_build_config = rebase_path(invoker.build_config, root_build_dir)
@@ -1994,19 +2000,13 @@
         "--include-resources=@FileArg($_rebased_build_config:android:sdk_jars)",
         "--aapt-path",
         rebase_path(_android_aapt_path, root_build_dir),
+        "--aapt2-path",
+        rebase_path(_android_aapt2_path, root_build_dir),
         "--dependencies-res-zips=@FileArg($_rebased_build_config:resources:dependency_zips)",
         "--extra-res-packages=@FileArg($_rebased_build_config:resources:extra_package_names)",
         "--extra-r-text-files=@FileArg($_rebased_build_config:resources:extra_r_text_files)",
       ]
 
-      if (_proto_format) {
-        inputs += [ _android_aapt2_path ]
-        args += [
-          "--aapt2-path",
-          rebase_path(_android_aapt2_path, root_build_dir),
-        ]
-      }
-
       inputs += [ invoker.android_manifest ]
       args += [
         "--android-manifest",
@@ -2043,6 +2043,25 @@
         ]
       }
 
+      if (defined(invoker.optimize_resources) && invoker.optimize_resources) {
+        args += [ "--optimize-resources" ]
+        if (defined(invoker.resources_config_path)) {
+          inputs += [ invoker.resources_config_path ]
+          args += [
+            "--resources-config-path",
+            rebase_path(invoker.resources_config_path, root_build_dir),
+          ]
+        }
+
+        if (defined(invoker.unoptimized_resources_path)) {
+          args += [
+            "--unoptimized-resources-path",
+            rebase_path(invoker.unoptimized_resources_path, root_build_dir),
+          ]
+          outputs += [ invoker.unoptimized_resources_path ]
+        }
+      }
+
       # Useful to have android:debuggable in the manifest even for Release
       # builds. Just omit it for officai
       if (debuggable_apks) {
@@ -2492,6 +2511,13 @@
           get_label_info(_incremental_compile_resources_target_name,
                          "target_gen_dir") + "/AndroidManifest.xml"
 
+      if (defined(invoker.unoptimized_resources_path)) {
+        _incremental_packaged_resources_path =
+            invoker.unoptimized_resources_path
+      } else {
+        _incremental_packaged_resources_path = invoker.packaged_resources_path
+      }
+
       _rebased_build_config =
           rebase_path(invoker.assets_build_config, root_build_dir)
 
@@ -2502,7 +2528,7 @@
         inputs = [
           _android_manifest,
           invoker.assets_build_config,
-          invoker.packaged_resources_path,
+          _incremental_packaged_resources_path,
         ]
         outputs = [
           # Output the non-compiled manifest for easy debugging (as opposed to
@@ -2517,7 +2543,7 @@
           "--out-manifest",
           rebase_path(_incremental_android_manifest, root_build_dir),
           "--in-apk",
-          rebase_path(invoker.packaged_resources_path, root_build_dir),
+          rebase_path(_incremental_packaged_resources_path, root_build_dir),
           "--out-apk",
           rebase_path(_incremental_compiled_resources_path, root_build_dir),
           "--aapt-path",
@@ -3129,7 +3155,11 @@
                                ])
       }
       if (type == "android_app_bundle_module") {
-        forward_variables_from(invoker, [ "proto_resources_path" ])
+        forward_variables_from(invoker,
+                               [
+                                 "proto_resources_path",
+                                 "module_rtxt_path",
+                               ])
       }
       build_config = _build_config
       is_prebuilt = _is_prebuilt
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni
index d7e92f0a..a390a56 100644
--- a/build/config/android/rules.gni
+++ b/build/config/android/rules.gni
@@ -1884,6 +1884,10 @@
   #   uncompress_shared_libraries: True if shared libraries should be stored
   #     uncompressed in the APK. Must be unset or true if load_library_from_apk
   #     is set to true.
+  #   optimize_resources: True if resource names should be stripped from the
+  #     resources.arsc file in the apk or module.
+  #   resources_config_path: Path to the aapt2 optimize config file that tags
+  #     resources with acceptable/non-acceptable optimizations.
   template("android_apk_or_module") {
     forward_variables_from(invoker, [ "testonly" ])
 
@@ -1913,10 +1917,11 @@
 
     if (defined(invoker.final_apk_path)) {
       _final_apk_path = invoker.final_apk_path
-    } else if (!_is_bundle_module) {
-      _final_apk_path = "$root_build_dir/apks/${invoker.name}.apk"
     } else {
-      _final_apk_path = "$root_build_dir/bundle_modules/${invoker.name}"
+      _final_apk_path = "$root_build_dir/apks/${invoker.name}.apk"
+    }
+    if (!_is_bundle_module) {
+      _final_rtxt_path = "${_final_apk_path}.R.txt"
     }
     _final_apk_path_no_ext_list =
         process_file_template([ _final_apk_path ],
@@ -2123,7 +2128,16 @@
       _android_sdk_dep = "//third_party/android_tools:android_sdk_java"
     }
 
+    _optimize_resources =
+        defined(invoker.optimize_resources) && invoker.optimize_resources
+    if (_optimize_resources) {
+      _unoptimized_resources_path =
+          "$target_out_dir/$_template_name.unoptimized.ap_"
+    }
+
     _compile_resources_target = "${_template_name}__compile_resources"
+    _compile_resources_rtxt_out =
+        "${target_gen_dir}/${_compile_resources_target}_R.txt"
     compile_resources(_compile_resources_target) {
       forward_variables_from(invoker,
                              [
@@ -2133,6 +2147,7 @@
                                "aapt_locale_whitelist",
                                "resource_blacklist_regex",
                                "resource_blacklist_exceptions",
+                               "resources_config_path",
                                "png_to_webp",
                                "no_xml_namespaces",
                              ])
@@ -2144,12 +2159,16 @@
         post_process_script = invoker.post_process_package_resources_script
       }
       srcjar_path = "${target_gen_dir}/${target_name}.srcjar"
-      r_text_out_path = "${target_gen_dir}/${target_name}_R.txt"
+      r_text_out_path = _compile_resources_rtxt_out
       proguard_file = _generated_proguard_config
       if (_enable_multidex) {
         proguard_file_main_dex = _generated_proguard_main_dex_config
       }
       output = _packaged_resources_path
+      if (_optimize_resources) {
+        optimize_resources = true
+        unoptimized_resources_path = _unoptimized_resources_path
+      }
 
       build_config = _build_config
       deps = _deps + [
@@ -2182,6 +2201,28 @@
       }
     }
 
+    if (!_is_bundle_module) {
+      # Output the R.txt file to a more easily discoverable location for
+      # archiving. This is necessary when stripping resource names so that we
+      # have an archive of resource names to ids for shipped apks (for
+      # debugging purposes). We copy the file rather than change the location
+      # of the original because other targets rely on the location of the R.txt
+      # file.
+      _copy_rtxt_target = "${_template_name}__copy_rtxt"
+      copy(_copy_rtxt_target) {
+        deps = [
+          ":$_compile_resources_target",
+        ]
+        sources = [
+          _compile_resources_rtxt_out,
+        ]
+        outputs = [
+          _final_rtxt_path,
+        ]
+      }
+      _final_deps += [ ":$_copy_rtxt_target" ]
+    }
+
     if (_is_base_module && _is_bundle_module) {
       # Bundle modules have to reference resources from the base module.
       # However, to compile the bundle module's resources we have to give it an
@@ -2365,6 +2406,7 @@
 
       if (_is_bundle_module) {
         proto_resources_path = _packaged_resources_path
+        module_rtxt_path = _compile_resources_rtxt_out
       }
 
       if (!_is_bundle_module) {
@@ -2562,6 +2604,9 @@
         if (_incremental_allowed) {
           android_manifest = _android_manifest
           base_path = _base_path
+          if (_optimize_resources) {
+            unoptimized_resources_path = _unoptimized_resources_path
+          }
         }
 
         # Incremental apk does not use native libs nor final dex.
@@ -2835,6 +2880,7 @@
                                "never_incremental",
                                "no_build_hooks",
                                "no_xml_namespaces",
+                               "optimize_resources",
                                "png_to_webp",
                                "post_process_package_resources_script",
                                "product_version_resources_dep",
@@ -2843,6 +2889,7 @@
                                "proguard_jar_path",
                                "resource_blacklist_regex",
                                "resource_blacklist_exceptions",
+                               "resources_config_path",
                                "secondary_abi_loadable_modules",
                                "secondary_abi_shared_libraries",
                                "secondary_native_lib_placeholders",
@@ -2932,6 +2979,7 @@
                                "native_lib_version_rule",
                                "negative_main_dex_globs",
                                "no_xml_namespaces",
+                               "optimize_resources",
                                "png_to_webp",
                                "product_version_resources_dep",
                                "proguard_configs",
@@ -2939,6 +2987,7 @@
                                "proguard_jar_path",
                                "resource_blacklist_regex",
                                "resource_blacklist_exceptions",
+                               "resources_config_path",
                                "secondary_abi_loadable_modules",
                                "secondary_abi_shared_libraries",
                                "secondary_native_lib_placeholders",
@@ -3856,6 +3905,7 @@
       _all_create_module_targets += [
         ":$_create_module_target",
         _module_build_config_target,
+        "${_module_target}__compile_resources",
       ]
       _all_module_zip_paths += [ _module_zip_path ]
       _all_module_build_configs += [ _module_build_config ]
@@ -3914,6 +3964,7 @@
       deps = _all_create_module_targets + [ ":$_build_config_target" ]
       args = [
         "--out-bundle=$_rebased_bundle_path",
+        "--rtxt-out-path=$_rebased_bundle_path.R.txt",
         "--module-zips=$_all_rebased_module_zip_paths",
       ]
       if (_sign_bundle) {
@@ -3936,6 +3987,8 @@
               "$_rebased_build_config:uncompressed_assets)",
           "--uncompress-shared-libraries=@FileArg(" +
               "$_rebased_build_config:native:uncompress_shared_libraries)",
+          "--rtxt-in-paths=@FileArg(" +
+              "$_rebased_build_config:deps_info:module_rtxt_path)",
         ]
       }
     }
diff --git a/build/config/fuchsia/testing_sandbox_policy b/build/config/fuchsia/testing_sandbox_policy
index b0ed870..d295d05 100644
--- a/build/config/fuchsia/testing_sandbox_policy
+++ b/build/config/fuchsia/testing_sandbox_policy
@@ -5,6 +5,7 @@
   "services": [
       "fuchsia.fonts.Provider",
       "fuchsia.media.Audio",
+      "fuchsia.mediacodec.CodecFactory",
       "fuchsia.net.LegacySocketProvider",
       "fuchsia.netstack.Netstack",
       "fuchsia.process.Launcher",
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index c202c68..cd544e8 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-544e4b9339ce00bc63a3616a78783d975949b38d
\ No newline at end of file
+347788cdd047836f67a991285b6d93b93615d82c
\ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index 5b3aaab..25639bd 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-2f3f1bf9489ae7f53df3203849b26b756743cadd
\ No newline at end of file
+aba94fa29d31e783ae10d9930d176336697d538a
\ No newline at end of file
diff --git a/cc/BUILD.gn b/cc/BUILD.gn
index 25cb9195..68ec7c5 100644
--- a/cc/BUILD.gn
+++ b/cc/BUILD.gn
@@ -54,6 +54,8 @@
     "input/snap_fling_controller.h",
     "input/snap_fling_curve.cc",
     "input/snap_fling_curve.h",
+    "input/snap_selection_strategy.cc",
+    "input/snap_selection_strategy.h",
     "input/touch_action.h",
     "layers/append_quads_data.cc",
     "layers/append_quads_data.h",
diff --git a/cc/animation/animation_host.cc b/cc/animation/animation_host.cc
index 696e69e..b78c578 100644
--- a/cc/animation/animation_host.cc
+++ b/cc/animation/animation_host.cc
@@ -12,7 +12,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/stl_util.h"
 #include "base/trace_event/trace_event.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "cc/animation/animation.h"
 #include "cc/animation/animation_delegate.h"
 #include "cc/animation/animation_events.h"
diff --git a/cc/animation/scroll_offset_animations_impl.cc b/cc/animation/scroll_offset_animations_impl.cc
index 7c11c2d..ec4bafb 100644
--- a/cc/animation/scroll_offset_animations_impl.cc
+++ b/cc/animation/scroll_offset_animations_impl.cc
@@ -5,7 +5,7 @@
 #include "cc/animation/scroll_offset_animations_impl.h"
 
 #include "base/trace_event/trace_event.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "cc/animation/animation_host.h"
 #include "cc/animation/animation_id_provider.h"
 #include "cc/animation/animation_timeline.h"
diff --git a/cc/base/devtools_instrumentation.h b/cc/base/devtools_instrumentation.h
index 0562877..e0b9314f 100644
--- a/cc/base/devtools_instrumentation.h
+++ b/cc/base/devtools_instrumentation.h
@@ -12,7 +12,7 @@
 #include "base/macros.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/trace_event/trace_event.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "cc/base/base_export.h"
 
 namespace cc {
diff --git a/cc/base/math_util.cc b/cc/base/math_util.cc
index 7ac7fb42..d212a73 100644
--- a/cc/base/math_util.cc
+++ b/cc/base/math_util.cc
@@ -11,7 +11,7 @@
 #include <xmmintrin.h>
 #endif
 
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "base/values.h"
 #include "ui/gfx/geometry/angle_conversions.h"
 #include "ui/gfx/geometry/quad_f.h"
diff --git a/cc/base/region.cc b/cc/base/region.cc
index 5653634..3187693 100644
--- a/cc/base/region.cc
+++ b/cc/base/region.cc
@@ -6,7 +6,7 @@
 
 #include <stddef.h>
 
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "base/values.h"
 #include "cc/base/simple_enclosed_region.h"
 #include "ui/gfx/geometry/vector2d.h"
diff --git a/cc/debug/rendering_stats.h b/cc/debug/rendering_stats.h
index 156db0c..4fe3f553 100644
--- a/cc/debug/rendering_stats.h
+++ b/cc/debug/rendering_stats.h
@@ -11,7 +11,7 @@
 #include <vector>
 
 #include "base/time/time.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "base/values.h"
 #include "cc/debug/debug_export.h"
 
diff --git a/cc/input/main_thread_scrolling_reason.cc b/cc/input/main_thread_scrolling_reason.cc
index d533265..728708ce 100644
--- a/cc/input/main_thread_scrolling_reason.cc
+++ b/cc/input/main_thread_scrolling_reason.cc
@@ -5,7 +5,7 @@
 #include "cc/input/main_thread_scrolling_reason.h"
 
 #include "base/stl_util.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 
 namespace cc {
 
diff --git a/cc/input/scroll_snap_data.cc b/cc/input/scroll_snap_data.cc
index 9e873ae..99e256e 100644
--- a/cc/input/scroll_snap_data.cc
+++ b/cc/input/scroll_snap_data.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "cc/input/scroll_snap_data.h"
+#include "cc/input/snap_selection_strategy.h"
 
 #include <algorithm>
 #include <cmath>
@@ -21,6 +22,14 @@
              : area.scroll_snap_align.alignment_block != SnapAlignment::kNone;
 }
 
+void SetOrUpdateResult(const SnapSearchResult& candidate,
+                       base::Optional<SnapSearchResult>* result) {
+  if (result->has_value())
+    result->value().Union(candidate);
+  else
+    *result = candidate;
+}
+
 }  // namespace
 
 bool SnapVisibleRange::Contains(float value) const {
@@ -88,13 +97,14 @@
 }
 
 bool SnapContainerData::FindSnapPosition(
-    const gfx::ScrollOffset& current_position,
-    bool should_snap_on_x,
-    bool should_snap_on_y,
+    const SnapSelectionStrategy& strategy,
     gfx::ScrollOffset* snap_position) const {
+  gfx::ScrollOffset base_position = strategy.base_position();
   SnapAxis axis = scroll_snap_type_.axis;
-  should_snap_on_x &= (axis == SnapAxis::kX || axis == SnapAxis::kBoth);
-  should_snap_on_y &= (axis == SnapAxis::kY || axis == SnapAxis::kBoth);
+  bool should_snap_on_x = strategy.ShouldSnapOnX() &&
+                          (axis == SnapAxis::kX || axis == SnapAxis::kBoth);
+  bool should_snap_on_y = strategy.ShouldSnapOnY() &&
+                          (axis == SnapAxis::kY || axis == SnapAxis::kBoth);
   if (!should_snap_on_x && !should_snap_on_y)
     return false;
 
@@ -102,18 +112,18 @@
   // A region that includes every reachable scroll position.
   gfx::RectF scrollable_region(0, 0, max_position_.x(), max_position_.y());
   if (should_snap_on_x) {
-    // Start from current offset in the cross axis and assume it's always
+    // Start from current position in the cross axis and assume it's always
     // visible.
     SnapSearchResult initial_snap_position_y = {
-        current_position.y(), SnapVisibleRange(0, max_position_.x())};
-    closest_x = FindClosestValidArea(SearchAxis::kX, current_position.x(),
-                                     initial_snap_position_y);
+        base_position.y(), SnapVisibleRange(0, max_position_.x())};
+    closest_x =
+        FindClosestValidArea(SearchAxis::kX, strategy, initial_snap_position_y);
   }
   if (should_snap_on_y) {
     SnapSearchResult initial_snap_position_x = {
-        current_position.x(), SnapVisibleRange(0, max_position_.y())};
-    closest_y = FindClosestValidArea(SearchAxis::kY, current_position.y(),
-                                     initial_snap_position_x);
+        base_position.x(), SnapVisibleRange(0, max_position_.y())};
+    closest_y =
+        FindClosestValidArea(SearchAxis::kY, strategy, initial_snap_position_x);
   }
 
   if (!closest_x.has_value() && !closest_y.has_value())
@@ -126,17 +136,18 @@
   if (closest_x.has_value() && closest_y.has_value() &&
       !IsMutualVisible(closest_x.value(), closest_y.value())) {
     bool candidate_on_x_axis_is_closer =
-        std::abs(closest_x.value().snap_offset() - current_position.x()) <=
-        std::abs(closest_y.value().snap_offset() - current_position.y());
-    if (candidate_on_x_axis_is_closer)
-      closest_y = FindClosestValidArea(SearchAxis::kY, current_position.y(),
-                                       closest_x.value());
-    else
-      closest_x = FindClosestValidArea(SearchAxis::kX, current_position.x(),
-                                       closest_y.value());
+        std::abs(closest_x.value().snap_offset() - base_position.x()) <=
+        std::abs(closest_y.value().snap_offset() - base_position.y());
+    if (candidate_on_x_axis_is_closer) {
+      closest_y =
+          FindClosestValidArea(SearchAxis::kY, strategy, closest_x.value());
+    } else {
+      closest_x =
+          FindClosestValidArea(SearchAxis::kX, strategy, closest_y.value());
+    }
   }
 
-  *snap_position = current_position;
+  *snap_position = strategy.current_position();
   if (closest_x.has_value())
     snap_position->set_x(closest_x.value().snap_offset());
   if (closest_y.has_value())
@@ -146,13 +157,36 @@
 
 base::Optional<SnapSearchResult> SnapContainerData::FindClosestValidArea(
     SearchAxis axis,
-    float current_offset,
+    const SnapSelectionStrategy& strategy,
     const SnapSearchResult& cros_axis_snap_result) const {
-  base::Optional<SnapSearchResult> result;
-  base::Optional<SnapSearchResult> inplace;
-  // The valid snap offsets immediately before and after the current offset.
+  // The search result from the snap area that's closest to the search origin.
+  base::Optional<SnapSearchResult> closest;
+  // The search result with the intended position if it makes a snap area cover
+  // the snapport.
+  base::Optional<SnapSearchResult> covering;
+  // The search result with the current position as a backup in case no other
+  // valid snap position exists.
+  base::Optional<SnapSearchResult> current;
+
+  // The valid snap positions immediately before and after the current position.
   float prev = std::numeric_limits<float>::lowest();
   float next = std::numeric_limits<float>::max();
+
+  // The current position before the scroll or snap happens. If no other snap
+  // position exists, this would become a backup option.
+  float current_position = axis == SearchAxis::kX
+                               ? strategy.current_position().x()
+                               : strategy.current_position().y();
+  // The intended position of the scroll operation if there's no snap. This
+  // scroll position becomes the covering candidate if there is a snap area that
+  // fully covers the snapport if this position is scrolled to.
+  float intended_position = axis == SearchAxis::kX
+                                ? strategy.intended_position().x()
+                                : strategy.intended_position().y();
+  // The position from which we search for the closest snap position.
+  float base_position = axis == SearchAxis::kX ? strategy.base_position().x()
+                                               : strategy.base_position().y();
+
   float smallest_distance =
       axis == SearchAxis::kX ? proximity_range_.x() : proximity_range_.y();
   for (const SnapAreaData& area : snap_area_list_) {
@@ -160,52 +194,54 @@
       continue;
 
     SnapSearchResult candidate = GetSnapSearchResult(axis, area);
-    if (IsSnapportCoveredOnAxis(axis, current_offset, area.rect)) {
-      // Since snap area is currently covering the snapport, we consider the
-      // current offset as a valid snap position.
-      SnapSearchResult inplace_candidate = candidate;
-      inplace_candidate.set_snap_offset(current_offset);
-      if (IsMutualVisible(inplace_candidate, cros_axis_snap_result)) {
-        // If we've already found a valid overflowing area before, we enlarge
-        // the area's visible region.
-        if (inplace.has_value())
-          inplace.value().Union(inplace_candidate);
-        else
-          inplace = inplace_candidate;
-        // Even if a snap area covers the snapport, we need to continue this
-        // search to find previous and next snap positions and also to have
-        // alternative snap candidates if this inplace candidate is ultimately
-        // rejected. And this covering snap area has its own alignment that may
-        // generates a snap position rejecting the current inplace candidate.
-      }
+    if (IsSnapportCoveredOnAxis(axis, intended_position, area.rect)) {
+      // Since snap area will cover the snapport, we consider the intended
+      // position as a valid snap position.
+      SnapSearchResult covering_candidate = candidate;
+      covering_candidate.set_snap_offset(intended_position);
+      if (IsMutualVisible(covering_candidate, cros_axis_snap_result))
+        SetOrUpdateResult(covering_candidate, &covering);
+      // Even if a snap area covers the snapport, we need to continue this
+      // search to find previous and next snap positions and also to have
+      // alternative snap candidates if this covering candidate is ultimately
+      // rejected. And this covering snap area has its own alignment that may
+      // generates a snap position rejecting the current inplace candidate.
     }
     if (!IsMutualVisible(candidate, cros_axis_snap_result))
       continue;
-    float distance = std::abs(candidate.snap_offset() - current_offset);
+    if (!strategy.IsValidSnapPosition(axis, candidate.snap_offset())) {
+      if (candidate.snap_offset() == current_position &&
+          scroll_snap_type_.strictness == SnapStrictness::kMandatory) {
+        SetOrUpdateResult(candidate, &current);
+      }
+      continue;
+    }
+    float distance = std::abs(candidate.snap_offset() - base_position);
     if (distance < smallest_distance) {
       smallest_distance = distance;
-      result = candidate;
+      closest = candidate;
     }
-    if (candidate.snap_offset() < current_offset &&
+    if (candidate.snap_offset() < intended_position &&
         candidate.snap_offset() > prev)
       prev = candidate.snap_offset();
-    if (candidate.snap_offset() > current_offset &&
+    if (candidate.snap_offset() > intended_position &&
         candidate.snap_offset() < next)
       next = candidate.snap_offset();
   }
   // According to the spec [1], if the snap area is covering the snapport, the
-  // scroll offset is a valid snap position only if the distance between the
+  // scroll position is a valid snap position only if the distance between the
   // geometrically previous and subsequent snap positions in that axis is larger
   // than size of the snapport in that axis.
   // [1] https://drafts.csswg.org/css-scroll-snap-1/#snap-overflow
   float size = axis == SearchAxis::kX ? rect_.width() : rect_.height();
-  if (inplace.has_value() &&
-      (prev == std::numeric_limits<float>::lowest() ||
-       next == std::numeric_limits<float>::max() || next - prev > size)) {
-    return inplace;
+  if (prev != std::numeric_limits<float>::lowest() &&
+      next != std::numeric_limits<float>::max() && next - prev <= size) {
+    covering = base::nullopt;
   }
 
-  return result;
+  const base::Optional<SnapSearchResult>& picked =
+      strategy.PickBestResult(closest, covering);
+  return picked.has_value() ? picked : current;
 }
 
 SnapSearchResult SnapContainerData::GetSnapSearchResult(
diff --git a/cc/input/scroll_snap_data.h b/cc/input/scroll_snap_data.h
index c18f737..a52da76c 100644
--- a/cc/input/scroll_snap_data.h
+++ b/cc/input/scroll_snap_data.h
@@ -14,6 +14,8 @@
 
 namespace cc {
 
+class SnapSelectionStrategy;
+
 // See https://www.w3.org/TR/css-scroll-snap-1/#snap-axis
 enum class SnapAxis : unsigned {
   kBoth,
@@ -85,8 +87,8 @@
   SnapAlignment alignment_inline;
 };
 
-// We should really use gfx::RangeF. However, it includes windows.h which would
-// bring in complexity to the compilation. https://crbug.com/855717
+// TODO(sunyunjia): Use gfx::RangeF as windows.h has already been removed from
+// range.h.
 class SnapVisibleRange {
  public:
   SnapVisibleRange() {}
@@ -196,9 +198,7 @@
     return !(*this == other);
   }
 
-  bool FindSnapPosition(const gfx::ScrollOffset& current_position,
-                        bool should_snap_on_x,
-                        bool should_snap_on_y,
+  bool FindSnapPosition(const SnapSelectionStrategy& strategy,
                         gfx::ScrollOffset* snap_position) const;
 
   void AddSnapAreaData(SnapAreaData snap_area_data);
@@ -222,8 +222,8 @@
   gfx::ScrollOffset proximity_range() const { return proximity_range_; }
 
  private:
-  // Finds the best SnapArea candidate that minimizes the distance between
-  // current and candidate positions, while satisfying two invariants:
+  // Finds the best SnapArea candidate that's optimal for the given selection
+  // strategy, while satisfying two invariants:
   // - |candidate.snap_offset| is within |cross_axis_snap_result|'s visible
   // range on |axis|.
   // - |cross_axis_snap_result.snap_offset| is within |candidate|'s visible
@@ -234,7 +234,7 @@
   // |snap_offset| and its visible range on the cross axis.
   base::Optional<SnapSearchResult> FindClosestValidArea(
       SearchAxis axis,
-      float current_offset,
+      const SnapSelectionStrategy& strategy,
       const SnapSearchResult& cross_axis_snap_result) const;
 
   // Returns all the info needed to snap at this area on the given axis,
diff --git a/cc/input/scroll_snap_data_unittest.cc b/cc/input/scroll_snap_data_unittest.cc
index d2347148..6f994d5 100644
--- a/cc/input/scroll_snap_data_unittest.cc
+++ b/cc/input/scroll_snap_data_unittest.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "cc/input/scroll_snap_data.h"
+#include "cc/input/snap_selection_strategy.h"
 
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -17,10 +18,12 @@
   SnapAreaData area(ScrollSnapAlign(SnapAlignment::kStart),
                     gfx::RectF(100, 150, 100, 100), false);
   container.AddSnapAreaData(area);
-  gfx::ScrollOffset current_position(0, 0);
+
   gfx::ScrollOffset snap_position;
-  EXPECT_TRUE(
-      container.FindSnapPosition(current_position, true, true, &snap_position));
+  std::unique_ptr<SnapSelectionStrategy> strategy =
+      SnapSelectionStrategy::CreateForEndPosition(gfx::ScrollOffset(0, 0), true,
+                                                  true);
+  EXPECT_TRUE(container.FindSnapPosition(*strategy, &snap_position));
   EXPECT_EQ(90, snap_position.x());
   EXPECT_EQ(140, snap_position.y());
 }
@@ -32,10 +35,12 @@
   SnapAreaData area(ScrollSnapAlign(SnapAlignment::kCenter),
                     gfx::RectF(100, 150, 100, 100), false);
   container.AddSnapAreaData(area);
-  gfx::ScrollOffset current_position(0, 0);
+
   gfx::ScrollOffset snap_position;
-  EXPECT_TRUE(
-      container.FindSnapPosition(current_position, true, true, &snap_position));
+  std::unique_ptr<SnapSelectionStrategy> strategy =
+      SnapSelectionStrategy::CreateForEndPosition(gfx::ScrollOffset(0, 0), true,
+                                                  true);
+  EXPECT_TRUE(container.FindSnapPosition(*strategy, &snap_position));
   EXPECT_EQ(40, snap_position.x());
   EXPECT_EQ(40, snap_position.y());
 }
@@ -47,10 +52,12 @@
   SnapAreaData area(ScrollSnapAlign(SnapAlignment::kEnd),
                     gfx::RectF(150, 200, 100, 100), false);
   container.AddSnapAreaData(area);
-  gfx::ScrollOffset current_position(0, 0);
+
   gfx::ScrollOffset snap_position;
-  EXPECT_TRUE(
-      container.FindSnapPosition(current_position, true, true, &snap_position));
+  std::unique_ptr<SnapSelectionStrategy> strategy =
+      SnapSelectionStrategy::CreateForEndPosition(gfx::ScrollOffset(0, 0), true,
+                                                  true);
+  EXPECT_TRUE(container.FindSnapPosition(*strategy, &snap_position));
   EXPECT_EQ(40, snap_position.x());
   EXPECT_EQ(90, snap_position.y());
 }
@@ -62,10 +69,12 @@
   SnapAreaData area(ScrollSnapAlign(SnapAlignment::kEnd, SnapAlignment::kStart),
                     gfx::RectF(200, 0, 100, 100), false);
   container.AddSnapAreaData(area);
-  gfx::ScrollOffset current_position(50, 50);
+
   gfx::ScrollOffset snap_position;
-  EXPECT_TRUE(
-      container.FindSnapPosition(current_position, true, true, &snap_position));
+  std::unique_ptr<SnapSelectionStrategy> strategy =
+      SnapSelectionStrategy::CreateForEndPosition(gfx::ScrollOffset(50, 50),
+                                                  true, true);
+  EXPECT_TRUE(container.FindSnapPosition(*strategy, &snap_position));
   // Aligning to start on x would lead the scroll offset larger than max, and
   // aligning to end on y would lead the scroll offset smaller than zero. So
   // we expect these are clamped.
@@ -85,13 +94,15 @@
       gfx::RectF(0, 70, 150, 150), false);
   SnapAreaData snap_on_both(ScrollSnapAlign(SnapAlignment::kStart),
                             gfx::RectF(50, 150, 150, 150), false);
-  gfx::ScrollOffset current_position(100, 100);
   container.AddSnapAreaData(snap_x_only);
   container.AddSnapAreaData(snap_y_only);
   container.AddSnapAreaData(snap_on_both);
+
   gfx::ScrollOffset snap_position;
-  EXPECT_TRUE(
-      container.FindSnapPosition(current_position, true, true, &snap_position));
+  std::unique_ptr<SnapSelectionStrategy> strategy =
+      SnapSelectionStrategy::CreateForEndPosition(gfx::ScrollOffset(100, 100),
+                                                  true, true);
+  EXPECT_TRUE(container.FindSnapPosition(*strategy, &snap_position));
   EXPECT_EQ(80, snap_position.x());
   EXPECT_EQ(70, snap_position.y());
 }
@@ -108,13 +119,15 @@
       gfx::RectF(0, 70, 150, 150), false);
   SnapAreaData snap_on_both(ScrollSnapAlign(SnapAlignment::kStart),
                             gfx::RectF(50, 150, 150, 150), false);
-  gfx::ScrollOffset current_position(40, 120);
+
   container.AddSnapAreaData(snap_x_only);
   container.AddSnapAreaData(snap_y_only);
   container.AddSnapAreaData(snap_on_both);
   gfx::ScrollOffset snap_position;
-  EXPECT_TRUE(
-      container.FindSnapPosition(current_position, true, true, &snap_position));
+  std::unique_ptr<SnapSelectionStrategy> strategy =
+      SnapSelectionStrategy::CreateForEndPosition(gfx::ScrollOffset(40, 120),
+                                                  true, true);
+  EXPECT_TRUE(container.FindSnapPosition(*strategy, &snap_position));
   EXPECT_EQ(50, snap_position.x());
   EXPECT_EQ(150, snap_position.y());
 }
@@ -129,12 +142,14 @@
   SnapAreaData snap_y_only(
       ScrollSnapAlign(SnapAlignment::kStart, SnapAlignment::kNone),
       gfx::RectF(0, 70, 150, 150), false);
-  gfx::ScrollOffset current_position(100, 100);
   container.AddSnapAreaData(snap_x_only);
   container.AddSnapAreaData(snap_y_only);
+
   gfx::ScrollOffset snap_position;
-  EXPECT_TRUE(container.FindSnapPosition(current_position, true, false,
-                                         &snap_position));
+  std::unique_ptr<SnapSelectionStrategy> strategy =
+      SnapSelectionStrategy::CreateForEndPosition(gfx::ScrollOffset(100, 100),
+                                                  true, false);
+  EXPECT_TRUE(container.FindSnapPosition(*strategy, &snap_position));
   EXPECT_EQ(80, snap_position.x());
   EXPECT_EQ(100, snap_position.y());
 }
@@ -149,19 +164,20 @@
   SnapAreaData snap_y_only(
       ScrollSnapAlign(SnapAlignment::kStart, SnapAlignment::kNone),
       gfx::RectF(400, 300, 100, 100), false);
-  gfx::ScrollOffset current_position(0, 0);
+
   container.AddSnapAreaData(snap_x_only);
   container.AddSnapAreaData(snap_y_only);
   gfx::ScrollOffset snap_position;
-  EXPECT_FALSE(
-      container.FindSnapPosition(current_position, true, true, &snap_position));
+  std::unique_ptr<SnapSelectionStrategy> strategy =
+      SnapSelectionStrategy::CreateForEndPosition(gfx::ScrollOffset(0, 0), true,
+                                                  true);
+  EXPECT_FALSE(container.FindSnapPosition(*strategy, &snap_position));
 }
 
 TEST_F(ScrollSnapDataTest, SnapOnClosestAxisFirstIfVisibilityConflicts) {
   SnapContainerData container(
       ScrollSnapType(false, SnapAxis::kBoth, SnapStrictness::kMandatory),
       gfx::RectF(0, 0, 200, 200), gfx::ScrollOffset(600, 800));
-  gfx::ScrollOffset current_position(0, 0);
 
   // Both the areas are currently visible.
   // However, if we snap to them on x and y independently, none is visible after
@@ -180,9 +196,12 @@
   container.AddSnapAreaData(snap_x);
   container.AddSnapAreaData(snap_y1);
   container.AddSnapAreaData(snap_y2);
+
   gfx::ScrollOffset snap_position;
-  EXPECT_TRUE(
-      container.FindSnapPosition(current_position, true, true, &snap_position));
+  std::unique_ptr<SnapSelectionStrategy> strategy =
+      SnapSelectionStrategy::CreateForEndPosition(gfx::ScrollOffset(0, 0), true,
+                                                  true);
+  EXPECT_TRUE(container.FindSnapPosition(*strategy, &snap_position));
   EXPECT_EQ(150, snap_position.x());
   EXPECT_EQ(80, snap_position.y());
 }
@@ -193,13 +212,15 @@
       gfx::RectF(0, 0, 200, 200), gfx::ScrollOffset(600, 800));
   container.set_proximity_range(gfx::ScrollOffset(50, 50));
 
-  gfx::ScrollOffset current_position(100, 100);
   SnapAreaData area(ScrollSnapAlign(SnapAlignment::kStart),
                     gfx::RectF(80, 160, 100, 100), false);
   container.AddSnapAreaData(area);
+
   gfx::ScrollOffset snap_position;
-  EXPECT_TRUE(
-      container.FindSnapPosition(current_position, true, true, &snap_position));
+  std::unique_ptr<SnapSelectionStrategy> strategy =
+      SnapSelectionStrategy::CreateForEndPosition(gfx::ScrollOffset(100, 100),
+                                                  true, true);
+  EXPECT_TRUE(container.FindSnapPosition(*strategy, &snap_position));
 
   // The snap position on x, 80, is within the proximity range of [50, 150].
   // However, the snap position on y, 160, is outside the proximity range of
diff --git a/cc/input/snap_fling_controller.h b/cc/input/snap_fling_controller.h
index 20f3056..eb07106 100644
--- a/cc/input/snap_fling_controller.h
+++ b/cc/input/snap_fling_controller.h
@@ -24,8 +24,8 @@
 class SnapFlingClient {
  public:
   virtual bool GetSnapFlingInfo(const gfx::Vector2dF& natural_displacement,
-                                gfx::Vector2dF* out_initial_offset,
-                                gfx::Vector2dF* out_target_offset) const = 0;
+                                gfx::Vector2dF* out_initial_position,
+                                gfx::Vector2dF* out_target_position) const = 0;
   virtual gfx::Vector2dF ScrollByForSnapFling(const gfx::Vector2dF& delta) = 0;
   virtual void ScrollEndForSnapFling() = 0;
   virtual void RequestAnimationForSnapFling() = 0;
diff --git a/cc/input/snap_selection_strategy.cc b/cc/input/snap_selection_strategy.cc
new file mode 100644
index 0000000..ce0f2655
--- /dev/null
+++ b/cc/input/snap_selection_strategy.cc
@@ -0,0 +1,151 @@
+// 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 "cc/input/snap_selection_strategy.h"
+
+namespace cc {
+
+std::unique_ptr<SnapSelectionStrategy>
+SnapSelectionStrategy::CreateForEndPosition(
+    const gfx::ScrollOffset& current_position,
+    bool scrolled_x,
+    bool scrolled_y) {
+  return std::make_unique<EndPositionStrategy>(current_position, scrolled_x,
+                                               scrolled_y);
+}
+
+std::unique_ptr<SnapSelectionStrategy>
+SnapSelectionStrategy::CreateForDirection(gfx::ScrollOffset current_position,
+                                          gfx::ScrollOffset step) {
+  return std::make_unique<DirectionStrategy>(current_position, step);
+}
+
+std::unique_ptr<SnapSelectionStrategy>
+SnapSelectionStrategy::CreateForEndAndDirection(
+    gfx::ScrollOffset current_position,
+    gfx::ScrollOffset displacement) {
+  return std::make_unique<EndAndDirectionStrategy>(current_position,
+                                                   displacement);
+}
+
+bool EndPositionStrategy::ShouldSnapOnX() const {
+  return scrolled_x_;
+}
+
+bool EndPositionStrategy::ShouldSnapOnY() const {
+  return scrolled_y_;
+}
+
+gfx::ScrollOffset EndPositionStrategy::intended_position() const {
+  return current_position_;
+}
+
+gfx::ScrollOffset EndPositionStrategy::base_position() const {
+  return current_position_;
+}
+
+// |position| is unused in this method.
+bool EndPositionStrategy::IsValidSnapPosition(SearchAxis axis,
+                                              float position) const {
+  return (scrolled_x_ && axis == SearchAxis::kX) ||
+         (scrolled_y_ && axis == SearchAxis::kY);
+}
+
+const base::Optional<SnapSearchResult>& EndPositionStrategy::PickBestResult(
+    const base::Optional<SnapSearchResult>& closest,
+    const base::Optional<SnapSearchResult>& covering) const {
+  return covering.has_value() ? covering : closest;
+}
+
+bool DirectionStrategy::ShouldSnapOnX() const {
+  return step_.x() != 0;
+}
+
+bool DirectionStrategy::ShouldSnapOnY() const {
+  return step_.y() != 0;
+}
+
+gfx::ScrollOffset DirectionStrategy::intended_position() const {
+  return current_position_ + step_;
+}
+
+gfx::ScrollOffset DirectionStrategy::base_position() const {
+  return current_position_;
+}
+
+bool DirectionStrategy::IsValidSnapPosition(SearchAxis axis,
+                                            float position) const {
+  if (axis == SearchAxis::kX) {
+    return (step_.x() > 0 &&
+            position > current_position_.x()) ||  // "Right" arrow
+           (step_.x() < 0 && position < current_position_.x());  // "Left" arrow
+  } else {
+    return (step_.y() > 0 &&
+            position > current_position_.y()) ||                 // "Down" arrow
+           (step_.y() < 0 && position < current_position_.y());  // "Up" arrow
+  }
+}
+
+const base::Optional<SnapSearchResult>& DirectionStrategy::PickBestResult(
+    const base::Optional<SnapSearchResult>& closest,
+    const base::Optional<SnapSearchResult>& covering) const {
+  // We choose the |closest| result only if the default landing position (using
+  // the default step) is not a valid snap position (not making a snap area
+  // covering the snapport), or the |closest| is closer than the default landing
+  // position.
+  if (!closest.has_value())
+    return covering;
+  if (!covering.has_value())
+    return closest;
+
+  // "Right" or "Down" arrow.
+  if ((step_.x() > 0 || step_.y() > 0) &&
+      closest.value().snap_offset() < covering.value().snap_offset()) {
+    return closest;
+  }
+  // "Left" or "Up" arrow.
+  if ((step_.x() < 0 || step_.y() < 0) &&
+      closest.value().snap_offset() > covering.value().snap_offset()) {
+    return closest;
+  }
+
+  return covering;
+}
+
+bool EndAndDirectionStrategy::ShouldSnapOnX() const {
+  return displacement_.x() != 0;
+}
+
+bool EndAndDirectionStrategy::ShouldSnapOnY() const {
+  return displacement_.y() != 0;
+}
+
+gfx::ScrollOffset EndAndDirectionStrategy::intended_position() const {
+  return current_position_ + displacement_;
+}
+
+gfx::ScrollOffset EndAndDirectionStrategy::base_position() const {
+  return current_position_ + displacement_;
+}
+
+bool EndAndDirectionStrategy::IsValidSnapPosition(SearchAxis axis,
+                                                  float position) const {
+  if (axis == SearchAxis::kX) {
+    return (displacement_.x() > 0 &&
+            position > current_position_.x()) ||  // Right
+           (displacement_.x() < 0 && position < current_position_.x());  // Left
+  } else {
+    return (displacement_.y() > 0 &&
+            position > current_position_.y()) ||                         // Down
+           (displacement_.y() < 0 && position < current_position_.y());  // Up
+  }
+}
+
+const base::Optional<SnapSearchResult>& EndAndDirectionStrategy::PickBestResult(
+    const base::Optional<SnapSearchResult>& closest,
+    const base::Optional<SnapSearchResult>& covering) const {
+  return covering.has_value() ? covering : closest;
+}
+
+}  // namespace cc
diff --git a/cc/input/snap_selection_strategy.h b/cc/input/snap_selection_strategy.h
new file mode 100644
index 0000000..cebc63e
--- /dev/null
+++ b/cc/input/snap_selection_strategy.h
@@ -0,0 +1,170 @@
+// 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 CC_INPUT_SNAP_SELECTION_STRATEGY_H_
+#define CC_INPUT_SNAP_SELECTION_STRATEGY_H_
+
+#include "scroll_snap_data.h"
+
+#include <memory>
+
+namespace cc {
+
+// This class represents an abstract strategy that decide which snap selection
+// should be considered valid. There are concrete implementations for three core
+// scrolling types: scroll with end position only, scroll with direction only,
+// and scroll with end position and direction.
+class CC_EXPORT SnapSelectionStrategy {
+ public:
+  SnapSelectionStrategy() = default;
+  virtual ~SnapSelectionStrategy() = default;
+  static std::unique_ptr<SnapSelectionStrategy> CreateForEndPosition(
+      const gfx::ScrollOffset& current_position,
+      bool scrolled_x,
+      bool scrolled_y);
+  static std::unique_ptr<SnapSelectionStrategy> CreateForDirection(
+      gfx::ScrollOffset current_position,
+      gfx::ScrollOffset step);
+  static std::unique_ptr<SnapSelectionStrategy> CreateForEndAndDirection(
+      gfx::ScrollOffset current_position,
+      gfx::ScrollOffset displacement);
+
+  // Returns whether it's snappable on x or y depending on the scroll performed.
+  virtual bool ShouldSnapOnX() const = 0;
+  virtual bool ShouldSnapOnY() const = 0;
+
+  // Returns the end position of the scroll if no snap interferes.
+  virtual gfx::ScrollOffset intended_position() const = 0;
+  // Returns the scroll position from which the snap position should minimize
+  // its distance.
+  virtual gfx::ScrollOffset base_position() const = 0;
+  // Returns the current scroll position of the snap container.
+  const gfx::ScrollOffset& current_position() const {
+    return current_position_;
+  }
+
+  // Returns true if the selection strategy considers the given snap offset
+  // valid for the current axis.
+  virtual bool IsValidSnapPosition(SearchAxis axis, float position) const = 0;
+
+  // Returns the best result according to snap selection strategy. This method
+  // is called at the end of selection process to make the final decision.
+  //
+  // -closest: snap search result representing closest match.
+  // -covering: snap search result representing the original target if it makes
+  //            a snaparea covering the snapport.
+  virtual const base::Optional<SnapSearchResult>& PickBestResult(
+      const base::Optional<SnapSearchResult>& closest,
+      const base::Optional<SnapSearchResult>& covering) const = 0;
+
+ protected:
+  explicit SnapSelectionStrategy(const gfx::ScrollOffset& current_position)
+      : current_position_(current_position) {}
+  const gfx::ScrollOffset current_position_;
+};
+
+// Examples for intended end position scrolls include
+// - a panning gesture, released without momentum
+// - manupulating the scrollbar "thumb" explicitly
+// - programmatically scrolling via APIs such as scrollTo()
+// - tabbing through the document's focusable elements
+// - navigating to an anchor within the page
+// - homing operations such as the Home/End keys
+// For this type of scrolls, we want to
+// * Minimize the distance between the snap position and the end position.
+// * Return the end position if that makes a snap area covers the snapport.
+class EndPositionStrategy : public SnapSelectionStrategy {
+ public:
+  EndPositionStrategy(const gfx::ScrollOffset& current_position,
+                      bool scrolled_x,
+                      bool scrolled_y)
+      : SnapSelectionStrategy(current_position),
+        scrolled_x_(scrolled_x),
+        scrolled_y_(scrolled_y) {}
+  ~EndPositionStrategy() override = default;
+
+  bool ShouldSnapOnX() const override;
+  bool ShouldSnapOnY() const override;
+
+  gfx::ScrollOffset intended_position() const override;
+  gfx::ScrollOffset base_position() const override;
+
+  bool IsValidSnapPosition(SearchAxis axis, float position) const override;
+
+  const base::Optional<SnapSearchResult>& PickBestResult(
+      const base::Optional<SnapSearchResult>& closest,
+      const base::Optional<SnapSearchResult>& covering) const override;
+
+ private:
+  // Whether the x axis and y axis have been scrolled in this scroll gesture.
+  const bool scrolled_x_;
+  const bool scrolled_y_;
+};
+
+// Examples for intended direction scrolls include
+// - pressing an arrow key on the keyboard
+// - a swiping gesture interpreted as a fixed (rather than inertial) scroll
+// For this type of scrolls, we want to
+// * Minimize the distance between the snap position and the starting position,
+//   so that we stop at the first snap position in that direction.
+// * Return the default intended position (using the default step) if that makes
+//   a snap area covers the snapport.
+class DirectionStrategy : public SnapSelectionStrategy {
+ public:
+  DirectionStrategy(const gfx::ScrollOffset& current_position,
+                    const gfx::ScrollOffset& step)
+      : SnapSelectionStrategy(current_position), step_(step) {}
+  ~DirectionStrategy() override = default;
+
+  bool ShouldSnapOnX() const override;
+  bool ShouldSnapOnY() const override;
+
+  gfx::ScrollOffset intended_position() const override;
+  gfx::ScrollOffset base_position() const override;
+
+  bool IsValidSnapPosition(SearchAxis axis, float position) const override;
+
+  const base::Optional<SnapSearchResult>& PickBestResult(
+      const base::Optional<SnapSearchResult>& closest,
+      const base::Optional<SnapSearchResult>& covering) const override;
+
+ private:
+  // The default step for this DirectionStrategy.
+  const gfx::ScrollOffset step_;
+};
+
+// Examples for intended direction and end position scrolls include
+// - a “fling” gesture, interpreted with momentum
+// - programmatically scrolling via APIs such as scrollBy()
+// - paging operations such as the PgUp/PgDn keys (or equivalent operations on
+//   the scrollbar)
+// For this type of scrolls, we want to
+// * Minimize the distance between the snap position and the end position.
+// * Return the end position if that makes a snap area covers the snapport.
+class EndAndDirectionStrategy : public SnapSelectionStrategy {
+ public:
+  EndAndDirectionStrategy(const gfx::ScrollOffset& current_position,
+                          const gfx::ScrollOffset& displacement)
+      : SnapSelectionStrategy(current_position), displacement_(displacement) {}
+  ~EndAndDirectionStrategy() override = default;
+
+  bool ShouldSnapOnX() const override;
+  bool ShouldSnapOnY() const override;
+
+  gfx::ScrollOffset intended_position() const override;
+  gfx::ScrollOffset base_position() const override;
+
+  bool IsValidSnapPosition(SearchAxis axis, float position) const override;
+
+  const base::Optional<SnapSearchResult>& PickBestResult(
+      const base::Optional<SnapSearchResult>& closest,
+      const base::Optional<SnapSearchResult>& covering) const override;
+
+ private:
+  const gfx::ScrollOffset displacement_;
+};
+
+}  // namespace cc
+
+#endif  // CC_INPUT_SNAP_SELECTION_STRATEGY_H_
diff --git a/cc/layers/heads_up_display_layer_impl.cc b/cc/layers/heads_up_display_layer_impl.cc
index 1c4e204..7dcb64d 100644
--- a/cc/layers/heads_up_display_layer_impl.cc
+++ b/cc/layers/heads_up_display_layer_impl.cc
@@ -16,7 +16,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/trace_event/process_memory_dump.h"
 #include "base/trace_event/trace_event.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "cc/debug/debug_colors.h"
 #include "cc/raster/scoped_gpu_raster.h"
 #include "cc/resources/memory_history.h"
diff --git a/cc/layers/layer_impl.cc b/cc/layers/layer_impl.cc
index 3a4bf453..7be0727 100644
--- a/cc/layers/layer_impl.cc
+++ b/cc/layers/layer_impl.cc
@@ -14,7 +14,7 @@
 #include "base/numerics/safe_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "base/trace_event/trace_event.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "cc/base/math_util.h"
 #include "cc/base/simple_enclosed_region.h"
 #include "cc/benchmarks/micro_benchmark_impl.h"
diff --git a/cc/layers/picture_layer_impl.cc b/cc/layers/picture_layer_impl.cc
index 35254eba..cd75db21 100644
--- a/cc/layers/picture_layer_impl.cc
+++ b/cc/layers/picture_layer_impl.cc
@@ -15,7 +15,7 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/no_destructor.h"
 #include "base/time/time.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "build/build_config.h"
 #include "cc/base/math_util.h"
 #include "cc/benchmarks/micro_benchmark_impl.h"
diff --git a/cc/layers/surface_layer_impl.cc b/cc/layers/surface_layer_impl.cc
index 9fbe46c..4a05173a 100644
--- a/cc/layers/surface_layer_impl.cc
+++ b/cc/layers/surface_layer_impl.cc
@@ -6,7 +6,7 @@
 
 #include <stdint.h>
 
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "cc/debug/debug_colors.h"
 #include "cc/layers/append_quads_data.h"
 #include "cc/trees/layer_tree_impl.h"
diff --git a/cc/paint/decoded_draw_image.h b/cc/paint/decoded_draw_image.h
index 3079fc4..63bc1ca 100644
--- a/cc/paint/decoded_draw_image.h
+++ b/cc/paint/decoded_draw_image.h
@@ -17,6 +17,11 @@
 
 namespace cc {
 
+// A DecodedDrawImage is a finalized (decoded, scaled, colorspace converted,
+// possibly uploaded) version of a DrawImage.  When this image is going to
+// be serialized, it uses the transfer cache entry id (see the function
+// PaintOpWriter::Write(DrawImage&) constructor.  When this image is going
+// to be rastered directly, it uses the SkImage constructor.
 class CC_PAINT_EXPORT DecodedDrawImage {
  public:
   DecodedDrawImage(sk_sp<const SkImage> image,
diff --git a/cc/paint/display_item_list.cc b/cc/paint/display_item_list.cc
index f2e5259..cacbe80e 100644
--- a/cc/paint/display_item_list.cc
+++ b/cc/paint/display_item_list.cc
@@ -9,7 +9,7 @@
 #include <string>
 
 #include "base/trace_event/trace_event.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "cc/base/math_util.h"
 #include "cc/debug/picture_debug_util.h"
 #include "cc/paint/solid_color_analyzer.h"
diff --git a/cc/paint/display_item_list_unittest.cc b/cc/paint/display_item_list_unittest.cc
index 5bcca13..0abe50d53 100644
--- a/cc/paint/display_item_list_unittest.cc
+++ b/cc/paint/display_item_list_unittest.cc
@@ -8,7 +8,7 @@
 
 #include <vector>
 
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "base/values.h"
 #include "cc/paint/filter_operation.h"
 #include "cc/paint/filter_operations.h"
diff --git a/cc/paint/draw_image.h b/cc/paint/draw_image.h
index 81c45d1..4e8fe7f 100644
--- a/cc/paint/draw_image.h
+++ b/cc/paint/draw_image.h
@@ -18,6 +18,10 @@
 
 namespace cc {
 
+// A DrawImage is a logical snapshot in time and space of a PaintImage.  It
+// includes decisions about scaling, animation frame, final colorspace, etc.
+// It has not been decoded yet.  DrawImage turns into DecodedDrawImage via
+// ImageDecodeCache::GetDecodedImageForDraw during playback.
 class CC_PAINT_EXPORT DrawImage {
  public:
   DrawImage();
diff --git a/cc/paint/filter_operation.cc b/cc/paint/filter_operation.cc
index 221dd572..3357afb 100644
--- a/cc/paint/filter_operation.cc
+++ b/cc/paint/filter_operation.cc
@@ -9,7 +9,7 @@
 #include "cc/paint/filter_operation.h"
 
 #include "base/numerics/ranges.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "base/values.h"
 #include "cc/base/math_util.h"
 #include "ui/gfx/animation/tween.h"
diff --git a/cc/paint/filter_operations.cc b/cc/paint/filter_operations.cc
index cc2dcc5..a7e7312c3 100644
--- a/cc/paint/filter_operations.cc
+++ b/cc/paint/filter_operations.cc
@@ -9,7 +9,7 @@
 #include <cmath>
 #include <numeric>
 
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "base/values.h"
 #include "cc/paint/filter_operation.h"
 #include "ui/gfx/geometry/rect.h"
diff --git a/cc/paint/paint_image.h b/cc/paint/paint_image.h
index aa69df05..0684c2d8 100644
--- a/cc/paint/paint_image.h
+++ b/cc/paint/paint_image.h
@@ -21,9 +21,23 @@
 class PaintOpBuffer;
 using PaintRecord = PaintOpBuffer;
 
-// A representation of an image for the compositor.
-// Note that aside from default construction, it can only be constructed using a
-// PaintImageBuilder, or copied/moved into using operator=.
+// A representation of an image for the compositor.  This is the most abstract
+// form of images, and represents what is known at paint time.  Note that aside
+// from default construction, it can only be constructed using a
+// PaintImageBuilder, or copied/moved into using operator=.  PaintImage can
+// be backed by different kinds of content, such as a lazy generator, a paint
+// record, a bitmap, or a texture.
+//
+// If backed by a generator, this image may not be decoded and information like
+// the animation frame, the target colorspace, or the scale at which it will be
+// used are not known yet.  A DrawImage is a PaintImage with those decisions
+// known but that might not have been decoded yet.  A DecodedDrawImage is a
+// DrawImage that has been decoded/scaled/uploaded with all of those parameters
+// applied.
+//
+// The PaintImage -> DrawImage -> DecodedDrawImage -> PaintImage (via SkImage)
+// path can be used to create a PaintImage that is snapshotted at a particular
+// scale or animation frame.
 class CC_PAINT_EXPORT PaintImage {
  public:
   using Id = int;
diff --git a/cc/raster/bitmap_raster_buffer_provider.cc b/cc/raster/bitmap_raster_buffer_provider.cc
index 1e4e21bb..fc98124 100644
--- a/cc/raster/bitmap_raster_buffer_provider.cc
+++ b/cc/raster/bitmap_raster_buffer_provider.cc
@@ -13,7 +13,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/trace_event/process_memory_dump.h"
 #include "base/trace_event/trace_event.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "cc/raster/raster_source.h"
 #include "cc/trees/layer_tree_frame_sink.h"
 #include "components/viz/common/resources/bitmap_allocation.h"
diff --git a/cc/raster/zero_copy_raster_buffer_provider.cc b/cc/raster/zero_copy_raster_buffer_provider.cc
index 21010d7..7007959 100644
--- a/cc/raster/zero_copy_raster_buffer_provider.cc
+++ b/cc/raster/zero_copy_raster_buffer_provider.cc
@@ -10,7 +10,7 @@
 
 #include "base/macros.h"
 #include "base/trace_event/trace_event.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "cc/resources/resource_pool.h"
 #include "components/viz/client/client_resource_provider.h"
 #include "components/viz/common/gpu/context_provider.h"
diff --git a/cc/scheduler/begin_frame_tracker.h b/cc/scheduler/begin_frame_tracker.h
index 33d124ad7..e80f738 100644
--- a/cc/scheduler/begin_frame_tracker.h
+++ b/cc/scheduler/begin_frame_tracker.h
@@ -10,7 +10,7 @@
 
 #include "base/location.h"
 #include "base/trace_event/trace_event.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "cc/cc_export.h"
 #include "components/viz/common/frame_sinks/begin_frame_args.h"
 
diff --git a/cc/scheduler/scheduler.cc b/cc/scheduler/scheduler.cc
index fcdbde8..d448b54 100644
--- a/cc/scheduler/scheduler.cc
+++ b/cc/scheduler/scheduler.cc
@@ -10,7 +10,7 @@
 #include "base/logging.h"
 #include "base/single_thread_task_runner.h"
 #include "base/trace_event/trace_event.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "cc/base/devtools_instrumentation.h"
 #include "cc/scheduler/compositor_timing_history.h"
 #include "components/viz/common/frame_sinks/delay_based_time_source.h"
diff --git a/cc/scheduler/scheduler_settings.cc b/cc/scheduler/scheduler_settings.cc
index de38d19a..9e488fc87 100644
--- a/cc/scheduler/scheduler_settings.cc
+++ b/cc/scheduler/scheduler_settings.cc
@@ -4,7 +4,7 @@
 
 #include "cc/scheduler/scheduler_settings.h"
 
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 
 namespace cc {
 
diff --git a/cc/scheduler/scheduler_state_machine.cc b/cc/scheduler/scheduler_state_machine.cc
index 327e907..f499423eb 100644
--- a/cc/scheduler/scheduler_state_machine.cc
+++ b/cc/scheduler/scheduler_state_machine.cc
@@ -7,7 +7,7 @@
 #include "base/format_macros.h"
 #include "base/logging.h"
 #include "base/trace_event/trace_event.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "base/values.h"
 
 namespace cc {
diff --git a/cc/test/mock_layer_client.h b/cc/test/mock_layer_client.h
index 2e4c6dd..e5ab750d 100644
--- a/cc/test/mock_layer_client.h
+++ b/cc/test/mock_layer_client.h
@@ -6,8 +6,8 @@
 #define CC_TEST_MOCK_LAYER_CLIENT_H_
 
 #include "base/macros.h"
-#include "base/trace_event/trace_event_argument.h"
 #include "base/trace_event/trace_event_impl.h"
+#include "base/trace_event/traced_value.h"
 #include "cc/layers/layer_client.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
diff --git a/cc/tiles/gpu_image_decode_cache.cc b/cc/tiles/gpu_image_decode_cache.cc
index 480a9bb..4bcab88e 100644
--- a/cc/tiles/gpu_image_decode_cache.cc
+++ b/cc/tiles/gpu_image_decode_cache.cc
@@ -792,12 +792,10 @@
     // Ref image and create a upload and decode tasks. We will release this ref
     // in UploadTaskCompleted.
     RefImage(draw_image, cache_key);
-    auto decode_task =
-        image_data->is_bitmap_backed
-            ? nullptr
-            : GetImageDecodeTaskAndRef(draw_image, tracing_info, task_type);
     task = base::MakeRefCounted<ImageUploadTaskImpl>(
-        this, draw_image, std::move(decode_task), tracing_info);
+        this, draw_image,
+        GetImageDecodeTaskAndRef(draw_image, tracing_info, task_type),
+        tracing_info);
     image_data->upload.task = task;
   } else {
     task = GetImageDecodeTaskAndRef(draw_image, tracing_info, task_type);
@@ -1122,11 +1120,8 @@
   DCHECK(image_data);
   DCHECK(image_data->is_budgeted) << "Must budget an image for pre-decoding";
 
-  if (image_data->is_bitmap_backed) {
-    RefImageDecode(draw_image, cache_key);
+  if (image_data->is_bitmap_backed)
     DecodeImageIfNecessary(draw_image, image_data, TaskType::kInRaster);
-  }
-
   UploadImageIfNecessary(draw_image, image_data);
 }
 
@@ -1192,8 +1187,8 @@
 
   ImageData* image_data = GetImageDataForDrawImage(draw_image, cache_key);
   DCHECK(image_data);
-  DCHECK(!image_data->is_bitmap_backed);
-  if (image_data->decode.is_locked()) {
+  // No decode is necessary for bitmap backed images.
+  if (image_data->decode.is_locked() || image_data->is_bitmap_backed) {
     // We should never be creating a decode task for a not budgeted image.
     DCHECK(image_data->is_budgeted);
     // We should never be creating a decode for an already-uploaded image.
diff --git a/cc/tiles/gpu_image_decode_cache_unittest.cc b/cc/tiles/gpu_image_decode_cache_unittest.cc
index 25758ca..3ba15f4 100644
--- a/cc/tiles/gpu_image_decode_cache_unittest.cc
+++ b/cc/tiles/gpu_image_decode_cache_unittest.cc
@@ -2271,6 +2271,27 @@
   cache->UnrefImage(draw_image);
 }
 
+TEST_P(GpuImageDecodeCacheTest, NonLazyImageUploadTaskCancelled) {
+  auto cache = CreateCache();
+  bool is_decomposable = true;
+  SkFilterQuality quality = kHigh_SkFilterQuality;
+
+  PaintImage image = CreateBitmapImageInternal(gfx::Size(10, 10));
+  DrawImage draw_image(image, SkIRect::MakeWH(image.width(), image.height()),
+                       quality,
+                       CreateMatrix(SkSize::Make(1.0f, 1.0f), is_decomposable),
+                       PaintImage::kDefaultFrameIndex, DefaultColorSpace());
+  auto result =
+      cache->GetTaskForImageAndRef(draw_image, ImageDecodeCache::TracingInfo());
+  EXPECT_TRUE(result.need_unref);
+  EXPECT_TRUE(result.task);
+  EXPECT_TRUE(result.task->dependencies().empty());
+  TestTileTaskRunner::CancelTask(result.task.get());
+  TestTileTaskRunner::CompleteTask(result.task.get());
+
+  cache->UnrefImage(draw_image);
+}
+
 TEST_P(GpuImageDecodeCacheTest, NonLazyImageLargeImageColorConverted) {
   auto cache = CreateCache();
   const bool should_cache_sw_image =
diff --git a/cc/tiles/picture_layer_tiling.cc b/cc/tiles/picture_layer_tiling.cc
index 13b5f93..c16c0bb2 100644
--- a/cc/tiles/picture_layer_tiling.cc
+++ b/cc/tiles/picture_layer_tiling.cc
@@ -15,7 +15,7 @@
 #include "base/logging.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/trace_event/trace_event.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "cc/base/math_util.h"
 #include "cc/raster/raster_source.h"
 #include "cc/tiles/prioritized_tile.h"
diff --git a/cc/tiles/tile.cc b/cc/tiles/tile.cc
index db0ba9f..96962c8 100644
--- a/cc/tiles/tile.cc
+++ b/cc/tiles/tile.cc
@@ -10,7 +10,7 @@
 
 #include "base/numerics/safe_conversions.h"
 #include "base/trace_event/trace_event.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "cc/base/math_util.h"
 #include "cc/tiles/tile_manager.h"
 #include "components/viz/common/resources/resource_sizes.h"
diff --git a/cc/tiles/tile_draw_info.h b/cc/tiles/tile_draw_info.h
index aab93183..993fcdc1 100644
--- a/cc/tiles/tile_draw_info.h
+++ b/cc/tiles/tile_draw_info.h
@@ -7,7 +7,7 @@
 
 #include <memory>
 
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "cc/resources/resource_pool.h"
 #include "components/viz/common/resources/platform_color.h"
 #include "components/viz/common/resources/resource_format_utils.h"
diff --git a/cc/tiles/tile_manager.cc b/cc/tiles/tile_manager.cc
index 8f07672..e9b1a799 100644
--- a/cc/tiles/tile_manager.cc
+++ b/cc/tiles/tile_manager.cc
@@ -20,7 +20,7 @@
 #include "base/optional.h"
 #include "base/sys_info.h"
 #include "base/threading/thread_checker.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "cc/base/devtools_instrumentation.h"
 #include "cc/base/histograms.h"
 #include "cc/layers/picture_layer_impl.h"
diff --git a/cc/tiles/tile_priority.cc b/cc/tiles/tile_priority.cc
index 0efe51e..78981630 100644
--- a/cc/tiles/tile_priority.cc
+++ b/cc/tiles/tile_priority.cc
@@ -5,7 +5,7 @@
 #include "cc/tiles/tile_priority.h"
 
 #include "base/numerics/safe_conversions.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "base/values.h"
 #include "cc/base/math_util.h"
 
diff --git a/cc/tiles/tile_priority.h b/cc/tiles/tile_priority.h
index 15746de6..015b0c4 100644
--- a/cc/tiles/tile_priority.h
+++ b/cc/tiles/tile_priority.h
@@ -12,7 +12,7 @@
 #include <memory>
 #include <string>
 
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "cc/cc_export.h"
 
 namespace base {
diff --git a/cc/trees/clip_node.cc b/cc/trees/clip_node.cc
index c1a73a9..edeba2a 100644
--- a/cc/trees/clip_node.cc
+++ b/cc/trees/clip_node.cc
@@ -2,12 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/trace_event/trace_event_argument.h"
+#include "cc/trees/clip_node.h"
+
 #include "cc/base/math_util.h"
 #include "cc/layers/layer.h"
-#include "cc/trees/clip_node.h"
 #include "cc/trees/property_tree.h"
 
+#include "base/trace_event/traced_value.h"
+
 namespace cc {
 
 ClipNode::ClipNode()
diff --git a/cc/trees/clip_node.h b/cc/trees/clip_node.h
index 5620f9d..54e5547 100644
--- a/cc/trees/clip_node.h
+++ b/cc/trees/clip_node.h
@@ -9,6 +9,7 @@
 #include "base/optional.h"
 #include "cc/cc_export.h"
 #include "cc/trees/clip_expander.h"
+#include "cc/trees/property_tree.h"
 #include "ui/gfx/geometry/rect_f.h"
 
 namespace base {
diff --git a/cc/trees/effect_node.cc b/cc/trees/effect_node.cc
index f5bc5bb..7809564b 100644
--- a/cc/trees/effect_node.cc
+++ b/cc/trees/effect_node.cc
@@ -2,9 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/trace_event/trace_event_argument.h"
-#include "cc/layers/layer.h"
 #include "cc/trees/effect_node.h"
+#include "base/trace_event/traced_value.h"
+#include "cc/layers/layer.h"
 #include "cc/trees/property_tree.h"
 
 namespace cc {
diff --git a/cc/trees/element_id.cc b/cc/trees/element_id.cc
index 0603ba7..95c79a7b1 100644
--- a/cc/trees/element_id.cc
+++ b/cc/trees/element_id.cc
@@ -9,7 +9,7 @@
 #include <ostream>
 
 #include "base/strings/stringprintf.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "base/values.h"
 
 namespace cc {
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc
index 31c8a2a..26f0833f 100644
--- a/cc/trees/layer_tree_host.cc
+++ b/cc/trees/layer_tree_host.cc
@@ -28,7 +28,7 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/timer/elapsed_timer.h"
 #include "base/trace_event/trace_event.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "build/build_config.h"
 #include "cc/base/devtools_instrumentation.h"
 #include "cc/base/histograms.h"
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index d35b911..c346e58a 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -26,7 +26,7 @@
 #include "base/stl_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/sys_info.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "build/build_config.h"
 #include "cc/base/devtools_instrumentation.h"
 #include "cc/base/histograms.h"
@@ -40,6 +40,7 @@
 #include "cc/input/scroll_state.h"
 #include "cc/input/scrollbar_animation_controller.h"
 #include "cc/input/scroller_size_metrics.h"
+#include "cc/input/snap_selection_strategy.h"
 #include "cc/layers/append_quads_data.h"
 #include "cc/layers/effect_tree_layer_list_iterator.h"
 #include "cc/layers/heads_up_display_layer_impl.h"
@@ -4500,12 +4501,13 @@
   const SnapContainerData& data = scroll_node->snap_container_data.value();
   gfx::ScrollOffset current_position = GetVisualScrollOffset(*scroll_node);
 
+  std::unique_ptr<SnapSelectionStrategy> strategy =
+      SnapSelectionStrategy::CreateForEndPosition(
+          current_position, did_scroll_x_for_scroll_gesture_,
+          did_scroll_y_for_scroll_gesture_);
   gfx::ScrollOffset snap_position;
-  if (!data.FindSnapPosition(current_position, did_scroll_x_for_scroll_gesture_,
-                             did_scroll_y_for_scroll_gesture_,
-                             &snap_position)) {
+  if (!data.FindSnapPosition(*strategy, &snap_position))
     return false;
-  }
 
   gfx::Vector2dF delta =
       ScrollOffsetToVector2dF(snap_position - current_position);
@@ -4548,8 +4550,8 @@
 
 bool LayerTreeHostImpl::GetSnapFlingInfo(
     const gfx::Vector2dF& natural_displacement_in_viewport,
-    gfx::Vector2dF* out_initial_offset,
-    gfx::Vector2dF* out_target_offset) const {
+    gfx::Vector2dF* out_initial_position,
+    gfx::Vector2dF* out_target_position) const {
   const ScrollNode* scroll_node = CurrentlyScrollingNode();
   if (!scroll_node || !scroll_node->snap_container_data.has_value())
     return false;
@@ -4559,24 +4561,19 @@
   gfx::Vector2dF natural_displacement_in_content =
       gfx::ScaleVector2d(natural_displacement_in_viewport, 1.f / scale_factor);
 
-  *out_initial_offset =
-      ScrollOffsetToVector2dF(GetVisualScrollOffset(*scroll_node));
-
-  bool did_scroll_x = did_scroll_x_for_scroll_gesture_ ||
-                      natural_displacement_in_content.x() != 0;
-  bool did_scroll_y = did_scroll_y_for_scroll_gesture_ ||
-                      natural_displacement_in_content.y() != 0;
+  gfx::ScrollOffset current_offset = GetVisualScrollOffset(*scroll_node);
+  *out_initial_position = ScrollOffsetToVector2dF(current_offset);
 
   gfx::ScrollOffset snap_offset;
-  if (!data.FindSnapPosition(gfx::ScrollOffset(*out_initial_offset +
-                                               natural_displacement_in_content),
-                             did_scroll_x, did_scroll_y, &snap_offset)) {
+  std::unique_ptr<SnapSelectionStrategy> strategy =
+      SnapSelectionStrategy::CreateForEndAndDirection(
+          current_offset, gfx::ScrollOffset(natural_displacement_in_content));
+  if (!data.FindSnapPosition(*strategy, &snap_offset))
     return false;
-  }
 
-  *out_target_offset = ScrollOffsetToVector2dF(snap_offset);
-  out_target_offset->Scale(scale_factor);
-  out_initial_offset->Scale(scale_factor);
+  *out_target_position = ScrollOffsetToVector2dF(snap_offset);
+  out_target_position->Scale(scale_factor);
+  out_initial_position->Scale(scale_factor);
   return true;
 }
 
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h
index 9201173..fc8bfce 100644
--- a/cc/trees/layer_tree_host_impl.h
+++ b/cc/trees/layer_tree_host_impl.h
@@ -615,8 +615,8 @@
   gfx::ScrollOffset GetVisualScrollOffset(const ScrollNode& scroll_node) const;
 
   bool GetSnapFlingInfo(const gfx::Vector2dF& natural_displacement_in_viewport,
-                        gfx::Vector2dF* out_initial_offset,
-                        gfx::Vector2dF* out_target_offset) const override;
+                        gfx::Vector2dF* out_initial_position,
+                        gfx::Vector2dF* out_target_position) const override;
 
   // Returns the amount of delta that can be applied to scroll_node, taking
   // page scale into account.
diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc
index 21811597..e14b18d 100644
--- a/cc/trees/layer_tree_impl.cc
+++ b/cc/trees/layer_tree_impl.cc
@@ -20,7 +20,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/timer/elapsed_timer.h"
 #include "base/trace_event/trace_event.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "cc/base/devtools_instrumentation.h"
 #include "cc/base/histograms.h"
 #include "cc/base/math_util.h"
diff --git a/cc/trees/property_tree.cc b/cc/trees/property_tree.cc
index 84cdffaaf..00fbcb7 100644
--- a/cc/trees/property_tree.cc
+++ b/cc/trees/property_tree.cc
@@ -10,7 +10,7 @@
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
 #include "base/numerics/checked_math.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "cc/layers/layer_impl.h"
 #include "cc/trees/clip_node.h"
 #include "cc/trees/effect_node.h"
diff --git a/cc/trees/proxy_impl.cc b/cc/trees/proxy_impl.cc
index 6aff668..da6a46df 100644
--- a/cc/trees/proxy_impl.cc
+++ b/cc/trees/proxy_impl.cc
@@ -11,7 +11,7 @@
 
 #include "base/auto_reset.h"
 #include "base/trace_event/trace_event.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "cc/base/devtools_instrumentation.h"
 #include "cc/benchmarks/benchmark_instrumentation.h"
 #include "cc/input/browser_controls_offset_manager.h"
diff --git a/cc/trees/proxy_main.cc b/cc/trees/proxy_main.cc
index c89bd779..ea4ab70 100644
--- a/cc/trees/proxy_main.cc
+++ b/cc/trees/proxy_main.cc
@@ -8,7 +8,7 @@
 #include <string>
 
 #include "base/trace_event/trace_event.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "cc/base/completion_event.h"
 #include "cc/base/devtools_instrumentation.h"
 #include "cc/benchmarks/benchmark_instrumentation.h"
diff --git a/cc/trees/scroll_node.cc b/cc/trees/scroll_node.cc
index 9a19d4b4..069c731 100644
--- a/cc/trees/scroll_node.cc
+++ b/cc/trees/scroll_node.cc
@@ -2,13 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/trace_event/trace_event_argument.h"
+#include "cc/trees/scroll_node.h"
+
 #include "cc/base/math_util.h"
 #include "cc/input/main_thread_scrolling_reason.h"
 #include "cc/layers/layer.h"
 #include "cc/trees/element_id.h"
 #include "cc/trees/property_tree.h"
-#include "cc/trees/scroll_node.h"
+
+#include "base/trace_event/traced_value.h"
 
 namespace cc {
 
diff --git a/cc/trees/scroll_node.h b/cc/trees/scroll_node.h
index b96b696e..de9f934 100644
--- a/cc/trees/scroll_node.h
+++ b/cc/trees/scroll_node.h
@@ -10,6 +10,7 @@
 #include "cc/input/overscroll_behavior.h"
 #include "cc/input/scroll_snap_data.h"
 #include "cc/paint/filter_operations.h"
+#include "cc/trees/element_id.h"
 #include "ui/gfx/geometry/size.h"
 
 namespace base {
diff --git a/cc/trees/transform_node.cc b/cc/trees/transform_node.cc
index c43fd23..9964f16 100644
--- a/cc/trees/transform_node.cc
+++ b/cc/trees/transform_node.cc
@@ -2,11 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/trace_event/trace_event_argument.h"
+#include "cc/trees/transform_node.h"
+#include "base/trace_event/traced_value.h"
 #include "cc/base/math_util.h"
 #include "cc/layers/layer.h"
 #include "cc/trees/property_tree.h"
-#include "cc/trees/transform_node.h"
 #include "ui/gfx/geometry/point3_f.h"
 
 namespace cc {
diff --git a/cc/trees/transform_node.h b/cc/trees/transform_node.h
index 9318675..c8f8ebf 100644
--- a/cc/trees/transform_node.h
+++ b/cc/trees/transform_node.h
@@ -6,6 +6,7 @@
 #define CC_TREES_TRANSFORM_NODE_H_
 
 #include "cc/cc_export.h"
+#include "cc/trees/element_id.h"
 #include "ui/gfx/geometry/point_f.h"
 #include "ui/gfx/geometry/scroll_offset.h"
 #include "ui/gfx/transform.h"
diff --git a/chrome/VERSION b/chrome/VERSION
index 459ef3c..d1c7f00 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=72
 MINOR=0
-BUILD=3593
+BUILD=3596
 PATCH=0
diff --git a/chrome/android/chrome_public_apk_tmpl.gni b/chrome/android/chrome_public_apk_tmpl.gni
index 1b99225..299c20c 100644
--- a/chrome/android/chrome_public_apk_tmpl.gni
+++ b/chrome/android/chrome_public_apk_tmpl.gni
@@ -107,6 +107,8 @@
     # Use zh-TW strings for zh-HK (https://crbug.com/780847).
     support_zh_hk = true
 
+    optimize_resources = true
+
     if (defined(shared_libraries) && shared_libraries != []) {
       _native_lib_file =
           rebase_path("$root_gen_dir/CHROME_VERSION.json", root_out_dir)
@@ -227,6 +229,9 @@
     # Webview supports all locales (has no omitted ones).
     aapt_locale_whitelist = locales
 
+    # Resources config for blocklisting resource names from obfuscation
+    resources_config_path = "//android_webview/aapt2.config"
+
     if (!defined(invoker.target_type) || invoker.target_type == "android_apk") {
       # Incremental install doesn't work for monochrome. See crbug.com/663492.
       never_incremental = true
diff --git a/chrome/android/java/AndroidManifest.xml b/chrome/android/java/AndroidManifest.xml
index e231e82..2d4d755a 100644
--- a/chrome/android/java/AndroidManifest.xml
+++ b/chrome/android/java/AndroidManifest.xml
@@ -877,11 +877,6 @@
             android:exported="false">
         </service>
 
-        <!-- Download service -->
-        <service android:name="org.chromium.chrome.browser.download.DownloadNotificationService"
-            android:exported="false">
-        </service>
-
         <!-- Bookmarks widget -->
         <receiver android:name="com.google.android.apps.chrome.appwidget.bookmarks.BookmarkThumbnailWidgetProvider"
             android:label="@string/bookmark_widget_title">
diff --git a/chrome/android/java/res/layout/language_ask_prompt_content.xml b/chrome/android/java/res/layout/language_ask_prompt_content.xml
new file mode 100644
index 0000000..75db7f4
--- /dev/null
+++ b/chrome/android/java/res/layout/language_ask_prompt_content.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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. -->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:paddingTop="14dp"
+    android:id="@+id/list_content"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+    <android.support.v7.widget.RecyclerView
+        android:id="@+id/recycler_view"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
+
+    <ImageView
+        android:id="@+id/top_shadow"
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/toolbar_shadow_height"
+        android:src="@drawable/modern_toolbar_shadow"
+        android:scaleType="fitXY"
+        android:importantForAccessibility="no"
+        android:layout_gravity="top"
+        android:visibility="invisible" />
+
+    <ImageView
+        android:id="@+id/bottom_shadow"
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/toolbar_shadow_height"
+        android:src="@drawable/modern_toolbar_shadow"
+        android:scaleType="fitXY"
+        android:scaleY="-1"
+        android:importantForAccessibility="no"
+        android:layout_gravity="bottom" />
+</FrameLayout>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
index 596ff4e..01ac935 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
@@ -1301,11 +1301,6 @@
             mBottomSheet = null;
         }
 
-        if (mTabModelsInitialized) {
-            TabModelSelector selector = getTabModelSelector();
-            if (selector != null) selector.destroy();
-        }
-
         if (mDidAddPolicyChangeListener) {
             CombinedPolicyProvider.get().removePolicyChangeListener(this);
             mDidAddPolicyChangeListener = false;
@@ -1328,6 +1323,11 @@
             mFullscreenManager = null;
         }
 
+        if (mTabModelsInitialized) {
+            TabModelSelector selector = getTabModelSelector();
+            if (selector != null) selector.destroy();
+        }
+
         AccessibilityManager manager = (AccessibilityManager)
                 getBaseContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
         manager.removeAccessibilityStateChangeListener(this);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java
index f693fe85..54e8b65 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java
@@ -85,9 +85,11 @@
             // Chrome is just the browser process).
             ApplicationStatus.initialize(this);
 
-            // Register application status listener for crashes, this needs to be done as early as
-            // possible so that this value is set before any crashes are reported.
-            ApplicationStatusTracker.getInstance().registerListener();
+            // Register and initialize application status listener for crashes, this needs to be
+            // done as early as possible so that this value is set before any crashes are reported.
+            ApplicationStatusTracker tracker = new ApplicationStatusTracker();
+            tracker.onApplicationStateChange(ApplicationStatus.getStateForApplication());
+            ApplicationStatus.registerApplicationStateListener(tracker);
 
             // Only browser process requires custom resources.
             BuildHooksAndroid.initCustomResources(this);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiController.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiController.java
index e064ead..6f4f94d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiController.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser.autofill_assistant;
 
+import android.accounts.Account;
 import android.os.Bundle;
 import android.support.annotation.Nullable;
 
@@ -20,6 +21,7 @@
 import org.chromium.chrome.browser.tabmodel.EmptyTabModelObserver;
 import org.chromium.chrome.browser.tabmodel.TabModel;
 import org.chromium.chrome.browser.tabmodel.TabModel.TabSelectionType;
+import org.chromium.components.signin.AccountManagerFacade;
 import org.chromium.components.variations.VariationsAssociatedData;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.payments.mojom.PaymentOptions;
@@ -47,6 +49,10 @@
     /** Special parameter that enables the feature. */
     private static final String PARAMETER_ENABLED = "ENABLED";
 
+    /** OAuth2 scope that RPCs require. */
+    private static final String AUTH_TOKEN_TYPE =
+            "oauth2:https://www.googleapis.com/auth/userinfo.profile";
+
     private final WebContents mWebContents;
     private final long mUiControllerAndroid;
     private final UiDelegateHolder mUiDelegateHolder;
@@ -54,6 +60,22 @@
     private AutofillAssistantPaymentRequest mAutofillAssistantPaymentRequest;
 
     /**
+     * Indicates whether {@link mAccount} has been initialized.
+     */
+    private boolean mAccountInitialized;
+
+    /**
+     * Account to authenticate as when sending RPCs. Not relevant until the accounts have been
+     * fetched, and mAccountInitialized set to true. Can still be null after the accounts are
+     * fetched, in which case authentication is disabled.
+     */
+    @Nullable
+    private Account mAccount;
+
+    /** If set, fetch the access token once the accounts are fetched. */
+    private boolean mShouldFetchAccessToken;
+
+    /**
      * Returns true if all conditions are satisfied to construct an AutofillAssistantUiController.
      *
      * @return True if a controller can be constructed.
@@ -73,6 +95,7 @@
         // Set mUiDelegate before nativeInit, as it can be accessed through native methods from
         // nativeInit already.
         mUiDelegateHolder = new UiDelegateHolder(new AutofillAssistantUiDelegate(activity, this));
+        chooseAccountAsync(activity.getInitialIntent().getExtras());
 
         Map<String, String> parameters = extractParameters(activity.getInitialIntent().getExtras());
         parameters.remove(PARAMETER_ENABLED);
@@ -81,7 +104,8 @@
         mWebContents = activityTab.getWebContents();
         mUiControllerAndroid =
                 nativeInit(mWebContents, parameters.keySet().toArray(new String[parameters.size()]),
-                        parameters.values().toArray(new String[parameters.size()]));
+                        parameters.values().toArray(new String[parameters.size()]),
+                        activity.getInitialIntent().getDataString());
 
         // Shut down Autofill Assistant when the tab is detached from the activity.
         activityTab.addObserver(new EmptyTabObserver() {
@@ -227,7 +251,7 @@
 
     @CalledByNative
     private void onRequestPaymentInformation(boolean requestShipping, boolean requestPayerName,
-            boolean requestPayerPhone, boolean requestPayerEmail, int shippingType) {
+            boolean requestPayerPhone, boolean requestPayerEmail, int shippingType, String title) {
         PaymentOptions paymentOtions = new PaymentOptions();
         paymentOtions.requestShipping = requestShipping;
         paymentOtions.requestPayerName = requestPayerName;
@@ -235,7 +259,7 @@
         paymentOtions.requestPayerEmail = requestPayerEmail;
         paymentOtions.shippingType = shippingType;
         mAutofillAssistantPaymentRequest =
-                new AutofillAssistantPaymentRequest(mWebContents, paymentOtions);
+                new AutofillAssistantPaymentRequest(mWebContents, paymentOtions, title);
 
         mUiDelegateHolder.performUiOperation(
                 uiDelegate -> mAutofillAssistantPaymentRequest.show(selectedPaymentInformation -> {
@@ -336,9 +360,96 @@
         }
     }
 
+    @CalledByNative
+    private void fetchAccessToken() {
+        if (!mAccountInitialized) {
+            // Still getting the account list. Fetch the token as soon as an account is available.
+            mShouldFetchAccessToken = true;
+            return;
+        }
+        if (mAccount == null) {
+            nativeOnAccessToken(mUiControllerAndroid, true, "");
+            return;
+        }
+
+        AccountManagerFacade.get().getAuthToken(
+                mAccount, AUTH_TOKEN_TYPE, new AccountManagerFacade.GetAuthTokenCallback() {
+                    @Override
+                    public void tokenAvailable(String token) {
+                        nativeOnAccessToken(mUiControllerAndroid, true, token);
+                    }
+
+                    @Override
+                    public void tokenUnavailable(boolean isTransientError) {
+                        if (!isTransientError) {
+                            nativeOnAccessToken(mUiControllerAndroid, false, "");
+                        }
+                    }
+                });
+    }
+
+    @CalledByNative
+    private void invalidateAccessToken(String accessToken) {
+        if (mAccount == null) {
+            return;
+        }
+
+        AccountManagerFacade.get().invalidateAuthToken(accessToken);
+    }
+
+    /** Choose an account to authenticate as for making RPCs to the backend. */
+    private void chooseAccountAsync(Bundle extras) {
+        AccountManagerFacade.get().tryGetGoogleAccounts(accounts -> {
+            if (accounts.length == 1) {
+                // If there's only one account, there aren't any doubts.
+                onAccountChosen(accounts[0]);
+                return;
+            }
+            Account signedIn =
+                    findAccountByName(accounts, nativeGetPrimaryAccountName(mUiControllerAndroid));
+            if (signedIn != null) {
+                // TODO(crbug.com/806868): Compare against account name from extras and complain if
+                // they don't match.
+                onAccountChosen(signedIn);
+                return;
+            }
+            for (String extra : extras.keySet()) {
+                if (extra.endsWith("ACCOUNT_NAME")) {
+                    Account account = findAccountByName(accounts, extras.getString(extra));
+                    if (account != null) {
+                        onAccountChosen(account);
+                        return;
+                    }
+                }
+            }
+            onAccountChosen(null);
+        });
+    }
+
+    private void onAccountChosen(@Nullable Account account) {
+        mAccount = account;
+        mAccountInitialized = true;
+        // TODO(crbug.com/806868): Consider providing a way of signing in this case, to enforce
+        // that all calls are authenticated.
+
+        if (mShouldFetchAccessToken) {
+            mShouldFetchAccessToken = false;
+            fetchAccessToken();
+        }
+    }
+
+    private static Account findAccountByName(Account[] accounts, String name) {
+        for (Account account : accounts) {
+            if (account.name.equals(name)) {
+                return account;
+            }
+        }
+        return null;
+    }
+
     // native methods.
-    private native long nativeInit(
-            WebContents webContents, String[] parameterNames, String[] parameterValues);
+    private native long nativeInit(WebContents webContents, String[] parameterNames,
+            String[] parameterValues, String initialUrl);
     private native void nativeDestroy(long nativeUiControllerAndroid);
     private native void nativeOnScriptSelected(long nativeUiControllerAndroid, String scriptPath);
     private native void nativeOnAddressSelected(long nativeUiControllerAndroid, String guid);
@@ -347,4 +458,7 @@
             boolean succeed, @Nullable String cardGuid, @Nullable String cardIssuerNetwork,
             @Nullable String addressGuid, @Nullable String payerName, @Nullable String payerPhone,
             @Nullable String payerEmail);
+    private native void nativeOnAccessToken(
+            long nativeUiControllerAndroid, boolean success, String accessToken);
+    private native String nativeGetPrimaryAccountName(long nativeUiControllerAndroid);
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/crash/ApplicationStatusTracker.java b/chrome/android/java/src/org/chromium/chrome/browser/crash/ApplicationStatusTracker.java
index 2094c50d..29ea88a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/crash/ApplicationStatusTracker.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/crash/ApplicationStatusTracker.java
@@ -11,28 +11,18 @@
 /**
  * This class updates crash keys when the application state changes.
  */
-public class ApplicationStatusTracker {
+public class ApplicationStatusTracker implements ApplicationStatus.ApplicationStateListener {
     private static final String APP_FOREGROUND = "app_foreground";
     private static final String APP_BACKGROUND = "app_background";
 
-    private static class Holder {
-        static final ApplicationStatusTracker INSTANCE = new ApplicationStatusTracker();
-    }
-
     private String mCurrentState;
 
-    private ApplicationStatusTracker() {}
-
-    public void registerListener() {
-        setApplicationStatus(ApplicationStatus.getStateForApplication());
-        ApplicationStatus.registerApplicationStateListener(this::setApplicationStatus);
-    }
-
-    private void setApplicationStatus(@ApplicationState int state) {
+    @Override
+    public void onApplicationStateChange(int newState) {
         ThreadUtils.assertOnUiThread();
         String appStatus;
         // TODO(wnwen): Add foreground service as another state.
-        if (isApplicationInForeground(state)) {
+        if (isApplicationInForeground(newState)) {
             appStatus = APP_FOREGROUND;
         } else {
             appStatus = APP_BACKGROUND;
@@ -47,11 +37,4 @@
         return state == ApplicationState.HAS_RUNNING_ACTIVITIES
                 || state == ApplicationState.HAS_PAUSED_ACTIVITIES;
     }
-
-    /**
-     * @return The shared instance of this class.
-     */
-    public static ApplicationStatusTracker getInstance() {
-        return Holder.INSTANCE;
-    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/crash/OWNERS b/chrome/android/java/src/org/chromium/chrome/browser/crash/OWNERS
new file mode 100644
index 0000000..232d47d
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/crash/OWNERS
@@ -0,0 +1,2 @@
+isherman@chromium.org
+wnwen@chromium.org
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesCategoryCardView.java b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesCategoryCardView.java
index 16f39536..7d5418c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesCategoryCardView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesCategoryCardView.java
@@ -228,6 +228,6 @@
         // TODO(petewil): Should I get the number of sites in this category from the model instead
         // of using MAX_TILE_COUNT?
         RecordHistogram.recordLinearCountHistogram("ExploreSites.SiteTilesClickIndex",
-                cardIndex * MAX_TILE_COUNT + tileIndex, 0, 100, 100);
+                cardIndex * MAX_TILE_COUNT + tileIndex, 1, 100, 100);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesSection.java b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesSection.java
index be19677..fe24fee 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesSection.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesSection.java
@@ -36,11 +36,6 @@
 public class ExploreSitesSection {
     private static final String TAG = "ExploreSitesSection";
     private static final int MAX_CATEGORIES = 3;
-    // This is a number of UMA histogram buckets that should be an upper bound
-    // of MAX_CATEGORIES over time, plus 1 for "More" button, and plus 1 for
-    // overflow bucket. If MAX_CATEGORIES changes, this value should be updated
-    // only upwards.
-    private static final int MAX_CATEGORIES_HISTOGRAM_BUCKETS = 5;
 
     @TileStyle
     private int mStyle;
@@ -194,8 +189,8 @@
     }
 
     private void onClicked(int tileIndex, ExploreSitesCategory category, View v) {
-        RecordHistogram.recordLinearCountHistogram("ExploreSites.ClickedNTPCategoryIndex",
-                tileIndex, 0, MAX_CATEGORIES, MAX_CATEGORIES_HISTOGRAM_BUCKETS);
+        RecordHistogram.recordLinearCountHistogram(
+                "ExploreSites.ClickedNTPCategoryIndex", tileIndex, 1, 100, 100);
         mNavigationDelegate.openUrl(WindowOpenDisposition.CURRENT_TAB,
                 new LoadUrlParams(category.getUrl(), PageTransition.AUTO_BOOKMARK));
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/ChromeFullscreenManager.java b/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/ChromeFullscreenManager.java
index 1bd7974..a92f9666 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/ChromeFullscreenManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/ChromeFullscreenManager.java
@@ -570,9 +570,16 @@
         if (mHidingTokenHolder.hasTokens()) {
             return false;
         }
-        if (getTab() != null
-                && TabBrowserControlsOffsetHelper.from(getTab()).isControlsOffsetOverridden()) {
-            return true;
+
+        Tab tab = getTab();
+        if (tab != null) {
+            if (tab.isInitialized()) {
+                if (TabBrowserControlsOffsetHelper.from(tab).isControlsOffsetOverridden()) {
+                    return true;
+                }
+            } else {
+                assert false : "Accessing a destroyed tab, setTab should have been called";
+            }
         }
 
         boolean showControls = !drawControlsAsTexture();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/FullscreenManager.java b/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/FullscreenManager.java
index 93aafc9..0d987a0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/FullscreenManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/FullscreenManager.java
@@ -192,5 +192,7 @@
     /**
      * Destroys the FullscreenManager
      */
-    public void destroy() {}
+    public void destroy() {
+        setTab(null);
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/language/LanguageAskPrompt.java b/chrome/android/java/src/org/chromium/chrome/browser/language/LanguageAskPrompt.java
index 2e99fb31..889f331e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/language/LanguageAskPrompt.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/language/LanguageAskPrompt.java
@@ -17,6 +17,7 @@
 import android.widget.TextView;
 
 import org.chromium.base.LocaleUtils;
+import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeActivity;
 import org.chromium.chrome.browser.ChromeFeatureList;
@@ -40,6 +41,17 @@
  * once at browser startup when no other promo or modals are shown.
  */
 public class LanguageAskPrompt implements ModalDialogView.Controller {
+    // Enum values for the Translate.ExplicitLanguageAsk.Event histogram.
+    private static final int PROMPT_EVENT_SHOWN = 0;
+    private static final int PROMPT_EVENT_SAVED = 1;
+    private static final int PROMPT_EVENT_CANCELLED = 2;
+    private static final int PROMPT_EVENT_MAX = PROMPT_EVENT_CANCELLED;
+
+    private void recordPromptEvent(int event) {
+        RecordHistogram.recordEnumeratedHistogram(
+                "Translate.ExplicitLanguageAsk.Event", event, PROMPT_EVENT_MAX);
+    }
+
     private class SeparatorViewHolder extends ViewHolder {
         SeparatorViewHolder(View view) {
             super(view);
@@ -193,6 +205,34 @@
         }
     }
 
+    private class ListScrollListener extends RecyclerView.OnScrollListener {
+        private RecyclerView mList;
+        private ImageView mTopShadow;
+        private ImageView mBottomShadow;
+
+        public ListScrollListener(RecyclerView list, ImageView topShadow, ImageView bottomShadow) {
+            mList = list;
+            mTopShadow = topShadow;
+            mBottomShadow = bottomShadow;
+            mList.setOnScrollListener(this);
+        }
+
+        @Override
+        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
+            if (mList.canScrollVertically(-1)) {
+                mTopShadow.setVisibility(View.VISIBLE);
+            } else {
+                mTopShadow.setVisibility(View.GONE);
+            }
+
+            if (mList.canScrollVertically(1)) {
+                mBottomShadow.setVisibility(View.VISIBLE);
+            } else {
+                mBottomShadow.setVisibility(View.GONE);
+            }
+        }
+    }
+
     /**
      * Displays the Explicit Language Ask prompt if the experiment is enabled.
      * @param activity The current activity to display the prompt into.
@@ -210,6 +250,7 @@
         return true;
     }
 
+    private ListScrollListener mListScrollListener;
     private ModalDialogManager mModalDialogManager;
     private ModalDialogView mDialog;
     private HashSet<String> mLanguagesUpdate;
@@ -246,6 +287,8 @@
     public void show(ChromeActivity activity) {
         if (activity == null) return;
 
+        recordPromptEvent(PROMPT_EVENT_SHOWN);
+
         List<String> userAcceptLanguagesList =
                 PrefServiceBridge.getInstance().getUserLanguageCodes();
         mInitialLanguages = new HashSet<String>();
@@ -258,14 +301,19 @@
         params.negativeButtonTextId = R.string.cancel;
         params.cancelOnTouchOutside = true;
 
-        RecyclerView list = new RecyclerView(activity);
+        params.customView = LayoutInflater.from(activity).inflate(
+                R.layout.language_ask_prompt_content, null, false);
+        RecyclerView list = (RecyclerView) params.customView.findViewById(R.id.recycler_view);
         LanguageItemAdapter adapter = new LanguageItemAdapter(activity, mLanguagesUpdate);
         list.setAdapter(adapter);
         LinearLayoutManager linearLayoutManager = new LinearLayoutManager(activity);
         linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
         list.setLayoutManager(linearLayoutManager);
         list.setHasFixedSize(true);
-        params.customView = list;
+
+        ImageView topShadow = (ImageView) params.customView.findViewById(R.id.top_shadow);
+        ImageView bottomShadow = (ImageView) params.customView.findViewById(R.id.bottom_shadow);
+        mListScrollListener = new ListScrollListener(list, topShadow, bottomShadow);
 
         List<LanguageItem> languages = PrefServiceBridge.getInstance().getChromeLanguageList();
         LinkedHashSet<String> currentGeoLanguages =
@@ -316,5 +364,11 @@
     }
 
     @Override
-    public void onDismiss(@DialogDismissalCause int dismissalCause) {}
+    public void onDismiss(@DialogDismissalCause int dismissalCause) {
+        if (dismissalCause == DialogDismissalCause.POSITIVE_BUTTON_CLICKED) {
+            recordPromptEvent(PROMPT_EVENT_SAVED);
+        } else {
+            recordPromptEvent(PROMPT_EVENT_CANCELLED);
+        }
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/MediaViewerUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/media/MediaViewerUtils.java
index 588d078..749a608 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/media/MediaViewerUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/media/MediaViewerUtils.java
@@ -66,7 +66,7 @@
         builder.setCloseButtonIcon(closeIcon);
         builder.setShowTitle(true);
 
-        if (allowExternalAppHandlers) {
+        if (allowExternalAppHandlers && !willExposeFileUri(contentUri)) {
             // Create a PendingIntent that can be used to view the file externally.
             // TODO(https://crbug.com/795968): Check if this is problematic in multi-window mode,
             //                                 where two different viewers could be visible at the
@@ -83,8 +83,7 @@
         // Create a PendingIntent that shares the file with external apps.
         // If the URI is a file URI and the Android version is N or later, this will throw a
         // FileUriExposedException. In this case, we just don't add the share button.
-        if (!contentUri.getScheme().equals(ContentResolver.SCHEME_FILE)
-                || Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
+        if (!willExposeFileUri(contentUri)) {
             PendingIntent pendingShareIntent = PendingIntent.getActivity(context, 0,
                     createShareIntent(contentUri, mimeType), PendingIntent.FLAG_CANCEL_CURRENT);
             builder.setActionButton(
@@ -151,8 +150,10 @@
     public static void setOriginalUrlAndReferralExtraToIntent(
             Intent intent, String originalUrl, String referrer) {
         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) return;
-        if (originalUrl != null) intent.putExtra(Intent.EXTRA_ORIGINATING_URI, originalUrl);
-        if (referrer != null) intent.putExtra(Intent.EXTRA_REFERRER, referrer);
+        if (originalUrl != null) {
+            intent.putExtra(Intent.EXTRA_ORIGINATING_URI, Uri.parse(originalUrl));
+        }
+        if (referrer != null) intent.putExtra(Intent.EXTRA_REFERRER, Uri.parse(originalUrl));
     }
 
     /**
@@ -256,4 +257,10 @@
 
         return MIMETYPE_IMAGE.equals(pieces[0]);
     }
+
+    private static boolean willExposeFileUri(Uri uri) {
+        // On Android N and later, an Exception is thrown if we try to expose a file:// URI.
+        return uri.getScheme().equals(ContentResolver.SCHEME_FILE)
+                && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N;
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillAssistantPaymentRequest.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillAssistantPaymentRequest.java
index 15a5ce12..a185ed3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillAssistantPaymentRequest.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/AutofillAssistantPaymentRequest.java
@@ -48,6 +48,7 @@
 
     private final WebContents mWebContents;
     private final PaymentOptions mPaymentOptions;
+    private final String mTitle;
     private final CardEditor mCardEditor;
     private final AddressEditor mAddressEditor;
     private final Map<String, PaymentMethodData> mMethodData;
@@ -89,10 +90,13 @@
      *
      * @webContents    The web contents of the payment request associated with.
      * @paymentOptions The options to request payment information.
+     * @title          The title to display in the payment request.
      */
-    public AutofillAssistantPaymentRequest(WebContents webContents, PaymentOptions paymentOptions) {
+    public AutofillAssistantPaymentRequest(
+            WebContents webContents, PaymentOptions paymentOptions, String title) {
         mWebContents = webContents;
         mPaymentOptions = paymentOptions;
+        mTitle = title;
 
         // This feature should only works in non-incognito mode.
         mAddressEditor = new AddressEditor(/* emailFieldIncluded= */ true, /* saveToDisk= */ true);
@@ -158,7 +162,8 @@
                 /* requestShippingOption= */ false,
                 mPaymentOptions.requestPayerName || mPaymentOptions.requestPayerPhone
                         || mPaymentOptions.requestPayerEmail,
-                /* canAddCards= */ true, /* showDataSource= */ true, mWebContents.getTitle(),
+                /* canAddCards= */ true, /* showDataSource= */ true,
+                mTitle.isEmpty() ? mWebContents.getTitle() : mTitle,
                 UrlFormatter.formatUrlForSecurityDisplay(mWebContents.getLastCommittedUrl()),
                 SecurityStateModel.getSecurityLevelForWebContents(mWebContents),
                 new ShippingStrings(mPaymentOptions.shippingType));
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/ExportFlow.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/ExportFlow.java
index 95f23ac9..de3bc38 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/ExportFlow.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/ExportFlow.java
@@ -23,7 +23,6 @@
 import org.chromium.ui.widget.Toast;
 
 import java.io.File;
-import java.io.IOException;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.concurrent.TimeUnit;
@@ -251,14 +250,26 @@
 
     /**
      * A helper method which processes the signal that serialized passwords have been stored in the
-     * temporary file. It produces a sharing URI for that file, logs some metrics and continues the
-     * flow.
+     * temporary file. It produces a sharing URI for that file, registers that file for deletion at
+     * the shutdown of the Java VM, logs some metrics and continues the flow.
+     * @param pathToPasswordsFile The filesystem path to the file containing the serialized
+     *                            passwords.
      */
-    private void shareSerializedPasswords() {
+    private void shareSerializedPasswords(String pathToPasswordsFile) {
         // Don't display any UI if the user cancelled the export in the meantime.
         if (mExportState == ExportState.INACTIVE) return;
 
-        // Record the time it took to read and serialise the passwords. This
+        File passwordsFile = new File(pathToPasswordsFile);
+        passwordsFile.deleteOnExit();
+
+        try {
+            mExportFileUri = ContentUriUtils.getContentUriFromFile(passwordsFile);
+        } catch (IllegalArgumentException e) {
+            showExportErrorAndAbort(R.string.save_password_preferences_export_tips, e.getMessage(),
+                    R.string.try_again, HistogramExportResult.WRITE_FAILED);
+            return;
+        }
+        // Record the time it took to read and serialize the passwords. This
         // excludes the time to write them into a file, to be consistent with
         // desktop (where writing is blocked on the user choosing a file
         // destination).
@@ -268,7 +279,17 @@
         tryExporting();
     }
 
-    /** Starts the password export flow.
+    /**
+     * Returns the path to the directory where serialized passwords are stored.
+     * @return A subdirectory of the cache, where serialized passwords are stored.
+     */
+    @VisibleForTesting
+    public static String getTargetDirectory() {
+        return ContextUtils.getApplicationContext().getCacheDir() + PASSWORDS_CACHE_DIR;
+    }
+
+    /**
+     * Starts the password export flow.
      * Current state of export flow: the user just tapped the menu item for export
      * The next steps are: passing reauthentication, confirming the export, waiting for exported
      * data (if needed) and choosing a consumer app for the data.
@@ -280,21 +301,17 @@
 
         // Start fetching the serialized passwords now to use the time the user spends
         // reauthenticating and reading the warning message. If the user cancels the export or
-        // fails the reauthentication, the serialised passwords will simply get ignored when
+        // fails the reauthentication, the serialized passwords will simply get ignored when
         // they arrive.
         mExportPreparationStart = System.currentTimeMillis();
 
-        String tempFileName = createTempFileName();
-        // Empty string means an error was reported and the flow aborted.
-        if (tempFileName.isEmpty()) return;
-
         mEntriesCount = null;
         PasswordManagerHandlerProvider.getInstance().getPasswordManagerHandler().serializePasswords(
-                tempFileName,
-                (Integer entriesCount)
+                getTargetDirectory(),
+                (int entriesCount, String pathToPasswordsFile)
                         -> {
                     mEntriesCount = entriesCount;
-                    shareSerializedPasswords();
+                    shareSerializedPasswords(pathToPasswordsFile);
                 },
                 (String errorMessage) -> {
                     showExportErrorAndAbort(R.string.save_password_preferences_export_tips,
@@ -485,40 +502,6 @@
     }
 
     /**
-     * This method returns a name of a temporary file in the cache directory. The name is unique and
-     * {@link File#deleteOnExit} is called on the file. If creating the file name fails, an error is
-     * shown and the export flow aborted. This method also derives a sharing URI from the file name.
-     * @return The name of the temporary file or an empty string on error.
-     */
-    private String createTempFileName() {
-        // First ensure that the PASSWORDS_CACHE_DIR cache directory exists.
-        File passwordsDir =
-                new File(ContextUtils.getApplicationContext().getCacheDir() + PASSWORDS_CACHE_DIR);
-        passwordsDir.mkdir();
-        // Now create or overwrite the temporary file for exported passwords there and return its
-        // content:// URI.
-        File tempFile;
-        try {
-            tempFile = File.createTempFile("pwd-export", ".csv", passwordsDir);
-        } catch (IOException e) {
-            showExportErrorAndAbort(R.string.save_password_preferences_export_tips, e.getMessage(),
-                    R.string.try_again, HistogramExportResult.WRITE_FAILED);
-            return "";
-        }
-        tempFile.deleteOnExit();
-
-        try {
-            mExportFileUri = ContentUriUtils.getContentUriFromFile(tempFile);
-        } catch (IllegalArgumentException e) {
-            showExportErrorAndAbort(R.string.save_password_preferences_export_tips, e.getMessage(),
-                    R.string.try_again, HistogramExportResult.WRITE_FAILED);
-            return "";
-        }
-
-        return tempFile.getPath();
-    }
-
-    /**
      * If the URI of the file with exported passwords is not null, passes it into an implicit
      * intent, so that the user can use a storage app to save the exported passwords.
      */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordManagerHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordManagerHandler.java
index f1e2492a..419735f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordManagerHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordManagerHandler.java
@@ -5,6 +5,7 @@
 package org.chromium.chrome.browser.preferences.password;
 
 import org.chromium.base.Callback;
+import org.chromium.base.IntStringCallback;
 
 /**
  * Interface for retrieving passwords and password exceptions (websites for which Chrome should not
@@ -69,9 +70,9 @@
      *
      * @param targetPath is the file to which the serialized passwords should be written.
      * @param successCallback is called on successful completion, with the count of the serialized
-     * passwords as argument.
+     * passwords and the path to the file containing them as argument.
      * @param errorCallback is called on failure, with the error message as argument.
      */
     void serializePasswords(
-            String targetPath, Callback<Integer> successCallback, Callback<String> errorCallback);
+            String targetPath, IntStringCallback successCallback, Callback<String> errorCallback);
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordUIView.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordUIView.java
index 63d90a0..e24cfc6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordUIView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordUIView.java
@@ -5,6 +5,7 @@
 package org.chromium.chrome.browser.preferences.password;
 
 import org.chromium.base.Callback;
+import org.chromium.base.IntStringCallback;
 import org.chromium.base.annotations.CalledByNative;
 
 /**
@@ -73,7 +74,7 @@
 
     @Override
     public void serializePasswords(
-            String targetPath, Callback<Integer> successCallback, Callback<String> errorCallback) {
+            String targetPath, IntStringCallback successCallback, Callback<String> errorCallback) {
         nativeHandleSerializePasswords(
                 mNativePasswordUIViewAndroid, targetPath, successCallback, errorCallback);
     }
@@ -118,5 +119,5 @@
     private native void nativeDestroy(long nativePasswordUIViewAndroid);
 
     private native void nativeHandleSerializePasswords(long nativePasswordUIViewAndroid,
-            String targetPath, Callback<Integer> successCallback, Callback<String> errorCallback);
+            String targetPath, IntStringCallback successCallback, Callback<String> errorCallback);
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/CurrencyFormatterTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/CurrencyFormatterTest.java
index d58504e..5c41ff4 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/CurrencyFormatterTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/CurrencyFormatterTest.java
@@ -31,7 +31,8 @@
     /**
      * Unicode non-breaking space.
      */
-    private static final String SPACE = "\u00A0";
+    private static final String NBSP = "\u00A0";
+    private static final String NarrowNBSP = "\u202F";
 
     @Before
     public void setUp() throws Exception {
@@ -109,12 +110,13 @@
 
             CurrencyFormatter formatter =
                     new CurrencyFormatter(currency, LocaleUtils.forLanguageTag(locale));
-
-            String formattedAmount = formatter.format(amount).replace(SPACE, " ");
+            // To make tests robust against the CLDR data change in terms of space (ASCII
+            // space, NBSP and Narrow NBSP), fold NBSP and NarrowNBSP into U+0020.
+            String formattedAmount = formatter.format(amount).replace(NBSP, " ");
             Assert.assertEquals("\"" + currency + "\" \"" + amount + "\" (\"" + locale
                             + "\" locale) should be formatted into \"" + expectedAmountFormatting
                             + "\"",
-                    expectedAmountFormatting, formattedAmount);
+                    expectedAmountFormatting, formattedAmount.replace(NarrowNBSP, " "));
             Assert.assertEquals("\"" + currency + "\""
                             + " should be formatted into \"" + expectedCurrencyFormatting + "\"",
                     expectedCurrencyFormatting, formatter.getFormattedCurrencyCode());
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/password/SavePasswordsPreferencesTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/password/SavePasswordsPreferencesTest.java
index 4aef62c..362204d3 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/password/SavePasswordsPreferencesTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/password/SavePasswordsPreferencesTest.java
@@ -72,6 +72,7 @@
 import org.junit.runner.RunWith;
 
 import org.chromium.base.Callback;
+import org.chromium.base.IntStringCallback;
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.test.BaseJUnit4ClassRunner;
 import org.chromium.base.test.util.Feature;
@@ -92,6 +93,7 @@
 import org.chromium.chrome.test.util.browser.Features.EnableFeatures;
 
 import java.io.File;
+import java.io.IOException;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
@@ -128,13 +130,13 @@
 
         // The following three data members are set once {@link #serializePasswords()} is called.
         @Nullable
-        private Callback<Integer> mExportSuccessCallback;
+        private IntStringCallback mExportSuccessCallback;
 
         @Nullable
         private Callback<String> mExportErrorCallback;
 
         @Nullable
-        private String mExportFileName;
+        private String mExportTargetPath;
 
         public void setSavedPasswords(ArrayList<SavedPasswordEntry> savedPasswords) {
             mSavedPasswords = savedPasswords;
@@ -144,7 +146,7 @@
             mSavedPasswordExeptions = savedPasswordExceptions;
         }
 
-        public Callback<Integer> getExportSuccessCallback() {
+        public IntStringCallback getExportSuccessCallback() {
             return mExportSuccessCallback;
         }
 
@@ -152,8 +154,8 @@
             return mExportErrorCallback;
         }
 
-        public String getExportFileName() {
-            return mExportFileName;
+        public String getExportTargetPath() {
+            return mExportTargetPath;
         }
 
         /**
@@ -197,11 +199,11 @@
         }
 
         @Override
-        public void serializePasswords(String targetPath, Callback<Integer> successCallback,
+        public void serializePasswords(String targetPath, IntStringCallback successCallback,
                 Callback<String> errorCallback) {
             mExportSuccessCallback = successCallback;
             mExportErrorCallback = errorCallback;
-            mExportFileName = targetPath;
+            mExportTargetPath = targetPath;
         }
     }
 
@@ -398,6 +400,17 @@
             Thread.sleep(100);
     }
 
+    /**
+     * Create a temporary file in the cache sub-directory for exported passwords, which the test can
+     * try to use for sharing.
+     * @return The {@link File} handle for such temporary file.
+     */
+    private File createFakeExportedPasswordsFile() throws IOException {
+        File passwordsDir = new File(ExportFlow.getTargetDirectory());
+        // Ensure that the directory exists.
+        passwordsDir.mkdir();
+        return File.createTempFile("test", ".csv", passwordsDir);
+    }
 
     /**
      * Ensure that resetting of empty passwords list works.
@@ -599,8 +612,8 @@
         Espresso.onView(withText(R.string.save_password_preferences_export_action_title))
                 .perform(click());
 
-        File exportPath = new File(mHandler.getExportFileName());
-        Assert.assertTrue(exportPath.canRead());
+        Assert.assertNotNull(mHandler.getExportTargetPath());
+        Assert.assertFalse(mHandler.getExportTargetPath().isEmpty());
     }
 
     /**
@@ -839,9 +852,9 @@
         Intents.init();
 
         reauthenticateAndRequestExport(preferences);
-
+        File tempFile = createFakeExportedPasswordsFile();
         // Pretend that passwords have been serialized to go directly to the intent.
-        mHandler.getExportSuccessCallback().onResult(123);
+        mHandler.getExportSuccessCallback().onResult(123, tempFile.getPath());
 
         // Before triggering the sharing intent chooser, stub it out to avoid leaving system UI open
         // after the test is finished.
@@ -869,6 +882,8 @@
 
         Intents.release();
 
+        tempFile.delete();
+
         Assert.assertEquals(1, successDelta.getDelta());
         Assert.assertEquals(1, countDelta.getDelta());
         Assert.assertEquals(1, progressBarDelta.getDelta());
@@ -905,8 +920,9 @@
             }
         });
 
+        File tempFile = createFakeExportedPasswordsFile();
         // Pretend that passwords have been serialized to go directly to the intent.
-        mHandler.getExportSuccessCallback().onResult(56);
+        mHandler.getExportSuccessCallback().onResult(56, tempFile.getPath());
 
         // Before triggering the sharing intent chooser, stub it out to avoid leaving system UI open
         // after the test is finished.
@@ -930,6 +946,8 @@
 
         Intents.release();
 
+        tempFile.delete();
+
         Assert.assertEquals(1, successDelta.getDelta());
         Assert.assertEquals(1, countDelta.getDelta());
     }
@@ -1120,8 +1138,9 @@
                 "PasswordManager.Android.ExportPasswordsProgressBarUsage",
                 ExportFlow.PROGRESS_HIDDEN_DELAYED);
 
+        File tempFile = createFakeExportedPasswordsFile();
         // Now pretend that passwords have been serialized.
-        mHandler.getExportSuccessCallback().onResult(12);
+        mHandler.getExportSuccessCallback().onResult(12, tempFile.getPath());
 
         // Check that the progress bar is still shown, though, because the timer has not gone off
         // yet.
@@ -1138,6 +1157,9 @@
                         allOf(hasAction(equalTo(Intent.ACTION_SEND)), hasType("text/csv"))))));
 
         Intents.release();
+
+        tempFile.delete();
+
         Assert.assertEquals(1, progressBarDelta.getDelta());
     }
 
@@ -1181,9 +1203,11 @@
                 "PasswordManager.Android.ExportPasswordsProgressBarUsage",
                 ExportFlow.PROGRESS_HIDDEN_DIRECTLY);
 
+        File tempFile = createFakeExportedPasswordsFile();
+
         // Now pretend that passwords have been serialized.
         allowProgressBarToBeHidden(preferences);
-        mHandler.getExportSuccessCallback().onResult(12);
+        mHandler.getExportSuccessCallback().onResult(12, tempFile.getPath());
 
         // After simulating the serialized passwords being received, check that the progress bar is
         // hidden.
@@ -1195,6 +1219,9 @@
                         allOf(hasAction(equalTo(Intent.ACTION_SEND)), hasType("text/csv"))))));
 
         Intents.release();
+
+        tempFile.delete();
+
         Assert.assertEquals(1, progressBarDelta.getDelta());
     }
 
diff --git a/chrome/android/profiles/newest.txt b/chrome/android/profiles/newest.txt
index dc75928..1554be1 100644
--- a/chrome/android/profiles/newest.txt
+++ b/chrome/android/profiles/newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-72.0.3592.0_rc-r1.afdo.bz2
\ No newline at end of file
+chromeos-chrome-amd64-72.0.3595.0_rc-r1.afdo.bz2
\ No newline at end of file
diff --git a/chrome/android/webapk/shell_apk/BUILD.gn b/chrome/android/webapk/shell_apk/BUILD.gn
index 221d3eb..87cc735 100644
--- a/chrome/android/webapk/shell_apk/BUILD.gn
+++ b/chrome/android/webapk/shell_apk/BUILD.gn
@@ -94,10 +94,16 @@
 
   # Generate manifest with test values.
   manifest_mustache_pass(_manifest_target_name) {
-    forward_variables_from(invoker, [ "config_file" ])
+    forward_variables_from(invoker,
+                           [
+                             "apk_package_name",
+                             "config_file",
+                             "delta_config_file",
+                           ])
 
     input = _manifest_to_upload_output
     output = _manifest_output
+    extra_variables = [ "manifest_package=$apk_package_name" ]
     deps = [
       ":$_manifest_to_upload_target_name",
     ]
@@ -208,27 +214,33 @@
 webapk_tmpl("webapk") {
   config_file = "manifest/bound_manifest_config.json"
   apk_name = "WebApk"
+  apk_package_name = "org.chromium.webapk"
 }
 
 webapk_tmpl("maps_go_webapk") {
   config_file = "manifest/maps_go_manifest_config.json"
   apk_name = "MapsWebApk"
+  apk_package_name = "org.chromium.maps_go_webapk"
 }
 
 webapk_tmpl("unbound_webapk") {
   config_file = "manifest/unbound_manifest_config.json"
   apk_name = "UnboundWebApk"
+  apk_package_name = "org.chromium.arbitrarypackage"
 }
 
 webapk_tmpl("http_webapk") {
-  config_file = "manifest/http_manifest_config.json"
+  config_file = "manifest/bound_manifest_config.json"
+  delta_config_file = "manifest/http_manifest_config_delta.json"
   apk_name = "HttpWebApk"
+  apk_package_name = "org.chromium.webapk.http"
 }
 
 webapk_tmpl("new_splash_webapk") {
   use_new_splash = true
-  config_file = "manifest/new_splash_manifest_config.json"
+  config_file = "manifest/bound_manifest_config.json"
   apk_name = "NewSplashWebApk"
+  apk_package_name = "org.chromium.webapk.new.splash"
 }
 
 android_library("shell_apk_javatests") {
diff --git a/chrome/android/webapk/shell_apk/manifest/bound_manifest_config.json b/chrome/android/webapk/shell_apk/manifest/bound_manifest_config.json
index dc9afb94..0ba6f57 100644
--- a/chrome/android/webapk/shell_apk/manifest/bound_manifest_config.json
+++ b/chrome/android/webapk/shell_apk/manifest/bound_manifest_config.json
@@ -1,5 +1,4 @@
 {
-  "manifest_package": "org.chromium.webapk",
   "scope_url": "https://pwa.rocks/",
   "intent_filters": {
     "scope_url_scheme": "https",
diff --git a/chrome/android/webapk/shell_apk/manifest/http_manifest_config.json b/chrome/android/webapk/shell_apk/manifest/http_manifest_config.json
deleted file mode 100644
index bf0e34f..0000000
--- a/chrome/android/webapk/shell_apk/manifest/http_manifest_config.json
+++ /dev/null
@@ -1,41 +0,0 @@
-{
-  "manifest_package": "org.chromium.webapk.http",
-  "scope_url": "http://pwa.rocks/",
-  "intent_filters": {
-    "scope_url_scheme": "http",
-    "scope_url_host": "pwa.rocks",
-    "scope_url_path_type": "android:pathPrefix",
-    "scope_url_path": "/"
-  },
-  "start_url": "http://pwa.rocks/",
-  "display_mode": "standalone",
-  "orientation": "portrait",
-  "theme_color": "2147483648L",
-  "background_color": "2147483648L",
-  "has_large_splash_icons": "false",
-  "icon_urls_and_icon_murmur2_hashes": "http://www.pwa.rocks/icon1.png 0 http://www.pwa.rocks/icon2.png 0",
-  "web_manifest_url": "https://pwa.rocks/pwa.webmanifest",
-  "distributor": "browser",
-  "version_code": "1",
-  "version_name": "1.0",
-  "bound_webapk": {
-    "runtime_host": "com.google.android.apps.chrome",
-    "runtime_host_application_name": "Chromium"
-  },
-  "share_template": [{
-	  "index": "0",
-	  "title": "Share All",
-	  "action": "http://pwa.rocks/share.html",
-	  "param_title": "title",
-	  "param_text": "text",
-	  "param_url": "url"
-  },
-  {
-	  "index": "1",
-	  "title": "Share Title",
-	  "action": "http://pwa.rocks/share_title.html",
-	  "param_title": "title",
-	  "param_text": "text",
-	  "param_url": "url"
-  }]
-}
diff --git a/chrome/android/webapk/shell_apk/manifest/http_manifest_config_delta.json b/chrome/android/webapk/shell_apk/manifest/http_manifest_config_delta.json
new file mode 100644
index 0000000..735c9f8
--- /dev/null
+++ b/chrome/android/webapk/shell_apk/manifest/http_manifest_config_delta.json
@@ -0,0 +1,10 @@
+{
+  "scope_url": "http://pwa.rocks/",
+  "intent_filters": {
+    "scope_url_scheme": "http",
+    "scope_url_host": "pwa.rocks",
+    "scope_url_path_type": "android:pathPrefix",
+    "scope_url_path": "/"
+  },
+  "start_url": "http://pwa.rocks/"
+}
diff --git a/chrome/android/webapk/shell_apk/manifest/manifest_mustache_pass.gni b/chrome/android/webapk/shell_apk/manifest/manifest_mustache_pass.gni
index d9ac21b..d4f7769b 100644
--- a/chrome/android/webapk/shell_apk/manifest/manifest_mustache_pass.gni
+++ b/chrome/android/webapk/shell_apk/manifest/manifest_mustache_pass.gni
@@ -23,6 +23,10 @@
     if (defined(invoker.config_file)) {
       sources += [ invoker.config_file ]
     }
+    if (defined(invoker.delta_config_file)) {
+      sources += [ invoker.delta_config_file ]
+    }
+
     script =
         "//chrome/android/webapk/shell_apk/manifest/manifest_mustache_pass.py"
 
@@ -42,6 +46,12 @@
         rebase_path(invoker.config_file, root_build_dir),
       ]
     }
+    if (defined(invoker.delta_config_file)) {
+      args += [
+        "--delta_config_file",
+        rebase_path(invoker.delta_config_file, root_build_dir),
+      ]
+    }
     if (defined(invoker.extra_variables)) {
       extra_variables = invoker.extra_variables
       args += [ "--extra_variables=${extra_variables}" ]
diff --git a/chrome/android/webapk/shell_apk/manifest/manifest_mustache_pass.py b/chrome/android/webapk/shell_apk/manifest/manifest_mustache_pass.py
index 5750224..39852ba 100755
--- a/chrome/android/webapk/shell_apk/manifest/manifest_mustache_pass.py
+++ b/chrome/android/webapk/shell_apk/manifest/manifest_mustache_pass.py
@@ -32,6 +32,7 @@
     variables[name] = value
   return variables
 
+
 def main():
   parser = argparse.ArgumentParser()
   parser.add_argument('--template', required=True,
@@ -40,6 +41,8 @@
                       help='The output file to generate.')
   parser.add_argument('--config_file',
                       help='JSON file with values to put into template.')
+  parser.add_argument('--delta_config_file', help='JSON file with '
+                      'substitutions to |config_file|.')
   parser.add_argument('--extra_variables', help='Variables to be made '
                       'available in the template processing environment (in '
                       'addition to those specified in config file), as a GN '
@@ -47,10 +50,15 @@
                       default='')
   options = parser.parse_args()
 
-  variables = {}
+  config = {}
   if options.config_file:
     with open(options.config_file, 'r') as f:
-      variables = json.loads(f.read())
+      config = json.loads(f.read())
+  if options.delta_config_file:
+    with open(options.delta_config_file, 'r') as f:
+      config.update(json.loads(f.read()))
+
+  variables = config
   variables = _AppendParsedVariables(variables, options.extra_variables,
                                      parser.error)
 
diff --git a/chrome/android/webapk/shell_apk/manifest/maps_go_manifest_config.json b/chrome/android/webapk/shell_apk/manifest/maps_go_manifest_config.json
index f9b6953..da8b4cd 100644
--- a/chrome/android/webapk/shell_apk/manifest/maps_go_manifest_config.json
+++ b/chrome/android/webapk/shell_apk/manifest/maps_go_manifest_config.json
@@ -1,5 +1,4 @@
 {
-  "manifest_package": "org.chromium.maps_go_webapk",
   "scope_url": "https://www.google.com/maps",
   "intent_filters": {
     "scope_url_scheme": "https",
diff --git a/chrome/android/webapk/shell_apk/manifest/new_splash_manifest_config.json b/chrome/android/webapk/shell_apk/manifest/new_splash_manifest_config.json
deleted file mode 100644
index 53624f0..0000000
--- a/chrome/android/webapk/shell_apk/manifest/new_splash_manifest_config.json
+++ /dev/null
@@ -1,40 +0,0 @@
-{
-  "manifest_package": "org.chromium.webapk.new.splash",
-  "scope_url": "https://pwa.rocks/",
-  "intent_filters": {
-    "scope_url_scheme": "https",
-    "scope_url_host": "pwa.rocks",
-    "scope_url_path_type": "android:pathPrefix",
-    "scope_url_path": "/"
-  },
-  "start_url": "https://pwa.rocks/",
-  "display_mode": "standalone",
-  "orientation": "portrait",
-  "theme_color": "2147483648L",
-  "background_color": "0L",
-  "has_large_splash_icons": "false",
-  "icon_urls_and_icon_murmur2_hashes": "http://www.pwa.rocks/icon1.png 0 http://www.pwa.rocks/icon2.png 0",
-  "web_manifest_url": "https://pwa.rocks/pwa.webmanifest",
-  "version_code": "1",
-  "version_name": "1.0",
-  "bound_webapk": {
-    "runtime_host": "com.google.android.apps.chrome",
-    "runtime_host_application_name": "Chromium"
-  },
-  "share_template": [{
-	  "index": "0",
-	  "title": "Share All",
-	  "action": "https://pwa.rocks/share.html",
-	  "param_title": "title",
-	  "param_text": "text",
-	  "param_url": "url"
-  },
-  {
-	  "index": "1",
-	  "title": "Share Title",
-	  "action": "https://pwa.rocks/share_title.html",
-	  "param_title": "title",
-	  "param_text": "text",
-	  "param_url": "url"
-  }]
-}
diff --git a/chrome/android/webapk/shell_apk/manifest/unbound_manifest_config.json b/chrome/android/webapk/shell_apk/manifest/unbound_manifest_config.json
index 1cbd1e3..e4620e4 100644
--- a/chrome/android/webapk/shell_apk/manifest/unbound_manifest_config.json
+++ b/chrome/android/webapk/shell_apk/manifest/unbound_manifest_config.json
@@ -1,5 +1,4 @@
 {
-  "manifest_package": "org.chromium.arbitrarypackage",
   "scope_url": "https://pwa.rocks/",
   "intent_filters": {
     "scope_url_scheme": "https",
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp
index 231e5538..396cd05 100644
--- a/chrome/app/settings_strings.grdp
+++ b/chrome/app/settings_strings.grdp
@@ -3627,9 +3627,16 @@
   <message name="IDS_SETTINGS_HISTORY_CHECKBOX_LABEL" desc="Label for the checkbox which enables or disables syncing history between multiple browser instances.">
     History
   </message>
+<if expr="chromeos">
   <message name="IDS_SETTINGS_THEMES_AND_WALLPAPERS_CHECKBOX_LABEL" desc="Label for the checkbox which enables or disables syncing themes and wallpapers between multiple browser instances.">
     Themes &amp; Wallpapers
   </message>
+</if>
+<if expr="not chromeos">
+  <message name="IDS_SETTINGS_THEMES_AND_WALLPAPERS_CHECKBOX_LABEL" desc="Label for the checkbox which enables or disables syncing themes and wallpapers between multiple browser instances.">
+    Themes
+  </message>
+</if>
   <message name="IDS_SETTINGS_BOOKMARKS_CHECKBOX_LABEL" desc="Label for the checkbox which enables or disables syncing bookmarks between multiple browser instances.">
     Bookmarks
   </message>
diff --git a/chrome/app/theme/default_100_percent/cros/notification_easyunlock_promo.png b/chrome/app/theme/default_100_percent/cros/notification_easyunlock_promo.png
deleted file mode 100644
index d3c4ab2c..0000000
--- a/chrome/app/theme/default_100_percent/cros/notification_easyunlock_promo.png
+++ /dev/null
Binary files differ
diff --git a/chrome/app/theme/default_200_percent/cros/notification_easyunlock_promo.png b/chrome/app/theme/default_200_percent/cros/notification_easyunlock_promo.png
deleted file mode 100644
index ae74736..0000000
--- a/chrome/app/theme/default_200_percent/cros/notification_easyunlock_promo.png
+++ /dev/null
Binary files differ
diff --git a/chrome/app/theme/theme_resources.grd b/chrome/app/theme/theme_resources.grd
index 2ed113a4..4eafe64 100644
--- a/chrome/app/theme/theme_resources.grd
+++ b/chrome/app/theme/theme_resources.grd
@@ -192,7 +192,6 @@
         <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_SCREENSHOT_ANNOTATE" file="cros/notification_screenshot_annotate.png" />
         <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_SCREENSHOT_COPY_TO_CLIPBOARD" file="cros/notification_screenshot_copy_to_clipboard.png" />
         <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_EASYUNLOCK_ENABLED" file="cros/notification_easyunlock_enabled.png" />
-        <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_EASYUNLOCK_PROMO" file="cros/notification_easyunlock_promo.png" />
       </if>
       <if expr="not is_android">
         <structure type="chrome_scaled_image" name="IDR_OMNIBOX_CALCULATOR_ROUND" file="chromium/calculator_round_24.png" />
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index f6d9dde..7ba7a9a 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -1638,6 +1638,7 @@
     "vr/vr_tab_helper.h",
     "web_data_service_factory.cc",
     "web_data_service_factory.h",
+    "webauthn/authenticator_list_observer.h",
     "webauthn/authenticator_reference.cc",
     "webauthn/authenticator_reference.h",
     "webauthn/authenticator_request_dialog_model.cc",
@@ -1647,6 +1648,8 @@
     "webauthn/authenticator_transport.h",
     "webauthn/chrome_authenticator_request_delegate.cc",
     "webauthn/chrome_authenticator_request_delegate.h",
+    "webauthn/observable_authenticator_list.cc",
+    "webauthn/observable_authenticator_list.h",
     "webshare/share_target_pref_helper.cc",
     "webshare/share_target_pref_helper.h",
     "webshare/webshare_target.cc",
diff --git a/chrome/browser/DEPS b/chrome/browser/DEPS
index b67eac9..1438322 100644
--- a/chrome/browser/DEPS
+++ b/chrome/browser/DEPS
@@ -63,6 +63,8 @@
   "+services/media_session/public",
   "+services/metrics/metrics_mojo_service.h",
   "+services/metrics/public",
+  "+services/network/cert_verifier_with_trust_anchors.h",
+  "+services/network/cert_verify_proc_chromeos.h",
   "+services/network/ignore_errors_cert_verifier.h",
   "+services/network/network_service.h",
   "+services/network/public",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index ab18b621..9e71fdb 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -4435,6 +4435,15 @@
     {"enable-send-tab-to-self", flag_descriptions::kSendTabToSelfName,
      flag_descriptions::kSendTabToSelfDescription, kOsAll,
      FEATURE_VALUE_TYPE(features::kSendTabToSelf)},
+
+#if defined(OS_CHROMEOS)
+    {"ash-enable-notification-expansion-animation",
+     flag_descriptions::kEnableNotificationExpansionAnimationName,
+     flag_descriptions::kEnableNotificationExpansionAnimationDescription,
+     kOsCrOS,
+     FEATURE_VALUE_TYPE(ash::features::kNotificationExpansionAnimation)},
+
+#endif  // defined(OS_CHROMEOS)
 };
 
 class FlagsStateSingleton {
diff --git a/chrome/browser/after_startup_task_utils.cc b/chrome/browser/after_startup_task_utils.cc
index da3a981..328c4eb9 100644
--- a/chrome/browser/after_startup_task_utils.cc
+++ b/chrome/browser/after_startup_task_utils.cc
@@ -91,8 +91,11 @@
   CHECK(queued_task->task);
 
   if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
-    base::PostTaskWithTraits(FROM_HERE, {BrowserThread::UI},
-                             base::BindOnce(QueueTask, std::move(queued_task)));
+    // Posted with USER_VISIBLE priority to avoid this becoming an after startup
+    // task itself.
+    base::PostTaskWithTraits(
+        FROM_HERE, {BrowserThread::UI, base::TaskPriority::USER_VISIBLE},
+        base::BindOnce(QueueTask, std::move(queued_task)));
     return;
   }
 
diff --git a/chrome/browser/android/autofill_assistant/ui_controller_android.cc b/chrome/browser/android/autofill_assistant/ui_controller_android.cc
index 8f189c9..a5ca3986 100644
--- a/chrome/browser/android/autofill_assistant/ui_controller_android.cc
+++ b/chrome/browser/android/autofill_assistant/ui_controller_android.cc
@@ -18,12 +18,15 @@
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/common/channel_info.h"
+#include "components/autofill_assistant/browser/access_token_fetcher.h"
 #include "components/autofill_assistant/browser/controller.h"
+#include "components/signin/core/browser/account_info.h"
 #include "components/variations/variations_associated_data.h"
 #include "components/version_info/channel.h"
 #include "content/public/browser/web_contents.h"
 #include "google_apis/google_api_keys.h"
 #include "jni/AutofillAssistantUiController_jni.h"
+#include "services/identity/public/cpp/identity_manager.h"
 
 using base::android::AttachCurrentThread;
 using base::android::JavaParamRef;
@@ -60,16 +63,21 @@
     jobject jcaller,
     const JavaParamRef<jobject>& webContents,
     const base::android::JavaParamRef<jobjectArray>& parameterNames,
-    const base::android::JavaParamRef<jobjectArray>& parameterValues)
+    const base::android::JavaParamRef<jobjectArray>& parameterValues,
+    const base::android::JavaParamRef<jstring>& initialUrlString)
     : ui_delegate_(nullptr) {
   java_autofill_assistant_ui_controller_.Reset(env, jcaller);
 
   content::WebContents* web_contents =
       content::WebContents::FromJavaWebContents(webContents);
   DCHECK(web_contents);
+  browser_context_ = web_contents->GetBrowserContext();
+  GURL initialUrl =
+      GURL(base::android::ConvertJavaStringToUTF8(env, initialUrlString));
   Controller::CreateAndStartForWebContents(
       web_contents, base::WrapUnique(this),
-      BuildParametersFromJava(env, parameterNames, parameterValues));
+      BuildParametersFromJava(env, parameterNames, parameterValues),
+      initialUrl);
   DCHECK(ui_delegate_);
 }
 
@@ -199,6 +207,27 @@
   std::move(get_payment_information_callback_).Run(std::move(payment_info));
 }
 
+void UiControllerAndroid::OnAccessToken(
+    JNIEnv* env,
+    const base::android::JavaParamRef<jobject>& jcaller,
+    jboolean success,
+    const JavaParamRef<jstring>& access_token) {
+  if (fetch_access_token_callback_) {
+    std::move(fetch_access_token_callback_)
+        .Run(success, base::android::ConvertJavaStringToUTF8(access_token));
+  }
+}
+
+base::android::ScopedJavaLocalRef<jstring>
+UiControllerAndroid::GetPrimaryAccountName(
+    JNIEnv* env,
+    const base::android::JavaParamRef<jobject>& jcaller) {
+  AccountInfo account_info = IdentityManagerFactory::GetForProfile(
+                                 Profile::FromBrowserContext(browser_context_))
+                                 ->GetPrimaryAccountInfo();
+  return base::android::ConvertUTF8ToJavaString(env, account_info.email);
+}
+
 void UiControllerAndroid::ChooseAddress(
     base::OnceCallback<void(const std::string&)> callback) {
   DCHECK(!address_or_card_callback_);
@@ -219,15 +248,18 @@
 
 void UiControllerAndroid::GetPaymentInformation(
     payments::mojom::PaymentOptionsPtr payment_options,
-    base::OnceCallback<void(std::unique_ptr<PaymentInformation>)> callback) {
+    base::OnceCallback<void(std::unique_ptr<PaymentInformation>)> callback,
+    const std::string& title) {
   DCHECK(!get_payment_information_callback_);
   get_payment_information_callback_ = std::move(callback);
+  JNIEnv* env = AttachCurrentThread();
   Java_AutofillAssistantUiController_onRequestPaymentInformation(
-      AttachCurrentThread(), java_autofill_assistant_ui_controller_,
+      env, java_autofill_assistant_ui_controller_,
       payment_options->request_shipping, payment_options->request_payer_name,
       payment_options->request_payer_phone,
       payment_options->request_payer_email,
-      static_cast<int>(payment_options->shipping_type));
+      static_cast<int>(payment_options->shipping_type),
+      base::android::ConvertUTF8ToJavaString(env, title));
 }
 
 void UiControllerAndroid::HideDetails() {
@@ -281,22 +313,8 @@
   return api_key;
 }
 
-identity::IdentityManager*
-UiControllerAndroid::GetIdentityManagerForPrimaryAccount() {
-  Profile* profile = ProfileManager::GetActiveUserProfile();
-  if (!profile) {
-    DLOG(ERROR) << "No active user profile. Cannot authenticate.";
-    return nullptr;
-  }
-  // TODO(crbug.com/806868): Log in as a specific account, instead of always the
-  // primary.
-  identity::IdentityManager* identity_manager =
-      profile ? IdentityManagerFactory::GetForProfile(profile) : nullptr;
-  if (!identity_manager || !identity_manager->HasPrimaryAccount()) {
-    DLOG(ERROR) << "No primary account. Cannot authenticate.";
-    return nullptr;
-  }
-  return identity_manager;
+AccessTokenFetcher* UiControllerAndroid::GetAccessTokenFetcher() {
+  return this;
 }
 
 autofill::PersonalDataManager* UiControllerAndroid::GetPersonalDataManager() {
@@ -313,6 +331,24 @@
   return this;
 }
 
+void UiControllerAndroid::FetchAccessToken(
+    base::OnceCallback<void(bool, const std::string&)> callback) {
+  DCHECK(!fetch_access_token_callback_);
+
+  fetch_access_token_callback_ = std::move(callback);
+  JNIEnv* env = AttachCurrentThread();
+  Java_AutofillAssistantUiController_fetchAccessToken(
+      env, java_autofill_assistant_ui_controller_);
+}
+
+void UiControllerAndroid::InvalidateAccessToken(
+    const std::string& access_token) {
+  JNIEnv* env = AttachCurrentThread();
+  Java_AutofillAssistantUiController_invalidateAccessToken(
+      env, java_autofill_assistant_ui_controller_,
+      base::android::ConvertUTF8ToJavaString(env, access_token));
+}
+
 void UiControllerAndroid::Destroy(JNIEnv* env,
                                   const JavaParamRef<jobject>& obj) {
   ui_delegate_->OnDestroy();
@@ -323,9 +359,11 @@
     const base::android::JavaParamRef<jobject>& jcaller,
     const base::android::JavaParamRef<jobject>& webContents,
     const base::android::JavaParamRef<jobjectArray>& parameterNames,
-    const base::android::JavaParamRef<jobjectArray>& parameterValues) {
+    const base::android::JavaParamRef<jobjectArray>& parameterValues,
+    const base::android::JavaParamRef<jstring>& initialUrlString) {
   auto* ui_controller_android = new autofill_assistant::UiControllerAndroid(
-      env, jcaller, webContents, parameterNames, parameterValues);
+      env, jcaller, webContents, parameterNames, parameterValues,
+      initialUrlString);
   return reinterpret_cast<intptr_t>(ui_controller_android);
 }
 
diff --git a/chrome/browser/android/autofill_assistant/ui_controller_android.h b/chrome/browser/android/autofill_assistant/ui_controller_android.h
index 225cc02..eb3c6a37 100644
--- a/chrome/browser/android/autofill_assistant/ui_controller_android.h
+++ b/chrome/browser/android/autofill_assistant/ui_controller_android.h
@@ -5,24 +5,33 @@
 #ifndef CHROME_BROWSER_ANDROID_AUTOFILL_ASSISTANT_UI_CONTROLLER_ANDROID_H_
 #define CHROME_BROWSER_ANDROID_AUTOFILL_ASSISTANT_UI_CONTROLLER_ANDROID_H_
 
+#include <memory>
 #include <string>
 #include <vector>
 
 #include "base/android/scoped_java_ref.h"
 #include "base/macros.h"
+#include "components/autofill_assistant/browser/access_token_fetcher.h"
 #include "components/autofill_assistant/browser/client.h"
 #include "components/autofill_assistant/browser/ui_controller.h"
 
+namespace content {
+class BrowserContext;
+}  // namespace content
+
 namespace autofill_assistant {
 // Class implements UiController, Client and starts the Controller.
-class UiControllerAndroid : public UiController, public Client {
+class UiControllerAndroid : public UiController,
+                            public Client,
+                            public AccessTokenFetcher {
  public:
   UiControllerAndroid(
       JNIEnv* env,
       jobject jcaller,
       const base::android::JavaParamRef<jobject>& webContents,
       const base::android::JavaParamRef<jobjectArray>& parameterNames,
-      const base::android::JavaParamRef<jobjectArray>& parameterValues);
+      const base::android::JavaParamRef<jobjectArray>& parameterValues,
+      const base::android::JavaParamRef<jstring>& initialUrlString);
   ~UiControllerAndroid() override;
 
   // Overrides UiController:
@@ -38,8 +47,8 @@
       base::OnceCallback<void(const std::string&)> callback) override;
   void GetPaymentInformation(
       payments::mojom::PaymentOptionsPtr payment_options,
-      base::OnceCallback<void(std::unique_ptr<PaymentInformation>)> callback)
-      override;
+      base::OnceCallback<void(std::unique_ptr<PaymentInformation>)> callback,
+      const std::string& title) override;
   void HideDetails() override;
   void ShowDetails(const DetailsProto& details) override;
   void ShowProgressBar(int progress, const std::string& message) override;
@@ -47,11 +56,16 @@
 
   // Overrides Client:
   std::string GetApiKey() override;
-  identity::IdentityManager* GetIdentityManagerForPrimaryAccount() override;
+  AccessTokenFetcher* GetAccessTokenFetcher() override;
   autofill::PersonalDataManager* GetPersonalDataManager() override;
   std::string GetServerUrl() override;
   UiController* GetUiController() override;
 
+  // Overrides AccessTokenFetcher
+  void FetchAccessToken(
+      base::OnceCallback<void(bool, const std::string&)>) override;
+  void InvalidateAccessToken(const std::string& access_token) override;
+
   // Called by Java.
   void Destroy(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj);
   void OnScriptSelected(
@@ -75,6 +89,13 @@
       const base::android::JavaParamRef<jstring>& jpayer_name,
       const base::android::JavaParamRef<jstring>& jpayer_phone,
       const base::android::JavaParamRef<jstring>& jpayer_email);
+  void OnAccessToken(JNIEnv* env,
+                     const base::android::JavaParamRef<jobject>& jcaller,
+                     jboolean success,
+                     const base::android::JavaParamRef<jstring>& access_token);
+  base::android::ScopedJavaLocalRef<jstring> GetPrimaryAccountName(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& jcaller);
 
  private:
   // Java-side AutofillAssistantUiController object.
@@ -82,10 +103,14 @@
       java_autofill_assistant_ui_controller_;
 
   UiDelegate* ui_delegate_;
+  content::BrowserContext* browser_context_;
 
   base::OnceCallback<void(const std::string&)> address_or_card_callback_;
   base::OnceCallback<void(std::unique_ptr<PaymentInformation>)>
       get_payment_information_callback_;
+  std::unique_ptr<AccessTokenFetcher> access_token_fetcher_;
+  base::OnceCallback<void(bool, const std::string&)>
+      fetch_access_token_callback_;
 
   DISALLOW_COPY_AND_ASSIGN(UiControllerAndroid);
 };
diff --git a/chrome/browser/android/bookmarks/bookmark_bridge.cc b/chrome/browser/android/bookmarks/bookmark_bridge.cc
index 41fc55e..bf790a4 100644
--- a/chrome/browser/android/bookmarks/bookmark_bridge.cc
+++ b/chrome/browser/android/bookmarks/bookmark_bridge.cc
@@ -19,7 +19,7 @@
 #include "chrome/browser/profiles/incognito_helpers.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_android.h"
-#include "chrome/browser/signin/signin_manager_factory.h"
+#include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/undo/bookmark_undo_service_factory.h"
 #include "components/bookmarks/browser/bookmark_model.h"
 #include "components/bookmarks/browser/bookmark_utils.h"
@@ -30,11 +30,11 @@
 #include "components/bookmarks/managed/managed_bookmark_service.h"
 #include "components/prefs/pref_service.h"
 #include "components/query_parser/query_parser.h"
-#include "components/signin/core/browser/signin_manager.h"
 #include "components/undo/bookmark_undo_service.h"
 #include "components/undo/undo_manager.h"
 #include "content/public/browser/browser_thread.h"
 #include "jni/BookmarkBridge_jni.h"
+#include "services/identity/public/cpp/identity_manager.h"
 
 using base::android::AttachCurrentThread;
 using base::android::ConvertUTF8ToJavaString;
@@ -874,11 +874,11 @@
   if (folder == managed_bookmark_service_->managed_node() && folder->empty())
     return false;
 
-  SigninManager* signin = SigninManagerFactory::GetForProfile(
-      profile_->GetOriginalProfile());
+  auto* identity_manager =
+      IdentityManagerFactory::GetForProfile(profile_->GetOriginalProfile());
   return (folder->type() != BookmarkNode::BOOKMARK_BAR &&
-      folder->type() != BookmarkNode::OTHER_NODE) ||
-      (signin && signin->IsAuthenticated());
+          folder->type() != BookmarkNode::OTHER_NODE) ||
+         (identity_manager && identity_manager->HasPrimaryAccount());
 }
 
 void BookmarkBridge::NotifyIfDoneLoading() {
diff --git a/chrome/browser/android/password_ui_view_android.cc b/chrome/browser/android/password_ui_view_android.cc
index 187fe4a..4587152 100644
--- a/chrome/browser/android/password_ui_view_android.cc
+++ b/chrome/browser/android/password_ui_view_android.cc
@@ -9,16 +9,19 @@
 #include <vector>
 
 #include "base/android/callback_android.h"
+#include "base/android/int_string_callback.h"
 #include "base/android/jni_string.h"
 #include "base/android/jni_weak_ref.h"
 #include "base/android/scoped_java_ref.h"
 #include "base/bind_helpers.h"
+#include "base/files/file.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/metrics/field_trial.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/strings/string_piece.h"
 #include "base/task/post_task.h"
+#include "base/threading/scoped_blocking_call.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
 #include "chrome/grit/generated_resources.h"
@@ -148,7 +151,7 @@
 void PasswordUIViewAndroid::HandleSerializePasswords(
     JNIEnv* env,
     const JavaRef<jobject>&,
-    const JavaRef<jstring>& java_target_path,
+    const JavaRef<jstring>& java_target_directory,
     const JavaRef<jobject>& success_callback,
     const JavaRef<jobject>& error_callback) {
   switch (state_) {
@@ -177,7 +180,7 @@
       base::BindOnce(
           &PasswordUIViewAndroid::ObtainAndSerializePasswords,
           base::Unretained(this),
-          base::FilePath(ConvertJavaStringToUTF8(env, java_target_path))),
+          base::FilePath(ConvertJavaStringToUTF8(env, java_target_directory))),
       base::BindOnce(&PasswordUIViewAndroid::PostSerializedPasswords,
                      base::Unretained(this),
                      base::android::ScopedJavaGlobalRef<jobject>(
@@ -202,7 +205,7 @@
 
 PasswordUIViewAndroid::SerializationResult
 PasswordUIViewAndroid::ObtainAndSerializePasswords(
-    const base::FilePath& target_path) {
+    const base::FilePath& target_directory) {
   // This is run on a backend task runner. Do not access any member variables
   // except for |credential_provider_for_testing_| and
   // |password_manager_presenter_|.
@@ -216,13 +219,36 @@
   // The UI should not trigger serialization if there are not passwords.
   DCHECK(!passwords.empty());
 
+  // Creating a file will block the execution on I/O.
+  base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::WILL_BLOCK);
+
+  // Ensure that the target directory exists.
+  base::File::Error error = base::File::FILE_OK;
+  if (!base::CreateDirectoryAndGetError(target_directory, &error)) {
+    return {0, std::string(), base::File::ErrorToString(error)};
+  }
+
+  // Create a temporary file in the target directory to hold the serialized
+  // passwords.
+  base::FilePath export_file;
+  if (!base::CreateTemporaryFileInDir(target_directory, &export_file)) {
+    return {
+        0, std::string(),
+        logging::SystemErrorCodeToString(logging::GetLastSystemErrorCode())};
+  }
+
+  // Write the serialized data in CSV.
   std::string data =
       password_manager::PasswordCSVWriter::SerializePasswords(passwords);
-  int bytes_written = base::WriteFile(target_path, data.data(), data.size());
-  if (bytes_written != base::checked_cast<int>(data.size()))
-    return {0, logging::GetLastSystemErrorCode()};
+  int bytes_written = base::WriteFile(export_file, data.data(), data.size());
+  if (bytes_written != base::checked_cast<int>(data.size())) {
+    return {
+        0, std::string(),
+        logging::SystemErrorCodeToString(logging::GetLastSystemErrorCode())};
+  }
 
-  return {static_cast<int>(passwords.size()), 0};
+  return {static_cast<int>(passwords.size()), export_file.value(),
+          std::string()};
 }
 
 void PasswordUIViewAndroid::PostSerializedPasswords(
@@ -240,12 +266,12 @@
         *export_target_for_testing_ = serialization_result;
       } else {
         if (serialization_result.entries_count) {
-          base::android::RunIntCallbackAndroid(
-              success_callback, serialization_result.entries_count);
+          base::android::RunIntStringCallbackAndroid(
+              success_callback, serialization_result.entries_count,
+              serialization_result.exported_file_path);
         } else {
-          base::android::RunStringCallbackAndroid(
-              error_callback,
-              logging::SystemErrorCodeToString(serialization_result.error));
+          base::android::RunStringCallbackAndroid(error_callback,
+                                                  serialization_result.error);
         }
       }
       break;
diff --git a/chrome/browser/android/password_ui_view_android.h b/chrome/browser/android/password_ui_view_android.h
index 62206012..888f713 100644
--- a/chrome/browser/android/password_ui_view_android.h
+++ b/chrome/browser/android/password_ui_view_android.h
@@ -36,9 +36,13 @@
     // The number of password entries written. 0 if error encountered.
     int entries_count;
 
-    // The system error code recorded after the last write operation. 0 if no
-    // error encountered.
-    logging::SystemErrorCode error;
+    // The path to the temporary file containing the serialized passwords. Empty
+    // if error encountered.
+    std::string exported_file_path;
+
+    // The error description recorded after the last write operation. Empty if
+    // no error encountered.
+    std::string error;
   };
 
   PasswordUIViewAndroid(JNIEnv* env, jobject);
@@ -75,7 +79,7 @@
   void HandleSerializePasswords(
       JNIEnv* env,
       const base::android::JavaRef<jobject>&,
-      const base::android::JavaRef<jstring>& java_target_path,
+      const base::android::JavaRef<jstring>& java_target_directory,
       const base::android::JavaRef<jobject>& success_callback,
       const base::android::JavaRef<jobject>& error_callback);
   // Destroy the native implementation.
@@ -112,11 +116,11 @@
 
   // Calls |password_manager_presenter_| to retrieve cached PasswordForm
   // objects, then PasswordCSVWriter to serialize them, and finally writes them
-  // to |target_path|. The steps involve a lot of memory allocation and copying,
-  // as well as I/O operations, so this method should be executed on a suitable
-  // task runner.
+  // to a temporary file in |target_directory|. The steps involve a lot of
+  // memory allocation and copying, as well as I/O operations, so this method
+  // should be executed on a suitable task runner.
   SerializationResult ObtainAndSerializePasswords(
-      const base::FilePath& target_path);
+      const base::FilePath& target_directory);
 
   // Sends |serialization_result| to Java via |success_callback| or
   // |error_callback|, depending on whether the result is a success or an error.
diff --git a/chrome/browser/android/password_ui_view_android_unittest.cc b/chrome/browser/android/password_ui_view_android_unittest.cc
index 4054ef4..d97493c9 100644
--- a/chrome/browser/android/password_ui_view_android_unittest.cc
+++ b/chrome/browser/android/password_ui_view_android_unittest.cc
@@ -104,7 +104,6 @@
         testing_profile_manager_.CreateTestingProfile("test profile");
 
     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
-    temp_file_ = temp_dir_.GetPath().Append("passwords.csv");
   }
 
   content::TestBrowserThreadBundle thread_bundle_;
@@ -112,7 +111,6 @@
   TestingProfile* testing_profile_;
   JNIEnv* env_;
   base::ScopedTempDir temp_dir_;
-  base::FilePath temp_file_;
 };
 
 // Test that the asynchronous processing of password serialization controlled by
@@ -137,21 +135,24 @@
   password_ui_view->set_credential_provider_for_testing(&provider);
   password_ui_view->HandleSerializePasswords(
       env_, nullptr,
-      base::android::ConvertUTF8ToJavaString(env_, temp_file_.AsUTF8Unsafe()),
+      base::android::ConvertUTF8ToJavaString(
+          env_, temp_dir_.GetPath().AsUTF8Unsafe()),
       nullptr, nullptr);
 
   content::RunAllTasksUntilIdle();
   // The buffer for actual result is 1 byte longer than the expected data to be
   // able to detect when the actual data are too long.
   char actual_result[expected_result.size() + 1];
-  int number_of_bytes_read =
-      base::ReadFile(temp_file_, actual_result, expected_result.size() + 1);
+  int number_of_bytes_read = base::ReadFile(
+      base::FilePath::FromUTF8Unsafe(serialized_passwords.exported_file_path),
+      actual_result, expected_result.size() + 1);
   EXPECT_EQ(static_cast<int>(expected_result.size()), number_of_bytes_read);
   EXPECT_EQ(expected_result,
             std::string(actual_result,
                         (number_of_bytes_read < 0) ? 0 : number_of_bytes_read));
   EXPECT_EQ(1, serialized_passwords.entries_count);
-  EXPECT_EQ(0, serialized_passwords.error);
+  EXPECT_FALSE(serialized_passwords.exported_file_path.empty());
+  EXPECT_EQ(std::string(), serialized_passwords.error);
 }
 
 // Test that destroying the PasswordUIView when tasks are pending does not lead
@@ -165,15 +166,16 @@
           new PasswordUIViewAndroid(env_, JavaParamRef<jobject>(nullptr)));
   PasswordUIViewAndroid::SerializationResult serialized_passwords;
   serialized_passwords.entries_count = 123;
-  serialized_passwords.error = 567;
+  serialized_passwords.exported_file_path = "somepath";
   password_ui_view->set_export_target_for_testing(&serialized_passwords);
   password_ui_view->set_credential_provider_for_testing(&provider);
-  base::android::ScopedJavaLocalRef<jstring> java_temp_file =
-      base::android::ConvertUTF8ToJavaString(env_, temp_file_.AsUTF8Unsafe());
+  base::android::ScopedJavaLocalRef<jstring> java_target_dir =
+      base::android::ConvertUTF8ToJavaString(
+          env_, temp_dir_.GetPath().AsUTF8Unsafe());
   password_ui_view->HandleSerializePasswords(
       env_, nullptr,
-      base::android::JavaParamRef<jstring>(env_, java_temp_file.obj()), nullptr,
-      nullptr);
+      base::android::JavaParamRef<jstring>(env_, java_target_dir.obj()),
+      nullptr, nullptr);
   // Register the PasswordUIView for deletion. It should not destruct itself
   // before the background tasks are run. The results of the background tasks
   // are waited for and then thrown out, so |serialized_passwords| should not be
@@ -182,7 +184,8 @@
   // Now run the background tasks (and the subsequent deletion).
   content::RunAllTasksUntilIdle();
   EXPECT_EQ(123, serialized_passwords.entries_count);
-  EXPECT_EQ(567, serialized_passwords.error);
+  EXPECT_EQ("somepath", serialized_passwords.exported_file_path);
+  EXPECT_EQ(std::string(), serialized_passwords.error);
 }
 
 // Test that an I/O error is reported.
@@ -197,15 +200,15 @@
   password_ui_view->set_export_target_for_testing(&serialized_passwords);
   password_ui_view->set_credential_provider_for_testing(&provider);
   base::android::ScopedJavaLocalRef<jstring> java_temp_file =
-      base::android::ConvertUTF8ToJavaString(env_, "Non-existing file");
+      base::android::ConvertUTF8ToJavaString(
+          env_, "/This directory cannot be created");
   password_ui_view->HandleSerializePasswords(
       env_, nullptr,
       base::android::JavaParamRef<jstring>(env_, java_temp_file.obj()), nullptr,
       nullptr);
-  // Now run the background tasks (and the subsequent deletion).
   content::RunAllTasksUntilIdle();
   EXPECT_EQ(0, serialized_passwords.entries_count);
-  EXPECT_LT(0, serialized_passwords.error);
+  EXPECT_FALSE(serialized_passwords.error.empty());
 }
 
 }  //  namespace android
diff --git a/chrome/browser/android/vr/arcore_device/ar_image_transport.cc b/chrome/browser/android/vr/arcore_device/ar_image_transport.cc
index 419e533..7e552c9 100644
--- a/chrome/browser/android/vr/arcore_device/ar_image_transport.cc
+++ b/chrome/browser/android/vr/arcore_device/ar_image_transport.cc
@@ -7,7 +7,7 @@
 #include "base/android/android_hardware_buffer_compat.h"
 #include "base/android/scoped_hardware_buffer_handle.h"
 #include "base/containers/queue.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "chrome/browser/android/vr/mailbox_to_surface_bridge.h"
 #include "gpu/ipc/common/gpu_memory_buffer_impl_android_hardware_buffer.h"
 #include "ui/gfx/gpu_fence.h"
diff --git a/chrome/browser/android/vr/arcore_device/arcore_gl.cc b/chrome/browser/android/vr/arcore_device/arcore_gl.cc
index 409b8cf..7b0ec13 100644
--- a/chrome/browser/android/vr/arcore_device/arcore_gl.cc
+++ b/chrome/browser/android/vr/arcore_device/arcore_gl.cc
@@ -15,7 +15,7 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/task/post_task.h"
 #include "base/threading/thread_task_runner_handle.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "chrome/browser/android/vr/arcore_device/ar_image_transport.h"
 #include "chrome/browser/android/vr/arcore_device/arcore_impl.h"
 #include "chrome/browser/android/vr/arcore_device/arcore_install_utils.h"
diff --git a/chrome/browser/android/vr/gvr_graphics_delegate.cc b/chrome/browser/android/vr/gvr_graphics_delegate.cc
index 6f8fe14..ac73b79a 100644
--- a/chrome/browser/android/vr/gvr_graphics_delegate.cc
+++ b/chrome/browser/android/vr/gvr_graphics_delegate.cc
@@ -7,7 +7,7 @@
 #include <algorithm>
 
 #include "base/time/time.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "chrome/browser/android/vr/gl_browser_interface.h"
 #include "chrome/browser/android/vr/gvr_util.h"
 #include "chrome/browser/vr/gl_texture_location.h"
diff --git a/chrome/browser/android/vr/gvr_scheduler_delegate.cc b/chrome/browser/android/vr/gvr_scheduler_delegate.cc
index 849bddcd..ca2ed49 100644
--- a/chrome/browser/android/vr/gvr_scheduler_delegate.cc
+++ b/chrome/browser/android/vr/gvr_scheduler_delegate.cc
@@ -10,7 +10,7 @@
 #include "base/android/android_hardware_buffer_compat.h"
 #include "base/metrics/field_trial_params.h"
 #include "base/threading/thread_task_runner_handle.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "chrome/browser/android/vr/gl_browser_interface.h"
 #include "chrome/browser/android/vr/mailbox_to_surface_bridge.h"
 #include "chrome/browser/android/vr/metrics_util_android.h"
diff --git a/chrome/browser/apps/app_shim/BUILD.gn b/chrome/browser/apps/app_shim/BUILD.gn
index d2d02de18..ffd8a3e7e 100644
--- a/chrome/browser/apps/app_shim/BUILD.gn
+++ b/chrome/browser/apps/app_shim/BUILD.gn
@@ -8,6 +8,8 @@
   sources = [
     "app_shim_handler_mac.cc",
     "app_shim_handler_mac.h",
+    "app_shim_host_bootstrap_mac.cc",
+    "app_shim_host_bootstrap_mac.h",
     "app_shim_host_mac.cc",
     "app_shim_host_mac.h",
     "app_shim_host_manager_mac.h",
diff --git a/chrome/browser/apps/app_shim/app_shim_host_bootstrap_mac.cc b/chrome/browser/apps/app_shim/app_shim_host_bootstrap_mac.cc
new file mode 100644
index 0000000..bea5124
--- /dev/null
+++ b/chrome/browser/apps/app_shim/app_shim_host_bootstrap_mac.cc
@@ -0,0 +1,102 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/apps/app_shim/app_shim_host_bootstrap_mac.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/bind.h"
+#include "mojo/public/cpp/system/message_pipe.h"
+
+// static
+void AppShimHostBootstrap::CreateForChannel(
+    mojo::PlatformChannelEndpoint endpoint) {
+  // AppShimHostBootstrap is initially owned by itself until it receives a
+  // LaunchApp message or a channel error. In LaunchApp, ownership is
+  // transferred to a unique_ptr.
+  (new AppShimHostBootstrap)->ServeChannel(std::move(endpoint));
+}
+
+AppShimHostBootstrap::AppShimHostBootstrap() : host_bootstrap_binding_(this) {}
+
+AppShimHostBootstrap::~AppShimHostBootstrap() {
+  DCHECK(!launch_app_callback_);
+}
+
+void AppShimHostBootstrap::ServeChannel(
+    mojo::PlatformChannelEndpoint endpoint) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  mojo::ScopedMessagePipeHandle message_pipe =
+      bootstrap_mojo_connection_.Connect(std::move(endpoint));
+  host_bootstrap_binding_.Bind(
+      chrome::mojom::AppShimHostBootstrapRequest(std::move(message_pipe)));
+  host_bootstrap_binding_.set_connection_error_with_reason_handler(
+      base::BindOnce(&AppShimHostBootstrap::ChannelError,
+                     base::Unretained(this)));
+}
+
+void AppShimHostBootstrap::ChannelError(uint32_t custom_reason,
+                                        const std::string& description) {
+  // Once |this| has received a LaunchApp message, it is owned by a unique_ptr
+  // (not the channel anymore).
+  if (has_received_launch_app_)
+    return;
+  LOG(ERROR) << "Channel error custom_reason:" << custom_reason
+             << " description: " << description;
+  delete this;
+}
+
+chrome::mojom::AppShimHostRequest
+AppShimHostBootstrap::GetLaunchAppShimHostRequest() {
+  return std::move(app_shim_host_request_);
+}
+
+apps::AppShimLaunchType AppShimHostBootstrap::GetLaunchType() const {
+  return launch_type_;
+}
+
+const std::vector<base::FilePath>& AppShimHostBootstrap::GetLaunchFiles()
+    const {
+  return files_;
+}
+
+apps::AppShimHandler::Host* AppShimHostBootstrap::GetHostForTesting() {
+  return connected_host_;
+}
+
+void AppShimHostBootstrap::LaunchApp(
+    chrome::mojom::AppShimHostRequest app_shim_host_request,
+    const base::FilePath& profile_dir,
+    const std::string& app_id,
+    apps::AppShimLaunchType launch_type,
+    const std::vector<base::FilePath>& files,
+    LaunchAppCallback callback) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(!has_received_launch_app_);
+  // Only one app launch message per channel.
+  if (has_received_launch_app_)
+    return;
+
+  app_shim_host_request_ = std::move(app_shim_host_request);
+  launch_type_ = launch_type;
+  files_ = files;
+  launch_app_callback_ = std::move(callback);
+
+  // Transfer ownership to a unique_ptr and mark that LaunchApp has been
+  // received. Note that after this point, a channel error will no longer
+  // cause |this| to be deleted.
+  has_received_launch_app_ = true;
+  std::unique_ptr<AppShimHostBootstrap> deleter(this);
+
+  // |connected_host_| takes ownership of itself and |this|.
+  connected_host_ = new AppShimHost(app_id, profile_dir);
+  connected_host_->OnBootstrapConnected(std::move(deleter));
+}
+
+void AppShimHostBootstrap::OnLaunchAppComplete(
+    apps::AppShimLaunchResult result,
+    chrome::mojom::AppShimRequest app_shim_request) {
+  std::move(launch_app_callback_).Run(result, std::move(app_shim_request));
+}
diff --git a/chrome/browser/apps/app_shim/app_shim_host_bootstrap_mac.h b/chrome/browser/apps/app_shim/app_shim_host_bootstrap_mac.h
new file mode 100644
index 0000000..f961ffd
--- /dev/null
+++ b/chrome/browser/apps/app_shim/app_shim_host_bootstrap_mac.h
@@ -0,0 +1,69 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_APPS_APP_SHIM_APP_SHIM_HOST_BOOTSTRAP_MAC_H_
+#define CHROME_BROWSER_APPS_APP_SHIM_APP_SHIM_HOST_BOOTSTRAP_MAC_H_
+
+#include <string>
+#include <vector>
+
+#include "base/files/file_path.h"
+#include "base/macros.h"
+#include "base/threading/thread_checker.h"
+#include "chrome/browser/apps/app_shim/app_shim_host_mac.h"
+#include "chrome/common/mac/app_shim.mojom.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/platform/platform_channel_endpoint.h"
+#include "mojo/public/cpp/system/isolated_connection.h"
+
+class AppShimHostBootstrap : public chrome::mojom::AppShimHostBootstrap {
+ public:
+  // Creates a new server-side mojo channel at |endpoint|, which should contain
+  // a file descriptor of a channel created by an UnixDomainSocketAcceptor, and
+  // begins listening for messages on it.
+  static void CreateForChannel(mojo::PlatformChannelEndpoint endpoint);
+  ~AppShimHostBootstrap() override;
+
+  void OnLaunchAppComplete(apps::AppShimLaunchResult result,
+                           chrome::mojom::AppShimRequest app_shim_request);
+
+  chrome::mojom::AppShimHostRequest GetLaunchAppShimHostRequest();
+  apps::AppShimLaunchType GetLaunchType() const;
+  const std::vector<base::FilePath>& GetLaunchFiles() const;
+
+  apps::AppShimHandler::Host* GetHostForTesting();
+
+ protected:
+  AppShimHostBootstrap();
+  void ServeChannel(mojo::PlatformChannelEndpoint endpoint);
+  void ChannelError(uint32_t custom_reason, const std::string& description);
+
+  // chrome::mojom::AppShimHostBootstrap.
+  void LaunchApp(chrome::mojom::AppShimHostRequest app_shim_host_request,
+                 const base::FilePath& profile_dir,
+                 const std::string& app_id,
+                 apps::AppShimLaunchType launch_type,
+                 const std::vector<base::FilePath>& files,
+                 LaunchAppCallback callback) override;
+
+  mojo::IsolatedConnection bootstrap_mojo_connection_;
+  mojo::Binding<chrome::mojom::AppShimHostBootstrap> host_bootstrap_binding_;
+
+  // The arguments from the LaunchApp call, and whether or not it has happened
+  // yet.
+  bool has_received_launch_app_ = false;
+  chrome::mojom::AppShimHostRequest app_shim_host_request_;
+  apps::AppShimLaunchType launch_type_;
+  std::vector<base::FilePath> files_;
+  LaunchAppCallback launch_app_callback_;
+
+  // The AppShimHost that has taken ownership of this object. Weak, set in
+  // LaunchApp.
+  AppShimHost* connected_host_ = nullptr;
+
+  THREAD_CHECKER(thread_checker_);
+  DISALLOW_COPY_AND_ASSIGN(AppShimHostBootstrap);
+};
+
+#endif  // CHROME_BROWSER_APPS_APP_SHIM_APP_SHIM_HOST_BOOTSTRAP_MAC_H_
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 2b73830..0f24d8f 100644
--- a/chrome/browser/apps/app_shim/app_shim_host_mac.cc
+++ b/chrome/browser/apps/app_shim/app_shim_host_mac.cc
@@ -10,90 +10,28 @@
 #include "base/files/file_path.h"
 #include "base/logging.h"
 #include "chrome/browser/apps/app_shim/app_shim_handler_mac.h"
+#include "chrome/browser/apps/app_shim/app_shim_host_bootstrap_mac.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/ns_view_bridge_factory_host.h"
 #include "content/public/common/ns_view_bridge_factory.mojom.h"
+#include "mojo/public/cpp/bindings/interface_request.h"
 #include "ui/base/ui_base_features.h"
 #include "ui/views/cocoa/bridge_factory_host.h"
 #include "ui/views_bridge_mac/mojo/bridge_factory.mojom.h"
 
 namespace {
-
 // Start counting host ids at 1000 to help in debugging.
 uint64_t g_next_host_id = 1000;
-
 }  // namespace
 
-AppShimHost::AppShimHost()
-    : host_bootstrap_binding_(this),
-      host_binding_(this),
-      app_shim_request_(mojo::MakeRequest(&app_shim_)) {}
-
-AppShimHost::~AppShimHost() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  apps::AppShimHandler* handler = apps::AppShimHandler::GetForAppMode(app_id_);
-  if (handler)
-    handler->OnShimClose(this);
-}
-
-void AppShimHost::ServeChannel(mojo::PlatformChannelEndpoint endpoint) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  mojo::ScopedMessagePipeHandle message_pipe =
-      bootstrap_mojo_connection_.Connect(std::move(endpoint));
-  host_bootstrap_binding_.Bind(
-      chrome::mojom::AppShimHostBootstrapRequest(std::move(message_pipe)));
-  host_bootstrap_binding_.set_connection_error_with_reason_handler(
-      base::BindOnce(&AppShimHost::BootstrapChannelError,
-                     base::Unretained(this)));
-}
-
-void AppShimHost::BootstrapChannelError(uint32_t custom_reason,
-                                        const std::string& description) {
-  // The bootstrap channel is expected to close after sending LaunchApp.
-  if (has_received_launch_app_)
-    return;
-  LOG(ERROR) << "Channel error custom_reason:" << custom_reason
-             << " description: " << description;
-  Close();
-}
-
-void AppShimHost::ChannelError(uint32_t custom_reason,
-                               const std::string& description) {
-  LOG(ERROR) << "Channel error custom_reason:" << custom_reason
-             << " description: " << description;
-  Close();
-}
-
-void AppShimHost::Close() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  delete this;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// AppShimHost, chrome::mojom::AppShimHost
-
-void AppShimHost::LaunchApp(
-    chrome::mojom::AppShimHostRequest app_shim_host_request,
-    const base::FilePath& profile_dir,
-    const std::string& app_id,
-    apps::AppShimLaunchType launch_type,
-    const std::vector<base::FilePath>& files,
-    LaunchAppCallback callback) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(!has_received_launch_app_);
-  // Only one app launch message per channel.
-  if (has_received_launch_app_)
-    return;
-  has_received_launch_app_ = true;
-
-  bootstrap_launch_app_callback_ = std::move(callback);
-  host_binding_.Bind(std::move(app_shim_host_request));
-  host_binding_.set_connection_error_with_reason_handler(
-      base::BindOnce(&AppShimHost::ChannelError, base::Unretained(this)));
-
+AppShimHost::AppShimHost(const std::string& app_id,
+                         const base::FilePath& profile_path)
+    : host_binding_(this),
+      app_shim_request_(mojo::MakeRequest(&app_shim_)),
+      app_id_(app_id),
+      profile_path_(profile_path) {
   // Create the interfaces used to host windows, so that browser windows may be
   // created before the host process finishes launching.
-  // TODO(ccameron): Move earlier in initialization.
   if (features::HostWindowsInAppShimProcess()) {
     uint64_t host_id = g_next_host_id++;
 
@@ -116,12 +54,44 @@
     app_shim_->CreateContentNSViewBridgeFactory(
         std::move(content_bridge_factory_request));
   }
-  profile_path_ = profile_dir;
-  app_id_ = app_id;
+}
+
+AppShimHost::~AppShimHost() {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  apps::AppShimHandler* handler = apps::AppShimHandler::GetForAppMode(app_id_);
+  if (handler)
+    handler->OnShimClose(this);
+}
+
+void AppShimHost::ChannelError(uint32_t custom_reason,
+                               const std::string& description) {
+  LOG(ERROR) << "Channel error custom_reason:" << custom_reason
+             << " description: " << description;
+  Close();
+}
+
+void AppShimHost::Close() {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  delete this;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// AppShimHost, chrome::mojom::AppShimHost
+
+void AppShimHost::OnBootstrapConnected(
+    std::unique_ptr<AppShimHostBootstrap> bootstrap) {
+  DCHECK(!bootstrap_);
+  bootstrap_ = std::move(bootstrap);
+
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  host_binding_.Bind(bootstrap_->GetLaunchAppShimHostRequest());
+  host_binding_.set_connection_error_with_reason_handler(
+      base::BindOnce(&AppShimHost::ChannelError, base::Unretained(this)));
 
   apps::AppShimHandler* handler = apps::AppShimHandler::GetForAppMode(app_id_);
   if (handler)
-    handler->OnShimLaunch(this, launch_type, files);
+    handler->OnShimLaunch(this, bootstrap_->GetLaunchType(),
+                          bootstrap_->GetLaunchFiles());
   // |handler| can only be NULL after AppShimHostManager is destroyed. Since
   // this only happens at shutdown, do nothing here.
 }
@@ -153,8 +123,8 @@
 
 void AppShimHost::OnAppLaunchComplete(apps::AppShimLaunchResult result) {
   if (!has_sent_on_launch_complete_) {
-    std::move(bootstrap_launch_app_callback_)
-        .Run(result, std::move(app_shim_request_));
+    DCHECK(bootstrap_);
+    bootstrap_->OnLaunchAppComplete(result, std::move(app_shim_request_));
     has_sent_on_launch_complete_ = true;
   }
 }
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 7ef6b7e1..b89fa994 100644
--- a/chrome/browser/apps/app_shim/app_shim_host_mac.h
+++ b/chrome/browser/apps/app_shim/app_shim_host_mac.h
@@ -14,8 +14,6 @@
 #include "chrome/browser/apps/app_shim/app_shim_handler_mac.h"
 #include "chrome/common/mac/app_shim.mojom.h"
 #include "mojo/public/cpp/bindings/binding.h"
-#include "mojo/public/cpp/platform/platform_channel_endpoint.h"
-#include "mojo/public/cpp/system/isolated_connection.h"
 
 namespace content {
 class NSViewBridgeFactoryHost;
@@ -25,38 +23,26 @@
 class BridgeFactoryHost;
 }  // namespace views
 
+class AppShimHostBootstrap;
+
 // This is the counterpart to AppShimController in
 // chrome/app/chrome_main_app_mode_mac.mm. The AppShimHost owns itself, and is
 // destroyed when the app it corresponds to is closed or when the channel
 // connected to the app shim is closed.
-class AppShimHost : public chrome::mojom::AppShimHostBootstrap,
-                    public chrome::mojom::AppShimHost,
+class AppShimHost : public chrome::mojom::AppShimHost,
                     public apps::AppShimHandler::Host {
  public:
-  AppShimHost();
+  AppShimHost(const std::string& app_id, const base::FilePath& profile_path);
   ~AppShimHost() override;
 
-  // Creates a new server-side mojo channel at |endpoint|, which should contain
-  // a file descriptor of a channel created by an UnixDomainSocketAcceptor, and
-  // begins listening for messages on it.
-  void ServeChannel(mojo::PlatformChannelEndpoint endpoint);
+  void OnBootstrapConnected(std::unique_ptr<AppShimHostBootstrap> bootstrap);
 
  protected:
-  void BootstrapChannelError(uint32_t custom_reason,
-                             const std::string& description);
   void ChannelError(uint32_t custom_reason, const std::string& description);
 
   // Closes the channel and destroys the AppShimHost.
   void Close();
 
-  // chrome::mojom::AppShimHostBootstrap.
-  void LaunchApp(chrome::mojom::AppShimHostRequest app_shim_host_request,
-                 const base::FilePath& profile_dir,
-                 const std::string& app_id,
-                 apps::AppShimLaunchType launch_type,
-                 const std::vector<base::FilePath>& files,
-                 LaunchAppCallback callback) override;
-
   // chrome::mojom::AppShimHost.
   void FocusApp(apps::AppShimFocusType focus_type,
                 const std::vector<base::FilePath>& files) override;
@@ -73,20 +59,17 @@
   std::string GetAppId() const override;
   views::BridgeFactoryHost* GetViewsBridgeFactoryHost() const override;
 
-  mojo::IsolatedConnection bootstrap_mojo_connection_;
-  mojo::Binding<chrome::mojom::AppShimHostBootstrap> host_bootstrap_binding_;
-  LaunchAppCallback bootstrap_launch_app_callback_;
-
   mojo::Binding<chrome::mojom::AppShimHost> host_binding_;
   chrome::mojom::AppShimPtr app_shim_;
   chrome::mojom::AppShimRequest app_shim_request_;
 
+  std::unique_ptr<AppShimHostBootstrap> bootstrap_;
+
   std::unique_ptr<views::BridgeFactoryHost> views_bridge_factory_host_;
   std::unique_ptr<content::NSViewBridgeFactoryHost> content_bridge_factory_;
 
   std::string app_id_;
   base::FilePath profile_path_;
-  bool has_received_launch_app_ = false;
   bool has_sent_on_launch_complete_ = false;
 
   THREAD_CHECKER(thread_checker_);
diff --git a/chrome/browser/apps/app_shim/app_shim_host_mac_unittest.cc b/chrome/browser/apps/app_shim/app_shim_host_mac_unittest.cc
index df998b1..22167a78 100644
--- a/chrome/browser/apps/app_shim/app_shim_host_mac_unittest.cc
+++ b/chrome/browser/apps/app_shim/app_shim_host_mac_unittest.cc
@@ -13,6 +13,7 @@
 #include "base/single_thread_task_runner.h"
 #include "base/test/scoped_task_environment.h"
 #include "base/test/test_simple_task_runner.h"
+#include "chrome/browser/apps/app_shim/app_shim_host_bootstrap_mac.h"
 #include "chrome/common/mac/app_shim_param_traits.h"
 #include "ipc/ipc_message.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -61,9 +62,9 @@
   DISALLOW_COPY_AND_ASSIGN(TestingAppShim);
 };
 
-class TestingAppShimHost : public AppShimHost {
+class TestingAppShimHostBootstrap : public AppShimHostBootstrap {
  public:
-  explicit TestingAppShimHost(
+  explicit TestingAppShimHostBootstrap(
       chrome::mojom::AppShimHostBootstrapRequest host_request)
       : test_weak_factory_(this) {
     // AppShimHost will bind to the request from ServeChannel. For testing
@@ -71,13 +72,13 @@
     host_bootstrap_binding_.Bind(std::move(host_request));
   }
 
-  base::WeakPtr<TestingAppShimHost> GetWeakPtr() {
+  base::WeakPtr<TestingAppShimHostBootstrap> GetWeakPtr() {
     return test_weak_factory_.GetWeakPtr();
   }
 
  private:
-  base::WeakPtrFactory<TestingAppShimHost> test_weak_factory_;
-  DISALLOW_COPY_AND_ASSIGN(TestingAppShimHost);
+  base::WeakPtrFactory<TestingAppShimHostBootstrap> test_weak_factory_;
+  DISALLOW_COPY_AND_ASSIGN(TestingAppShimHostBootstrap);
 };
 
 const char kTestAppId[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
@@ -98,7 +99,7 @@
   scoped_refptr<base::SingleThreadTaskRunner> task_runner() {
     return task_runner_;
   }
-  TestingAppShimHost* host() { return host_.get(); }
+  TestingAppShimHostBootstrap* host() { return host_.get(); }
   chrome::mojom::AppShimHostBootstrap* GetBootstrapMojoHost() {
     return host_.get();
   }
@@ -151,8 +152,8 @@
   void SetUp() override {
     testing::Test::SetUp();
     shim_.reset(new TestingAppShim());
-    TestingAppShimHost* host =
-        new TestingAppShimHost(shim_->GetHostBootstrapRequest());
+    TestingAppShimHostBootstrap* host =
+        new TestingAppShimHostBootstrap(shim_->GetHostBootstrapRequest());
     host_ = host->GetWeakPtr();
   }
 
@@ -163,7 +164,7 @@
 
   // AppShimHost will destroy itself in AppShimHost::Close, so use a weak
   // pointer here to avoid lifetime issues.
-  base::WeakPtr<TestingAppShimHost> host_;
+  base::WeakPtr<TestingAppShimHostBootstrap> host_;
   chrome::mojom::AppShimHostPtr host_ptr_;
 
   DISALLOW_COPY_AND_ASSIGN(AppShimHostTest);
@@ -175,8 +176,7 @@
 TEST_F(AppShimHostTest, TestLaunchAppWithHandler) {
   apps::AppShimHandler::RegisterHandler(kTestAppId, this);
   LaunchApp(apps::APP_SHIM_LAUNCH_NORMAL);
-  EXPECT_EQ(kTestAppId,
-            static_cast<apps::AppShimHandler::Host*>(host())->GetAppId());
+  EXPECT_EQ(kTestAppId, host()->GetHostForTesting()->GetAppId());
   EXPECT_EQ(apps::APP_SHIM_LAUNCH_SUCCESS, GetLaunchResult());
   EXPECT_EQ(1, launch_count_);
   EXPECT_EQ(1, launch_now_count_);
@@ -184,8 +184,8 @@
   EXPECT_EQ(0, close_count_);
 
   // A second OnAppLaunchComplete is ignored.
-  static_cast<apps::AppShimHandler::Host*>(host())
-      ->OnAppLaunchComplete(apps::APP_SHIM_LAUNCH_APP_NOT_FOUND);
+  host()->GetHostForTesting()->OnAppLaunchComplete(
+      apps::APP_SHIM_LAUNCH_APP_NOT_FOUND);
   EXPECT_EQ(apps::APP_SHIM_LAUNCH_SUCCESS, GetLaunchResult());
 
   GetMojoHost()->FocusApp(apps::APP_SHIM_FOCUS_NORMAL,
@@ -207,8 +207,7 @@
 TEST_F(AppShimHostTest, TestNoLaunchNow) {
   apps::AppShimHandler::RegisterHandler(kTestAppId, this);
   LaunchApp(apps::APP_SHIM_LAUNCH_REGISTER_ONLY);
-  EXPECT_EQ(kTestAppId,
-            static_cast<apps::AppShimHandler::Host*>(host())->GetAppId());
+  EXPECT_EQ(kTestAppId, host()->GetHostForTesting()->GetAppId());
   EXPECT_EQ(apps::APP_SHIM_LAUNCH_SUCCESS, GetLaunchResult());
   EXPECT_EQ(1, launch_count_);
   EXPECT_EQ(0, launch_now_count_);
diff --git a/chrome/browser/apps/app_shim/app_shim_host_manager_mac.mm b/chrome/browser/apps/app_shim/app_shim_host_manager_mac.mm
index 407cb79..e9a0e6c 100644
--- a/chrome/browser/apps/app_shim/app_shim_host_manager_mac.mm
+++ b/chrome/browser/apps/app_shim/app_shim_host_manager_mac.mm
@@ -14,7 +14,7 @@
 #include "base/task/post_task.h"
 #include "base/threading/scoped_blocking_call.h"
 #include "chrome/browser/apps/app_shim/app_shim_handler_mac.h"
-#include "chrome/browser/apps/app_shim/app_shim_host_mac.h"
+#include "chrome/browser/apps/app_shim/app_shim_host_bootstrap_mac.h"
 #include "chrome/browser/apps/app_shim/extension_app_shim_handler_mac.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/chrome_switches.h"
@@ -24,11 +24,6 @@
 
 namespace {
 
-void CreateAppShimHost(mojo::PlatformChannelEndpoint endpoint) {
-  // AppShimHost takes ownership of itself.
-  (new AppShimHost)->ServeChannel(std::move(endpoint));
-}
-
 base::FilePath GetDirectoryInTmpTemplate(const base::FilePath& user_data_dir) {
   base::FilePath temp_dir;
   CHECK(base::PathService::Get(base::DIR_TEMP, &temp_dir));
@@ -163,7 +158,8 @@
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
   base::CreateSingleThreadTaskRunnerWithTraits({content::BrowserThread::UI})
       ->PostTask(FROM_HERE,
-                 base::BindOnce(&CreateAppShimHost, std::move(endpoint)));
+                 base::BindOnce(&AppShimHostBootstrap::CreateForChannel,
+                                std::move(endpoint)));
 }
 
 void AppShimHostManager::OnListenError() {
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 134a8d8..2a233a1 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
@@ -747,8 +747,7 @@
 // chrome::NOTIFICATION_BROWSER_OPENED and then call OnAppActivated.
 // If this notification is removed, check that OnBrowserAdded is called after
 // the BrowserWindow is ready.
-void ExtensionAppShimHandler::OnBrowserAdded(Browser* browser) {
-}
+void ExtensionAppShimHandler::OnBrowserAdded(Browser* browser) {}
 
 void ExtensionAppShimHandler::OnBrowserRemoved(Browser* browser) {
   const Extension* extension = MaybeGetAppForBrowser(browser);
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd
index e86e0af..33151fd 100644
--- a/chrome/browser/browser_resources.grd
+++ b/chrome/browser/browser_resources.grd
@@ -40,6 +40,7 @@
         <structure name="IDR_KEYBOARD_UTILS_JS" file="resources\chromeos\keyboard\keyboard_utils.js" flattenhtml="true" type="chrome_html" />
         <structure name="IDR_CHROMEOS_DISCOVER_APP_HTML" file="resources\chromeos\login\discover\discover_app.html" flattenhtml="true" type="chrome_html"/>
         <structure name="IDR_CHROMEOS_DISCOVER_APP_JS" file="resources\chromeos\login\discover\discover_app.js" flattenhtml="true" type="chrome_html"/>
+        <structure name="IDR_CHROMEOS_DISCOVER_MANIFEST" file="resources\chromeos\login\discover\manifest.json" flattenhtml="true" type="chrome_html"/>
         <structure name="IDR_CUSTOM_ELEMENTS_OOBE_HTML" file="resources\chromeos\login\custom_elements_oobe.html" flattenhtml="true" type="chrome_html" />
         <structure name="IDR_CUSTOM_ELEMENTS_OOBE_JS" file="resources\chromeos\login\custom_elements_oobe.js" flattenhtml="true" type="chrome_html" />
         <structure name="IDR_CUSTOM_ELEMENTS_LOCK_HTML" file="resources\chromeos\login\custom_elements_lock.html" flattenhtml="true" type="chrome_html" />
@@ -709,6 +710,7 @@
       <include name="IDR_MEDIA_ENGAGEMENT_HTML" file="resources\media\media_engagement.html" flattenhtml="true" type="BINDATA" compress="gzip" allowexternalscript="true" />
       <include name="IDR_MEDIA_ENGAGEMENT_JS" file="resources\media\media_engagement.js" flattenhtml="true" type="BINDATA" compress="gzip" />
       <include name="IDR_MEDIA_ENGAGEMENT_MOJO_JS" file="${root_gen_dir}\chrome\browser\media\media_engagement_score_details.mojom.js" use_base_dir="false" type="BINDATA" compress="gzip" />
+      <include name="IDR_PWA_HTML" file="resources\pwa.html" type="BINDATA" />
       <if expr="chromeos">
         <include name="IDR_SYS_INTERNALS_HTML" file="resources\chromeos\sys_internals\index.html" type="BINDATA" />
         <include name="IDR_SYS_INTERNALS_CSS" file="resources\chromeos\sys_internals\index.css" type="BINDATA" />
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 113ade2..f24c232 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -352,6 +352,7 @@
 #include "chrome/browser/chromeos/login/signin_partition_manager.h"
 #include "chrome/browser/chromeos/login/startup_utils.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
+#include "chrome/browser/chromeos/policy/policy_cert_service_factory.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/chromeos/system/input_device_settings.h"
 #include "chrome/browser/ui/ash/chrome_browser_main_extra_parts_ash.h"
@@ -2586,6 +2587,13 @@
   return nullptr;
 }
 
+#if defined(OS_CHROMEOS)
+void ChromeContentBrowserClient::OnUsedTrustAnchor(
+    const std::string& username_hash) {
+  policy::PolicyCertServiceFactory::SetUsedPolicyCertificates(username_hash);
+}
+#endif
+
 scoped_refptr<network::SharedURLLoaderFactory>
 ChromeContentBrowserClient::GetSystemSharedURLLoaderFactory() {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) ||
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h
index 65cd8fb..cfea18f 100644
--- a/chrome/browser/chrome_content_browser_client.h
+++ b/chrome/browser/chrome_content_browser_client.h
@@ -256,6 +256,9 @@
       const url::Origin& requesting_origin,
       const url::Origin& embedding_origin) override;
   std::string GetWebBluetoothBlocklist() override;
+#if defined(OS_CHROMEOS)
+  void OnUsedTrustAnchor(const std::string& username_hash) override;
+#endif
   net::CookieStore* OverrideCookieStoreForURL(
       const GURL& url,
       content::ResourceContext* context) override;
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index abd3426..2aaf22f 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -1370,8 +1370,6 @@
     "multidevice_setup/multidevice_setup_client_factory.h",
     "multidevice_setup/oobe_completion_tracker_factory.cc",
     "multidevice_setup/oobe_completion_tracker_factory.h",
-    "net/cert_verify_proc_chromeos.cc",
-    "net/cert_verify_proc_chromeos.h",
     "net/client_cert_filter_chromeos.cc",
     "net/client_cert_filter_chromeos.h",
     "net/client_cert_store_chromeos.cc",
@@ -1526,8 +1524,6 @@
     "policy/policy_cert_service.h",
     "policy/policy_cert_service_factory.cc",
     "policy/policy_cert_service_factory.h",
-    "policy/policy_cert_verifier.cc",
-    "policy/policy_cert_verifier.h",
     "policy/policy_oauth2_token_fetcher.cc",
     "policy/policy_oauth2_token_fetcher.h",
     "policy/pre_signin_policy_fetcher.cc",
@@ -1608,6 +1604,8 @@
     "power/auto_screen_brightness/fake_als_reader.h",
     "power/auto_screen_brightness/fake_brightness_monitor.cc",
     "power/auto_screen_brightness/fake_brightness_monitor.h",
+    "power/auto_screen_brightness/gaussian_trainer.cc",
+    "power/auto_screen_brightness/gaussian_trainer.h",
     "power/auto_screen_brightness/modeller.h",
     "power/auto_screen_brightness/modeller_impl.cc",
     "power/auto_screen_brightness/modeller_impl.h",
@@ -2227,7 +2225,6 @@
     "mobile/mobile_activator_unittest.cc",
     "mobile_config_unittest.cc",
     "multidevice_setup/android_sms_app_helper_delegate_impl_unittest.cc",
-    "net/cert_verify_proc_chromeos_unittest.cc",
     "net/client_cert_store_chromeos_unittest.cc",
     "net/network_portal_detector_impl_unittest.cc",
     "net/network_pref_state_observer_unittest.cc",
@@ -2292,6 +2289,7 @@
     "policy/user_cloud_policy_store_chromeos_unittest.cc",
     "power/auto_screen_brightness/als_reader_impl_unittest.cc",
     "power/auto_screen_brightness/brightness_monitor_impl_unittest.cc",
+    "power/auto_screen_brightness/gaussian_trainer_unittest.cc",
     "power/auto_screen_brightness/modeller_impl_unittest.cc",
     "power/auto_screen_brightness/monotone_cubic_spline_unittest.cc",
     "power/auto_screen_brightness/utils_unittest.cc",
diff --git a/chrome/browser/chromeos/accessibility/select_to_speak_browsertest.cc b/chrome/browser/chromeos/accessibility/select_to_speak_browsertest.cc
index 5db5f5fa..0f3ad72 100644
--- a/chrome/browser/chromeos/accessibility/select_to_speak_browsertest.cc
+++ b/chrome/browser/chromeos/accessibility/select_to_speak_browsertest.cc
@@ -13,7 +13,6 @@
 #include "ash/root_window_controller.h"
 #include "ash/shell.h"
 #include "ash/system/status_area_widget.h"
-#include "ash/system/tray/system_tray.h"
 #include "ash/system/unified/unified_system_tray.h"
 #include "base/bind.h"
 #include "base/memory/weak_ptr.h"
@@ -158,14 +157,11 @@
 };
 
 IN_PROC_BROWSER_TEST_F(SelectToSpeakTest, SpeakStatusTray) {
-  gfx::Rect tray_bounds =
-      ash::features::IsSystemTrayUnifiedEnabled()
-          ? ash::Shell::Get()
-                ->GetPrimaryRootWindowController()
-                ->GetStatusAreaWidget()
-                ->unified_system_tray()
-                ->GetBoundsInScreen()
-          : ash::Shell::Get()->GetPrimarySystemTray()->GetBoundsInScreen();
+  gfx::Rect tray_bounds = ash::Shell::Get()
+                              ->GetPrimaryRootWindowController()
+                              ->GetStatusAreaWidget()
+                              ->unified_system_tray()
+                              ->GetBoundsInScreen();
 
   // Hold down Search and click a few pixels into the status tray bounds.
   generator_->PressKey(ui::VKEY_LWIN, 0 /* flags */);
diff --git a/chrome/browser/chromeos/accessibility/spoken_feedback_browsertest.cc b/chrome/browser/chromeos/accessibility/spoken_feedback_browsertest.cc
index 052c0db0..ddd3ef9d 100644
--- a/chrome/browser/chromeos/accessibility/spoken_feedback_browsertest.cc
+++ b/chrome/browser/chromeos/accessibility/spoken_feedback_browsertest.cc
@@ -6,13 +6,9 @@
 
 #include "ash/accelerators/accelerator_controller.h"
 #include "ash/public/cpp/accelerators.h"
-#include "ash/public/cpp/app_list/app_list_features.h"
-#include "ash/public/cpp/app_list/app_list_switches.h"
-#include "ash/public/cpp/ash_features.h"
 #include "ash/root_window_controller.h"
 #include "ash/shell.h"
 #include "ash/system/status_area_widget.h"
-#include "ash/system/tray/system_tray.h"
 #include "ash/system/unified/unified_system_tray.h"
 #include "base/command_line.h"
 #include "base/macros.h"
@@ -669,15 +665,10 @@
 
   // Send an accessibility hover event on the system tray, which is
   // what we get when you tap it on a touch screen when ChromeVox is on.
-  ash::TrayBackgroundView* tray =
-      ash::features::IsSystemTrayUnifiedEnabled()
-          ? static_cast<ash::TrayBackgroundView*>(
-                ash::Shell::Get()
-                    ->GetPrimaryRootWindowController()
-                    ->GetStatusAreaWidget()
-                    ->unified_system_tray())
-          : static_cast<ash::TrayBackgroundView*>(
-                ash::Shell::Get()->GetPrimarySystemTray());
+  ash::TrayBackgroundView* tray = ash::Shell::Get()
+                                      ->GetPrimaryRootWindowController()
+                                      ->GetStatusAreaWidget()
+                                      ->unified_system_tray();
   tray->NotifyAccessibilityEvent(ax::mojom::Event::kHover, true);
 
   EXPECT_EQ("Status tray,", speech_monitor_.GetNextUtterance());
diff --git a/chrome/browser/chromeos/accessibility/sticky_keys_browsertest.cc b/chrome/browser/chromeos/accessibility/sticky_keys_browsertest.cc
index b41fdcf..f9b441102 100644
--- a/chrome/browser/chromeos/accessibility/sticky_keys_browsertest.cc
+++ b/chrome/browser/chromeos/accessibility/sticky_keys_browsertest.cc
@@ -4,13 +4,11 @@
 
 #include <stddef.h>
 
-#include "ash/public/cpp/ash_features.h"
 #include "ash/root_window_controller.h"
 #include "ash/shell.h"
 #include "ash/sticky_keys/sticky_keys_controller.h"
 #include "ash/sticky_keys/sticky_keys_overlay.h"
 #include "ash/system/status_area_widget.h"
-#include "ash/system/tray/system_tray.h"
 #include "ash/system/unified/unified_system_tray.h"
 #include "base/macros.h"
 #include "base/run_loop.h"
@@ -44,25 +42,19 @@
   }
 
   bool IsSystemTrayBubbleOpen() {
-    return ash::features::IsSystemTrayUnifiedEnabled()
-               ? ash::Shell::Get()
-                     ->GetPrimaryRootWindowController()
-                     ->GetStatusAreaWidget()
-                     ->unified_system_tray()
-                     ->IsBubbleShown()
-               : ash::Shell::Get()->GetPrimarySystemTray()->HasSystemBubble();
+    return ash::Shell::Get()
+        ->GetPrimaryRootWindowController()
+        ->GetStatusAreaWidget()
+        ->unified_system_tray()
+        ->IsBubbleShown();
   }
 
   void CloseSystemTrayBubble() {
-    if (ash::features::IsSystemTrayUnifiedEnabled()) {
-      ash::Shell::Get()
-          ->GetPrimaryRootWindowController()
-          ->GetStatusAreaWidget()
-          ->unified_system_tray()
-          ->CloseBubble();
-    } else {
-      ash::Shell::Get()->GetPrimarySystemTray()->CloseBubble();
-    }
+    ash::Shell::Get()
+        ->GetPrimaryRootWindowController()
+        ->GetStatusAreaWidget()
+        ->unified_system_tray()
+        ->CloseBubble();
   }
 
   void SendKeyPress(ui::KeyboardCode key) {
diff --git a/chrome/browser/chromeos/app_mode/kiosk_app_manager.cc b/chrome/browser/chromeos/app_mode/kiosk_app_manager.cc
index fa71541..c05ce702 100644
--- a/chrome/browser/chromeos/app_mode/kiosk_app_manager.cc
+++ b/chrome/browser/chromeos/app_mode/kiosk_app_manager.cc
@@ -165,8 +165,11 @@
 }
 
 scoped_refptr<base::SequencedTaskRunner> GetBackgroundTaskRunner() {
+  // TODO(eseckler): The ExternalCacheImpl that uses this TaskRunner seems to be
+  // important during startup, which is why we cannot currently use the
+  // BEST_EFFORT TaskPriority here.
   return base::CreateSequencedTaskRunnerWithTraits(
-      {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
+      {base::MayBlock(), base::TaskPriority::USER_VISIBLE,
        base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN});
 }
 
diff --git a/chrome/browser/chromeos/drive/drive_integration_service.cc b/chrome/browser/chromeos/drive/drive_integration_service.cc
index e02d12d..a83945a 100644
--- a/chrome/browser/chromeos/drive/drive_integration_service.cc
+++ b/chrome/browser/chromeos/drive/drive_integration_service.cc
@@ -342,9 +342,29 @@
   return pinned_files;
 }
 
-void UmaEmitMountOutcome(DriveMountStatus status,
-                         const base::TimeTicks& time_started) {
+DriveMountStatus ConvertMountFailure(
+    drivefs::DriveFsHost::MountObserver::MountFailure failure) {
+  switch (failure) {
+    case drivefs::DriveFsHost::MountObserver::MountFailure::kInvocation:
+      return DriveMountStatus::kInvocationFailure;
+    case drivefs::DriveFsHost::MountObserver::MountFailure::kIpcDisconnect:
+      return DriveMountStatus::kUnexpectedDisconnect;
+    case drivefs::DriveFsHost::MountObserver::MountFailure::kNeedsRestart:
+      return DriveMountStatus::kTemporaryUnavailable;
+    case drivefs::DriveFsHost::MountObserver::MountFailure::kTimeout:
+      return DriveMountStatus::kTimeout;
+    case drivefs::DriveFsHost::MountObserver::MountFailure::kUnknown:
+      return DriveMountStatus::kUnknownFailure;
+  }
+  NOTREACHED();
+}
+
+void UmaEmitMountStatus(DriveMountStatus status) {
   UMA_HISTOGRAM_ENUMERATION("DriveCommon.Lifecycle.Mount", status);
+}
+
+void UmaEmitMountTime(DriveMountStatus status,
+                      const base::TimeTicks& time_started) {
   if (status == DriveMountStatus::kSuccess) {
     UMA_HISTOGRAM_MEDIUM_TIMES("DriveCommon.Lifecycle.MountTime.SuccessTime",
                                base::TimeTicks::Now() - time_started);
@@ -354,6 +374,12 @@
   }
 }
 
+void UmaEmitMountOutcome(DriveMountStatus status,
+                         const base::TimeTicks& time_started) {
+  UmaEmitMountStatus(status);
+  UmaEmitMountTime(status, time_started);
+}
+
 void UmaEmitUnmountOutcome(DriveMountStatus status) {
   UMA_HISTOGRAM_ENUMERATION("DriveCommon.Lifecycle.Unmount", status);
 }
@@ -493,8 +519,9 @@
     return *DriveNotificationManagerFactory::GetForBrowserContext(profile_);
   }
 
-  void OnMountFailed(base::Optional<base::TimeDelta> remount_delay) override {
-    mount_observer_->OnMountFailed(remount_delay);
+  void OnMountFailed(MountFailure failure,
+                     base::Optional<base::TimeDelta> remount_delay) override {
+    mount_observer_->OnMountFailed(failure, std::move(remount_delay));
   }
 
   void OnMounted(const base::FilePath& path) override {
@@ -502,7 +529,7 @@
   }
 
   void OnUnmounted(base::Optional<base::TimeDelta> remount_delay) override {
-    mount_observer_->OnUnmounted(remount_delay);
+    mount_observer_->OnUnmounted(std::move(remount_delay));
   }
 
   const std::string& GetProfileSalt() {
@@ -1006,14 +1033,15 @@
 }
 
 void DriveIntegrationService::OnMountFailed(
+    MountFailure failure,
     base::Optional<base::TimeDelta> remount_delay) {
   PrefService* prefs = profile_->GetPrefs();
+  DriveMountStatus status = ConvertMountFailure(failure);
+  UmaEmitMountStatus(status);
   bool was_ever_mounted =
       prefs->GetBoolean(prefs::kDriveFsWasLaunchedAtLeastOnce);
   if (was_ever_mounted) {
-    UmaEmitMountOutcome(remount_delay ? DriveMountStatus::kTemporaryUnavailable
-                                      : DriveMountStatus::kUnknownFailure,
-                        mount_start_);
+    UmaEmitMountTime(status, mount_start_);
   } else {
     // We don't record mount time until we mount successfully at least once.
   }
diff --git a/chrome/browser/chromeos/drive/drive_integration_service.h b/chrome/browser/chromeos/drive/drive_integration_service.h
index 800dd85..5728232 100644
--- a/chrome/browser/chromeos/drive/drive_integration_service.h
+++ b/chrome/browser/chromeos/drive/drive_integration_service.h
@@ -61,7 +61,10 @@
   kSuccess = 0,
   kUnknownFailure = 1,
   kTemporaryUnavailable = 2,
-  kMaxValue = kTemporaryUnavailable,
+  kInvocationFailure = 3,
+  kUnexpectedDisconnect = 4,
+  kTimeout = 5,
+  kMaxValue = kTimeout,
 };
 
 // Interface for classes that need to observe events from
@@ -149,7 +152,8 @@
   // MountObserver implementation.
   void OnMounted(const base::FilePath& mount_path) override;
   void OnUnmounted(base::Optional<base::TimeDelta> remount_delay) override;
-  void OnMountFailed(base::Optional<base::TimeDelta> remount_delay) override;
+  void OnMountFailed(MountFailure failure,
+                     base::Optional<base::TimeDelta> remount_delay) override;
 
   EventLogger* event_logger() { return logger_.get(); }
   DriveServiceInterface* drive_service() { return drive_service_.get(); }
diff --git a/chrome/browser/chromeos/file_manager/path_util.cc b/chrome/browser/chromeos/file_manager/path_util.cc
index 39bc644..5e4a4b4 100644
--- a/chrome/browser/chromeos/file_manager/path_util.cc
+++ b/chrome/browser/chromeos/file_manager/path_util.cc
@@ -418,21 +418,28 @@
                            drive_integration_service->GetMountPointPath()
                                .Append(kRootRelativeToDriveMount)
                                .value(),
-                           kGoogleDriveDisplayName)) {
+                           base::FilePath(kGoogleDriveDisplayName)
+                               .Append(l10n_util::GetStringUTF8(
+                                   IDS_FILE_BROWSER_DRIVE_MY_DRIVE_LABEL))
+                               .value())) {
   } else if (drive_integration_service &&
              ReplacePrefix(&result,
                            drive_integration_service->GetMountPointPath()
                                .Append(kTeamDrivesRelativeToDriveMount)
                                .value(),
-                           l10n_util::GetStringUTF8(
-                               IDS_FILE_BROWSER_DRIVE_TEAM_DRIVES_LABEL))) {
+                           base::FilePath(kGoogleDriveDisplayName)
+                               .Append(l10n_util::GetStringUTF8(
+                                   IDS_FILE_BROWSER_DRIVE_TEAM_DRIVES_LABEL))
+                               .value())) {
   } else if (drive_integration_service &&
              ReplacePrefix(&result,
                            drive_integration_service->GetMountPointPath()
                                .Append(kComputersRelativeToDriveMount)
                                .value(),
-                           l10n_util::GetStringUTF8(
-                               IDS_FILE_BROWSER_DRIVE_COMPUTERS_LABEL))) {
+                           base::FilePath(kGoogleDriveDisplayName)
+                               .Append(l10n_util::GetStringUTF8(
+                                   IDS_FILE_BROWSER_DRIVE_COMPUTERS_LABEL))
+                               .value())) {
   } else if (ReplacePrefix(&result, kAndroidFilesPath,
                            l10n_util::GetStringUTF8(
                                IDS_FILE_BROWSER_ANDROID_FILES_ROOT_LABEL))) {
diff --git a/chrome/browser/chromeos/file_manager/path_util_unittest.cc b/chrome/browser/chromeos/file_manager/path_util_unittest.cc
index bd9b9d8..1664ceaa 100644
--- a/chrome/browser/chromeos/file_manager/path_util_unittest.cc
+++ b/chrome/browser/chromeos/file_manager/path_util_unittest.cc
@@ -138,17 +138,17 @@
     base::test::ScopedFeatureList features;
     features.InitAndDisableFeature(chromeos::features::kDriveFs);
     drive::DriveIntegrationServiceFactory::GetForProfile(&profile);
-    EXPECT_EQ("Google Drive \u203a foo",
+    EXPECT_EQ("Google Drive \u203a My Drive \u203a foo",
               GetPathDisplayTextForSettings(
                   &profile, "/special/drive-0123456789abcdef/root/foo"));
     EXPECT_EQ(
-        "Team Drives \u203a A Team Drive \u203a foo",
+        "Google Drive \u203a Team Drives \u203a A Team Drive \u203a foo",
         GetPathDisplayTextForSettings(
             &profile,
             "/special/drive-0123456789abcdef/team_drives/A Team Drive/foo"));
 
     EXPECT_EQ(
-        "Computers \u203a My Other Computer \u203a bar",
+        "Google Drive \u203a Computers \u203a My Other Computer \u203a bar",
         GetPathDisplayTextForSettings(
             &profile,
             "/special/drive-0123456789abcdef/Computers/My Other Computer/bar"));
@@ -167,20 +167,21 @@
 
     drive::DriveIntegrationServiceFactory::GetForProfile(&profile2);
     EXPECT_EQ(
-        "Google Drive \u203a foo",
+        "Google Drive \u203a My Drive \u203a foo",
         GetPathDisplayTextForSettings(
             &profile2,
             "/media/fuse/drivefs-84675c855b63e12f384d45f033826980/root/foo"));
-    EXPECT_EQ("Team Drives \u203a A Team Drive \u203a foo",
+    EXPECT_EQ("Google Drive \u203a Team Drives \u203a A Team Drive \u203a foo",
               GetPathDisplayTextForSettings(
                   &profile2,
                   "/media/fuse/drivefs-84675c855b63e12f384d45f033826980/"
                   "team_drives/A Team Drive/foo"));
-    EXPECT_EQ("Computers \u203a My Other Computer \u203a bar",
-              GetPathDisplayTextForSettings(
-                  &profile2,
-                  "/media/fuse/drivefs-84675c855b63e12f384d45f033826980/"
-                  "Computers/My Other Computer/bar"));
+    EXPECT_EQ(
+        "Google Drive \u203a Computers \u203a My Other Computer \u203a bar",
+        GetPathDisplayTextForSettings(
+            &profile2,
+            "/media/fuse/drivefs-84675c855b63e12f384d45f033826980/"
+            "Computers/My Other Computer/bar"));
   }
   chromeos::disks::DiskMountManager::Shutdown();
 }
diff --git a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_notification_controller.cc b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_notification_controller.cc
index 95244b3..a36889f2 100644
--- a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_notification_controller.cc
+++ b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_notification_controller.cc
@@ -30,9 +30,6 @@
 const char kEasyUnlockPairingChangeAppliedNotifierId[] =
     "easyunlock_notification_ids.pairing_change_applied";
 
-const char kEasyUnlockPromotionNotifierId[] =
-    "easyunlock_notification_ids.promotion";
-
 const char kLockScreenSettingsSubpage[] = "lockScreen";
 const char kSmartLockSettingsSubpage[] = "multidevice/features/smartLock";
 
@@ -129,25 +126,6 @@
                                weak_ptr_factory_.GetWeakPtr())));
 }
 
-void EasyUnlockNotificationController::ShowPromotionNotification() {
-  message_center::RichNotificationData rich_notification_data;
-  rich_notification_data.buttons.push_back(
-      message_center::ButtonInfo(l10n_util::GetStringUTF16(
-          IDS_EASY_UNLOCK_SETUP_NOTIFICATION_BUTTON_TITLE)));
-
-  ShowNotification(CreateNotification(
-      kEasyUnlockPromotionNotifierId,
-      l10n_util::GetStringFUTF16(IDS_EASY_UNLOCK_SETUP_NOTIFICATION_TITLE,
-                                 ui::GetChromeOSDeviceName()),
-      l10n_util::GetStringFUTF16(IDS_EASY_UNLOCK_SETUP_NOTIFICATION_MESSAGE,
-                                 ui::GetChromeOSDeviceName()),
-      ui::ResourceBundle::GetSharedInstance().GetImageNamed(
-          IDR_NOTIFICATION_EASYUNLOCK_PROMO),
-      rich_notification_data,
-      new NotificationDelegate(kEasyUnlockPromotionNotifierId,
-                               weak_ptr_factory_.GetWeakPtr())));
-}
-
 void EasyUnlockNotificationController::ShowNotification(
     std::unique_ptr<message_center::Notification> notification) {
   notification->SetSystemPriority();
diff --git a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_notification_controller.h b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_notification_controller.h
index 60ff0a1..b82d9307 100644
--- a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_notification_controller.h
+++ b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_notification_controller.h
@@ -31,7 +31,6 @@
   void ShowPairingChangeNotification() override;
   void ShowPairingChangeAppliedNotification(
       const std::string& phone_name) override;
-  void ShowPromotionNotification() override;
 
  protected:
   // Exposed for testing.
diff --git a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_notification_controller_chromeos_unittest.cc b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_notification_controller_chromeos_unittest.cc
index 74a7e2b..967d88c4 100644
--- a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_notification_controller_chromeos_unittest.cc
+++ b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_notification_controller_chromeos_unittest.cc
@@ -138,24 +138,5 @@
   EXPECT_TRUE(display_service_->GetNotification(kPairingAppliedId));
 }
 
-TEST_F(EasyUnlockNotificationControllerTest, TestShowPromotionNotification) {
-  const char kNotificationId[] = "easyunlock_notification_ids.promotion";
-
-  notification_controller_->ShowPromotionNotification();
-  base::Optional<message_center::Notification> notification =
-      display_service_->GetNotification(kNotificationId);
-  ASSERT_TRUE(notification);
-  ASSERT_EQ(1u, notification->buttons().size());
-  EXPECT_EQ(message_center::SYSTEM_PRIORITY, notification->priority());
-
-  // Clicking notification button should launch settings.
-  EXPECT_CALL(*notification_controller_, LaunchEasyUnlockSettings());
-  notification->delegate()->Click(0, base::nullopt);
-
-  // Clicking the notification itself should also launch settings.
-  EXPECT_CALL(*notification_controller_, LaunchEasyUnlockSettings());
-  notification->delegate()->Click(base::nullopt, base::nullopt);
-}
-
 }  // namespace
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/login_browsertest.cc b/chrome/browser/chromeos/login/login_browsertest.cc
index d63ab4a9..47f48c0 100644
--- a/chrome/browser/chromeos/login/login_browsertest.cc
+++ b/chrome/browser/chromeos/login/login_browsertest.cc
@@ -4,11 +4,9 @@
 
 #include <string>
 
-#include "ash/public/cpp/ash_features.h"
 #include "ash/shelf/shelf.h"
 #include "ash/shell.h"
 #include "ash/system/status_area_widget.h"
-#include "ash/system/tray/system_tray.h"
 #include "ash/system/unified/unified_system_tray.h"
 #include "base/command_line.h"
 #include "base/location.h"
@@ -194,11 +192,7 @@
   aura::Window* primary_win = ash::Shell::GetPrimaryRootWindow();
   ash::Shelf* shelf = ash::Shelf::ForWindow(primary_win);
   ash::TrayBackgroundView* tray =
-      ash::features::IsSystemTrayUnifiedEnabled()
-          ? static_cast<ash::TrayBackgroundView*>(
-                shelf->GetStatusAreaWidget()->unified_system_tray())
-          : static_cast<ash::TrayBackgroundView*>(
-                shelf->GetStatusAreaWidget()->system_tray());
+      shelf->GetStatusAreaWidget()->unified_system_tray();
   SCOPED_TRACE(testing::Message()
                << "ShelfVisibilityState=" << shelf->GetVisibilityState()
                << " ShelfAutoHideBehavior=" << shelf->auto_hide_behavior());
diff --git a/chrome/browser/chromeos/login/ui/DEPS b/chrome/browser/chromeos/login/ui/DEPS
index a45b953..dfe6fb3 100644
--- a/chrome/browser/chromeos/login/ui/DEPS
+++ b/chrome/browser/chromeos/login/ui/DEPS
@@ -30,6 +30,5 @@
   "login_display_host_webui\.cc": [
     "+ash/accessibility/focus_ring_controller.h",
     "+ash/shell.h",
-    "+ash/system/tray/system_tray.h",
   ],
 }
diff --git a/chrome/browser/chromeos/login/ui/login_display_host_webui.cc b/chrome/browser/chromeos/login/ui/login_display_host_webui.cc
index a8dbbbc5..a5111ea1 100644
--- a/chrome/browser/chromeos/login/ui/login_display_host_webui.cc
+++ b/chrome/browser/chromeos/login/ui/login_display_host_webui.cc
@@ -11,7 +11,6 @@
 #include "ash/public/cpp/ash_features.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/shell.h"
-#include "ash/system/tray/system_tray.h"
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/location.h"
diff --git a/chrome/browser/chromeos/login/users/multi_profile_user_controller_unittest.cc b/chrome/browser/chromeos/login/users/multi_profile_user_controller_unittest.cc
index 54f80df..5631232 100644
--- a/chrome/browser/chromeos/login/users/multi_profile_user_controller_unittest.cc
+++ b/chrome/browser/chromeos/login/users/multi_profile_user_controller_unittest.cc
@@ -18,7 +18,6 @@
 #include "chrome/browser/chromeos/login/users/multi_profile_user_controller_delegate.h"
 #include "chrome/browser/chromeos/policy/policy_cert_service.h"
 #include "chrome/browser/chromeos/policy/policy_cert_service_factory.h"
-#include "chrome/browser/chromeos/policy/policy_cert_verifier.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/prefs/browser_prefs.h"
 #include "chrome/common/pref_names.h"
@@ -34,6 +33,7 @@
 #include "net/cert/x509_certificate.h"
 #include "net/test/cert_test_util.h"
 #include "net/test/test_data_directory.h"
+#include "services/network/cert_verifier_with_trust_anchors.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace chromeos {
@@ -108,9 +108,10 @@
     },
 };
 
-// Weak ptr to PolicyCertVerifier - object is freed in test destructor once
-// we've ensured the profile has been shut down.
-policy::PolicyCertVerifier* g_policy_cert_verifier_for_factory = NULL;
+// Weak ptr to network::CertVerifierWithTrustAnchors - object is freed in test
+// destructor once we've ensured the profile has been shut down.
+network::CertVerifierWithTrustAnchors* g_policy_cert_verifier_for_factory =
+    NULL;
 
 std::unique_ptr<KeyedService> TestPolicyCertServiceFactory(
     content::BrowserContext* context) {
@@ -182,13 +183,13 @@
   }
 
   void TearDown() override {
-    // Clear our cached pointer to the PolicyCertVerifier.
+    // Clear our cached pointer to the network::CertVerifierWithTrustAnchors.
     g_policy_cert_verifier_for_factory = NULL;
 
-    // We must ensure that the PolicyCertVerifier outlives the
-    // PolicyCertService so shutdown the profile here. Additionally, we need
+    // We must ensure that the network::CertVerifierWithTrustAnchors outlives
+    // the PolicyCertService so shutdown the profile here. Additionally, we need
     // to run the message loop between freeing the PolicyCertService and
-    // freeing the PolicyCertVerifier (see
+    // freeing the network::CertVerifierWithTrustAnchors (see
     // PolicyCertService::OnTrustAnchorsChanged() which is called from
     // PolicyCertService::Shutdown()).
     controller_.reset();
@@ -237,7 +238,7 @@
   TestingProfile* profile(int index) { return user_profiles_[index]; }
 
   content::TestBrowserThreadBundle threads_;
-  std::unique_ptr<policy::PolicyCertVerifier> cert_verifier_;
+  std::unique_ptr<network::CertVerifierWithTrustAnchors> cert_verifier_;
   std::unique_ptr<TestingProfileManager> profile_manager_;
   FakeChromeUserManager* fake_user_manager_;  // Not owned
   user_manager::ScopedUserManager user_manager_enabler_;
@@ -410,7 +411,8 @@
       test_users_[0].GetUserEmail());
   LoginUser(0);
 
-  cert_verifier_.reset(new policy::PolicyCertVerifier(base::Closure()));
+  cert_verifier_.reset(
+      new network::CertVerifierWithTrustAnchors(base::Closure()));
   cert_verifier_->InitializeOnIOThread(
       base::MakeRefCounted<MockCertVerifyProc>());
   g_policy_cert_verifier_for_factory = cert_verifier_.get();
@@ -448,7 +450,8 @@
   // changed back to enabled.
   SetPrefBehavior(0, MultiProfileUserController::kBehaviorUnrestricted);
 
-  cert_verifier_.reset(new policy::PolicyCertVerifier(base::Closure()));
+  cert_verifier_.reset(
+      new network::CertVerifierWithTrustAnchors(base::Closure()));
   cert_verifier_->InitializeOnIOThread(
       base::MakeRefCounted<MockCertVerifyProc>());
   g_policy_cert_verifier_for_factory = cert_verifier_.get();
diff --git a/chrome/browser/chromeos/ownership/owner_settings_service_chromeos.cc b/chrome/browser/chromeos/ownership/owner_settings_service_chromeos.cc
index a3a2c22..617654e 100644
--- a/chrome/browser/chromeos/ownership/owner_settings_service_chromeos.cc
+++ b/chrome/browser/chromeos/ownership/owner_settings_service_chromeos.cc
@@ -116,9 +116,12 @@
     crypto::ScopedPK11Slot private_slot) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
+  // TODO(eseckler): It seems loading the key is important for the UsersPrivate
+  // extension API to work correctly during startup, which is why we cannot
+  // currently use the BEST_EFFORT TaskPriority here.
   scoped_refptr<base::TaskRunner> task_runner =
       base::CreateTaskRunnerWithTraits(
-          {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
+          {base::MayBlock(), base::TaskPriority::USER_VISIBLE,
            base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN});
   task_runner->PostTask(
       FROM_HERE,
diff --git a/chrome/browser/chromeos/policy/policy_cert_service.cc b/chrome/browser/chromeos/policy/policy_cert_service.cc
index a479f909..e7468ac 100644
--- a/chrome/browser/chromeos/policy/policy_cert_service.cc
+++ b/chrome/browser/chromeos/policy/policy_cert_service.cc
@@ -10,55 +10,83 @@
 #include "base/memory/ptr_util.h"
 #include "base/task/post_task.h"
 #include "chrome/browser/chromeos/policy/policy_cert_service_factory.h"
-#include "chrome/browser/chromeos/policy/policy_cert_verifier.h"
 #include "chrome/browser/chromeos/policy/temp_certs_cache_nss.h"
+#include "chrome/browser/net/profile_network_context_service.h"
+#include "chrome/browser/net/profile_network_context_service_factory.h"
+#include "chrome/browser/profiles/profile.h"
 #include "components/user_manager/user_manager.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
 #include "net/cert/x509_certificate.h"
+#include "services/network/cert_verifier_with_trust_anchors.h"
+#include "services/network/public/cpp/features.h"
 
 namespace policy {
 
 PolicyCertService::~PolicyCertService() {
-  DCHECK(cert_verifier_)
-      << "CreatePolicyCertVerifier() must be called after construction.";
+  if (!base::FeatureList::IsEnabled(network::features::kNetworkService)) {
+    DCHECK(cert_verifier_)
+        << "CreatePolicyCertVerifier() must be called after construction.";
+  }
 }
 
 PolicyCertService::PolicyCertService(
+    Profile* profile,
     const std::string& user_id,
     UserNetworkConfigurationUpdater* net_conf_updater,
     user_manager::UserManager* user_manager)
-    : cert_verifier_(NULL),
+    : profile_(profile),
+      cert_verifier_(NULL),
       user_id_(user_id),
       net_conf_updater_(net_conf_updater),
       user_manager_(user_manager),
-      has_trust_anchors_(false),
       weak_ptr_factory_(this) {
   DCHECK(net_conf_updater_);
   DCHECK(user_manager_);
 }
 
-PolicyCertService::PolicyCertService(const std::string& user_id,
-                                     PolicyCertVerifier* verifier,
-                                     user_manager::UserManager* user_manager)
+PolicyCertService::PolicyCertService(
+    const std::string& user_id,
+    network::CertVerifierWithTrustAnchors* verifier,
+    user_manager::UserManager* user_manager)
     : cert_verifier_(verifier),
       user_id_(user_id),
       net_conf_updater_(NULL),
       user_manager_(user_manager),
-      has_trust_anchors_(false),
-      weak_ptr_factory_(this) {
-}
+      weak_ptr_factory_(this) {}
 
-std::unique_ptr<PolicyCertVerifier>
+std::unique_ptr<network::CertVerifierWithTrustAnchors>
 PolicyCertService::CreatePolicyCertVerifier() {
+  DCHECK(!base::FeatureList::IsEnabled(network::features::kNetworkService));
   base::Closure callback = base::Bind(
       &PolicyCertServiceFactory::SetUsedPolicyCertificates, user_id_);
   constexpr base::TaskTraits traits = {content::BrowserThread::UI};
-  cert_verifier_ = new PolicyCertVerifier(
+  auto cert_verifier = std::make_unique<network::CertVerifierWithTrustAnchors>(
       base::Bind(base::IgnoreResult(&base::PostTaskWithTraits), FROM_HERE,
                  traits, callback));
+  cert_verifier_ = cert_verifier.get();
   // Certs are forwarded to |cert_verifier_|, thus register here after
   // |cert_verifier_| is created.
+  StartObservingPolicyCertsInternal(true /* notify */);
+
+  return cert_verifier;
+}
+
+void PolicyCertService::StartObservingPolicyCerts() {
+  DCHECK(base::FeatureList::IsEnabled(network::features::kNetworkService));
+  // Don't notify the network service since it will get the initial list of
+  // trust anchors in NetworkContextParams::initial_trust_anchors.
+  StartObservingPolicyCertsInternal(false /* notify */);
+}
+
+void PolicyCertService::OnPolicyProvidedCertsChanged(
+    const net::CertificateList& all_server_and_authority_certs,
+    const net::CertificateList& trust_anchors) {
+  OnPolicyProvidedCertsChangedInternal(all_server_and_authority_certs,
+                                       trust_anchors, true /* notify */);
+}
+
+void PolicyCertService::StartObservingPolicyCertsInternal(bool notify) {
   net_conf_updater_->AddPolicyProvidedCertsObserver(this);
 
   // Set the current list of policy-provided server and authority certificates,
@@ -67,16 +95,14 @@
       net_conf_updater_->GetAllServerAndAuthorityCertificates();
   net::CertificateList trust_anchors =
       net_conf_updater_->GetWebTrustedCertificates();
-  OnPolicyProvidedCertsChanged(all_server_and_authority_certs, trust_anchors);
-
-  return base::WrapUnique(cert_verifier_);
+  OnPolicyProvidedCertsChangedInternal(all_server_and_authority_certs,
+                                       trust_anchors, notify);
 }
 
-void PolicyCertService::OnPolicyProvidedCertsChanged(
+void PolicyCertService::OnPolicyProvidedCertsChangedInternal(
     const net::CertificateList& all_server_and_authority_certs,
-    const net::CertificateList& trust_anchors) {
-  DCHECK(cert_verifier_);
-
+    const net::CertificateList& trust_anchors,
+    bool notify) {
   // Make all policy-provided server and authority certificates available to NSS
   // as temp certificates.
   // Note that this is done on the UI thread because the assumption is that NSS
@@ -96,7 +122,18 @@
     return;
   }
 
-  has_trust_anchors_ = !trust_anchors.empty();
+  trust_anchors_ = trust_anchors;
+
+  if (!notify)
+    return;
+
+  if (base::FeatureList::IsEnabled(network::features::kNetworkService)) {
+    ProfileNetworkContextServiceFactory::GetForContext(profile_)
+        ->UpdateTrustAnchors(trust_anchors_);
+    return;
+  }
+
+  DCHECK(cert_verifier_);
 
   // It's safe to use base::Unretained here, because it's guaranteed that
   // |cert_verifier_| outlives this object (see description of
@@ -105,8 +142,8 @@
   // DeleteSoon on IO, i.e. after all pending tasks on IO are finished.
   base::PostTaskWithTraits(
       FROM_HERE, {content::BrowserThread::IO},
-      base::BindOnce(&PolicyCertVerifier::SetTrustAnchors,
-                     base::Unretained(cert_verifier_), trust_anchors));
+      base::BindOnce(&network::CertVerifierWithTrustAnchors::SetTrustAnchors,
+                     base::Unretained(cert_verifier_), trust_anchors_));
 }
 
 bool PolicyCertService::UsedPolicyCertificates() const {
@@ -126,7 +163,7 @@
 // static
 std::unique_ptr<PolicyCertService> PolicyCertService::CreateForTesting(
     const std::string& user_id,
-    PolicyCertVerifier* verifier,
+    network::CertVerifierWithTrustAnchors* verifier,
     user_manager::UserManager* user_manager) {
   return base::WrapUnique(
       new PolicyCertService(user_id, verifier, user_manager));
diff --git a/chrome/browser/chromeos/policy/policy_cert_service.h b/chrome/browser/chromeos/policy/policy_cert_service.h
index c1b6119..22b9d595 100644
--- a/chrome/browser/chromeos/policy/policy_cert_service.h
+++ b/chrome/browser/chromeos/policy/policy_cert_service.h
@@ -17,6 +17,8 @@
 #include "chromeos/policy_certificate_provider.h"
 #include "components/keyed_service/core/keyed_service.h"
 
+class Profile;
+
 namespace user_manager {
 class UserManager;
 }
@@ -26,8 +28,11 @@
 typedef std::vector<scoped_refptr<X509Certificate> > CertificateList;
 }
 
+namespace network {
+class CertVerifierWithTrustAnchors;
+}
+
 namespace policy {
-class PolicyCertVerifier;
 class TempCertsCacheNSS;
 
 // This service is the counterpart of PolicyCertVerifier on the UI thread. It's
@@ -38,21 +43,30 @@
 class PolicyCertService : public KeyedService,
                           public chromeos::PolicyCertificateProvider::Observer {
  public:
-  PolicyCertService(const std::string& user_id,
+  PolicyCertService(Profile* profile,
+                    const std::string& user_id,
                     UserNetworkConfigurationUpdater* net_conf_updater,
                     user_manager::UserManager* user_manager);
   ~PolicyCertService() override;
 
   // Creates an associated PolicyCertVerifier. The returned object must only be
   // used on the IO thread and must outlive this object.
-  std::unique_ptr<PolicyCertVerifier> CreatePolicyCertVerifier();
+  // This can only be called if the network service is disabled.
+  std::unique_ptr<network::CertVerifierWithTrustAnchors>
+  CreatePolicyCertVerifier();
+
+  // Start listening for trust anchor changes to push to the network service.
+  // This only needs to be called with the network service.
+  void StartObservingPolicyCerts();
 
   // Returns true if the profile that owns this service has used certificates
   // installed via policy to establish a secure connection before. This means
   // that it may have cached content from an untrusted source.
   bool UsedPolicyCertificates() const;
 
-  bool has_policy_certificates() const { return has_trust_anchors_; }
+  bool has_policy_certificates() const { return !trust_anchors_.empty(); }
+
+  const net::CertificateList& trust_anchors() const { return trust_anchors_; }
 
   // UserNetworkConfigurationUpdater::PolicyProvidedCertsObserver:
   void OnPolicyProvidedCertsChanged(
@@ -64,19 +78,26 @@
 
   static std::unique_ptr<PolicyCertService> CreateForTesting(
       const std::string& user_id,
-      PolicyCertVerifier* verifier,
+      network::CertVerifierWithTrustAnchors* verifier,
       user_manager::UserManager* user_manager);
 
  private:
   PolicyCertService(const std::string& user_id,
-                    PolicyCertVerifier* verifier,
+                    network::CertVerifierWithTrustAnchors* verifier,
                     user_manager::UserManager* user_manager);
 
-  PolicyCertVerifier* cert_verifier_;
+  void StartObservingPolicyCertsInternal(bool notify);
+  void OnPolicyProvidedCertsChangedInternal(
+      const net::CertificateList& all_server_and_authority_certs,
+      const net::CertificateList& trust_anchors,
+      bool notify);
+
+  Profile* profile_ = nullptr;
+  network::CertVerifierWithTrustAnchors* cert_verifier_;
   std::string user_id_;
   UserNetworkConfigurationUpdater* net_conf_updater_;
   user_manager::UserManager* user_manager_;
-  bool has_trust_anchors_;
+  net::CertificateList trust_anchors_;
 
   // Holds all policy-provided server and authority certificates and makes them
   // available to NSS as temp certificates. This is needed so they can be used
diff --git a/chrome/browser/chromeos/policy/policy_cert_service_factory.cc b/chrome/browser/chromeos/policy/policy_cert_service_factory.cc
index a60b2ba00..9c9c7fcf 100644
--- a/chrome/browser/chromeos/policy/policy_cert_service_factory.cc
+++ b/chrome/browser/chromeos/policy/policy_cert_service_factory.cc
@@ -7,7 +7,6 @@
 #include "base/memory/singleton.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/policy/policy_cert_service.h"
-#include "chrome/browser/chromeos/policy/policy_cert_verifier.h"
 #include "chrome/browser/chromeos/policy/user_network_configuration_updater_factory.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/profiles/incognito_helpers.h"
@@ -17,6 +16,8 @@
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/scoped_user_pref_update.h"
 #include "components/user_manager/user_manager.h"
+#include "services/network/cert_verifier_with_trust_anchors.h"
+#include "services/network/public/cpp/features.h"
 
 namespace policy {
 
@@ -27,17 +28,33 @@
 }
 
 // static
-std::unique_ptr<PolicyCertVerifier> PolicyCertServiceFactory::CreateForProfile(
-    Profile* profile) {
+std::unique_ptr<network::CertVerifierWithTrustAnchors>
+PolicyCertServiceFactory::CreateForProfile(Profile* profile) {
+  DCHECK(!base::FeatureList::IsEnabled(network::features::kNetworkService));
   DCHECK(!GetInstance()->GetServiceForBrowserContext(profile, false));
   PolicyCertService* service = static_cast<PolicyCertService*>(
       GetInstance()->GetServiceForBrowserContext(profile, true));
   if (!service)
-    return std::unique_ptr<PolicyCertVerifier>();
+    return nullptr;
   return service->CreatePolicyCertVerifier();
 }
 
 // static
+bool PolicyCertServiceFactory::CreateAndStartObservingForProfile(
+    Profile* profile) {
+  DCHECK(base::FeatureList::IsEnabled(network::features::kNetworkService));
+  // This can be called multiple times if the network process crashes.
+  if (GetInstance()->GetServiceForBrowserContext(profile, false))
+    return true;
+  PolicyCertService* service = static_cast<PolicyCertService*>(
+      GetInstance()->GetServiceForBrowserContext(profile, true));
+  if (!service)
+    return false;
+  service->StartObservingPolicyCerts();
+  return true;
+}
+
+// static
 PolicyCertServiceFactory* PolicyCertServiceFactory::GetInstance() {
   return base::Singleton<PolicyCertServiceFactory>::get();
 }
@@ -103,7 +120,7 @@
   if (!net_conf_updater)
     return NULL;
 
-  return new PolicyCertService(user->GetAccountId().GetUserEmail(),
+  return new PolicyCertService(profile, user->GetAccountId().GetUserEmail(),
                                net_conf_updater, user_manager);
 }
 
diff --git a/chrome/browser/chromeos/policy/policy_cert_service_factory.h b/chrome/browser/chromeos/policy/policy_cert_service_factory.h
index 8ee3aef..1e170ba6 100644
--- a/chrome/browser/chromeos/policy/policy_cert_service_factory.h
+++ b/chrome/browser/chromeos/policy/policy_cert_service_factory.h
@@ -20,10 +20,13 @@
 class PrefRegistrySimple;
 class Profile;
 
+namespace network {
+class CertVerifierWithTrustAnchors;
+}
+
 namespace policy {
 
 class PolicyCertService;
-class PolicyCertVerifier;
 
 // Factory to create PolicyCertServices.
 class PolicyCertServiceFactory : public BrowserContextKeyedServiceFactory {
@@ -33,13 +36,25 @@
   static PolicyCertService* GetForProfile(Profile* profile);
 
   // Creates a new PolicyCertService and returns the associated
-  // PolicyCertVerifier. Returns NULL if this service isn't allowed for
+  // PolicyCertVerifier. Returns nullptr if this service isn't allowed for
   // |profile|, i.e. if NetworkConfigurationUpdater doesn't exist.
   // This service is created separately for the original profile and the
   // incognito profile.
   // Note: NetworkConfigurationUpdater is currently only created for the primary
   // user's profile.
-  static std::unique_ptr<PolicyCertVerifier> CreateForProfile(Profile* profile);
+  // This should  only be called if the network service is disabled.
+  static std::unique_ptr<network::CertVerifierWithTrustAnchors>
+  CreateForProfile(Profile* profile);
+
+  // Creates (if it's not already created) a PolicyCertService and gets it to
+  // start listening for trust anchors for the profile. Returns false if this
+  // service isn't allowed for |profile|, i.e. if NetworkConfigurationUpdater
+  // doesn't exist. This service is created separately for the original profile
+  // and the incognito profile.
+  // Note: NetworkConfigurationUpdater is currently only created for the primary
+  // user's profile.
+  // This should only be called if the network service is enabled.
+  static bool CreateAndStartObservingForProfile(Profile* profile);
 
   static PolicyCertServiceFactory* GetInstance();
 
diff --git a/chrome/browser/chromeos/policy/user_network_configuration_updater_factory_browsertest.cc b/chrome/browser/chromeos/policy/user_network_configuration_updater_factory_browsertest.cc
index b637344..8654bef 100644
--- a/chrome/browser/chromeos/policy/user_network_configuration_updater_factory_browsertest.cc
+++ b/chrome/browser/chromeos/policy/user_network_configuration_updater_factory_browsertest.cc
@@ -48,12 +48,13 @@
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 #include "content/public/browser/notification_service.h"
+#include "content/public/browser/storage_partition.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/test_utils.h"
 #include "crypto/scoped_test_nss_db.h"
+#include "mojo/public/cpp/bindings/sync_call_restrictions.h"
 #include "net/base/test_completion_callback.h"
 #include "net/cert/cert_database.h"
-#include "net/cert/cert_verifier.h"
 #include "net/cert/nss_cert_database.h"
 #include "net/cert/x509_util_nss.h"
 #include "net/test/cert_test_util.h"
@@ -145,49 +146,17 @@
   DISALLOW_COPY_AND_ASSIGN(CertDatabaseChangedObserver);
 };
 
-// Called on the IO thread to verify the |test_server_cert| using the
-// CertVerifier from |request_context_getter|. The result will be written into
-// |verification_result|.
-void VerifyTestServerCertOnIOThread(
-    scoped_refptr<net::URLRequestContextGetter> request_context_getter,
-    scoped_refptr<net::X509Certificate> test_server_cert,
-    int* verification_result) {
-  net::CertVerifier* cert_verifier =
-      request_context_getter->GetURLRequestContext()->cert_verifier();
-
-  net::TestCompletionCallback test_callback;
-  net::CertVerifyResult verify_result;
-  std::unique_ptr<net::CertVerifier::Request> request;
-  // CertVerifier will offload work to a worker pool and post a task back to IO
-  // thread. We need to wait for that to happen. TestCompletionCallback performs
-  // a RunLoop when waiting for the notification to allow tasks to run. As this
-  // is effectively a _nested_ RunLoop, we need ScopedNestableTaskAllower to
-  // allow it.
-  base::MessageLoopCurrent::ScopedNestableTaskAllower allow_nested;
-  *verification_result = test_callback.GetResult(cert_verifier->Verify(
-      net::CertVerifier::RequestParams(test_server_cert.get(), "127.0.0.1", 0,
-                                       std::string()),
-      &verify_result, test_callback.callback(), &request,
-      net::NetLogWithSource()));
-}
-
 // Verifies |certificate| with |profile|'s CertVerifier and returns the result.
 int VerifyTestServerCert(
     Profile* profile,
     const scoped_refptr<net::X509Certificate>& certificate) {
-  base::RunLoop().RunUntilIdle();
-  base::RunLoop run_loop;
-  int verification_result;
-  scoped_refptr<net::URLRequestContextGetter> url_request_context_getter =
-      profile->GetRequestContext();
-  base::PostTaskWithTraitsAndReply(
-      FROM_HERE, {content::BrowserThread::IO},
-      base::BindOnce(&VerifyTestServerCertOnIOThread,
-                     url_request_context_getter, certificate,
-                     &verification_result),
-      run_loop.QuitClosure());
-  run_loop.Run();
-  return verification_result;
+  mojo::ScopedAllowSyncCallForTesting allow_sync_call;
+  int result = net::OK;
+  content::BrowserContext::GetDefaultStoragePartition(profile)
+      ->GetNetworkContext()
+      ->VerifyCertificateForTesting(certificate, "127.0.0.1", std::string(),
+                                    &result);
+  return result;
 }
 
 bool IsSessionStarted() {
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/gaussian_trainer.cc b/chrome/browser/chromeos/power/auto_screen_brightness/gaussian_trainer.cc
new file mode 100644
index 0000000..f0e092a
--- /dev/null
+++ b/chrome/browser/chromeos/power/auto_screen_brightness/gaussian_trainer.cc
@@ -0,0 +1,325 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/power/auto_screen_brightness/gaussian_trainer.h"
+
+#include "base/metrics/field_trial_params.h"
+#include "chromeos/chromeos_features.h"
+
+#include <algorithm>
+#include <cmath>
+#include <limits>
+
+#include "base/logging.h"
+
+namespace chromeos {
+namespace power {
+namespace auto_screen_brightness {
+
+namespace {
+
+constexpr double kTol = 1e-10;
+
+// Calculates lower bound from |reference_brightness| using the min of
+// 1. Division by a scaling factor and
+// 2. Subtraction of an offset.
+double BrightnessLowerBound(double reference_brightness,
+                            double scale,
+                            double offset) {
+  DCHECK_GT(scale, 0.0);
+  DCHECK_GE(offset, 0.0);
+
+  return std::max(0.0, std::min(reference_brightness / scale,
+                                reference_brightness - offset));
+}
+
+// Calculates upper bound from |reference_brightness| using the max of
+// 1. Multiplication by a scaling factor and
+// 2. Addition of an offset.
+// The upper bound is also capped at 100.0.
+double BrightnessUpperBound(double reference_brightness,
+                            double scale,
+                            double offset) {
+  DCHECK_GT(scale, 0.0);
+  DCHECK_GE(offset, 0.0);
+
+  return std::min(100.0, std::max(reference_brightness * scale,
+                                  reference_brightness + offset));
+}
+
+// Returns whether |brightness| is an outlier from a |reference_brightness|.
+bool IsBrightnessOutlier(double brightness,
+                         double reference_brightness,
+                         const GaussianTrainer::Params& params) {
+  DCHECK_GE(reference_brightness, 0.0);
+  DCHECK_LE(reference_brightness, 100.0);
+  return brightness < BrightnessLowerBound(reference_brightness,
+                                           params.brightness_bound_scale,
+                                           params.brightness_bound_offset) ||
+         brightness > BrightnessUpperBound(reference_brightness,
+                                           params.brightness_bound_scale,
+                                           params.brightness_bound_offset);
+}
+
+// User's selected |brightness_new| may not be the value that the user needs for
+// various reasons, e.g. they could overshoot. Hence this function calculates
+// the bounded brightness change based on a heuristic magnitude. The new
+// brightness is bounded within a factor of 1+|brightness_step_size| from
+// |brightness_old|.
+double BoundedBrightnessAdjustment(double brightness_old,
+                                   double brightness_new,
+                                   double brightness_step_size) {
+  const double lower_bound = brightness_old / (1.0 + brightness_step_size);
+  const double upper_bound = brightness_old * (1.0 + brightness_step_size);
+
+  return std::min(std::max(brightness_new, lower_bound), upper_bound) -
+         brightness_old;
+}
+
+// Calculates recommended brightness change, given old brightness, user's
+// selected new brghtness and model's predicted brightness.
+double ModelPredictionAdjustment(double brightness_old,
+                                 double brightness_new,
+                                 double model_brightness,
+                                 const GaussianTrainer::Params& params) {
+  DCHECK_GE(brightness_old, 0.0);
+  DCHECK_LE(brightness_old, 100.0);
+  DCHECK_GE(brightness_new, 0.0);
+  DCHECK_LE(brightness_new, 100.0);
+  DCHECK_GE(model_brightness, 0.0);
+  DCHECK_LE(model_brightness, 100.0);
+
+  const double bounded_user_adjustment = BoundedBrightnessAdjustment(
+      brightness_old, brightness_new, params.brightness_step_size);
+
+  DCHECK_GE(bounded_user_adjustment, -100.0);
+  DCHECK_LE(bounded_user_adjustment, 100.0);
+
+  const double target_brightness = brightness_old + bounded_user_adjustment;
+  DCHECK_GE(target_brightness, 0.0);
+  DCHECK_LE(target_brightness, 100.0);
+
+  // If model's prediction is consistent with user's selection, then no
+  // brightness change will be necessary.
+  // TODO(jiameng): add UMA metrics.
+  if ((model_brightness >= target_brightness && bounded_user_adjustment >= 0) ||
+      (model_brightness <= target_brightness && bounded_user_adjustment <= 0))
+    return 0.0;
+
+  // Model prediction is incorrect, calculate the change we need to make by
+  // treating |model_brightness| as the old brightness and |target_brightness|
+  // as the new brightness.
+  // TODO(jiameng): we currently use 2*step_size, revise.
+  return BoundedBrightnessAdjustment(model_brightness, target_brightness,
+                                     2.0 * params.brightness_step_size);
+}
+
+double Gaussian(double x, double sigma) {
+  double xs = x / sigma;
+  return std::exp(-xs * xs);
+}
+
+}  // namespace
+
+// TODO(jiameng): move these params checking into another method and log errors
+// in UMA if any value is invalid. Also disable it if param isn't valid.
+GaussianTrainer::GaussianTrainer() {
+  params_.brightness_bound_scale = GetFieldTrialParamByFeatureAsDouble(
+      features::kAutoScreenBrightness, "brightness_bound_scale",
+      params_.brightness_bound_scale);
+  DCHECK_GT(params_.brightness_bound_scale, 0.0);
+
+  params_.brightness_bound_offset = GetFieldTrialParamByFeatureAsDouble(
+      features::kAutoScreenBrightness, "brightness_bound_offset",
+      params_.brightness_bound_offset);
+  DCHECK_GE(params_.brightness_bound_offset, 0.0);
+
+  params_.brightness_step_size = GetFieldTrialParamByFeatureAsDouble(
+      features::kAutoScreenBrightness, "brightness_step_size",
+      params_.brightness_step_size);
+  DCHECK_GT(params_.brightness_step_size, 0.0);
+
+  params_.sigma = GetFieldTrialParamByFeatureAsDouble(
+      features::kAutoScreenBrightness, "sigma", params_.sigma);
+  DCHECK_GT(params_.sigma, 0.0);
+
+  params_.low_log_lux_threshold = GetFieldTrialParamByFeatureAsDouble(
+      features::kAutoScreenBrightness, "low_log_lux_threshold",
+      params_.low_log_lux_threshold);
+
+  params_.min_grad_low_lux = GetFieldTrialParamByFeatureAsDouble(
+      features::kAutoScreenBrightness, "min_grad_low_lux",
+      params_.min_grad_low_lux);
+  params_.min_grad = GetFieldTrialParamByFeatureAsDouble(
+      features::kAutoScreenBrightness, "min_grad", params_.min_grad);
+  params_.max_grad = GetFieldTrialParamByFeatureAsDouble(
+      features::kAutoScreenBrightness, "max_grad", params_.max_grad);
+
+  DCHECK_GE(params_.min_grad_low_lux, 0.0);
+  DCHECK_LT(params_.min_grad_low_lux, 1.0);
+  DCHECK_GE(params_.min_grad, 0.0);
+  DCHECK_LT(params_.min_grad, 1.0);
+  DCHECK_GE(params_.min_grad, params_.min_grad_low_lux);
+  DCHECK_GT(params_.max_grad, params_.min_grad);
+
+  params_.min_brightness = GetFieldTrialParamByFeatureAsDouble(
+      features::kAutoScreenBrightness, "min_brightness",
+      params_.min_brightness);
+  DCHECK_GE(params_.min_brightness, 0.0);
+}
+
+GaussianTrainer::~GaussianTrainer() = default;
+
+// TODO(jiameng): add slope constraint check in |current_curve| and return check
+// result to the caller.
+void GaussianTrainer::SetInitialCurves(
+    const MonotoneCubicSpline& global_curve,
+    const MonotoneCubicSpline& current_curve) {
+  // This function should be called once only.
+  DCHECK(!global_curve_);
+  DCHECK(!current_curve_);
+  global_curve_.emplace(global_curve);
+  current_curve_.emplace(current_curve);
+
+  ambient_log_lux_ = current_curve_->GetControlPointsX();
+  brightness_ = current_curve_->GetControlPointsY();
+  const size_t num_points = ambient_log_lux_.size();
+
+  // Global curve and personal curve should have the same ambient log lux.
+  const std::vector<double> global_log_lux = global_curve_->GetControlPointsX();
+  DCHECK_EQ(global_log_lux.size(), num_points);
+
+  for (size_t i = 0; i < num_points; ++i) {
+    DCHECK_LE(std::abs(global_log_lux[i] - ambient_log_lux_[i]), kTol);
+  }
+
+  // Calculate |min_ratios_| and |max_ratios_| from global curve.
+  min_ratios_.resize(num_points - 1);
+  max_ratios_.resize(num_points - 1);
+  const std::vector<double> global_brightness =
+      global_curve_->GetControlPointsY();
+
+  // TODO(jiameng): may revise to allow 0 as a control point.
+  DCHECK_GT(global_brightness[0], 0);
+
+  for (size_t i = 0; i < num_points - 1; ++i) {
+    const double min_grad = global_log_lux[i] < params_.low_log_lux_threshold
+                                ? params_.min_grad_low_lux
+                                : params_.min_grad;
+
+    const double ratio = global_brightness[i + 1] / global_brightness[i];
+    DCHECK_GE(ratio, 1);
+    min_ratios_[i] = std::pow(ratio, min_grad);
+    max_ratios_[i] = std::pow(ratio, params_.max_grad);
+  }
+}
+
+MonotoneCubicSpline GaussianTrainer::Train(
+    const std::vector<TrainingDataPoint>& data) {
+  DCHECK(global_curve_);
+  DCHECK(current_curve_);
+  DCHECK(!data.empty());
+
+  for (const auto& data_point : data) {
+    AdjustCurveWithSingleDataPoint(data_point);
+  }
+
+  if (!need_to_update_curve_)
+    return *current_curve_;
+
+  current_curve_.emplace(MonotoneCubicSpline(ambient_log_lux_, brightness_));
+  need_to_update_curve_ = false;
+  return *current_curve_;
+}
+
+void GaussianTrainer::AdjustCurveWithSingleDataPoint(
+    const TrainingDataPoint& data) {
+  const double brightness_global =
+      global_curve_->Interpolate(data.ambient_log_lux);
+
+  // Check if this |data| is an outlier and should be ignored. It's an outlier
+  // if its original/old brightness is too far off from the brightness as
+  // predicted by the global curve. This assumes the global curve is reasonably
+  // accurate.
+  // TODO(jiameng): add UMA metrics to record this.
+  if (IsBrightnessOutlier(data.brightness_old, brightness_global, params_)) {
+    return;
+  }
+
+  // Calculate how much adjustment we need to make to the current personal
+  // curve at |data.ambient_log_lux|.
+  const double model_brightness =
+      current_curve_->Interpolate(data.ambient_log_lux);
+  const double brightness_adjustment = ModelPredictionAdjustment(
+      data.brightness_old, data.brightness_new, model_brightness, params_);
+
+  if (std::abs(brightness_adjustment) <= kTol)
+    return;
+
+  need_to_update_curve_ = true;
+
+  // Index of the log-lux in |ambient_log_lux_| that's closest to
+  // |data.ambient_log_lux|.
+  size_t center_index = 0;
+  double min_dist = std::numeric_limits<double>::max();
+  for (size_t i = 0; i < ambient_log_lux_.size(); ++i) {
+    // Adjust brightness of each control point in the current brightness curve.
+    const double dist = std::abs(data.ambient_log_lux - ambient_log_lux_[i]);
+    brightness_[i] += brightness_adjustment * Gaussian(dist, params_.sigma);
+
+    if (dist < min_dist) {
+      center_index = i;
+      min_dist = dist;
+    }
+  }
+
+  EnforceMonotonicity(center_index);
+}
+
+void GaussianTrainer::EnforceMonotonicity(size_t center_index) {
+  DCHECK_LT(center_index, ambient_log_lux_.size());
+  brightness_[center_index] = std::min(
+      100.0, std::max(params_.min_brightness, brightness_[center_index]));
+
+  // Updates control points to the left of |center_index| so that brightness
+  // values satisfy min/max ratio requirement.
+  for (size_t i = center_index; i > 0; --i) {
+    const double min_value = brightness_[i] / max_ratios_[i - 1];
+    const double max_value = brightness_[i] / min_ratios_[i - 1];
+    brightness_[i - 1] =
+        std::max(std::min(brightness_[i - 1], max_value), min_value);
+    // TODO(jiameng): add UMA metrics.
+    if (brightness_[i - 1] > 100.0)
+      brightness_[i - 1] = 100.0;
+  }
+
+  // Updates control points to the right of |center_index| so that brightness
+  // values satisfy min/max ratio requirement.
+  for (size_t i = center_index; i < ambient_log_lux_.size() - 1; ++i) {
+    const double min_value = brightness_[i] * min_ratios_[i];
+    const double max_value = brightness_[i] * max_ratios_[i];
+    brightness_[i + 1] =
+        std::max(std::min(brightness_[i + 1], max_value), min_value);
+    // TODO(jiameng): add UMA metrics.
+    if (brightness_[i + 1] > 100.0)
+      brightness_[i + 1] = 100.0;
+  }
+
+#ifndef NDEBUG
+  // Check that final |brightness_| array is monotonic across whole range and
+  // each value is in [0, 100].
+  for (size_t i = 0; i < ambient_log_lux_.size() - 1; ++i) {
+    DCHECK_GE(brightness_[i], 0);
+    DCHECK_LE(brightness_[i], 100);
+    DCHECK_LE(brightness_[i], brightness_[i + 1]);
+  }
+
+  DCHECK_GE(brightness_.back(), 0);
+  DCHECK_LE(brightness_.back(), 100);
+#endif
+}
+
+}  // namespace auto_screen_brightness
+}  // namespace power
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/gaussian_trainer.h b/chrome/browser/chromeos/power/auto_screen_brightness/gaussian_trainer.h
new file mode 100644
index 0000000..c7fa1fc
--- /dev/null
+++ b/chrome/browser/chromeos/power/auto_screen_brightness/gaussian_trainer.h
@@ -0,0 +1,104 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_POWER_AUTO_SCREEN_BRIGHTNESS_GAUSSIAN_TRAINER_H_
+#define CHROME_BROWSER_CHROMEOS_POWER_AUTO_SCREEN_BRIGHTNESS_GAUSSIAN_TRAINER_H_
+
+#include <memory>
+
+#include "chrome/browser/chromeos/power/auto_screen_brightness/trainer.h"
+
+namespace chromeos {
+namespace power {
+namespace auto_screen_brightness {
+
+// GaussianTrainer updates an existing brightness curve (a mapping from
+// ambient light to screen brightness) using training data points that represent
+// how user changes brightness following an ambient value change. The update
+// procedure is Gaussian hence the name. It uses a global curve to check for
+// outliers that may exist in training data. It also ensures new curves are
+// monotone and also satisfy requirements on the slope.
+class GaussianTrainer : public Trainer {
+ public:
+  // TODO(jiameng): revise default values.
+  struct Params {
+    // |brightness_bound_scale| and |brightness_bound_offset| are used to define
+    // training example outliers.
+    double brightness_bound_scale = 1.5;
+    double brightness_bound_offset = 40;
+
+    // |brightness_step_size| defines reasonable brightness change scale: a
+    // reasonable change would be between
+    // brightness_old/(1+|brightness_step_size|) and
+    // brightness_old*(1+|brightness_step_size|)
+    double brightness_step_size = 0.2;
+
+    // One training data point could modify all the points on the curve, but its
+    // effect is greatest on the point nearest to it (as measured by difference
+    // in ambient value). The effect on the other points decay with a Gaussian
+    // distribution with standard deviation |sigma|.
+    double sigma = 1;
+
+    // If log lux is below |low_log_lux_threshold| then we'll use
+    // |min_grad_low_lux| as gradient constraint.
+    double low_log_lux_threshold = 0.1;
+    double min_grad_low_lux = 0;
+
+    // Min and max grad as a power of brightness ratios.
+    double min_grad = 0.25;
+    double max_grad = 1;
+
+    double min_brightness = 0;
+  };
+
+  GaussianTrainer();
+  ~GaussianTrainer() override;
+
+  // Trainer overrides:
+  void SetInitialCurves(const MonotoneCubicSpline& global_curve,
+                        const MonotoneCubicSpline& current_curve) override;
+  MonotoneCubicSpline Train(
+      const std::vector<TrainingDataPoint>& data) override;
+
+ private:
+  // Updates |brightness_| using |data|. It also sets |need_to_update_curve_|
+  // to true if |brightness_| is actually changed.
+  void AdjustCurveWithSingleDataPoint(const TrainingDataPoint& data);
+
+  // Called each time |AdjustCurveWithSingleDataPoint| changes |brightness_|.
+  // It ensures the curve is still monotone and also satisfies min/max grad
+  // constraints. It does this by changing points to the left and to the right
+  // of |center_index|.
+  void EnforceMonotonicity(size_t center_index);
+
+  Params params_;
+  // |global_curve| does not change after |SetInitialCurves| is called.
+  base::Optional<MonotoneCubicSpline> global_curve_;
+  // |current_curve_| initially is set by |SetInitialCurves| and then gets
+  // updated during training.
+  base::Optional<MonotoneCubicSpline> current_curve_;
+
+  // Whether the |brightness_| has been updated since last time |Train| updated
+  // the curve.
+  bool need_to_update_curve_ = false;
+
+  // (|ambient_log_lux_|, |brightness_|) are the control points of
+  // |current_curve_|. |ambient_log_lux_| doesn't change, but |brightness_| may
+  // be updated during training.
+  std::vector<double> ambient_log_lux_;
+  std::vector<double> brightness_;
+
+  // Minimum and max brightness ratios of two adjacent control points. They are
+  // calculated from the global curve's brightness values.
+  std::vector<double> min_ratios_;
+  std::vector<double> max_ratios_;
+
+  DISALLOW_COPY_AND_ASSIGN(GaussianTrainer);
+};
+
+}  // namespace auto_screen_brightness
+}  // namespace power
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_POWER_AUTO_SCREEN_BRIGHTNESS_GAUSSIAN_TRAINER_H_
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/gaussian_trainer_unittest.cc b/chrome/browser/chromeos/power/auto_screen_brightness/gaussian_trainer_unittest.cc
new file mode 100644
index 0000000..1b15613
--- /dev/null
+++ b/chrome/browser/chromeos/power/auto_screen_brightness/gaussian_trainer_unittest.cc
@@ -0,0 +1,374 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/power/auto_screen_brightness/gaussian_trainer.h"
+
+#include "base/strings/string_number_conversions.h"
+#include "base/test/scoped_feature_list.h"
+#include "base/test/simple_test_tick_clock.h"
+#include "chrome/browser/chromeos/power/auto_screen_brightness/monotone_cubic_spline.h"
+#include "chromeos/chromeos_features.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chromeos {
+namespace power {
+namespace auto_screen_brightness {
+
+class GaussianTrainerTest : public testing::Test {
+ public:
+  GaussianTrainerTest()
+      : global_curve_(MonotoneCubicSpline(log_lux_, global_brightness_)),
+        personal_curve_(MonotoneCubicSpline(log_lux_, personal_brightness_)) {}
+
+  void ResetModelWithParams(const std::map<std::string, std::string>& params) {
+    base::test::ScopedFeatureList scoped_feature_list;
+    scoped_feature_list.InitAndEnableFeatureWithParameters(
+        features::kAutoScreenBrightness, params);
+
+    gaussian_trainer_ = std::make_unique<GaussianTrainer>();
+  }
+
+  ~GaussianTrainerTest() override = default;
+
+ protected:
+  const std::vector<double> log_lux_ = {-4, -2, 0,  2,  4,  6,  8,
+                                        10, 12, 14, 16, 18, 20, 22,
+                                        24, 26, 28, 30, 32, 34, 36};
+  const std::vector<double> global_brightness_ = {1,  5,  10, 15, 20, 25, 30,
+                                                  35, 40, 45, 50, 55, 60, 65,
+                                                  70, 75, 80, 85, 90, 95, 100};
+  const std::vector<double> personal_brightness_ = {
+      3,  8,  12, 17, 22, 27, 32, 37, 42, 46, 56,
+      61, 66, 71, 76, 79, 81, 86, 91, 95, 100};
+
+  // These values are set to not constrain anything (e.g. outliers). Individual
+  // param will be overridden in unit tests.
+  const std::map<std::string, std::string> default_params_{
+      {"brightness_bound_scale", "100"},
+      {"brightness_bound_offset", "100"},
+      {"brightness_step_size", "100"},
+      {"sigma", "0.1"},
+      {"low_log_lux_threshold", "0"},
+      {"min_grad_low_lux", "0"},
+      {"min_grad", "0"},
+      {"max_grad", "1"},
+      {"min_brightness", "0"}};
+
+  // Tests below generally test changes to the |ref_index_|'th entry in the
+  // brightness curve.
+  const size_t ref_index_ = 10;
+  const double ref_log_lux_ = log_lux_[ref_index_];
+  const double ref_global_brightness_ = global_brightness_[ref_index_];
+  const double ref_personal_brightness_ = personal_brightness_[ref_index_];
+
+  MonotoneCubicSpline global_curve_;
+  MonotoneCubicSpline personal_curve_;
+  base::SimpleTestTickClock tick_clock_;
+
+  std::unique_ptr<GaussianTrainer> gaussian_trainer_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(GaussianTrainerTest);
+};
+
+// Tests the effect of |brightness_bound_scale| on outlier checks. A larger
+// value would result in a data point less likely to be considered an outlier.
+TEST_F(GaussianTrainerTest, OutlierBoundScale) {
+  std::map<std::string, std::string> params = default_params_;
+  const double bound_scale = 1.5;
+
+  params["brightness_bound_scale"] = base::NumberToString(bound_scale);
+  params["brightness_bound_offset"] = "0";
+
+  ResetModelWithParams(params);
+  gaussian_trainer_->SetInitialCurves(global_curve_, personal_curve_);
+
+  const double min_bound = ref_global_brightness_ / bound_scale;
+  const double max_bound = ref_global_brightness_ * bound_scale;
+
+  const TrainingDataPoint data_too_low = {min_bound - 5, min_bound - 10,
+                                          ref_log_lux_, tick_clock_.NowTicks()};
+
+  const TrainingDataPoint data_too_high = {
+      max_bound + 5, max_bound + 10, ref_log_lux_, tick_clock_.NowTicks()};
+
+  // |data_too_low| and |data_too_high| are both ignored. Hence there is no
+  // change in the personal curve.
+  const MonotoneCubicSpline trained_curve1 =
+      gaussian_trainer_->Train({data_too_low, data_too_high});
+  EXPECT_EQ(trained_curve1, personal_curve_);
+
+  // Next increase |brightness_bound_scale|, so that the two training data
+  // points are no longer outliers. A new curve will be trained.
+  params["brightness_bound_scale"] = base::NumberToString(bound_scale * 100);
+  ResetModelWithParams(params);
+  gaussian_trainer_->SetInitialCurves(global_curve_, personal_curve_);
+
+  const MonotoneCubicSpline trained_curve2 =
+      gaussian_trainer_->Train({data_too_low, data_too_high});
+  EXPECT_FALSE(trained_curve2 == personal_curve_);
+  const std::vector<double> new_log_lux2 = trained_curve2.GetControlPointsX();
+
+  for (size_t i = 0; i < personal_brightness_.size(); ++i) {
+    EXPECT_DOUBLE_EQ(new_log_lux2[i], log_lux_[i]);
+  }
+}
+
+// Tests the effect of |brightness_bound_offset| on outlier checks. A larger
+// value would result in a data point less likely to be considered an outlier.
+TEST_F(GaussianTrainerTest, OutlierBoundOffset) {
+  std::map<std::string, std::string> params = default_params_;
+  const double bound_offset = 40;
+
+  params["brightness_bound_scale"] = "1";
+  params["brightness_bound_offset"] = base::NumberToString(bound_offset);
+
+  ResetModelWithParams(params);
+  gaussian_trainer_->SetInitialCurves(global_curve_, personal_curve_);
+
+  const double min_bound = ref_global_brightness_ - bound_offset;
+  const double max_bound = ref_global_brightness_ + bound_offset;
+
+  const TrainingDataPoint data_too_low = {min_bound - 5, min_bound - 10,
+                                          ref_log_lux_, tick_clock_.NowTicks()};
+
+  const TrainingDataPoint data_too_high = {
+      max_bound + 5, max_bound + 10, ref_log_lux_, tick_clock_.NowTicks()};
+
+  // |data_too_low| and |data_too_high| are both ignored. Hence there is no
+  // change in the personal curve.
+  const MonotoneCubicSpline trained_curve1 =
+      gaussian_trainer_->Train({data_too_low, data_too_high});
+  EXPECT_EQ(trained_curve1, personal_curve_);
+
+  // Next increase |brightness_bound_offset|, so that the two training data
+  // points are no longer outliers. A new curve will be trained.
+  params["brightness_bound_offset"] = base::NumberToString(bound_offset + 20);
+  ResetModelWithParams(params);
+  gaussian_trainer_->SetInitialCurves(global_curve_, personal_curve_);
+
+  const MonotoneCubicSpline trained_curve2 =
+      gaussian_trainer_->Train({data_too_low, data_too_high});
+  EXPECT_FALSE(trained_curve2 == personal_curve_);
+  const std::vector<double> new_log_lux2 = trained_curve2.GetControlPointsX();
+
+  for (size_t i = 0; i < personal_brightness_.size(); ++i) {
+    EXPECT_DOUBLE_EQ(new_log_lux2[i], log_lux_[i]);
+  }
+}
+
+// Tests the effect of |brightness_step_size| on the training data point and
+// hence the trained curve. A smaller value would lead to a narrower brightness
+// change that is considered plausible. Hence changes on brightness curve will
+// be smaller too.
+TEST_F(GaussianTrainerTest, BrightnessStepSize) {
+  // Brightness change occurs at a control point (|ref_log_lux_|).
+  const TrainingDataPoint data = {ref_personal_brightness_ + 1,
+                                  ref_personal_brightness_ + 20, ref_log_lux_,
+                                  tick_clock_.NowTicks()};
+
+  // First train the curve with |brightness_step_size| = 100.
+  std::map<std::string, std::string> params = default_params_;
+  ResetModelWithParams(params);
+  gaussian_trainer_->SetInitialCurves(global_curve_, personal_curve_);
+
+  const MonotoneCubicSpline trained_curve1 = gaussian_trainer_->Train({data});
+  const std::vector<double> new_log_lux1 = trained_curve1.GetControlPointsX();
+  const std::vector<double> new_brightness1 =
+      trained_curve1.GetControlPointsY();
+
+  // Next train the curve with a smaller |brightness_step_size|. Hence increase
+  // in brightness adjustment is effectively capped.
+  params["brightness_step_size"] = "0.2";
+  ResetModelWithParams(params);
+  gaussian_trainer_->SetInitialCurves(global_curve_, personal_curve_);
+
+  const MonotoneCubicSpline trained_curve2 = gaussian_trainer_->Train({data});
+  const std::vector<double> new_log_lux2 = trained_curve2.GetControlPointsX();
+  const std::vector<double> new_brightness2 =
+      trained_curve2.GetControlPointsY();
+
+  EXPECT_EQ(new_log_lux1.size(), log_lux_.size());
+  EXPECT_EQ(new_log_lux2.size(), log_lux_.size());
+
+  for (size_t i = 0; i < personal_brightness_.size(); ++i) {
+    EXPECT_DOUBLE_EQ(new_log_lux1[i], log_lux_[i]);
+    EXPECT_DOUBLE_EQ(new_log_lux2[i], log_lux_[i]);
+
+    if (i == ref_index_) {
+      // At |ref_index_| brightness of |trained_curve1| should be strictly
+      // bigger because it has a larger step size.
+      EXPECT_GT(new_brightness1[i], new_brightness2[i]);
+      EXPECT_GT(new_brightness2[i], personal_brightness_[i]);
+    } else {
+      // At other points, |trained_curve1| should be not smaller than
+      // |trained_curve2|. The actual difference depends on |sigma|.
+      EXPECT_GE(new_brightness1[i], new_brightness2[i]);
+      EXPECT_GE(new_brightness2[i], personal_brightness_[i]);
+    }
+  }
+}
+
+// Tests the effect of |sigma| on the globalness/localness of a single data
+// point on the entire curve. A larger value would result in more control points
+// being updated (in addition to the one nearest to the training data).
+TEST_F(GaussianTrainerTest, Sigma) {
+  // Brightness change occurs at a control point (|ref_log_lux_|).
+  const TrainingDataPoint data = {ref_personal_brightness_ + 1,
+                                  ref_personal_brightness_ + 5, ref_log_lux_,
+                                  tick_clock_.NowTicks()};
+
+  // First train the curve with |sigma| = 0.1.
+  std::map<std::string, std::string> params = default_params_;
+  ResetModelWithParams(params);
+  gaussian_trainer_->SetInitialCurves(global_curve_, personal_curve_);
+
+  const MonotoneCubicSpline trained_curve1 = gaussian_trainer_->Train({data});
+  const std::vector<double> new_log_lux1 = trained_curve1.GetControlPointsX();
+  const std::vector<double> new_brightness1 =
+      trained_curve1.GetControlPointsY();
+
+  // Next train the curve with a larger |sigma|. Hence more control points have
+  // larger brightness.
+  params["sigma"] = "10";
+  ResetModelWithParams(params);
+  gaussian_trainer_->SetInitialCurves(global_curve_, personal_curve_);
+
+  const MonotoneCubicSpline trained_curve2 = gaussian_trainer_->Train({data});
+  const std::vector<double> new_log_lux2 = trained_curve2.GetControlPointsX();
+  const std::vector<double> new_brightness2 =
+      trained_curve2.GetControlPointsY();
+
+  EXPECT_EQ(new_log_lux1.size(), log_lux_.size());
+  EXPECT_EQ(new_log_lux2.size(), log_lux_.size());
+
+  // Total brightness difference between |trained_curve2| and |trained_curve1|.
+  double brightness_diff_21 = 0;
+  for (size_t i = 0; i < personal_brightness_.size(); ++i) {
+    EXPECT_DOUBLE_EQ(new_log_lux1[i], log_lux_[i]);
+    EXPECT_DOUBLE_EQ(new_log_lux2[i], log_lux_[i]);
+
+    if (i == ref_index_) {
+      EXPECT_DOUBLE_EQ(new_brightness1[i], new_brightness2[i]);
+      EXPECT_GT(new_brightness1[i], personal_brightness_[i]);
+    } else {
+      EXPECT_GE(new_brightness2[i], new_brightness1[i]);
+      EXPECT_GE(new_brightness1[i], personal_brightness_[i]);
+    }
+    brightness_diff_21 += new_brightness2[i] - new_brightness1[i];
+  }
+
+  EXPECT_GT(brightness_diff_21, 0);
+}
+
+// Tests the effect of |max_grad| on the trained curve. A smaller value would
+// lead to a flatter curve.
+TEST_F(GaussianTrainerTest, MaxGrad) {
+  // Brightness change occurs at a control point (|ref_log_lux_|).
+  const TrainingDataPoint data = {ref_personal_brightness_ + 1,
+                                  ref_personal_brightness_ + 20, ref_log_lux_,
+                                  tick_clock_.NowTicks()};
+
+  // First train the curve with |max_grad| = 1.
+  std::map<std::string, std::string> params = default_params_;
+  ResetModelWithParams(params);
+  gaussian_trainer_->SetInitialCurves(global_curve_, personal_curve_);
+
+  const MonotoneCubicSpline trained_curve1 = gaussian_trainer_->Train({data});
+  const std::vector<double> new_log_lux1 = trained_curve1.GetControlPointsX();
+  const std::vector<double> new_brightness1 =
+      trained_curve1.GetControlPointsY();
+
+  // Next train the curve with a smaller |max_grad|. Hence the curve will be
+  // flatter.
+  params["max_grad"] = "0.2";
+  ResetModelWithParams(params);
+  gaussian_trainer_->SetInitialCurves(global_curve_, personal_curve_);
+
+  const MonotoneCubicSpline trained_curve2 = gaussian_trainer_->Train({data});
+  const std::vector<double> new_log_lux2 = trained_curve2.GetControlPointsX();
+  const std::vector<double> new_brightness2 =
+      trained_curve2.GetControlPointsY();
+
+  EXPECT_EQ(new_log_lux1.size(), log_lux_.size());
+  EXPECT_EQ(new_log_lux2.size(), log_lux_.size());
+
+  // It's not guaranteed that each point on |trained_curve2| would have a
+  // smaller slope than the corresponding point on |trained_curve1|. Hence we
+  // check max slope of |trained_curve2| is larger than the min slope of
+  // |trained_curve1|.
+  double max_ratio1 = std::numeric_limits<double>::min();
+  double max_ratio2 = std::numeric_limits<double>::min();
+
+  for (size_t i = 0; i < personal_brightness_.size(); ++i) {
+    EXPECT_DOUBLE_EQ(new_log_lux1[i], log_lux_[i]);
+    EXPECT_DOUBLE_EQ(new_log_lux2[i], log_lux_[i]);
+
+    if (i < personal_brightness_.size() - 1) {
+      const double ratio1 = new_brightness1[i + 1] / new_brightness1[i];
+      const double ratio2 = new_brightness2[i + 1] / new_brightness2[i];
+      max_ratio1 = std::max(max_ratio1, ratio1);
+      max_ratio2 = std::max(max_ratio2, ratio2);
+    }
+  }
+  EXPECT_GT(max_ratio1, max_ratio2);
+}
+
+// The current curve isn't updated because training data point is consistent
+// with existing model prediction.
+TEST_F(GaussianTrainerTest, ConsistentModelPredictionNoCurveUpdate) {
+  ResetModelWithParams(default_params_);
+  gaussian_trainer_->SetInitialCurves(global_curve_, personal_curve_);
+
+  // User increased brightness and target is lower than model prediction. Hence
+  // no change to the curve.
+  EXPECT_EQ(gaussian_trainer_->Train(
+                {{ref_personal_brightness_ - 20, ref_personal_brightness_ - 10,
+                  ref_log_lux_, tick_clock_.NowTicks()}}),
+            personal_curve_);
+
+  ResetModelWithParams(default_params_);
+  gaussian_trainer_->SetInitialCurves(global_curve_, personal_curve_);
+
+  // User decreased brightness and target is higher than model prediction. Hence
+  // no change to the curve.
+  EXPECT_EQ(gaussian_trainer_->Train(
+                {{ref_personal_brightness_ + 20, ref_personal_brightness_ + 10,
+                  ref_log_lux_, tick_clock_.NowTicks()}}),
+            personal_curve_);
+}
+
+// Tests numerical results of a trained curve so that we could detect any
+// unexpected changes when algorithm changes.
+TEST_F(GaussianTrainerTest, TrainedCurveValue) {
+  // Brightness change occurs at a control point (|ref_log_lux_|).
+  const TrainingDataPoint data = {ref_personal_brightness_ + 1,
+                                  ref_personal_brightness_ + 20, ref_log_lux_,
+                                  tick_clock_.NowTicks()};
+
+  const std::map<std::string, std::string> params{
+      {"brightness_bound_scale", "1.5"},
+      {"brightness_bound_offset", "40"},
+      {"brightness_step_size", "0.2"},
+      {"sigma", "1"},
+      {"low_log_lux_threshold", "0"},
+      {"min_grad_low_lux", "0"},
+      {"min_grad", "0"},
+      {"max_grad", "1"},
+      {"min_brightness", "0"}};
+
+  ResetModelWithParams(params);
+  gaussian_trainer_->SetInitialCurves(global_curve_, personal_curve_);
+
+  const MonotoneCubicSpline trained_curve = gaussian_trainer_->Train({data});
+  const MonotoneCubicSpline expected_curve(
+      log_lux_,
+      {3.0,  8.0,  13.68, 20.52, 27.36, 34.2, 41.04, 47.88, 54.72, 61.56, 68.4,
+       68.4, 68.4, 71.0,  76.0,  79.0,  81.0, 86.0,  91.0,  95.0,  100.0});
+  EXPECT_EQ(trained_curve, expected_curve);
+}
+
+}  // namespace auto_screen_brightness
+}  // namespace power
+}  // namespace chromeos
diff --git a/chrome/browser/component_updater/widevine_cdm_component_installer.cc b/chrome/browser/component_updater/widevine_cdm_component_installer.cc
index 137858d..f4a03a2 100644
--- a/chrome/browser/component_updater/widevine_cdm_component_installer.cc
+++ b/chrome/browser/component_updater/widevine_cdm_component_installer.cc
@@ -115,11 +115,14 @@
 // The following strings are used to specify supported codecs in the
 // parameter |kCdmCodecsListName|.
 const char kCdmSupportedCodecVp8[] = "vp8";
-const char kCdmSupportedCodecVp9[] = "vp9.0";
+// Legacy VP9, which is equivalent to VP9 profile 0.
+// TODO(xhwang): Newer CDMs should support "vp09" below. Remove this after older
+// CDMs are obsolete.
+const char kCdmSupportedCodecLegacyVp9[] = "vp9.0";
+// Supports at least VP9 profile 0 and profile 2.
+const char kCdmSupportedCodecVp9[] = "vp09";
 const char kCdmSupportedCodecAv1[] = "av01";
-#if BUILDFLAG(USE_PROPRIETARY_CODECS)
 const char kCdmSupportedCodecAvc1[] = "avc1";
-#endif
 
 // The following strings are used to specify supported encryption schemes in
 // the parameter |kCdmSupportedEncryptionSchemesName|.
@@ -183,10 +186,12 @@
 }
 
 // Returns true and updates |video_codecs| if the appropriate manifest entry is
-// valid. Returns false and does not modify |video_codecs| if the manifest entry
-// is incorrectly formatted.
+// valid. When VP9 is supported, sets |supports_vp9_profile2| if profile 2 is
+// supported. Older CDMs may only support profile 0. Returns false and does not
+// modify |video_codecs| if the manifest entry is incorrectly formatted.
 bool GetCodecs(const base::DictionaryValue& manifest,
-               std::vector<media::VideoCodec>* video_codecs) {
+               std::vector<media::VideoCodec>* video_codecs,
+               bool* supports_vp9_profile2) {
   DCHECK(video_codecs);
 
   const base::Value* value = manifest.FindKey(kCdmCodecsListName);
@@ -212,17 +217,23 @@
       base::SplitStringPiece(codecs, kCdmValueDelimiter, base::TRIM_WHITESPACE,
                              base::SPLIT_WANT_NONEMPTY);
 
+  // Assuming VP9 profile 2 is not supported by default. Will only be set when
+  // kCdmSupportedCodecVp9 is available below.
+  *supports_vp9_profile2 = false;
+
   for (const auto& codec : supported_codecs) {
-    if (codec == kCdmSupportedCodecVp8)
+    if (codec == kCdmSupportedCodecVp8) {
       result.push_back(media::VideoCodec::kCodecVP8);
-    else if (codec == kCdmSupportedCodecVp9)
+    } else if (codec == kCdmSupportedCodecLegacyVp9) {
       result.push_back(media::VideoCodec::kCodecVP9);
-    else if (codec == kCdmSupportedCodecAv1)
+    } else if (codec == kCdmSupportedCodecVp9) {
+      result.push_back(media::VideoCodec::kCodecVP9);
+      *supports_vp9_profile2 = true;
+    } else if (codec == kCdmSupportedCodecAv1) {
       result.push_back(media::VideoCodec::kCodecAV1);
-#if BUILDFLAG(USE_PROPRIETARY_CODECS)
-    else if (codec == kCdmSupportedCodecAvc1)
+    } else if (codec == kCdmSupportedCodecAvc1) {
       result.push_back(media::VideoCodec::kCodecH264);
-#endif  // BUILDFLAG(USE_PROPRIETARY_CODECS)
+    }
   }
 
   video_codecs->swap(result);
@@ -354,7 +365,8 @@
 // may or may not be updated.
 bool ParseManifest(const base::DictionaryValue& manifest,
                    content::CdmCapability* capability) {
-  return GetCodecs(manifest, &capability->video_codecs) &&
+  return GetCodecs(manifest, &capability->video_codecs,
+                   &capability->supports_vp9_profile2) &&
          GetEncryptionSchemes(manifest, &capability->encryption_schemes) &&
          GetSessionTypes(manifest, &capability->session_types) &&
          GetCdmProxyProtocols(manifest, &capability->cdm_proxy_protocols);
diff --git a/chrome/browser/extensions/tab_helper.cc b/chrome/browser/extensions/tab_helper.cc
index b7721ef9..3968d51 100644
--- a/chrome/browser/extensions/tab_helper.cc
+++ b/chrome/browser/extensions/tab_helper.cc
@@ -29,7 +29,6 @@
 #include "chrome/browser/ui/browser_dialogs.h"
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/web_applications/components/web_app_helpers.h"
-#include "chrome/common/extensions/api/webstore/webstore_api_constants.h"
 #include "chrome/common/extensions/extension_constants.h"
 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
 #include "chrome/common/render_messages.h"
diff --git a/chrome/browser/feedback/feedback_uploader_chrome.cc b/chrome/browser/feedback/feedback_uploader_chrome.cc
index 231d8b3..037b8c9 100644
--- a/chrome/browser/feedback/feedback_uploader_chrome.cc
+++ b/chrome/browser/feedback/feedback_uploader_chrome.cc
@@ -56,7 +56,7 @@
       IdentityManagerFactory::GetForProfile(profile);
 
   if (identity_manager && identity_manager->HasPrimaryAccount()) {
-    OAuth2TokenService::ScopeSet scopes;
+    identity::ScopeSet scopes;
     scopes.insert("https://www.googleapis.com/auth/supportcontent");
     token_fetcher_ =
         std::make_unique<identity::PrimaryAccountAccessTokenFetcher>(
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 0baf2fa..f57e804c6 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -670,6 +670,11 @@
 const char kEnableNotificationScrollBarDescription[] =
     "Enable the scroll bar of the notification list in Unified System Tray.";
 
+const char kEnableNotificationExpansionAnimationName[] =
+    "Enable notification expansion animations";
+const char kEnableNotificationExpansionAnimationDescription[] =
+    "Enable notification animations whenever the expansion state is toggled.";
+
 const char kEnableNupPrintingName[] = "Enable N-up printing";
 const char kEnableNupPrintingDescription[] =
     "Enable N-up printing in the print preview panel.";
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 585bf84..9de89c4 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -428,6 +428,9 @@
 extern const char kEnableNotificationScrollBarName[];
 extern const char kEnableNotificationScrollBarDescription[];
 
+extern const char kEnableNotificationExpansionAnimationName[];
+extern const char kEnableNotificationExpansionAnimationDescription[];
+
 extern const char kEnableNupPrintingName[];
 extern const char kEnableNupPrintingDescription[];
 
diff --git a/chrome/browser/io_thread.cc b/chrome/browser/io_thread.cc
index e38572c..517b257 100644
--- a/chrome/browser/io_thread.cc
+++ b/chrome/browser/io_thread.cc
@@ -94,10 +94,10 @@
 #endif  // defined(OS_ANDROID)
 
 #if defined(OS_CHROMEOS)
-#include "chrome/browser/chromeos/net/cert_verify_proc_chromeos.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chromeos/network/dhcp_pac_file_fetcher_factory_chromeos.h"
 #include "chromeos/network/host_resolver_impl_chromeos.h"
+#include "services/network/cert_verify_proc_chromeos.h"
 #endif
 
 using content::BrowserThread;
@@ -394,7 +394,7 @@
       // Creates a CertVerifyProc that doesn't allow any profile-provided certs.
       cert_verifier = std::make_unique<net::CachingCertVerifier>(
           std::make_unique<net::MultiThreadedCertVerifier>(
-              base::MakeRefCounted<chromeos::CertVerifyProcChromeOS>()));
+              base::MakeRefCounted<network::CertVerifyProcChromeOS>()));
 #else
       cert_verifier = std::make_unique<net::CachingCertVerifier>(
           std::make_unique<net::MultiThreadedCertVerifier>(
diff --git a/chrome/browser/navigation_predictor/navigation_predictor.cc b/chrome/browser/navigation_predictor/navigation_predictor.cc
index 3b6bff6..51fb24f5 100644
--- a/chrome/browser/navigation_predictor/navigation_predictor.cc
+++ b/chrome/browser/navigation_predictor/navigation_predictor.cc
@@ -242,6 +242,11 @@
   metrics_map.reserve(metrics->size());
 
   for (auto& metric : *metrics) {
+    // Do not include anchor elements that point to the same URL as the URL of
+    // the current navigation since these are unlikely to be clicked.
+    if (metric->target_url == metric->source_url)
+      continue;
+
     const std::string& key = metric->target_url.spec();
     auto iter = metrics_map.find(key);
     if (iter == metrics_map.end()) {
@@ -288,6 +293,10 @@
   }
 
   metrics->clear();
+
+  if (metrics_map.empty())
+    return;
+
   metrics->reserve(metrics_map.size());
   for (auto& metric_mapping : metrics_map) {
     metrics->push_back(std::move(metric_mapping.second));
@@ -321,6 +330,9 @@
 
   MergeMetricsSameTargetUrl(&metrics);
 
+  if (metrics.empty())
+    return;
+
   // Count the number of anchors that have specific metrics.
   for (const auto& metric : metrics) {
     number_of_anchors_same_host_ += static_cast<int>(metric->is_same_host);
diff --git a/chrome/browser/navigation_predictor/navigation_predictor_browsertest.cc b/chrome/browser/navigation_predictor/navigation_predictor_browsertest.cc
index 45d62825..602f7f9 100644
--- a/chrome/browser/navigation_predictor/navigation_predictor_browsertest.cc
+++ b/chrome/browser/navigation_predictor/navigation_predictor_browsertest.cc
@@ -64,10 +64,15 @@
   if (base::FeatureList::IsEnabled(
           blink::features::kRecordAnchorMetricsVisible)) {
     histogram_tester.ExpectUniqueSample(
-        "AnchorElementMetrics.Visible.NumberOfAnchorElements", 2, 1);
+        "AnchorElementMetrics.Visible.NumberOfAnchorElements", 3, 1);
+    // Same document anchor element should be removed after merge.
+    histogram_tester.ExpectUniqueSample(
+        "AnchorElementMetrics.Visible.NumberOfAnchorElementsAfterMerge", 2, 1);
   } else {
     histogram_tester.ExpectTotalCount(
         "AnchorElementMetrics.Visible.NumberOfAnchorElements", 0);
+    histogram_tester.ExpectTotalCount(
+        "AnchorElementMetrics.Visible.NumberOfAnchorElementsAfterMerge", 0);
   }
 }
 
diff --git a/chrome/browser/net/profile_network_context_service.cc b/chrome/browser/net/profile_network_context_service.cc
index dd9f903..c93abca 100644
--- a/chrome/browser/net/profile_network_context_service.cc
+++ b/chrome/browser/net/profile_network_context_service.cc
@@ -39,6 +39,13 @@
 #include "net/net_buildflags.h"
 #include "services/network/public/cpp/features.h"
 
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/chromeos/policy/policy_cert_service.h"
+#include "chrome/browser/chromeos/policy/policy_cert_service_factory.h"
+#include "chrome/browser/chromeos/profiles/profile_helper.h"
+#include "components/user_manager/user.h"
+#endif
+
 #if BUILDFLAG(ENABLE_EXTENSIONS)
 #include "extensions/common/constants.h"
 #endif
@@ -188,6 +195,21 @@
   *network_context_params = network::mojom::NetworkContextParams::New();
 }
 
+#if defined(OS_CHROMEOS)
+void ProfileNetworkContextService::UpdateTrustAnchors(
+    const net::CertificateList& trust_anchors) {
+  content::BrowserContext::ForEachStoragePartition(
+      profile_,
+      base::BindRepeating(
+          [](const net::CertificateList& trust_anchors,
+             content::StoragePartition* storage_partition) {
+            storage_partition->GetNetworkContext()->UpdateTrustAnchors(
+                trust_anchors);
+          },
+          trust_anchors));
+}
+#endif
+
 void ProfileNetworkContextService::RegisterProfilePrefs(
     user_prefs::PrefRegistrySyncable* registry) {
   registry->RegisterBooleanPref(prefs::kQuicAllowed, true);
@@ -407,6 +429,29 @@
     }
   }
 
+#if defined(OS_CHROMEOS)
+  user_manager::UserManager* user_manager = user_manager::UserManager::Get();
+  if (base::FeatureList::IsEnabled(network::features::kNetworkService) &&
+      user_manager &&
+      policy::PolicyCertServiceFactory::CreateAndStartObservingForProfile(
+          profile_)) {
+    const user_manager::User* user =
+        chromeos::ProfileHelper::Get()->GetUserByProfile(profile_);
+    // No need to initialize NSS for users with empty username hash:
+    // Getters for a user's NSS slots always return NULL slot if the user's
+    // username hash is empty, even when the NSS is not initialized for the
+    // user.
+    if (user && !user->username_hash().empty()) {
+      network_context_params->username_hash = user->username_hash();
+      network_context_params->nss_path = profile_->GetPath();
+
+      policy::PolicyCertService* service =
+          policy::PolicyCertServiceFactory::GetForProfile(profile_);
+      network_context_params->initial_trust_anchors = service->trust_anchors();
+    }
+  }
+#endif
+
   return network_context_params;
 }
 
diff --git a/chrome/browser/net/profile_network_context_service.h b/chrome/browser/net/profile_network_context_service.h
index 4656c25f..abce71d 100644
--- a/chrome/browser/net/profile_network_context_service.h
+++ b/chrome/browser/net/profile_network_context_service.h
@@ -66,6 +66,10 @@
       network::mojom::NetworkContextRequest* network_context_request,
       network::mojom::NetworkContextParamsPtr* network_context_params);
 
+#if defined(OS_CHROMEOS)
+  void UpdateTrustAnchors(const net::CertificateList& trust_anchors);
+#endif
+
   static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
 
   // Flushes all pending proxy configuration changes.
diff --git a/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_io_data.cc b/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_io_data.cc
index 1a4b72bd..5c9668c 100644
--- a/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_io_data.cc
+++ b/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_io_data.cc
@@ -85,11 +85,9 @@
 
 std::unique_ptr<data_reduction_proxy::DataReductionProxyIOData>
 CreateDataReductionProxyChromeIOData(
-    net::NetLog* net_log,
     PrefService* prefs,
     const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner,
     const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner) {
-  DCHECK(net_log);
   DCHECK(prefs);
 
   bool enabled =
diff --git a/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_io_data.h b/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_io_data.h
index ff750c5..3e711a0 100644
--- a/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_io_data.h
+++ b/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_io_data.h
@@ -19,15 +19,11 @@
 class DataReductionProxyIOData;
 }
 
-namespace net {
-class NetLog;
-}
 
 // Constructs DataReductionProxyIOData suitable for use by ProfileImpl and
 // ProfileImplIOData.
 std::unique_ptr<data_reduction_proxy::DataReductionProxyIOData>
 CreateDataReductionProxyChromeIOData(
-    net::NetLog* net_log,
     PrefService* prefs,
     const scoped_refptr<base::SingleThreadTaskRunner>& io_thread_runner,
     const scoped_refptr<base::SingleThreadTaskRunner>& ui_thread_runner);
diff --git a/chrome/browser/net/system_network_context_manager.cc b/chrome/browser/net/system_network_context_manager.cc
index 074bbdf5..c6780ef8 100644
--- a/chrome/browser/net/system_network_context_manager.cc
+++ b/chrome/browser/net/system_network_context_manager.cc
@@ -13,6 +13,7 @@
 #include "base/logging.h"
 #include "base/metrics/field_trial_params.h"
 #include "base/process/process_handle.h"
+#include "base/sequence_checker.h"
 #include "base/strings/string_split.h"
 #include "base/task/post_task.h"
 #include "base/values.h"
@@ -233,7 +234,9 @@
     : public network::SharedURLLoaderFactory {
  public:
   explicit URLLoaderFactoryForSystem(SystemNetworkContextManager* manager)
-      : manager_(manager) {}
+      : manager_(manager) {
+    DETACH_FROM_SEQUENCE(sequence_checker_);
+  }
 
   // mojom::URLLoaderFactory implementation:
 
@@ -245,7 +248,7 @@
                             network::mojom::URLLoaderClientPtr client,
                             const net::MutableNetworkTrafficAnnotationTag&
                                 traffic_annotation) override {
-    DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
     if (!manager_)
       return;
     manager_->GetURLLoaderFactory()->CreateLoaderAndStart(
@@ -261,7 +264,7 @@
 
   // SharedURLLoaderFactory implementation:
   std::unique_ptr<network::SharedURLLoaderFactoryInfo> Clone() override {
-    DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
     return std::make_unique<network::CrossThreadSharedURLLoaderFactoryInfo>(
         this);
   }
@@ -272,6 +275,7 @@
   friend class base::RefCounted<URLLoaderFactoryForSystem>;
   ~URLLoaderFactoryForSystem() override {}
 
+  SEQUENCE_CHECKER(sequence_checker_);
   SystemNetworkContextManager* manager_;
 
   DISALLOW_COPY_AND_ASSIGN(URLLoaderFactoryForSystem);
diff --git a/chrome/browser/policy/policy_browsertest.cc b/chrome/browser/policy/policy_browsertest.cc
index 5b1bb7b..2fd2e6c2 100644
--- a/chrome/browser/policy/policy_browsertest.cc
+++ b/chrome/browser/policy/policy_browsertest.cc
@@ -190,6 +190,7 @@
 #include "content/public/common/content_features.h"
 #include "content/public/common/content_paths.h"
 #include "content/public/common/content_switches.h"
+#include "content/public/common/network_service_util.h"
 #include "content/public/common/result_codes.h"
 #include "content/public/common/service_manager_connection.h"
 #include "content/public/common/service_names.mojom.h"
@@ -4589,12 +4590,8 @@
             browser()->tab_strip_model()->GetActiveWebContents()->GetTitle());
 
   // Now ensure that this setting still works after a network process crash.
-  if (!base::FeatureList::IsEnabled(network::features::kNetworkService) ||
-      base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kSingleProcess) ||
-      base::FeatureList::IsEnabled(features::kNetworkServiceInProcess)) {
+  if (!content::IsOutOfProcessNetworkService())
     return;
-  }
 
   ui_test_utils::NavigateToURL(browser(),
                                https_server_ok.GetURL("/title1.html"));
diff --git a/chrome/browser/printing/cloud_print/gcd_api_flow_impl.cc b/chrome/browser/printing/cloud_print/gcd_api_flow_impl.cc
index 0bb4657..9ddc221 100644
--- a/chrome/browser/printing/cloud_print/gcd_api_flow_impl.cc
+++ b/chrome/browser/printing/cloud_print/gcd_api_flow_impl.cc
@@ -100,7 +100,7 @@
 
 void GCDApiFlowImpl::Start(std::unique_ptr<Request> request) {
   request_ = std::move(request);
-  OAuth2TokenService::ScopeSet oauth_scopes;
+  identity::ScopeSet oauth_scopes;
   oauth_scopes.insert(request_->GetOAuthScope());
   DCHECK(identity_manager_);
   token_fetcher_ = std::make_unique<identity::PrimaryAccountAccessTokenFetcher>(
diff --git a/chrome/browser/printing/cloud_print/privet_traffic_detector.cc b/chrome/browser/printing/cloud_print/privet_traffic_detector.cc
index 22b6ea16..47b5c38a 100644
--- a/chrome/browser/printing/cloud_print/privet_traffic_detector.cc
+++ b/chrome/browser/printing/cloud_print/privet_traffic_detector.cc
@@ -163,29 +163,25 @@
       base::BindOnce(&CreateUDPSocketOnUIThread, profile_,
                      mojo::MakeRequest(&socket_), std::move(receiver_ptr)));
 
-  net::IPEndPoint multicast_addr =
-      net::GetMDnsIPEndPoint(net::ADDRESS_FAMILY_IPV4);
-  net::IPEndPoint bind_endpoint(
-      net::IPAddress::AllZeros(multicast_addr.address().size()),
-      multicast_addr.port());
-
   network::mojom::UDPSocketOptionsPtr socket_options =
       network::mojom::UDPSocketOptions::New();
-  socket_options->allow_address_reuse = true;
+  socket_options->allow_address_sharing_for_multicast = true;
   socket_options->multicast_loopback_mode = false;
 
-  socket_->Bind(bind_endpoint, std::move(socket_options),
-                base::BindOnce(&Helper::OnBindComplete,
-                               weak_ptr_factory_.GetWeakPtr(), multicast_addr));
+  socket_->Bind(
+      net::GetMDnsReceiveEndPoint(net::ADDRESS_FAMILY_IPV4),
+      std::move(socket_options),
+      base::BindOnce(&Helper::OnBindComplete, weak_ptr_factory_.GetWeakPtr(),
+                     net::GetMDnsGroupEndPoint(net::ADDRESS_FAMILY_IPV4)));
 }
 
 void PrivetTrafficDetector::Helper::OnBindComplete(
-    net::IPEndPoint multicast_addr,
+    net::IPEndPoint multicast_group_addr,
     int rv,
     const base::Optional<net::IPEndPoint>& ip_endpoint) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
   if (rv == net::OK) {
-    socket_->JoinGroup(multicast_addr.address(),
+    socket_->JoinGroup(multicast_group_addr.address(),
                        base::BindOnce(&Helper::OnJoinGroupComplete,
                                       weak_ptr_factory_.GetWeakPtr()));
     return;
diff --git a/chrome/browser/profiles/profile_downloader.cc b/chrome/browser/profiles/profile_downloader.cc
index e36e62e..73f18a4 100644
--- a/chrome/browser/profiles/profile_downloader.cc
+++ b/chrome/browser/profiles/profile_downloader.cc
@@ -136,7 +136,7 @@
 }
 
 void ProfileDownloader::StartFetchingOAuth2AccessToken() {
-  OAuth2TokenService::ScopeSet scopes;
+  identity::ScopeSet scopes;
   scopes.insert(GaiaConstants::kGoogleUserInfoProfile);
   // Required to determine if lock should be enabled.
   scopes.insert(GaiaConstants::kGoogleUserInfoEmail);
diff --git a/chrome/browser/profiles/profile_impl_io_data.cc b/chrome/browser/profiles/profile_impl_io_data.cc
index 656055cb..b1e1e4f 100644
--- a/chrome/browser/profiles/profile_impl_io_data.cc
+++ b/chrome/browser/profiles/profile_impl_io_data.cc
@@ -187,7 +187,7 @@
 
   io_data_->set_data_reduction_proxy_io_data(
       CreateDataReductionProxyChromeIOData(
-          g_browser_process->io_thread()->net_log(), profile_->GetPrefs(),
+          profile_->GetPrefs(),
           base::CreateSingleThreadTaskRunnerWithTraits({BrowserThread::IO}),
           base::CreateSingleThreadTaskRunnerWithTraits({BrowserThread::UI})));
 
diff --git a/chrome/browser/profiles/profile_io_data.cc b/chrome/browser/profiles/profile_io_data.cc
index 6fb8de3..ff6a9923 100644
--- a/chrome/browser/profiles/profile_io_data.cc
+++ b/chrome/browser/profiles/profile_io_data.cc
@@ -130,12 +130,10 @@
 #include "chrome/browser/chromeos/certificate_provider/certificate_provider_service_factory.h"
 #include "chrome/browser/chromeos/fileapi/external_file_protocol_handler.h"
 #include "chrome/browser/chromeos/login/startup_utils.h"
-#include "chrome/browser/chromeos/net/cert_verify_proc_chromeos.h"
 #include "chrome/browser/chromeos/net/client_cert_filter_chromeos.h"
 #include "chrome/browser/chromeos/net/client_cert_store_chromeos.h"
 #include "chrome/browser/chromeos/policy/policy_cert_service.h"
 #include "chrome/browser/chromeos/policy/policy_cert_service_factory.h"
-#include "chrome/browser/chromeos/policy/policy_cert_verifier.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
 #include "chrome/browser/net/nss_context.h"
@@ -148,6 +146,8 @@
 #include "components/user_manager/user_manager.h"
 #include "crypto/nss_util.h"
 #include "crypto/nss_util_internal.h"
+#include "services/network/cert_verifier_with_trust_anchors.h"
+#include "services/network/cert_verify_proc_chromeos.h"
 #endif  // defined(OS_CHROMEOS)
 
 #if defined(USE_NSS_CERTS)
@@ -1031,7 +1031,7 @@
       // The private slot won't be ready by this point. It shouldn't be
       // necessary for cert trust purposes anyway.
       scoped_refptr<net::CertVerifyProc> verify_proc(
-          new chromeos::CertVerifyProcChromeOS(std::move(public_slot)));
+          new network::CertVerifyProcChromeOS(std::move(public_slot)));
       if (profile_params_->policy_cert_verifier) {
         profile_params_->policy_cert_verifier->InitializeOnIOThread(
             verify_proc);
diff --git a/chrome/browser/profiles/profile_io_data.h b/chrome/browser/profiles/profile_io_data.h
index ddaae1f..5ee8b310 100644
--- a/chrome/browser/profiles/profile_io_data.h
+++ b/chrome/browser/profiles/profile_io_data.h
@@ -78,9 +78,9 @@
 #endif  // BUILDFLAG(ENABLE_REPORTING)
 }  // namespace net
 
-namespace policy {
-class PolicyCertVerifier;
-}  // namespace policy
+namespace network {
+class CertVerifierWithTrustAnchors;
+}  // namespace network
 
 // Conceptually speaking, the ProfileIOData represents data that lives on the IO
 // thread that is owned by a Profile, such as, but not limited to, network
@@ -353,7 +353,7 @@
     std::unique_ptr<net::URLRequestInterceptor> new_tab_page_interceptor;
 
 #if defined(OS_CHROMEOS)
-    std::unique_ptr<policy::PolicyCertVerifier> policy_cert_verifier;
+    std::unique_ptr<network::CertVerifierWithTrustAnchors> policy_cert_verifier;
     std::string username_hash;
     SystemKeySlotUseType system_key_slot_use_type = SystemKeySlotUseType::kNone;
     std::unique_ptr<chromeos::CertificateProvider> certificate_provider;
diff --git a/chrome/browser/renderer_host/render_process_host_chrome_browsertest.cc b/chrome/browser/renderer_host/render_process_host_chrome_browsertest.cc
index ad7437e5..e7e3e35 100644
--- a/chrome/browser/renderer_host/render_process_host_chrome_browsertest.cc
+++ b/chrome/browser/renderer_host/render_process_host_chrome_browsertest.cc
@@ -155,9 +155,19 @@
     const extensions::Extension* extension =
         LoadExtension(test_data_dir_.AppendASCII("options_page"));
 
+    content::RenderFrameDeletedObserver before_webui_obs(
+        content::ConvertToRenderFrameHost(
+            browser()->tab_strip_model()->GetActiveWebContents()));
+
     // Change the first tab to be the omnibox page (WebUI).
     GURL omnibox(chrome::kChromeUIOmniboxURL);
     ui_test_utils::NavigateToURL(browser(), omnibox);
+
+    // The host objects from the page before the WebUI navigation stick around
+    // until the old renderer cleans up and ACKs, which may happen later than
+    // the navigation in the WebUI's renderer. So wait for that.
+    before_webui_obs.WaitUntilDeleted();
+
     EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
     tab1 = browser()->tab_strip_model()->GetWebContentsAt(tab_count - 1);
     rph1 = tab1->GetMainFrame()->GetProcess();
@@ -257,14 +267,7 @@
   DISALLOW_COPY_AND_ASSIGN(ChromeRenderProcessHostTestWithCommandLine);
 };
 
-// Disable on Windows and Mac due to ongoing flakiness. (crbug.com/442785)
-#if defined(OS_WIN) || defined(OS_MACOSX)
-#define MAYBE_ProcessPerTab DISABLED_ProcessPerTab
-#else
-#define MAYBE_ProcessPerTab ProcessPerTab
-#endif
-
-IN_PROC_BROWSER_TEST_F(ChromeRenderProcessHostTest, MAYBE_ProcessPerTab) {
+IN_PROC_BROWSER_TEST_F(ChromeRenderProcessHostTest, ProcessPerTab) {
   // Set max renderers to 1 to force running out of processes.
   content::RenderProcessHost::SetMaxRendererProcessCount(1);
 
@@ -275,9 +278,20 @@
   int tab_count = 1;
   int host_count = 1;
 
+  content::RenderFrameDeletedObserver before_webui_obs(
+      content::ConvertToRenderFrameHost(
+          browser()->tab_strip_model()->GetActiveWebContents()));
+
   // Change the first tab to be a WebUI page.
   GURL omnibox(chrome::kChromeUIOmniboxURL);
   ui_test_utils::NavigateToURL(browser(), omnibox);
+
+  // The host objects from the page before the WebUI navigation stick around
+  // until the old renderer cleans up and ACKs, which may happen later than the
+  // navigation in the WebUI's renderer. So wait for that.
+  before_webui_obs.WaitUntilDeleted();
+
+  // Expect just the WebUI tab's process to be around.
   EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
   EXPECT_EQ(host_count, RenderProcessHostCount());
 
@@ -455,31 +469,16 @@
   }
 }
 
-// TODO(nasko): crbug.com/173137
-// Disable on Windows and Mac due to ongoing flakiness. (crbug.com/442785)
-#if defined(OS_WIN) || defined(OS_MACOSX)
-#define MAYBE_ProcessOverflow DISABLED_ProcessOverflow
-#else
-#define MAYBE_ProcessOverflow ProcessOverflow
-#endif
-
-IN_PROC_BROWSER_TEST_F(ChromeRenderProcessHostTest, MAYBE_ProcessOverflow) {
+IN_PROC_BROWSER_TEST_F(ChromeRenderProcessHostTest, ProcessOverflow) {
   // Set max renderers to 1 to force running out of processes.
   content::RenderProcessHost::SetMaxRendererProcessCount(1);
   TestProcessOverflow();
 }
 
-// Disable on Windows and Mac due to ongoing flakiness. (crbug.com/442785)
-#if defined(OS_WIN) || defined(OS_MACOSX)
-#define MAYBE_ProcessOverflowCommandLine DISABLED_ProcessOverflowCommandLine
-#else
-#define MAYBE_ProcessOverflowCommandLine ProcessOverflowCommandLine
-#endif
-
 // Variation of the ProcessOverflow test, which is driven through command line
 // parameter instead of direct function call into the class.
 IN_PROC_BROWSER_TEST_F(ChromeRenderProcessHostTestWithCommandLine,
-                       MAYBE_ProcessOverflowCommandLine) {
+                       ProcessOverflowCommandLine) {
   TestProcessOverflow();
 }
 
diff --git a/chrome/browser/resource_coordinator/tab_manager.cc b/chrome/browser/resource_coordinator/tab_manager.cc
index dd1a59a..c18db17 100644
--- a/chrome/browser/resource_coordinator/tab_manager.cc
+++ b/chrome/browser/resource_coordinator/tab_manager.cc
@@ -23,7 +23,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/sys_info.h"
 #include "base/threading/thread.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h"
diff --git a/chrome/browser/resources/chromeos/assistant_optin/assistant_value_prop.js b/chrome/browser/resources/chromeos/assistant_optin/assistant_value_prop.js
index dd9362d..626dda1 100644
--- a/chrome/browser/resources/chromeos/assistant_optin/assistant_value_prop.js
+++ b/chrome/browser/resources/chromeos/assistant_optin/assistant_value_prop.js
@@ -169,6 +169,14 @@
   reloadPage: function() {
     this.fire('loading');
 
+    if (this.initialized_) {
+      chrome.send(
+          'login.AssistantOptInFlowScreen.ValuePropScreen.userActed',
+          ['reload-requested']);
+      this.settingZippyLoaded_ = false;
+      this.consentStringLoaded_ = false;
+    }
+
     this.loadingError_ = false;
     this.headerReceived_ = false;
     this.valuePropView_.src =
@@ -270,7 +278,7 @@
       var description = document.createElement('div');
       description.className = 'zippy-description';
       description.innerHTML = this.sanitizer_.sanitizeHtml(data['description']);
-      zippy.appendChild(description);
+      description.innerHTML += '&ensp;';
 
       var learnMoreLink = document.createElement('a');
       learnMoreLink.className = 'learn-more-link';
@@ -279,7 +287,9 @@
       learnMoreLink.onclick = function(title, additionalInfo) {
         this.showLearnMoreOverlay(title, additionalInfo);
       }.bind(this, data['title'], data['additionalInfo']);
-      zippy.appendChild(learnMoreLink);
+
+      description.appendChild(learnMoreLink);
+      zippy.appendChild(description);
 
       this.$['consents-container'].appendChild(zippy);
     }
@@ -322,8 +332,8 @@
           this.onWebViewErrorOccurred.bind(this), requestFilter);
       this.valuePropView_.request.onHeadersReceived.addListener(
           this.onWebViewHeadersReceived.bind(this), requestFilter);
-      this.valuePropView_.request.onCompleted.addListener(
-          this.onWebViewContentLoad.bind(this), requestFilter);
+      this.valuePropView_.addEventListener(
+          'contentload', this.onWebViewContentLoad.bind(this));
 
       this.valuePropView_.addContentScripts([{
         name: 'stripLinks',
@@ -335,9 +345,8 @@
         run_at: 'document_end'
       }]);
 
+      this.reloadPage();
       this.initialized_ = true;
     }
-
-    this.reloadPage();
   },
 });
diff --git a/chrome/browser/resources/chromeos/login/discover/discover_app.html b/chrome/browser/resources/chromeos/login/discover/discover_app.html
index 0a32765..f5b38da3 100644
--- a/chrome/browser/resources/chromeos/login/discover/discover_app.html
+++ b/chrome/browser/resources/chromeos/login/discover/discover_app.html
@@ -8,6 +8,7 @@
     <meta name="google" value="notranslate">
     <title i18n-content="title"></title>
     <link rel="stylesheet" href="discover_app.css">
+    <link rel="manifest" href="chrome://oobe/manifest.json">
     <link rel="import" href="chrome://resources/html/polymer.html">
     <link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout-classes.html">
     <link rel="import" href="chrome://resources/html/i18n_behavior.html">
diff --git a/chrome/browser/resources/chromeos/login/discover/manifest.json b/chrome/browser/resources/chromeos/login/discover/manifest.json
new file mode 100644
index 0000000..689fc1c
--- /dev/null
+++ b/chrome/browser/resources/chromeos/login/discover/manifest.json
@@ -0,0 +1,13 @@
+{
+  "short_name": "Discover",
+  "display": "standalone",
+  "icons": [
+    {
+      "src": "chrome://oobe/logo.png",
+      "sizes": "192x192",
+      "type": "image/png"
+    }
+  ],
+  "start_url": "/discover",
+  "theme_color": "#FFFFFF"
+}
diff --git a/chrome/browser/resources/omnibox/omnibox.css b/chrome/browser/resources/omnibox/omnibox.css
index 0ecd71c..cfd7461 100644
--- a/chrome/browser/resources/omnibox/omnibox.css
+++ b/chrome/browser/resources/omnibox/omnibox.css
@@ -23,7 +23,10 @@
 .x-mark {
   background-position: center;
   background-repeat: no-repeat;
+  background-size: contain;
   font-size: 0;
+  height: 16px;
+  width: 16px;
 }
 
 .check-mark {
diff --git a/chrome/browser/resources/omnibox/omnibox.html b/chrome/browser/resources/omnibox/omnibox.html
index 7311809..f7a5398 100644
--- a/chrome/browser/resources/omnibox/omnibox.html
+++ b/chrome/browser/resources/omnibox/omnibox.html
@@ -73,6 +73,32 @@
     <div id="contents"></div>
   </template>
 
+  <template id="results-group-template">
+    <div class="details"></div>
+    <div class="combined-results">
+      <p>Combined results</p>
+    </div>
+    <div class="individual-results"></div>
+  </template>
+
+  <template id="results-group-details-template">
+    <p>cursor position = <span class="cursor-position"></span></p>
+    <p>elapsed time = <span class="time"></span>ms</p>
+    <p>all providers done = <span class="done"></span></p>
+    <p>host = <span class="host"></span>, has isTypedHost = <span class="is-typed-host"></span></p>
+  </template>
+
+  <template id="results-group-individual-results-template">
+    <p>individual results</p>
+  </template>
+
+  <template id="results-table-template">
+    <table class="autocomplete-results-table">
+      <tbody class="results-table-body">
+      </tbody>
+    </table>
+  </template>
+
   <omnibox-inputs id="omnibox-inputs" class="section"></omnibox-inputs>
   <omnibox-output id="omnibox-output" class="section"></omnibox-output>
 </body>
diff --git a/chrome/browser/resources/omnibox/omnibox.js b/chrome/browser/resources/omnibox/omnibox.js
index 12122c88..7a7e1b0b 100644
--- a/chrome/browser/resources/omnibox/omnibox.js
+++ b/chrome/browser/resources/omnibox/omnibox.js
@@ -27,36 +27,6 @@
   let cursorPosition = -1;
 
   /**
-   * Returns a simple object with information about how to display an
-   * autocomplete result data field.
-   */
-  class PresentationInfoRecord {
-    /**
-     * @param {string} header the label for the top of the column/table.
-     * @param {string} url the URL that the header should point
-     *     to (if non-empty).
-     * @param {string} propertyName the name of the property in the autocomplete
-     *     result record that we lookup.
-     * @param {boolean} displayAlways whether the property should be displayed
-     *     regardless of whether we're in detailed mode.
-     * @param {string} tooltip a description of the property that will be
-     *     presented as a tooltip when the mouse is hovered over the column title.
-     */
-    constructor(header, url, propertyName, displayAlways, tooltip) {
-      /** @type {string} */
-      this.header = header;
-      /** @type {string} */
-      this.url = url;
-      /** @type {string} */
-      this.propertyName = propertyName;
-      /** @type {boolean} */
-      this.displayAlways = displayAlways;
-      /** @type {string} */
-      this.tooltip = tooltip;
-    }
-  }
-
-  /**
    * Tracks and aggregates responses from the C++ autocomplete controller.
    * Typically, the C++ controller returns 3 sets of results per query, unless
    * a new query is submitted before all 3 responses. OutputController also
@@ -66,11 +36,11 @@
   class OutputController {
     constructor() {
       /** @private {!Array<mojom.OmniboxResult>} */
-      this.outputResultsGroups = [];
+      this.outputResultsGroups_ = [];
     }
 
     clear() {
-      this.outputResultsGroups = [];
+      this.outputResultsGroups_ = [];
       omniboxOutput.clearOutput();
     }
 
@@ -82,10 +52,11 @@
      */
     /** @param {!mojom.OmniboxResult} response A response from C++ autocomplete controller */
     add(response) {
-      this.outputResultsGroups.push(response);
+      this.outputResultsGroups_.push(response);
       if (!omniboxInputs.$$('show-incomplete-results').checked)
         omniboxOutput.clearOutput();
-      addResultToOutput(this.outputResultsGroups[this.outputResultsGroups.length - 1]);
+      addResultToOutput(
+          this.outputResultsGroups_[this.outputResultsGroups_.length - 1]);
     }
 
     /*
@@ -95,87 +66,15 @@
     refresh() {
       omniboxOutput.clearOutput();
       if (omniboxInputs.$$('show-incomplete-results').checked) {
-        this.outputResultsGroups.forEach(addResultToOutput);
-      } else if (this.outputResultsGroups.length) {
+        this.outputResultsGroups_.forEach(addResultToOutput);
+      } else if (this.outputResultsGroups_.length) {
         addResultToOutput(
-            this.outputResultsGroups[this.outputResultsGroups.length - 1]);
+            this.outputResultsGroups_[this.outputResultsGroups_.length - 1]);
       }
     }
   }
 
   /**
-   * A constant that's used to decide what autocomplete result
-   * properties to output in what order.  This is an array of
-   * PresentationInfoRecord() objects; for details see that
-   * function.
-   * @type {!Array<!PresentationInfoRecord>}
-   */
-  const PROPERTY_OUTPUT_ORDER = [
-    new PresentationInfoRecord(
-        'Provider', '', 'providerName', true,
-        'The AutocompleteProvider suggesting this result.'),
-    new PresentationInfoRecord(
-        'Type', '', 'type', true, 'The type of the result.'),
-    new PresentationInfoRecord(
-        'Relevance', '', 'relevance', true,
-        'The result score. Higher is more relevant.'),
-    new PresentationInfoRecord(
-        'Contents', '', 'contents', true,
-        'The text that is presented identifying the result.'),
-    new PresentationInfoRecord(
-        'Can Be Default', '', 'allowedToBeDefaultMatch', false,
-        'A green checkmark indicates that the result can be the default ' +
-        'match (i.e., can be the match that pressing enter in the ' +
-        'omnibox navigates to).'),
-    new PresentationInfoRecord(
-        'Starred', '', 'starred', false,
-        'A green checkmark indicates that the result has been bookmarked.'),
-    new PresentationInfoRecord(
-        'Has tab match', '', 'hasTabMatch', false,
-        'A green checkmark indicates that the result URL matches an open tab.'),
-    new PresentationInfoRecord(
-        'Description', '', 'description', false,
-        'The page title of the result.'),
-    new PresentationInfoRecord(
-        'URL', '', 'destinationUrl', true, 'The URL for the result.'),
-    new PresentationInfoRecord(
-        'Fill Into Edit', '', 'fillIntoEdit', false,
-        'The text shown in the omnibox when the result is selected.'),
-    new PresentationInfoRecord(
-        'Inline Autocompletion', '', 'inlineAutocompletion', false,
-        'The text shown in the omnibox as a blue highlight selection ' +
-        'following the cursor, if this match is shown inline.'),
-    new PresentationInfoRecord(
-        'Del', '', 'deletable', false,
-        'A green checkmark indicates that the result can be deleted from ' +
-        'the visit history.'),
-    new PresentationInfoRecord('Prev', '', 'fromPrevious', false, ''),
-    new PresentationInfoRecord(
-        'Tran',
-        'https://cs.chromium.org/chromium/src/ui/base/page_transition_types.h' +
-        '?q=page_transition_types.h&sq=package:chromium&dr=CSs&l=14',
-        'transition', false, 'How the user got to the result.'),
-    new PresentationInfoRecord(
-        'Done', '', 'providerDone', false,
-        'A green checkmark indicates that the provider is done looking for ' +
-        'more results.'),
-    new PresentationInfoRecord(
-        'Associated Keyword', '', 'associatedKeyword', false,
-        'If non-empty, a "press tab to search" hint will be shown and will ' +
-        'engage this keyword.'),
-    new PresentationInfoRecord(
-        'Keyword', '', 'keyword', false,
-        'The keyword of the search engine to be used.'),
-    new PresentationInfoRecord(
-        'Duplicates', '', 'duplicates', false,
-        'The number of matches that have been marked as duplicates of this ' +
-        'match.'),
-    new PresentationInfoRecord(
-        'Additional Info', '', 'additionalInfo', false,
-        'Provider-specific information about the result.'),
-  ];
-
-  /**
    * Appends some human-readable information about the provided
    * autocomplete result to the HTML node with id omnibox-debug-text.
    * The current human-readable form is a few lines about general
@@ -183,215 +82,11 @@
    * for each autocomplete match.  The input parameter is an OmniboxResultMojo.
    */
   function addResultToOutput(result) {
-    // Output the result-level features in detailed mode and in
-    // show incomplete results mode.  We do the latter because without
-    // these result-level features, one can't make sense of each
-    // batch of results.
-    if (omniboxInputs.$$('show-details').checked
-        || omniboxInputs.$$('show-incomplete-results').checked) {
-      addParagraph(`cursor position = ${cursorPosition}`);
-      addParagraph(`inferred input type = ${result.type}`);
-      addParagraph(`elapsed time = ${result.timeSinceOmniboxStartedMs}ms`);
-      addParagraph(`all providers done = ${result.done}`);
-      let p = document.createElement('p');
-      p.textContent = `host = ${result.host}`;
-      // The field isn't actually optional in the mojo object; instead it assumes
-      // failed lookups are not typed hosts.  Fix this to make it optional.
-      // http://crbug.com/863201
-      if ('isTypedHost' in result) {
-        // Only output the isTypedHost information if available.  (It may
-        // be missing if the history database lookup failed.)
-        p.textContent =
-            p.textContent + ` has isTypedHost = ${result.isTypedHost}`;
-      }
-      omniboxOutput.addOutput(p);
-    }
-
-    // Combined results go after the lines below.
-    let group = document.createElement('a');
-    group.className = 'group-separator';
-    group.textContent = 'Combined results.';
-    omniboxOutput.addOutput(group);
-
-    // Add combined/merged result table.
-    let p = document.createElement('p');
-    p.appendChild(addResultTableToOutput(result.combinedResults));
-    omniboxOutput.addOutput(p);
-
-    // Move forward only if you want to display per provider results.
-    if (!omniboxInputs.$$('show-all-providers').checked) {
-      return;
-    }
-
-    // Individual results go after the lines below.
-    group = document.createElement('a');
-    group.className = 'group-separator';
-    group.textContent = 'Results for individual providers.';
-    omniboxOutput.addOutput(group);
-
-    // Add the per-provider result tables with labels. We do not append the
-    // combined/merged result table since we already have the per provider
-    // results.
-    result.resultsByProvider.forEach(providerResults => {
-      // If we have no results we do not display anything.
-      if (providerResults.results.length === 0)
-        return;
-      let p = document.createElement('p');
-      p.appendChild(addResultTableToOutput(providerResults.results));
-      omniboxOutput.addOutput(p);
-    });
-  }
-
-  /**
-   * @param {Object} result an array of AutocompleteMatchMojos.
-   * @return {Element} that is a user-readable HTML
-   *     representation of this object.
-   */
-  function addResultTableToOutput(result) {
-    let inDetailedMode = omniboxInputs.$$('show-details').checked;
-    // Create a table to hold all the autocomplete items.
-    let table = document.createElement('table');
-    table.className = 'autocomplete-results-table';
-    table.appendChild(createAutocompleteResultTableHeader());
-    // Loop over every autocomplete item and add it as a row in the table.
-    result.forEach(autocompleteSuggestion => {
-      let row = document.createElement('tr');
-      // Loop over all the columns/properties and output either them
-      // all (if we're in detailed mode) or only the ones marked displayAlways.
-      // Keep track of which properties we displayed.
-      let displayedProperties = {};
-      PROPERTY_OUTPUT_ORDER.forEach(property => {
-        if (inDetailedMode || property.displayAlways) {
-          row.appendChild(createCellForPropertyAndRemoveProperty(
-              autocompleteSuggestion, property.propertyName));
-          displayedProperties[property.propertyName] = true;
-        }
-      });
-
-      // Now, if we're in detailed mode, add all the properties that
-      // haven't already been output.  (We know which properties have
-      // already been output because we delete the property when we output
-      // it.  The only way we have properties left at this point if
-      // we're in detailed mode and we're getting back properties
-      // not listed in PROPERTY_OUTPUT_ORDER.  Perhaps someone added
-      // something to the C++ code but didn't bother to update this
-      // Javascript?  In any case, we want to display them.)
-      if (inDetailedMode) {
-        for (let key in autocompleteSuggestion) {
-          if (!displayedProperties[key] &&
-              typeof autocompleteSuggestion[key] !== 'function') {
-            let cell = document.createElement('td');
-            cell.textContent = key + '=' + autocompleteSuggestion[key];
-            row.appendChild(cell);
-          }
-        }
-      }
-
-      table.appendChild(row);
-    });
-    return table;
-  }
-
-  /**
-   * Returns an HTML Element of type table row that contains the
-   * headers we'll use for labeling the columns.  If we're in
-   * detailedMode, we use all the headers.  If not, we only use ones
-   * marked displayAlways.
-   */
-  function createAutocompleteResultTableHeader() {
-    let row = document.createElement('tr');
-    let inDetailedMode = omniboxInputs.$$('show-details').checked;
-    PROPERTY_OUTPUT_ORDER.forEach(property => {
-      if (inDetailedMode || property.displayAlways) {
-        let headerCell = document.createElement('th');
-        if (property.url !== '') {
-          // Wrap header text in URL.
-          let linkNode = document.createElement('a');
-          linkNode.href = property.url;
-          linkNode.textContent = property.header;
-          headerCell.appendChild(linkNode);
-        } else {
-          // Output header text without a URL.
-          headerCell.textContent = property.header;
-          headerCell.className = 'table-header';
-          headerCell.title = property.tooltip;
-        }
-        row.appendChild(headerCell);
-      }
-    });
-    return row;
-  }
-
-  /**
-   * @param {!Object} autocompleteSuggestion the particular
-   *     autocomplete suggestion we're in the process of displaying.
-   * @param {string} propertyName the particular property of the autocomplete
-   *     suggestion that should go in this cell.
-   * @return {Element} that contains the value within this
-   *     autocompleteSuggestion associated with propertyName.
-   */
-  function createCellForPropertyAndRemoveProperty(autocompleteSuggestion, propertyName) {
-    let cell = document.createElement('td');
-    if (propertyName in autocompleteSuggestion) {
-      if (propertyName === 'additionalInfo') {
-        // |additionalInfo| embeds a two-column table of provider-specific data
-        // within this cell. |additionalInfo| is an array of
-        // AutocompleteAdditionalInfo.
-        let additionalInfoTable = document.createElement('table');
-        autocompleteSuggestion[propertyName].forEach(additionalInfo => {
-          let additionalInfoRow = document.createElement('tr');
-
-          // Set the title (name of property) cell text.
-          let propertyCell = document.createElement('td');
-          propertyCell.textContent = additionalInfo.key + ':';
-          propertyCell.className = 'additional-info-property';
-          additionalInfoRow.appendChild(propertyCell);
-
-          // Set the value of the property cell text.
-          let valueCell = document.createElement('td');
-          valueCell.textContent = additionalInfo.value;
-          valueCell.className = 'additional-info-value';
-          additionalInfoRow.appendChild(valueCell);
-
-          additionalInfoTable.appendChild(additionalInfoRow);
-        });
-        cell.appendChild(additionalInfoTable);
-      } else if (typeof autocompleteSuggestion[propertyName] === 'boolean') {
-        // If this is a boolean, display a checkmark or an X instead of
-        // the strings true or false.
-        if (autocompleteSuggestion[propertyName]) {
-          cell.className = 'check-mark';
-          cell.textContent = 'true';
-        } else {
-          cell.className = 'x-mark';
-          cell.textContent = 'false';
-        }
-      } else {
-        let text = String(autocompleteSuggestion[propertyName]);
-        // If it's a URL wrap it in an href.
-        let re = /^(http|https|ftp|chrome|file):\/\//;
-        if (re.test(text)) {
-          let aCell = document.createElement('a');
-          aCell.textContent = text;
-          aCell.href = text;
-          cell.appendChild(aCell);
-        } else {
-          // All other data types (integer, strings, etc.) display their
-          // normal toString() output.
-          cell.textContent = autocompleteSuggestion[propertyName];
-        }
-      }
-    }  // else: if propertyName is undefined, we leave the cell blank
-    return cell;
-  }
-
-  /**
-   * Appends a paragraph node containing text to the parent node.
-   */
-  function addParagraph(text) {
-    let p = document.createElement('p');
-    p.textContent = text;
-    omniboxOutput.addOutput(p);
+    const resultsGroup = new omnibox_output.OutputResultsGroup(result).render(
+        omniboxInputs.$$('show-details').checked,
+        omniboxInputs.$$('show-incomplete-results').checked,
+        omniboxInputs.$$('show-all-providers').checked);
+    omniboxOutput.addOutput(resultsGroup);
   }
 
   class BrowserProxy {
@@ -401,7 +96,7 @@
       Mojo.bindInterface(
           mojom.OmniboxPageHandler.name,
           mojo.makeRequest(this.pagehandlePtr_).handle);
-      let client = new mojom.OmniboxPagePtr;
+      const client = new mojom.OmniboxPagePtr;
       // NOTE: Need to keep a global reference to the |binding_| such that it is
       // not garbage collected, which causes the pipe to close and future calls
       // from C++ to JS to get dropped.
@@ -442,18 +137,18 @@
   }
 
   /** @type {BrowserProxy} */
-  let browserProxy;
+  const browserProxy = new BrowserProxy();
   /** @type {OmniboxInputs} */
   let omniboxInputs;
-  /** @type {OmniboxOutput} */
+  /** @type {omnibox_output.OmniboxOutput} */
   let omniboxOutput;
   /** @type {OutputController} */
-  let outputController = new OutputController();
+  const outputController = new OutputController();
 
   document.addEventListener('DOMContentLoaded', () => {
-    browserProxy = new BrowserProxy();
     omniboxInputs = /** @type {!OmniboxInputs} */ ($('omnibox-inputs'));
-    omniboxOutput = /** @type {!OmniboxOutput} */ ($('omnibox-output'));
+    omniboxOutput =
+        /** @type {!omnibox_output.OmniboxOutput} */ ($('omnibox-output'));
     omniboxInputs.addEventListener('query-inputs-changed', event =>
         browserProxy.makeRequest(
             event.detail.inputText,
diff --git a/chrome/browser/resources/omnibox/omnibox_element.js b/chrome/browser/resources/omnibox/omnibox_element.js
index d8c3248..959ef2ff 100644
--- a/chrome/browser/resources/omnibox/omnibox_element.js
+++ b/chrome/browser/resources/omnibox/omnibox_element.js
@@ -2,22 +2,17 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// Helper class to be used as the super class of all Custom Elements in
-// chrome://omnibox. Constructed with a string id of a <template> element. When
-// this element is added to the DOM, it instantiates its internal DOM from the
-// corresponding <template> element.
+/**
+ * Helper class to be used as the super class of all custom elements in
+ * chrome://omnibox.
+ * @abstract
+ */
 class OmniboxElement extends HTMLElement {
-  /** @param {string} templateId Template's HTML id attribute */
+  /** @param {string} templateId */
   constructor(templateId) {
     super();
-    /** @type {string} */
-    this.templateId = templateId;
-  }
-
-  /** @override */
-  connectedCallback() {
     this.attachShadow({mode: 'open'});
-    let template = $(this.templateId).content.cloneNode(true);
+    const template = OmniboxElement.getTemplate(templateId);
     this.shadowRoot.appendChild(template);
   }
 
@@ -29,4 +24,12 @@
   $$(id) {
     return this.shadowRoot.getElementById(id);
   }
+
+  /**
+   * @param {string} templateId
+   * @return {Element}
+   */
+  static getTemplate(templateId) {
+    return $(templateId).content.cloneNode(true);
+  }
 }
diff --git a/chrome/browser/resources/omnibox/omnibox_inputs.js b/chrome/browser/resources/omnibox/omnibox_inputs.js
index 6d235ef..4897c62 100644
--- a/chrome/browser/resources/omnibox/omnibox_inputs.js
+++ b/chrome/browser/resources/omnibox/omnibox_inputs.js
@@ -14,28 +14,29 @@
 
   /** @override */
   connectedCallback() {
-    super.connectedCallback();
-    this.setupElementListeners();
+    this.setupElementListeners_();
   }
 
-  setupElementListeners() {
-    const onQueryInputsChanged = this.onQueryInputsChanged.bind(this);
-    const onDisplayInputsChagned = this.onDisplayInputsChagned.bind(this);
+  /** @private */
+  setupElementListeners_() {
+    const onQueryInputsChanged = this.onQueryInputsChanged_.bind(this);
+    const onDisplayInputsChagned = this.onDisplayInputsChagned_.bind(this);
 
     this.$$('input-text').addEventListener('input', onQueryInputsChanged);
     [
       this.$$('prevent-inline-autocomplete'),
       this.$$('prefer-keyword'),
       this.$$('page-classification'),
-    ].forEach(element => element.addEventListener('change', onQueryInputsChanged));
+    ].forEach(elem => elem.addEventListener('change', onQueryInputsChanged));
     [
       this.$$('show-incomplete-results'),
       this.$$('show-details'),
       this.$$('show-all-providers'),
-    ].forEach(element => element.addEventListener('change', onDisplayInputsChagned));
+    ].forEach(elem => elem.addEventListener('change', onDisplayInputsChagned));
   }
 
-  onQueryInputsChanged() {
+  /** @private */
+  onQueryInputsChanged_() {
     this.dispatchEvent(new CustomEvent('query-inputs-changed', {
       detail: {
         inputText: this.$$('input-text').value,
@@ -47,7 +48,8 @@
     }));
   }
 
-  onDisplayInputsChagned() {
+  /** @private */
+  onDisplayInputsChagned_() {
     this.dispatchEvent(new CustomEvent('display-inputs-changed'));
   }
 }
diff --git a/chrome/browser/resources/omnibox/omnibox_output.js b/chrome/browser/resources/omnibox/omnibox_output.js
index 56dad4d..124afdb8 100644
--- a/chrome/browser/resources/omnibox/omnibox_output.js
+++ b/chrome/browser/resources/omnibox/omnibox_output.js
@@ -2,25 +2,474 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-class OmniboxOutput extends OmniboxElement {
-  /** @return {string} */
-  static get is() {
-    return 'omnibox-output';
+cr.define('omnibox_output', function() {
+  /**
+   * Details how to display an autocomplete result data field.
+   * @typedef {{
+   *   header: string,
+   *   url: string,
+   *   propertyName: string,
+   *   displayAlways: boolean,
+   *   tooltip: string,
+   * }}
+   */
+  let PresentationInfoRecord;
+
+  /**
+   * A constant that's used to decide what autocomplete result
+   * properties to output in what order.
+   * @type {!Array<!PresentationInfoRecord>}
+   */
+  const PROPERTY_OUTPUT_ORDER = [
+    {
+      header: 'Provider',
+      url: '',
+      propertyName: 'providerName',
+      displayAlways: true,
+      tooltip: 'The AutocompleteProvider suggesting this result.'
+    },
+    {
+      header: 'Type',
+      url: '',
+      propertyName: 'type',
+      displayAlways: true,
+      tooltip: 'The type of the result.'
+    },
+    {
+      header: 'Relevance',
+      url: '',
+      propertyName: 'relevance',
+      displayAlways: true,
+      tooltip: 'The result score. Higher is more relevant.'
+    },
+    {
+      header: 'Contents',
+      url: '',
+      propertyName: 'contents',
+      displayAlways: true,
+      tooltip: 'The text that is presented identifying the result.'
+    },
+    {
+      header: 'CanBeDefault',
+      url: '',
+      propertyName: 'allowedToBeDefaultMatch',
+      displayAlways: false,
+      tooltip:
+          'A green checkmark indicates that the result can be the default ' +
+          'match(i.e., can be the match that pressing enter in the omnibox' +
+          'navigates to).'
+    },
+    {
+      header: 'Starred',
+      url: '',
+      propertyName: 'starred',
+      displayAlways: false,
+      tooltip:
+          'A green checkmark indicates that the result has been bookmarked.'
+    },
+    {
+      header: 'Hastabmatch',
+      url: '',
+      propertyName: 'hasTabMatch',
+      displayAlways: false,
+      tooltip:
+          'A green checkmark indicates that the result URL matches an open' +
+          'tab.'
+    },
+    {
+      header: 'Description',
+      url: '',
+      propertyName: 'description',
+      displayAlways: false,
+      tooltip: 'The page title of the result.'
+    },
+    {
+      header: 'URL',
+      url: '',
+      propertyName: 'destinationUrl',
+      displayAlways: true,
+      tooltip: 'The URL for the result.'
+    },
+    {
+      header: 'FillIntoEdit',
+      url: '',
+      propertyName: 'fillIntoEdit',
+      displayAlways: false,
+      tooltip: 'The text shown in the omnibox when the result is selected.'
+    },
+    {
+      header: 'InlineAutocompletion',
+      url: '',
+      propertyName: 'inlineAutocompletion',
+      displayAlways: false,
+      tooltip: 'The text shown in the omnibox as a blue highlight selection ' +
+          'following the cursor, if this match is shown inline.'
+    },
+    {
+      header: 'Del',
+      url: '',
+      propertyName: 'deletable',
+      displayAlways: false,
+      tooltip:
+          'A green checkmark indicates that the result can be deleted from ' +
+          'the visit history.'
+    },
+    {
+      header: 'Prev',
+      url: '',
+      propertyName: 'fromPrevious',
+      displayAlways: false,
+      tooltip: ''
+    },
+    {
+      header: 'Tran',
+      url:
+          'https://cs.chromium.org/chromium/src/ui/base/page_transition_types.h?q=page_transition_types.h&sq=package:chromium&dr=CSs&l=14',
+      propertyName: 'transition',
+      displayAlways: false,
+      tooltip: 'How the user got to the result.'
+    },
+    {
+      header: 'Done',
+      url: '',
+      propertyName: 'providerDone',
+      displayAlways: false,
+      tooltip:
+          'A green checkmark indicates that the provider is done looking ' +
+          'for more results.'
+    },
+    {
+      header: 'AssociatedKeyword',
+      url: '',
+      propertyName: 'associatedKeyword',
+      displayAlways: false,
+      tooltip: 'If non-empty, a "press tab to search" hint will be shown and ' +
+          'will engage this keyword.'
+    },
+    {
+      header: 'Keyword',
+      url: '',
+      propertyName: 'keyword',
+      displayAlways: false,
+      tooltip: 'The keyword of the search engine to be used.'
+    },
+    {
+      header: 'Duplicates',
+      url: '',
+      propertyName: 'duplicates',
+      displayAlways: false,
+      tooltip: 'The number of matches that have been marked as duplicates of ' +
+          'this match..'
+    },
+    {
+      header: 'AdditionalInfo',
+      url: '',
+      propertyName: 'additionalInfo',
+      displayAlways: false,
+      tooltip: 'Provider-specific information about the result.'
+    }
+  ];
+
+  class OmniboxOutput extends OmniboxElement {
+    /** @return {string} */
+    static get is() {
+      return 'omnibox-output';
+    }
+
+    constructor() {
+      super('omnibox-output-template');
+    }
+
+    /** @param {Element} element the element to the output */
+    addOutput(element) {
+      this.$$('contents').appendChild(element);
+    }
+
+    clearOutput() {
+      while (this.$$('contents').firstChild)
+        this.$$('contents').removeChild(this.$$('contents').firstChild);
+    }
   }
 
-  constructor() {
-    super('omnibox-output-template');
+  /**
+   * Helps track and render a results group. C++ Autocomplete typically returns
+   * 3 result groups per query. It may return less if the next query is
+   * submitted before all 3 have been returned. Each result group contains
+   * top level information (e.g., how long the result took to generate), as well
+   * as a single list of combined results and multiple lists of individual
+   * results. Each of these lists is tracked and rendered by OutputResultsTable
+   * below.
+   */
+  class OutputResultsGroup {
+    /** @param {!mojom.OmniboxResult} resultsGroup */
+    constructor(resultsGroup) {
+      /** @struct */
+      this.details = {
+        cursorPosition: 0,
+        time: resultsGroup.timeSinceOmniboxStartedMs,
+        done: resultsGroup.done,
+        host: resultsGroup.host,
+        isTypedHost: resultsGroup.isTypedHost
+      };
+      /** @type {OutputResultsTable} */
+      this.combinedResults =
+          new OutputResultsTable(resultsGroup.combinedResults);
+      /** @type {Array<OutputResultsTable>} */
+      this.individualResultsList =
+          resultsGroup.resultsByProvider
+              .map(resultsWrapper => resultsWrapper.results)
+              .filter(results => results.length > 0)
+              .map(results => new OutputResultsTable(results));
+    }
+
+    /**
+     * Creates a HTML Node representing this data.
+     * @param {boolean} showDetails
+     * @param {boolean} showIncompleteResults
+     * @param {boolean} showAllProviders
+     * @return {Element}
+     */
+    render(showDetails, showIncompleteResults, showAllProviders) {
+      const resultsGroupNode =
+          OmniboxElement.getTemplate('results-group-template');
+      if (showDetails || showIncompleteResults) {
+        resultsGroupNode.querySelector('.details')
+            .appendChild(this.renderDetails_());
+      }
+      resultsGroupNode.querySelector('.combined-results')
+          .appendChild(this.combinedResults.render(showDetails));
+      if (showAllProviders) {
+        resultsGroupNode.querySelector('.individual-results')
+            .appendChild(this.renderIndividualResults_(showDetails));
+      }
+      return resultsGroupNode;
+    }
+
+    /**
+     * @private
+     * @return {Element}
+     */
+    renderDetails_() {
+      const details =
+          OmniboxElement.getTemplate('results-group-details-template');
+      details.querySelector('.cursor-position').textContent =
+          this.details.cursorPosition;
+      details.querySelector('.time').textContent = this.details.time;
+      details.querySelector('.done').textContent = this.details.done;
+      details.querySelector('.host').textContent = this.details.host;
+      details.querySelector('.is-typed-host').textContent =
+          this.details.isTypedHost;
+      return details;
+    }
+
+    /**
+     * @private
+     * @param {boolean} showDetails
+     * @return {Element}
+     */
+    renderIndividualResults_(showDetails) {
+      const individualResultsNode = OmniboxElement.getTemplate(
+          'results-group-individual-results-template');
+      this.individualResultsList.forEach(
+          individualResults => individualResultsNode.appendChild(
+              individualResults.render(showDetails)));
+      return individualResultsNode;
+    }
   }
 
-  /** @param {Element} element the element to the output */
-  addOutput(element) {
-    this.$$('contents').appendChild(element);
+  /**
+   * Helps track and render a list of results. Each result is tracked and
+   * rendered by OutputMatch below.
+   */
+  class OutputResultsTable {
+    /** @param {Array<!mojom.AutocompleteMatch>} results */
+    constructor(results) {
+      /** @type {Array<OutputMatch>} */
+      this.matches = results.map(match => new OutputMatch(match));
+    }
+
+    /**
+     * Creates a HTML Node representing this data.
+     * @param {boolean} showDetails
+     * @return {Element}
+     */
+    render(showDetails) {
+      const resultsTable = OmniboxElement.getTemplate('results-table-template');
+      // The additional properties column only needs be displayed if at least
+      // one of the results have additional properties.
+      const showAdditionalPropertiesHeader = this.matches.some(
+          match => match.showAdditionalProperties(showDetails));
+      resultsTable.querySelector('.results-table-body')
+          .appendChild(OutputMatch.renderHeader_(
+              showDetails, showAdditionalPropertiesHeader));
+      this.matches.forEach(
+          match => resultsTable.querySelector('.results-table-body')
+                       .appendChild(match.render(showDetails)));
+      return resultsTable;
+    }
   }
 
-  clearOutput() {
-    while (this.$$('contents').firstChild)
-      this.$$('contents').removeChild(this.$$('contents').firstChild);
-  }
-}
+  /** Helps track and render a single match. */
+  class OutputMatch {
+    /** @param {!mojom.AutocompleteMatch} match */
+    constructor(match) {
+      /** @dict */
+      this.properties = {};
+      /** @dict */
+      this.additionalProperties = {};
+      Object.entries(match).forEach(propertyNameValueTuple => {
+        // TODO(manukh) replace with destructuring when the styleguide is
+        // updated
+        // https://chromium-review.googlesource.com/c/chromium/src/+/1271915
+        const propertyName = propertyNameValueTuple[0];
+        const propertyValue = propertyNameValueTuple[1];
 
-window.customElements.define(OmniboxOutput.is, OmniboxOutput);
+        if (PROPERTY_OUTPUT_ORDER.some(
+                displayProperty =>
+                    displayProperty.propertyName === propertyName)) {
+          this.properties[propertyName] = propertyValue;
+        } else {
+          this.additionalProperties[propertyName] = propertyValue;
+        }
+      });
+    }
+
+    /**
+     * Creates a HTML Node representing this data.
+     * @param {boolean} showDetails
+     * @return {Element}
+     */
+    render(showDetails) {
+      const row = document.createElement('tr');
+      OutputMatch.displayedProperties(showDetails)
+          .map(property => {
+            const value = this.properties[property.propertyName];
+            if (typeof value === 'object')
+              return OutputMatch.renderJsonProperty_(value);
+            if (typeof value === 'boolean')
+              return OutputMatch.renderBooleanProperty_(value);
+            return OutputMatch.renderTextProperty_(value);
+          })
+          .forEach(cell => row.appendChild(cell));
+
+      if (this.showAdditionalProperties(showDetails)) {
+        row.appendChild(
+            OutputMatch.renderJsonProperty_(this.additionalProperties));
+      }
+      return row;
+    }
+
+    /**
+     * TODO(manukh) replace these static render_ functions with subclasses when
+     * rendering becomes more substantial
+     * @private
+     * @param {string} propertyValue
+     * @return {Element}
+     */
+    static renderTextProperty_(propertyValue) {
+      const cell = document.createElement('td');
+      cell.textContent = propertyValue;
+      return cell;
+    }
+
+    /**
+     * @private
+     * @param {Object} propertyValue
+     * @return {Element}
+     */
+    static renderJsonProperty_(propertyValue) {
+      const cell = document.createElement('td');
+      const pre = document.createElement('pre');
+      pre.textContent = JSON.stringify(propertyValue, null, 2);
+      cell.appendChild(pre);
+      return cell;
+    }
+
+    /**
+     * @private
+     * @param {boolean} propertyValue
+     * @return {Element}
+     */
+    static renderBooleanProperty_(propertyValue) {
+      const cell = document.createElement('td');
+      const icon = document.createElement('div');
+      icon.className = propertyValue ? 'check-mark' : 'x-mark';
+      icon.textContent = propertyValue;
+      cell.appendChild(icon);
+      return cell;
+    }
+
+    /**
+     * @private
+     * @param {boolean} showDetails
+     * @param {boolean} showAdditionalHeader
+     * @return {Element}
+     */
+    static renderHeader_(showDetails, showAdditionalHeader) {
+      const row = document.createElement('tr');
+      const headerCells =
+          OutputMatch.displayedProperties(showDetails)
+              .map(
+                  displayProperty => OutputMatch.renderHeaderCell_(
+                      displayProperty.header, displayProperty.url,
+                      displayProperty.tooltip));
+      if (showAdditionalHeader) {
+        headerCells.push(
+            OutputMatch.renderHeaderCell_('Additional Properties'));
+      }
+      headerCells.forEach(headerCell => row.appendChild(headerCell));
+      return row;
+    }
+
+    /**
+     * @private
+     * @param {string} name
+     * @param {string=} url
+     * @param {string=} tooltip
+     * @return {Element}
+     */
+    static renderHeaderCell_(name, url, tooltip) {
+      const cell = document.createElement('th');
+      if (url) {
+        const link = document.createElement('a');
+        link.textContent = name;
+        link.href = url;
+        cell.appendChild(link);
+      } else {
+        cell.textContent = name;
+      }
+      cell.title = tooltip || '';
+      return cell;
+    }
+
+    /**
+     * @return {Array<PresentationInfoRecord>} Array representing which columns
+     * need to be displayed.
+     */
+    static displayedProperties(showDetails) {
+      return showDetails ?
+          PROPERTY_OUTPUT_ORDER :
+          PROPERTY_OUTPUT_ORDER.filter(property => property.displayAlways);
+    }
+
+    /**
+     * @return {boolean} True if the additional properties column is required
+     * to be displayed for this result. False if the column can be hidden
+     * because this result does not have additional properties.
+     */
+    showAdditionalProperties(showDetails) {
+      return showDetails && Object.keys(this.additionalProperties).length;
+    }
+  }
+
+  window.customElements.define(OmniboxOutput.is, OmniboxOutput);
+
+  // TODO(manukh) remove PROPERTY_OUTPUT_ORDER from exports after the remaining
+  // OmniboxOutput classes are extracted
+  // TODO(manukh) use shorthand object creation if/when approved
+  // https://chromium.googlesource.com/chromium/src/+/master/styleguide/web/es6.md#object-literal-extensions
+  return {
+    OmniboxOutput: OmniboxOutput,
+    OutputResultsGroup: OutputResultsGroup,
+  };
+});
diff --git a/chrome/browser/resources/pwa.html b/chrome/browser/resources/pwa.html
new file mode 100644
index 0000000..4ee165b
--- /dev/null
+++ b/chrome/browser/resources/pwa.html
@@ -0,0 +1,7 @@
+<!-- TODO(calamity): Remove this once manifest URL installs are implemented. -->
+<!-- See https://crbug.com/896575 for details -->
+<html>
+<head>
+  <link rel="manifest" href="manifest.json">
+</head>
+</html>
diff --git a/chrome/browser/resources/settings/manifest.json b/chrome/browser/resources/settings/manifest.json
new file mode 100644
index 0000000..c7a72e04
--- /dev/null
+++ b/chrome/browser/resources/settings/manifest.json
@@ -0,0 +1,13 @@
+{
+  "name": "Settings",
+  "display": "standalone",
+  "icons": [
+    {
+      "src": "icon-192.png",
+      "sizes": "192x192",
+      "type": "image/png"
+    }
+  ],
+  "start_url": "/",
+  "theme_color": "#254FAE"
+}
diff --git a/chrome/browser/resources/settings/passwords_and_forms_page/password_list_item.html b/chrome/browser/resources/settings/passwords_and_forms_page/password_list_item.html
index cebf867..20a9580 100644
--- a/chrome/browser/resources/settings/passwords_and_forms_page/password_list_item.html
+++ b/chrome/browser/resources/settings/passwords_and_forms_page/password_list_item.html
@@ -4,6 +4,7 @@
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html">
 <link rel="import" href="../focus_row_behavior.html">
 <link rel="import" href="../settings_shared_css.html">
+<link rel="import" href="../site_favicon.html">
 <link rel="import" href="passwords_shared_css.html">
 <link rel="import" href="show_password_behavior.html">
 
@@ -47,6 +48,7 @@
     <div class="list-item" focus-row-container>
       <div class="website-column no-min-width"
           title="[[item.entry.loginPair.urls.link]]">
+        <site-favicon url="[[item.entry.loginPair.urls.link]]"></site-favicon>
         <a id="originUrl" target="_blank" class="no-min-width"
             href="[[item.entry.loginPair.urls.link]]"
             focus-row-control focus-type="originUrl">
diff --git a/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.html b/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.html
index 2d8ef4c..492d6e5 100644
--- a/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.html
+++ b/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.html
@@ -17,6 +17,7 @@
 <link rel="import" href="../global_scroll_target_behavior.html">
 <link rel="import" href="../prefs/prefs.html">
 <link rel="import" href="../settings_shared_css.html">
+<link rel="import" href="../site_favicon.html">
 <link rel="import" href="password_edit_dialog.html">
 <link rel="import" href="passwords_export_dialog.html">
 <link rel="import" href="passwords_shared_css.html">
@@ -158,7 +159,8 @@
       <template is="dom-repeat" items="[[passwordExceptions]]"
           filter="[[passwordExceptionFilter_(filter)]]">
         <div class="list-item">
-          <div class="start">
+          <div class="start website-column">
+            <site-favicon url="[[item.urls.link]]"></site-favicon>
             <a id="exception" href="[[item.urls.link]]" target="_blank">
               [[item.urls.shown]]
             </a>
diff --git a/chrome/browser/resources/settings/passwords_and_forms_page/passwords_shared_css.html b/chrome/browser/resources/settings/passwords_and_forms_page/passwords_shared_css.html
index 62693628..7c97ad9 100644
--- a/chrome/browser/resources/settings/passwords_and_forms_page/passwords_shared_css.html
+++ b/chrome/browser/resources/settings/passwords_and_forms_page/passwords_shared_css.html
@@ -47,6 +47,11 @@
         text-overflow: ellipsis;
         white-space: nowrap;
       }
+
+      site-favicon {
+        margin-inline-end: 8px;
+        min-width: 16px;
+      }
     </style>
   </template>
 </dom-module>
diff --git a/chrome/browser/resources/settings/people_page/people_page.html b/chrome/browser/resources/settings/people_page/people_page.html
index bc4cd21..b5ad088 100644
--- a/chrome/browser/resources/settings/people_page/people_page.html
+++ b/chrome/browser/resources/settings/people_page/people_page.html
@@ -227,8 +227,9 @@
         </template>
 </if>
 
-        <template is="dom-if" if="[[isAdvancedSyncSettingsVisible_(
-            syncStatus, unifiedConsentEnabled_)]]">
+        <template is="dom-if"
+            if="[[isPreUnifiedConsentAdvancedSyncSettingsVisible_(
+                syncStatus, unifiedConsentEnabled_)]]">
           <div class$="settings-box two-line
                   [[getSyncStatusClass_(syncStatus)]]"
               on-click="onSyncTap_" id="sync-status"
@@ -335,13 +336,14 @@
 
       </neon-animatable>
       <template is="dom-if" route-path="/syncSetup"
-          no-search="[[!isAdvancedSyncSettingsVisible_(
+          no-search="[[!isAdvancedSyncSettingsSearchable_(
               syncStatus, unifiedConsentEnabled_)]]">
         <settings-subpage
-            associated-control="[[$$('#sync-status')]]"
+            associated-control="[[getAdvancedSyncSettingsAssociatedControl_(
+                unifiedConsentEnabled_)]]"
             page-title="$i18n{syncPageTitle}"
             learn-more-url="$i18n{syncAndGoogleServicesLearnMoreURL}"
-            no-search$="[[!isAdvancedSyncSettingsVisible_(syncStatus,
+            no-search$="[[!isAdvancedSyncSettingsSearchable_(syncStatus,
                 unifiedConsentEnabled_)]]">
           <settings-sync-page
 <if expr="not chromeos">
diff --git a/chrome/browser/resources/settings/people_page/people_page.js b/chrome/browser/resources/settings/people_page/people_page.js
index 7546e97..2032986 100644
--- a/chrome/browser/resources/settings/people_page/people_page.js
+++ b/chrome/browser/resources/settings/people_page/people_page.js
@@ -479,7 +479,7 @@
    * @param {?settings.SyncStatus} syncStatus
    * @return {boolean}
    */
-  isAdvancedSyncSettingsVisible_: function(syncStatus) {
+  isPreUnifiedConsentAdvancedSyncSettingsVisible_: function(syncStatus) {
     return !!syncStatus && !!syncStatus.signedIn &&
         !!syncStatus.syncSystemEnabled && !this.unifiedConsentEnabled_;
   },
@@ -487,6 +487,25 @@
   /**
    * @private
    * @param {?settings.SyncStatus} syncStatus
+   * @return {boolean}
+   */
+  isAdvancedSyncSettingsSearchable_: function(syncStatus) {
+    return this.isPreUnifiedConsentAdvancedSyncSettingsVisible_(syncStatus) ||
+        !!this.unifiedConsentEnabled_;
+  },
+
+  /**
+   * @private
+   * @return {Element|null}
+   */
+  getAdvancedSyncSettingsAssociatedControl_: function() {
+    return !!this.unifiedConsentEnabled_ ? this.$$('#sync-setup') :
+                                           this.$$('#sync-status');
+  },
+
+  /**
+   * @private
+   * @param {?settings.SyncStatus} syncStatus
    * @return {boolean} Whether an action can be taken with the sync status. sync
    *     status is actionable if sync is not managed and if there is a sync
    *     error, there is an action associated with it.
diff --git a/chrome/browser/resources/settings/settings_resources.grd b/chrome/browser/resources/settings/settings_resources.grd
index d9e905c1..fe651b8 100644
--- a/chrome/browser/resources/settings/settings_resources.grd
+++ b/chrome/browser/resources/settings/settings_resources.grd
@@ -34,6 +34,10 @@
         <structure name="IDR_SETTINGS_TTS_SUBPAGE_HTML"
                    file="a11y_page/tts_subpage.html"
                    type="chrome_html" />
+        <structure name="IDR_MD_SETTINGS_MANIFEST"
+                   file="manifest.json"
+                   type="chrome_html" />
+
       </if>
       <structure name="IDR_SETTINGS_ABOUT_PAGE_BROWSER_PROXY_HTML"
                  file="about_page/about_page_browser_proxy.html"
diff --git a/chrome/browser/resources/settings/settings_resources_vulcanized.grd b/chrome/browser/resources/settings/settings_resources_vulcanized.grd
index 46a832e1..7614982 100644
--- a/chrome/browser/resources/settings/settings_resources_vulcanized.grd
+++ b/chrome/browser/resources/settings/settings_resources_vulcanized.grd
@@ -18,6 +18,7 @@
       <include name="IDR_MD_SETTINGS_LAZY_LOAD_VULCANIZED_HTML" file="${root_gen_dir}\chrome\browser\resources\settings\lazy_load.vulcanized.html" use_base_dir="false" flattenhtml="true" allowexternalscript="true" type="BINDATA" compress="gzip" />
       <include name="IDR_MD_SETTINGS_LAZY_LOAD_VULCANIZED_P2_HTML" file="${root_gen_dir}\chrome\browser\resources\settings\lazy_load.vulcanized.p2.html" use_base_dir="false" flattenhtml="true" allowexternalscript="true" type="BINDATA" compress="gzip" />
       <include name="IDR_MD_SETTINGS_LAZY_LOAD_CRISPER_JS" file="${root_gen_dir}\chrome\browser\resources\settings\lazy_load.crisper.js" use_base_dir="false" flattenhtml="true" type="BINDATA" compress="gzip" />
+      <include name="IDR_MD_SETTINGS_MANIFEST" file="manifest.json" type="BINDATA" compress="gzip" />
     </includes>
   </release>
 </grit>
diff --git a/chrome/browser/safe_browsing/advanced_protection_status_manager.cc b/chrome/browser/safe_browsing/advanced_protection_status_manager.cc
index 4c252ed..5f00982 100644
--- a/chrome/browser/safe_browsing/advanced_protection_status_manager.cc
+++ b/chrome/browser/safe_browsing/advanced_protection_status_manager.cc
@@ -187,7 +187,7 @@
     return;
 
   // Refresh OAuth access token.
-  OAuth2TokenService::ScopeSet scopes;
+  identity::ScopeSet scopes;
   scopes.insert(GaiaConstants::kOAuth1LoginScope);
 
   access_token_fetcher_ =
diff --git a/chrome/browser/safe_browsing/download_protection/check_client_download_request.cc b/chrome/browser/safe_browsing/download_protection/check_client_download_request.cc
index 4f5b9ac..680a5286 100644
--- a/chrome/browser/safe_browsing/download_protection/check_client_download_request.cc
+++ b/chrome/browser/safe_browsing/download_protection/check_client_download_request.cc
@@ -190,7 +190,6 @@
 void CheckClientDownloadRequest::OnDownloadDestroyed(
     download::DownloadItem* download) {
   Cancel(/*download_destroyed=*/true);
-  DCHECK(item_ == NULL);
 }
 
 // TODO: this method puts "DownloadProtectionService::" in front of a lot of
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 fe306a2..aaf3c585 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
@@ -1755,6 +1755,10 @@
                   tmp_path_, BinaryFeatureExtractor::kDefaultOptions, _, _))
       .WillOnce(SetDosHeaderContents("dummy dos header"));
 #endif  // OS_MACOSX
+
+  PrepareResponse(ClientDownloadResponse::SAFE, net::HTTP_OK,
+                  net::URLRequestStatus::SUCCESS);
+
   RunLoop run_loop;
   download_service_->CheckClientDownload(
       &item, base::Bind(&DownloadProtectionServiceTest::CheckDoneCallback,
@@ -1828,6 +1832,9 @@
                   tmp_path_, BinaryFeatureExtractor::kDefaultOptions, _, _));
 #endif  // OS_MACOSX
 
+  PrepareResponse(ClientDownloadResponse::SAFE, net::HTTP_OK,
+                  net::URLRequestStatus::SUCCESS);
+
   RunLoop run_loop;
   download_service_->CheckClientDownload(
       &item, base::Bind(&DownloadProtectionServiceTest::CheckDoneCallback,
@@ -1896,6 +1903,9 @@
                 interceptor_run_loop.Quit();
             }));
 
+    PrepareResponse(ClientDownloadResponse::SAFE, net::HTTP_OK,
+                    net::URLRequestStatus::SUCCESS);
+
     RunLoop run_loop;
     download_service_->CheckClientDownload(
         &item, base::Bind(&DownloadProtectionServiceTest::CheckDoneCallback,
@@ -1964,6 +1974,9 @@
                   reinterpret_cast<history::ContextID>(1), 0, GURL(), redirects,
                   ui::PAGE_TRANSITION_TYPED, history::SOURCE_BROWSED, false);
 
+    PrepareResponse(ClientDownloadResponse::SAFE, net::HTTP_OK,
+                    net::URLRequestStatus::SUCCESS);
+
     RunLoop run_loop;
     download_service_->CheckClientDownload(
         &item, base::Bind(&DownloadProtectionServiceTest::CheckDoneCallback,
diff --git a/chrome/browser/search/background/ntp_background_service.cc b/chrome/browser/search/background/ntp_background_service.cc
index f47ff38..1fd29a24 100644
--- a/chrome/browser/search/background/ntp_background_service.cc
+++ b/chrome/browser/search/background/ntp_background_service.cc
@@ -286,7 +286,7 @@
   // This is particularly important if the current token fetch results in an
   // auth error because the user has since signed out.
   album_info_.clear();
-  OAuth2TokenService::ScopeSet scopes{kScopePhotos};
+  identity::ScopeSet scopes{kScopePhotos};
   token_fetcher_ = std::make_unique<identity::PrimaryAccountAccessTokenFetcher>(
       "ntp_backgrounds_service", identity_manager_, scopes,
       base::BindOnce(&NtpBackgroundService::GetAccessTokenForAlbumCallback,
@@ -407,7 +407,7 @@
   album_photos_.clear();
   requested_album_id_ = album_id;
   requested_photo_container_id_ = photo_container_id;
-  OAuth2TokenService::ScopeSet scopes{kScopePhotos};
+  identity::ScopeSet scopes{kScopePhotos};
   token_fetcher_ = std::make_unique<identity::PrimaryAccountAccessTokenFetcher>(
       "ntp_backgrounds_service", identity_manager_, scopes,
       base::BindOnce(&NtpBackgroundService::GetAccessTokenForPhotosCallback,
diff --git a/chrome/browser/signin/chrome_signin_client.cc b/chrome/browser/signin/chrome_signin_client.cc
index e20f0ec..0c5f8c6d 100644
--- a/chrome/browser/signin/chrome_signin_client.cc
+++ b/chrome/browser/signin/chrome_signin_client.cc
@@ -69,7 +69,7 @@
 SigninClient::SignoutDecision IsSignoutAllowed(
     Profile* profile,
     const signin_metrics::ProfileSignout signout_source_metric) {
-  // TODO(chcunningham): This logic should be reworked to only prohibit user-
+  // TODO(msarda): This logic should be reworked to only prohibit user-
   // initiated sign-out. For now signin_util::IsUserSignoutAllowedForProfile()
   // prohibits ALL sign-outs with the exception of ACCOUNT_REMOVED_FROM_DEVICE
   // because this preserves the original behavior. A follow-up CL will make the
diff --git a/chrome/browser/signin/chrome_signin_client_unittest.cc b/chrome/browser/signin/chrome_signin_client_unittest.cc
index e74e132..71f1f1f 100644
--- a/chrome/browser/signin/chrome_signin_client_unittest.cc
+++ b/chrome/browser/signin/chrome_signin_client_unittest.cc
@@ -315,7 +315,7 @@
     case signin_metrics::ProfileSignout::USER_TUNED_OFF_SYNC_FROM_DICE_UI:
       return true;
     case signin_metrics::ProfileSignout::ACCOUNT_REMOVED_FROM_DEVICE:
-      // TODO(chcunningham): Add more of the above cases to this "false" branch.
+      // TODO(msarda): Add more of the above cases to this "false" branch.
       // For now only ACCOUNT_REMOVED_FROM_DEVICE is here to preserve the status
       // quo. Additional internal sources of sign-out will be moved here in a
       // follow up CL.
diff --git a/chrome/browser/ssl/ssl_browsertest.cc b/chrome/browser/ssl/ssl_browsertest.cc
index 03cbe65e..0a5d970 100644
--- a/chrome/browser/ssl/ssl_browsertest.cc
+++ b/chrome/browser/ssl/ssl_browsertest.cc
@@ -122,6 +122,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_manager_connection.h"
 #include "content/public/common/service_names.mojom.h"
@@ -170,8 +171,10 @@
 #include "ui/base/l10n/l10n_util.h"
 
 #if defined(USE_NSS_CERTS)
+#include "chrome/browser/certificate_manager_model.h"
 #include "chrome/browser/net/nss_context.h"
 #include "net/cert/nss_cert_database.h"
+#include "net/cert/x509_util_nss.h"
 #endif  // defined(USE_NSS_CERTS)
 
 using namespace ssl_test_util;
@@ -6017,6 +6020,70 @@
   CheckAuthenticatedState(tab, AuthState::NONE);
 }
 
+#if defined(OS_CHROMEOS)
+
+class SSLUITestNoCert : public SSLUITest,
+                        public CertificateManagerModel::Observer {
+ public:
+  SSLUITestNoCert() = default;
+  ~SSLUITestNoCert() = default;
+
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    command_line->AppendSwitch(switches::kDisableTestCerts);
+    SSLUITest::SetUpCommandLine(command_line);
+  }
+
+  // CertificateManagerModel::Observer implementation:
+  void CertificatesRefreshed() override {}
+};
+
+INSTANTIATE_TEST_CASE_P(, SSLUITestNoCert, ::testing::Values(false, true));
+
+// Checks that a newly-added certificate authority is usable immediately.
+IN_PROC_BROWSER_TEST_P(SSLUITestNoCert, NewCertificateAuthority) {
+  if (!content::IsOutOfProcessNetworkService())
+    return;
+
+  ASSERT_TRUE(https_server_.Start());
+
+  WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
+  ui_test_utils::NavigateToURL(browser(),
+                               https_server_.GetURL("/ssl/google.html"));
+  EXPECT_TRUE(IsShowingInterstitial(tab));
+
+  std::unique_ptr<CertificateManagerModel> model;
+  base::RunLoop run_loop;
+  CertificateManagerModel::Create(
+      browser()->profile(), this,
+      base::BindLambdaForTesting(
+          [&](std::unique_ptr<CertificateManagerModel> model2) {
+            model = std::move(model2);
+            run_loop.Quit();
+          }));
+  run_loop.Run();
+
+  scoped_refptr<net::X509Certificate> cert =
+      net::CreateCertificateChainFromFile(
+          net::GetTestCertsDirectory(), "root_ca_cert.pem",
+          net::X509Certificate::FORMAT_PEM_CERT_SEQUENCE);
+
+  net::ScopedCERTCertificateList nss_certs =
+      net::x509_util::CreateCERTCertificateListFromX509Certificate(cert.get());
+
+  net::NSSCertDatabase::ImportCertFailureList not_imported;
+  EXPECT_TRUE(model->ImportCACerts(nss_certs, net::NSSCertDatabase::TRUSTED_SSL,
+                                   &not_imported));
+  EXPECT_TRUE(not_imported.empty());
+
+  content::FlushNetworkServiceInstanceForTesting();
+
+  ui_test_utils::NavigateToURL(browser(),
+                               https_server_.GetURL("/ssl/google.html"));
+  EXPECT_FALSE(IsShowingInterstitial(tab));
+}
+
+#endif  // defined(OS_CHROMEOS)
+
 // Regression test for http://crbug.com/635833 (crash when a window with no
 // NavigationEntry commits).
 IN_PROC_BROWSER_TEST_P(SSLUITestIgnoreLocalhostCertErrors,
diff --git a/chrome/browser/sync/profile_sync_service_factory.cc b/chrome/browser/sync/profile_sync_service_factory.cc
index 8e487773..2f60419 100644
--- a/chrome/browser/sync/profile_sync_service_factory.cc
+++ b/chrome/browser/sync/profile_sync_service_factory.cc
@@ -241,17 +241,27 @@
         base::BindRepeating(&GetSigninScopedDeviceIdForProfile, profile);
     init_params.gaia_cookie_manager_service =
         GaiaCookieManagerServiceFactory::GetForProfile(profile);
+
     bool use_fcm_invalidations =
         base::FeatureList::IsEnabled(invalidation::switches::kFCMInvalidations);
-    auto* invalidation_provider =
-        use_fcm_invalidations
-            ? invalidation::ProfileInvalidationProviderFactory::GetForProfile(
-                  profile)
-            : invalidation::DeprecatedProfileInvalidationProviderFactory::
-                  GetForProfile(profile);
-    if (invalidation_provider) {
-      init_params.invalidations_identity_provider =
-          invalidation_provider->GetIdentityProvider();
+    if (use_fcm_invalidations) {
+      auto* fcm_invalidation_provider =
+          invalidation::ProfileInvalidationProviderFactory::GetForProfile(
+              profile);
+      if (fcm_invalidation_provider) {
+        init_params.invalidations_identity_providers.push_back(
+            fcm_invalidation_provider->GetIdentityProvider());
+      }
+    }
+    // This code should stay here until all invalidation client are
+    // migrated from deprecated invalidation  infructructure.
+    // Since invalidations will work only if ProfileSyncService calls
+    // SetActiveAccountId for all identity providers.
+    auto* deprecated_invalidation_provider = invalidation::
+        DeprecatedProfileInvalidationProviderFactory::GetForProfile(profile);
+    if (deprecated_invalidation_provider) {
+      init_params.invalidations_identity_providers.push_back(
+          deprecated_invalidation_provider->GetIdentityProvider());
     }
 
     // TODO(tim): Currently, AUTO/MANUAL settings refer to the *first* time sync
diff --git a/chrome/browser/sync/profile_sync_test_util.cc b/chrome/browser/sync/profile_sync_test_util.cc
index c064cf0..31c31db 100644
--- a/chrome/browser/sync/profile_sync_test_util.cc
+++ b/chrome/browser/sync/profile_sync_test_util.cc
@@ -58,14 +58,15 @@
   init_params.network_time_update_callback = base::DoNothing();
   bool fcm_invalidations_enabled =
       base::FeatureList::IsEnabled(invalidation::switches::kFCMInvalidations);
-  init_params.invalidations_identity_provider =
-      fcm_invalidations_enabled
-          ? invalidation::ProfileInvalidationProviderFactory::GetForProfile(
-                profile)
-                ->GetIdentityProvider()
-          : invalidation::DeprecatedProfileInvalidationProviderFactory::
-                GetForProfile(profile)
-                    ->GetIdentityProvider();
+  if (fcm_invalidations_enabled) {
+    init_params.invalidations_identity_providers.push_back(
+        invalidation::ProfileInvalidationProviderFactory::GetForProfile(profile)
+            ->GetIdentityProvider());
+  }
+  init_params.invalidations_identity_providers.push_back(
+      invalidation::DeprecatedProfileInvalidationProviderFactory::GetForProfile(
+          profile)
+          ->GetIdentityProvider());
   init_params.url_loader_factory =
       content::BrowserContext::GetDefaultStoragePartition(profile)
           ->GetURLLoaderFactoryForBrowserProcess();
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 7fb4e6ad..03c5004 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -1259,6 +1259,10 @@
       deps += [
         "//chrome/browser/web_applications",
 
+        # TODO(calamity): Remove once SystemWebAppManager is moved into
+        # web_applications/.
+        "//chrome/browser/web_applications/bookmark_apps",
+
         # TODO(loyso): Erase these. crbug.com/877898.
         "//chrome/browser/web_applications:web_applications_on_extensions",
         "//chrome/browser/web_applications/components",
@@ -2809,6 +2813,8 @@
       "views/webauthn/authenticator_request_sheet_view.h",
       "views/webauthn/authenticator_transport_selector_sheet_view.cc",
       "views/webauthn/authenticator_transport_selector_sheet_view.h",
+      "views/webauthn/ble_device_selection_sheet_view.cc",
+      "views/webauthn/ble_device_selection_sheet_view.h",
       "views/webauthn/ble_pin_entry_view.cc",
       "views/webauthn/ble_pin_entry_view.h",
       "views/webauthn/hover_list_view.cc",
@@ -2820,6 +2826,8 @@
       "views_mode_controller.cc",
       "views_mode_controller.h",
       "webauthn/authenticator_request_sheet_model.h",
+      "webauthn/ble_device_hover_list_model.cc",
+      "webauthn/ble_device_hover_list_model.h",
       "webauthn/hover_list_model.h",
       "webauthn/other_transports_menu_model.cc",
       "webauthn/other_transports_menu_model.h",
@@ -3265,6 +3273,8 @@
         "ash/launcher/shelf_spinner_item_controller.h",
         "views/arc_app_dialog_view.cc",
         "views/arc_data_removal_dialog_view.cc",
+        "views/crostini/crostini_app_restart_view.cc",
+        "views/crostini/crostini_app_restart_view.h",
         "views/crostini/crostini_installer_view.cc",
         "views/crostini/crostini_installer_view.h",
         "views/crostini/crostini_uninstaller_view.cc",
diff --git a/chrome/browser/ui/ash/launcher/crostini_app_window_shelf_controller.cc b/chrome/browser/ui/ash/launcher/crostini_app_window_shelf_controller.cc
index 7a3e68e5..7e4b09d 100644
--- a/chrome/browser/ui/ash/launcher/crostini_app_window_shelf_controller.cc
+++ b/chrome/browser/ui/ash/launcher/crostini_app_window_shelf_controller.cc
@@ -102,7 +102,7 @@
   app_window->SetController(item_controller);
 }
 
-void CrostiniAppWindowShelfController::RemoveFromShelf(
+ash::ShelfID CrostiniAppWindowShelfController::RemoveFromShelf(
     aura::Window* window,
     AppWindowBase* app_window) {
   UnregisterAppWindow(app_window);
@@ -113,8 +113,12 @@
       owner()->shelf_model()->GetAppWindowLauncherItemController(
           app_window->shelf_id());
 
-  if (item_controller != nullptr && item_controller->window_count() == 0)
-    owner()->CloseLauncherItem(item_controller->shelf_id());
+  if (item_controller != nullptr && item_controller->window_count() == 0) {
+    ash::ShelfID shelf_id = item_controller->shelf_id();
+    owner()->CloseLauncherItem(shelf_id);
+    return shelf_id;
+  }
+  return ash::ShelfID();
 }
 
 void CrostiniAppWindowShelfController::ActiveUserChanged(
@@ -257,7 +261,16 @@
   if (app_window_it == aura_window_to_app_window_.end())
     return;
 
-  RemoveFromShelf(window, app_window_it->second.get());
+  ash::ShelfID shelf_id = RemoveFromShelf(window, app_window_it->second.get());
+  if (!shelf_id.IsNull()) {
+    const std::string& app_id = shelf_id.app_id;
+    if (app_id == app_id_to_restart_) {
+      crostini::LaunchCrostiniApp(
+          ChromeLauncherController::instance()->profile(), app_id,
+          display_id_to_restart_in_);
+      app_id_to_restart_.clear();
+    }
+  }
 
   aura_window_to_app_window_.erase(app_window_it);
 }
@@ -309,3 +322,10 @@
     int64_t display_id) {
   crostini_app_display_.Register(app_id, display_id);
 }
+
+void CrostiniAppWindowShelfController::Restart(const ash::ShelfID& shelf_id,
+                                               int64_t display_id) {
+  app_id_to_restart_ = shelf_id.app_id;
+  display_id_to_restart_in_ = display_id;
+  ChromeLauncherController::instance()->Close(shelf_id);
+}
diff --git a/chrome/browser/ui/ash/launcher/crostini_app_window_shelf_controller.h b/chrome/browser/ui/ash/launcher/crostini_app_window_shelf_controller.h
index 5a2ef8f19..360121ab 100644
--- a/chrome/browser/ui/ash/launcher/crostini_app_window_shelf_controller.h
+++ b/chrome/browser/ui/ash/launcher/crostini_app_window_shelf_controller.h
@@ -54,6 +54,9 @@
   void OnAppLaunchRequested(const std::string& app_id,
                             int64_t display_id) override;
 
+  // Close app with |shelf_id| and then restart it on |display_id|.
+  void Restart(const ash::ShelfID& shelf_id, int64_t display_id);
+
  private:
   using AuraWindowToAppWindow =
       std::map<aura::Window*, std::unique_ptr<AppWindowBase>>;
@@ -61,7 +64,9 @@
   void RegisterAppWindow(aura::Window* window, const std::string& shelf_app_id);
   void UnregisterAppWindow(AppWindowBase* app_window);
   void AddToShelf(aura::Window* window, AppWindowBase* app_window);
-  void RemoveFromShelf(aura::Window* window, AppWindowBase* app_window);
+
+  // Returns ID of the shelf item that is removed, or a null id.
+  ash::ShelfID RemoveFromShelf(aura::Window* window, AppWindowBase* app_window);
 
   // AppWindowLauncherController:
   AppWindowLauncherItemController* ControllerForWindow(
@@ -72,6 +77,12 @@
   std::set<aura::Window*> observed_windows_;
   CrostiniAppDisplay crostini_app_display_;
 
+  // These two member variables track an app restart request. When
+  // app_id_to_restart_ is not empty the controller observes that app and
+  // relaunches it when all of its windows are closed.
+  std::string app_id_to_restart_;
+  int64_t display_id_to_restart_in_;
+
   DISALLOW_COPY_AND_ASSIGN(CrostiniAppWindowShelfController);
 };
 
diff --git a/chrome/browser/ui/ash/launcher/crostini_shelf_context_menu.cc b/chrome/browser/ui/ash/launcher/crostini_shelf_context_menu.cc
index 5de0f6f1..baef205 100644
--- a/chrome/browser/ui/ash/launcher/crostini_shelf_context_menu.cc
+++ b/chrome/browser/ui/ash/launcher/crostini_shelf_context_menu.cc
@@ -13,8 +13,10 @@
 #include "chrome/browser/chromeos/crostini/crostini_registry_service_factory.h"
 #include "chrome/browser/chromeos/crostini/crostini_util.h"
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
+#include "chrome/browser/ui/views/crostini/crostini_app_restart_view.h"
 #include "chrome/grit/generated_resources.h"
 #include "ui/base/ui_base_features.h"
+#include "ui/strings/grit/ui_strings.h"
 
 CrostiniShelfContextMenu::CrostiniShelfContextMenu(
     ChromeLauncherController* controller,
@@ -55,6 +57,18 @@
                                     IDS_APP_CONTEXT_MENU_ACTIVATE_ARC);
   }
 
+  // Offer users the ability to toggle per-application UI scaling.
+  // Some apps have high-density display support and do not require scaling
+  // to match the system display density, but others are density-unaware and
+  // look better when scaled to match the display density.
+  if (registration.has_value() && registration->IsScaled()) {
+    menu_model->AddCheckItemWithStringId(ash::CROSTINI_USE_HIGH_DENSITY,
+                                         IDS_CROSTINI_USE_HIGH_DENSITY);
+  } else {
+    menu_model->AddCheckItemWithStringId(ash::CROSTINI_USE_LOW_DENSITY,
+                                         IDS_CROSTINI_USE_LOW_DENSITY);
+  }
+
   if (!features::IsTouchableAppContextMenuEnabled())
     menu_model->AddSeparator(ui::NORMAL_SEPARATOR);
 }
@@ -76,5 +90,16 @@
                                 display_id());
     return;
   }
+  if (command_id == ash::CROSTINI_USE_LOW_DENSITY ||
+      command_id == ash::CROSTINI_USE_HIGH_DENSITY) {
+    crostini::CrostiniRegistryService* registry_service =
+        crostini::CrostiniRegistryServiceFactory::GetForProfile(
+            controller()->profile());
+    bool scaled = command_id == ash::CROSTINI_USE_LOW_DENSITY;
+    registry_service->SetAppScaled(item().id.app_id, scaled);
+    if (controller()->IsOpen(item().id))
+      CrostiniAppRestartView::Show(item().id, display_id());
+    return;
+  }
   NOTREACHED();
 }
diff --git a/chrome/browser/ui/ash/session_controller_client_unittest.cc b/chrome/browser/ui/ash/session_controller_client_unittest.cc
index d144f6e..ad864a4 100644
--- a/chrome/browser/ui/ash/session_controller_client_unittest.cc
+++ b/chrome/browser/ui/ash/session_controller_client_unittest.cc
@@ -19,7 +19,6 @@
 #include "chrome/browser/chromeos/login/users/multi_profile_user_controller.h"
 #include "chrome/browser/chromeos/policy/policy_cert_service.h"
 #include "chrome/browser/chromeos/policy/policy_cert_service_factory.h"
-#include "chrome/browser/chromeos/policy/policy_cert_verifier.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/chromeos/settings/scoped_cros_settings_test_helper.h"
 #include "chrome/browser/supervised_user/supervised_user_service.h"
@@ -37,6 +36,7 @@
 #include "net/cert/x509_certificate.h"
 #include "net/test/cert_test_util.h"
 #include "net/test/test_data_directory.h"
+#include "services/network/cert_verifier_with_trust_anchors.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 using chromeos::FakeChromeUserManager;
@@ -47,9 +47,10 @@
 constexpr char kUser[] = "user@test.com";
 constexpr char kUserGaiaId[] = "0123456789";
 
-// Weak ptr to PolicyCertVerifier - object is freed in test destructor once
-// we've ensured the profile has been shut down.
-policy::PolicyCertVerifier* g_policy_cert_verifier_for_factory = nullptr;
+// Weak ptr to network::CertVerifierWithTrustAnchors - object is freed in test
+// destructor once we've ensured the profile has been shut down.
+network::CertVerifierWithTrustAnchors* g_policy_cert_verifier_for_factory =
+    nullptr;
 
 std::unique_ptr<KeyedService> CreateTestPolicyCertService(
     content::BrowserContext* context) {
@@ -200,14 +201,14 @@
   void TearDown() override {
     user_manager_enabler_.reset();
     user_manager_ = nullptr;
-    // Clear our cached pointer to the PolicyCertVerifier.
+    // Clear our cached pointer to the network::CertVerifierWithTrustAnchors.
     g_policy_cert_verifier_for_factory = nullptr;
     profile_manager_.reset();
 
-    // We must ensure that the PolicyCertVerifier outlives the
-    // PolicyCertService so shutdown the profile here. Additionally, we need
+    // We must ensure that the network::CertVerifierWithTrustAnchors outlives
+    // the PolicyCertService so shutdown the profile here. Additionally, we need
     // to run the message loop between freeing the PolicyCertService and
-    // freeing the PolicyCertVerifier (see
+    // freeing the network::CertVerifierWithTrustAnchors (see
     // PolicyCertService::OnTrustAnchorsChanged() which is called from
     // PolicyCertService::Shutdown()).
     base::RunLoop().RunUntilIdle();
@@ -260,7 +261,7 @@
   }
 
   content::TestBrowserThreadBundle threads_;
-  std::unique_ptr<policy::PolicyCertVerifier> cert_verifier_;
+  std::unique_ptr<network::CertVerifierWithTrustAnchors> cert_verifier_;
   std::unique_ptr<TestingProfileManager> profile_manager_;
   session_manager::SessionManager session_manager_;
 
@@ -390,7 +391,8 @@
   user_manager()->LoginUser(account_id);
   EXPECT_EQ(ash::AddUserSessionPolicy::ALLOWED,
             SessionControllerClient::GetAddUserSessionPolicy());
-  cert_verifier_.reset(new policy::PolicyCertVerifier(base::Closure()));
+  cert_verifier_.reset(
+      new network::CertVerifierWithTrustAnchors(base::Closure()));
   g_policy_cert_verifier_for_factory = cert_verifier_.get();
   ASSERT_TRUE(
       policy::PolicyCertServiceFactory::GetInstance()->SetTestingFactoryAndUse(
diff --git a/chrome/browser/ui/ash/system_tray_client_browsertest.cc b/chrome/browser/ui/ash/system_tray_client_browsertest.cc
index ce1c48d..91068948 100644
--- a/chrome/browser/ui/ash/system_tray_client_browsertest.cc
+++ b/chrome/browser/ui/ash/system_tray_client_browsertest.cc
@@ -4,7 +4,6 @@
 
 #include "chrome/browser/ui/ash/system_tray_client.h"
 
-#include "ash/public/cpp/ash_features.h"
 #include "ash/public/cpp/ash_view_ids.h"
 #include "ash/public/interfaces/constants.mojom.h"
 #include "ash/public/interfaces/system_tray_test_api.mojom.h"
@@ -63,103 +62,6 @@
   DISALLOW_COPY_AND_ASSIGN(SystemTrayClientTest);
 };
 
-// Test that a chrome update shows the update icon in the system menu.
-IN_PROC_BROWSER_TEST_F(SystemTrayClientTest, UpdateTrayIcon) {
-  // The tray icon is removed in UnifiedSystemTray.
-  // TODO(tetsui): Remove the test after UnifiedSystemTray launch.
-  // https://crbug.com/847104
-  if (ash::features::IsSystemTrayUnifiedEnabled())
-    return;
-
-  ash::mojom::SystemTrayTestApiAsyncWaiter wait_for(tray_test_api_.get());
-
-  // When no update is pending, the icon isn't visible.
-  bool visible = false;
-  wait_for.IsTrayViewVisible(ash::VIEW_ID_TRAY_UPDATE_ICON, &visible);
-  EXPECT_FALSE(visible);
-
-  // Simulate an upgrade. This sends a mojo message to ash.
-  UpgradeDetector* detector = UpgradeDetector::GetInstance();
-  detector->set_upgrade_notification_stage(
-      UpgradeDetector::UPGRADE_ANNOYANCE_LOW);
-  detector->NotifyUpgrade();
-  content::RunAllPendingInMessageLoop();
-
-  // Tray icon is now visible.
-  wait_for.IsTrayViewVisible(ash::VIEW_ID_TRAY_UPDATE_ICON, &visible);
-  EXPECT_TRUE(visible);
-}
-
-// Tests that the update icon becomes visible after an update is detected
-// available for downloading over cellular connection. The update icon hides
-// after user's one time permission on the update is set successfully in Update
-// Engine.
-IN_PROC_BROWSER_TEST_F(SystemTrayClientTest, UpdateOverCellularTrayIcon) {
-  // The tray icon is removed in UnifiedSystemTray.
-  // TODO(tetsui): Remove the test after UnifiedSystemTray launch.
-  // https://crbug.com/847104
-  if (ash::features::IsSystemTrayUnifiedEnabled())
-    return;
-
-  ash::mojom::SystemTrayTestApiAsyncWaiter wait_for(tray_test_api_.get());
-  wait_for.DisableAnimations();
-
-  // When no update is pending, the icon isn't visible.
-  bool visible = false;
-  wait_for.IsTrayViewVisible(ash::VIEW_ID_TRAY_UPDATE_ICON, &visible);
-  EXPECT_FALSE(visible);
-
-  chromeos::UpdateEngineClient::Status status;
-  status.status =
-      chromeos::UpdateEngineClient::UPDATE_STATUS_NEED_PERMISSION_TO_UPDATE;
-  fake_update_engine_client_->set_default_status(status);
-  fake_update_engine_client_->NotifyObserversThatStatusChanged(status);
-  content::RunAllPendingInMessageLoop();
-
-  // When an update is available over cellular networks, the icon is visible.
-  wait_for.IsTrayViewVisible(ash::VIEW_ID_TRAY_UPDATE_ICON, &visible);
-  EXPECT_TRUE(visible);
-
-  wait_for.ShowBubble();
-  base::string16 label;
-  wait_for.GetBubbleLabelText(ash::VIEW_ID_TRAY_UPDATE_MENU_LABEL, &label);
-  EXPECT_EQ("Click to view update details", base::UTF16ToUTF8(label));
-
-  // Notifies that the user's one time permission on update over cellular
-  // connection is granted.
-  fake_update_engine_client_
-      ->NotifyUpdateOverCellularOneTimePermissionGranted();
-  content::RunAllPendingInMessageLoop();
-
-  // When user permission is granted, the icon becomes invisible.
-  wait_for.IsTrayViewVisible(ash::VIEW_ID_TRAY_UPDATE_ICON, &visible);
-  EXPECT_FALSE(visible);
-}
-
-// Test that a flash update causes the update UI to show in the system menu.
-IN_PROC_BROWSER_TEST_F(SystemTrayClientTest, FlashUpdateTrayIcon) {
-  // The tray icon is removed in UnifiedSystemTray.
-  // TODO(tetsui): Remove the test after UnifiedSystemTray launch.
-  // https://crbug.com/847104
-  if (ash::features::IsSystemTrayUnifiedEnabled())
-    return;
-
-  ash::mojom::SystemTrayTestApiAsyncWaiter wait_for(tray_test_api_.get());
-
-  // When no update is pending, the icon isn't visible.
-  bool visible = false;
-  wait_for.IsTrayViewVisible(ash::VIEW_ID_TRAY_UPDATE_ICON, &visible);
-  EXPECT_FALSE(visible);
-
-  // Simulate a Flash update. This sends a mojo message to ash.
-  SystemTrayClient::Get()->SetFlashUpdateAvailable();
-  content::RunAllPendingInMessageLoop();
-
-  // Tray icon is now visible.
-  wait_for.IsTrayViewVisible(ash::VIEW_ID_TRAY_UPDATE_ICON, &visible);
-  EXPECT_TRUE(visible);
-}
-
 using SystemTrayClientEnterpriseTest = policy::DevicePolicyCrosBrowserTest;
 
 IN_PROC_BROWSER_TEST_F(SystemTrayClientEnterpriseTest, TrayEnterprise) {
diff --git a/chrome/browser/ui/ash/system_tray_tray_cast_browsertest_media_router_chromeos.cc b/chrome/browser/ui/ash/system_tray_tray_cast_browsertest_media_router_chromeos.cc
index 1def23f..bfe5670 100644
--- a/chrome/browser/ui/ash/system_tray_tray_cast_browsertest_media_router_chromeos.cc
+++ b/chrome/browser/ui/ash/system_tray_tray_cast_browsertest_media_router_chromeos.cc
@@ -5,7 +5,6 @@
 #include <memory>
 #include <vector>
 
-#include "ash/public/cpp/ash_features.h"
 #include "ash/public/cpp/ash_view_ids.h"
 #include "ash/public/interfaces/ash_message_center_controller.mojom.h"
 #include "ash/public/interfaces/constants.mojom.h"
@@ -64,39 +63,19 @@
   bool IsTrayVisible() { return IsViewDrawn(ash::VIEW_ID_CAST_MAIN_VIEW); }
 
   bool IsCastingNotificationVisible() {
-    ash::mojom::SystemTrayTestApiAsyncWaiter wait_for(tray_test_api_.get());
-    if (ash::features::IsSystemTrayUnifiedEnabled())
-      return !GetNotificationString().empty();
-    else
-      return IsViewDrawn(ash::VIEW_ID_CAST_CAST_VIEW);
-  }
-
-  bool IsTraySelectViewVisible() {
-    // TODO(tetsui): Remove this method because in UnifiedSystemTray we don't
-    // have distinction between select view and cast view.
-    if (ash::features::IsSystemTrayUnifiedEnabled())
-      return IsTrayVisible();
-    ash::mojom::SystemTrayTestApiAsyncWaiter wait_for(tray_test_api_.get());
-    return IsViewDrawn(ash::VIEW_ID_CAST_SELECT_VIEW);
+    return !GetNotificationString().empty();
   }
 
   base::string16 GetNotificationString() {
-    if (ash::features::IsSystemTrayUnifiedEnabled()) {
-      ash::mojom::AshMessageCenterControllerAsyncWaiter wait_for(
-          ash_message_center_controller_.get());
-      std::vector<message_center::Notification> notifications;
-      wait_for.GetActiveNotifications(&notifications);
-      for (const auto& notification : notifications) {
-        if (notification.id() == kNotificationId)
-          return notification.title();
-      }
-      return base::string16();
-    } else {
-      base::string16 result;
-      ash::mojom::SystemTrayTestApiAsyncWaiter wait_for(tray_test_api_.get());
-      wait_for.GetBubbleLabelText(ash::VIEW_ID_CAST_CAST_VIEW_LABEL, &result);
-      return result;
+    ash::mojom::AshMessageCenterControllerAsyncWaiter wait_for(
+        ash_message_center_controller_.get());
+    std::vector<message_center::Notification> notifications;
+    wait_for.GetActiveNotifications(&notifications);
+    for (const auto& notification : notifications) {
+      if (notification.id() == kNotificationId)
+        return notification.title();
     }
+    return base::string16();
   }
 
   media_router::MediaSinksObserver* media_sinks_observer() const {
@@ -189,7 +168,6 @@
   media_sinks_observer()->OnSinksUpdated(two_sinks, std::vector<url::Origin>());
   content::RunAllPendingInMessageLoop();
   EXPECT_TRUE(IsTrayVisible());
-  EXPECT_TRUE(IsTraySelectViewVisible());
 
   // And if all of the sinks go away, it should be hidden again.
   media_sinks_observer()->OnSinksUpdated(zero_sinks,
diff --git a/chrome/browser/ui/autofill/local_card_migration_dialog_controller_impl.cc b/chrome/browser/ui/autofill/local_card_migration_dialog_controller_impl.cc
index f05a879..8506c2b 100644
--- a/chrome/browser/ui/autofill/local_card_migration_dialog_controller_impl.cc
+++ b/chrome/browser/ui/autofill/local_card_migration_dialog_controller_impl.cc
@@ -108,13 +108,12 @@
 void LocalCardMigrationDialogControllerImpl::OnViewCardsButtonClicked() {
   // TODO(crbug.com/867194): Add metrics.
   constexpr int kPaymentsProfileUserIndex = 0;
-  web_contents_->OpenURL(content::OpenURLParams(
-      payments::GetManageInstrumentsUrl(kPaymentsProfileUserIndex),
-      content::Referrer(), WindowOpenDisposition::NEW_FOREGROUND_TAB,
-      ui::PAGE_TRANSITION_LINK, /*is_renderer_initiated=*/false));
+  OpenUrl(payments::GetManageInstrumentsUrl(kPaymentsProfileUserIndex));
 }
 
-void LocalCardMigrationDialogControllerImpl::OnLegalMessageLinkClicked() {
+void LocalCardMigrationDialogControllerImpl::OnLegalMessageLinkClicked(
+    const GURL& url) {
+  OpenUrl(url);
   AutofillMetrics::LogLocalCardMigrationDialogUserInteractionMetric(
       dialog_is_visible_duration_timer_.Elapsed(), 0,
       migratable_credit_cards_.size(),
@@ -126,4 +125,10 @@
     local_card_migration_dialog_ = nullptr;
 }
 
+void LocalCardMigrationDialogControllerImpl::OpenUrl(const GURL& url) {
+  web_contents_->OpenURL(content::OpenURLParams(
+      url, content::Referrer(), WindowOpenDisposition::NEW_FOREGROUND_TAB,
+      ui::PAGE_TRANSITION_LINK, false));
+}
+
 }  // namespace autofill
diff --git a/chrome/browser/ui/autofill/local_card_migration_dialog_controller_impl.h b/chrome/browser/ui/autofill/local_card_migration_dialog_controller_impl.h
index cbf6e1d7..e432345 100644
--- a/chrome/browser/ui/autofill/local_card_migration_dialog_controller_impl.h
+++ b/chrome/browser/ui/autofill/local_card_migration_dialog_controller_impl.h
@@ -42,7 +42,7 @@
       const std::vector<std::string>& selected_cards_guids) override;
   void OnCancelButtonClicked() override;
   void OnViewCardsButtonClicked() override;
-  void OnLegalMessageLinkClicked() override;
+  void OnLegalMessageLinkClicked(const GURL& url) override;
   void OnDialogClosed() override;
 
  protected:
@@ -53,6 +53,8 @@
   friend class content::WebContentsUserData<
       LocalCardMigrationDialogControllerImpl>;
 
+  void OpenUrl(const GURL& url);
+
   content::WebContents* web_contents_;
 
   LocalCardMigrationDialog* local_card_migration_dialog_;
diff --git a/chrome/browser/ui/browser_dialogs.h b/chrome/browser/ui/browser_dialogs.h
index f68bd5a7..2698a18 100644
--- a/chrome/browser/ui/browser_dialogs.h
+++ b/chrome/browser/ui/browser_dialogs.h
@@ -281,6 +281,7 @@
   ARC_DATA_REMOVAL_CONFIRMATION = 88,
   CROSTINI_UPGRADE = 89,
   HATS_BUBBLE = 90,
+  CROSTINI_APP_RESTART = 91,
   MAX_VALUE
 };
 
diff --git a/chrome/browser/ui/signin_view_controller.cc b/chrome/browser/ui/signin_view_controller.cc
index 81ca9ea9..9324b5d0 100644
--- a/chrome/browser/ui/signin_view_controller.cc
+++ b/chrome/browser/ui/signin_view_controller.cc
@@ -11,7 +11,7 @@
 #include "chrome/browser/signin/account_consistency_mode_manager.h"
 #include "chrome/browser/signin/account_tracker_service_factory.h"
 #include "chrome/browser/signin/dice_tab_helper.h"
-#include "chrome/browser/signin/signin_manager_factory.h"
+#include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/signin/signin_promo.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_dialogs.h"
@@ -22,9 +22,9 @@
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/webui_url_constants.h"
 #include "components/signin/core/browser/profile_management_switches.h"
-#include "components/signin/core/browser/signin_manager.h"
 #include "content/public/browser/web_contents.h"
 #include "google_apis/gaia/gaia_urls.h"
+#include "services/identity/public/cpp/identity_manager.h"
 #include "url/url_constants.h"
 
 namespace {
@@ -129,8 +129,8 @@
     std::string email;
     if (GetSigninReasonFromMode(mode) ==
         signin_metrics::Reason::REASON_REAUTHENTICATION) {
-      SigninManagerBase* manager = SigninManagerFactory::GetForProfile(profile);
-      email = manager->GetAuthenticatedAccountInfo().email;
+      auto* manager = IdentityManagerFactory::GetForProfile(profile);
+      email = manager->GetPrimaryAccountInfo().email;
     }
     signin_metrics::PromoAction promo_action = GetPromoActionForNewAccount(
         AccountTrackerServiceFactory::GetForProfile(profile),
diff --git a/chrome/browser/ui/views/autofill/local_card_migration_dialog_view.cc b/chrome/browser/ui/views/autofill/local_card_migration_dialog_view.cc
index 73bc5f0..d2b24ec 100644
--- a/chrome/browser/ui/views/autofill/local_card_migration_dialog_view.cc
+++ b/chrome/browser/ui/views/autofill/local_card_migration_dialog_view.cc
@@ -128,8 +128,7 @@
     return;
 
   SetLayoutManager(std::make_unique<views::FillLayout>());
-  offer_view_ =
-      new LocalCardMigrationOfferView(controller_, this, web_contents_);
+  offer_view_ = new LocalCardMigrationOfferView(controller_, this);
   AddChildView(offer_view_);
 }
 
diff --git a/chrome/browser/ui/views/autofill/local_card_migration_offer_view.cc b/chrome/browser/ui/views/autofill/local_card_migration_offer_view.cc
index 9ab5fe9..67942d0 100644
--- a/chrome/browser/ui/views/autofill/local_card_migration_offer_view.cc
+++ b/chrome/browser/ui/views/autofill/local_card_migration_offer_view.cc
@@ -20,9 +20,6 @@
 #include "components/constrained_window/constrained_window_views.h"
 #include "components/grit/components_scaled_resources.h"
 #include "components/strings/grit/components_strings.h"
-#include "components/web_modal/web_contents_modal_dialog_host.h"
-#include "components/web_modal/web_contents_modal_dialog_manager.h"
-#include "components/web_modal/web_contents_modal_dialog_manager_delegate.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
@@ -57,9 +54,8 @@
 
 LocalCardMigrationOfferView::LocalCardMigrationOfferView(
     LocalCardMigrationDialogController* controller,
-    views::ButtonListener* listener,
-    content::WebContents* web_contents)
-    : controller_(controller), web_contents_(web_contents) {
+    views::ButtonListener* listener)
+    : controller_(controller) {
   Init(listener);
 }
 
@@ -72,10 +68,8 @@
   if (!controller_)
     return;
 
-  controller_->OnLegalMessageLinkClicked();
-  // TODO(crbug.com/867194): Should be controller's responsibility to open
-  // links.
-  legal_message_container_->OnLinkClicked(label, range, web_contents_);
+  controller_->OnLegalMessageLinkClicked(
+      legal_message_container_->GetUrlForLink(label, range));
 }
 
 void LocalCardMigrationOfferView::Init(views::ButtonListener* listener) {
diff --git a/chrome/browser/ui/views/autofill/local_card_migration_offer_view.h b/chrome/browser/ui/views/autofill/local_card_migration_offer_view.h
index 50a1098..beecb9a 100644
--- a/chrome/browser/ui/views/autofill/local_card_migration_offer_view.h
+++ b/chrome/browser/ui/views/autofill/local_card_migration_offer_view.h
@@ -10,10 +10,6 @@
 #include "ui/views/controls/button/button.h"
 #include "ui/views/controls/styled_label_listener.h"
 
-namespace content {
-class WebContents;
-}  // namespace content
-
 namespace autofill {
 
 class LocalCardMigrationDialogController;
@@ -27,8 +23,7 @@
                                     public views::StyledLabelListener {
  public:
   LocalCardMigrationOfferView(LocalCardMigrationDialogController* controller,
-                              views::ButtonListener* listener,
-                              content::WebContents* web_contents);
+                              views::ButtonListener* listener);
   ~LocalCardMigrationOfferView() override;
 
   // views::StyledLabelListener:
@@ -43,8 +38,6 @@
 
   LocalCardMigrationDialogController* controller_;
 
-  content::WebContents* web_contents_;
-
   views::View* card_list_view_ = nullptr;
 
   // The view that contains legal message and handles legal message links
diff --git a/chrome/browser/ui/views/autofill/save_card_offer_bubble_views.cc b/chrome/browser/ui/views/autofill/save_card_offer_bubble_views.cc
index 60f823a..9f5137ad 100644
--- a/chrome/browser/ui/views/autofill/save_card_offer_bubble_views.cc
+++ b/chrome/browser/ui/views/autofill/save_card_offer_bubble_views.cc
@@ -49,8 +49,8 @@
     const gfx::Point& anchor_point,
     content::WebContents* web_contents,
     SaveCardBubbleController* controller)
-    : SaveCardBubbleViews(anchor_view, anchor_point, web_contents, controller),
-      web_contents_(web_contents) {}
+    : SaveCardBubbleViews(anchor_view, anchor_point, web_contents, controller) {
+}
 
 views::View* SaveCardOfferBubbleViews::CreateFootnoteView() {
   if (controller()->GetLegalMessageLines().empty())
@@ -100,7 +100,8 @@
   if (!controller())
     return;
 
-  legal_message_view_->OnLinkClicked(label, range, web_contents_);
+  controller()->OnLegalMessageLinkClicked(
+      legal_message_view_->GetUrlForLink(label, range));
 }
 
 void SaveCardOfferBubbleViews::ContentsChanged(
diff --git a/chrome/browser/ui/views/autofill/save_card_offer_bubble_views.h b/chrome/browser/ui/views/autofill/save_card_offer_bubble_views.h
index fe71f2ec..56b21ff 100644
--- a/chrome/browser/ui/views/autofill/save_card_offer_bubble_views.h
+++ b/chrome/browser/ui/views/autofill/save_card_offer_bubble_views.h
@@ -51,8 +51,6 @@
 
   ~SaveCardOfferBubbleViews() override;
 
-  content::WebContents* web_contents_;
-
   views::Textfield* cardholder_name_textfield_ = nullptr;
 
   LegalMessageView* legal_message_view_ = nullptr;
diff --git a/chrome/browser/ui/views/autofill/view_util.cc b/chrome/browser/ui/views/autofill/view_util.cc
index fce5c7cf..9e6deec 100644
--- a/chrome/browser/ui/views/autofill/view_util.cc
+++ b/chrome/browser/ui/views/autofill/view_util.cc
@@ -158,9 +158,8 @@
   return label;
 }
 
-void LegalMessageView::OnLinkClicked(views::StyledLabel* label,
-                                     const gfx::Range& range,
-                                     content::WebContents* web_contents) {
+const GURL LegalMessageView::GetUrlForLink(views::StyledLabel* label,
+                                           const gfx::Range& range) {
   // Index of |label| within its parent's view hierarchy is the same as the
   // legal message line index. DCHECK this assumption to guard against future
   // layout changes.
@@ -171,15 +170,12 @@
       legal_message_lines_[label->parent()->GetIndexOf(label)].links();
   for (const LegalMessageLine::Link& link : links) {
     if (link.range == range) {
-      web_contents->OpenURL(content::OpenURLParams(
-          link.url, content::Referrer(),
-          WindowOpenDisposition::NEW_FOREGROUND_TAB, ui::PAGE_TRANSITION_LINK,
-          /*is_renderer_initiated=*/false));
-      return;
+      return link.url;
     }
   }
   // |range| was not found.
   NOTREACHED();
+  return GURL();
 }
 
 }  // namespace autofill
diff --git a/chrome/browser/ui/views/autofill/view_util.h b/chrome/browser/ui/views/autofill/view_util.h
index 25fe675..097dbe8 100644
--- a/chrome/browser/ui/views/autofill/view_util.h
+++ b/chrome/browser/ui/views/autofill/view_util.h
@@ -12,6 +12,7 @@
 #include "ui/gfx/color_palette.h"
 #include "ui/views/controls/styled_label_listener.h"
 #include "ui/views/view.h"
+#include "url/gurl.h"
 
 namespace views {
 class Label;
@@ -53,9 +54,7 @@
                             views::StyledLabelListener* listener);
   ~LegalMessageView() override;
 
-  void OnLinkClicked(views::StyledLabel* label,
-                     const gfx::Range& range,
-                     content::WebContents* web_contents);
+  const GURL GetUrlForLink(views::StyledLabel* label, const gfx::Range& range);
 
  private:
   std::unique_ptr<views::StyledLabel> CreateLegalMessageLineLabel(
diff --git a/chrome/browser/ui/views/crostini/crostini_app_restart_view.cc b/chrome/browser/ui/views/crostini/crostini_app_restart_view.cc
new file mode 100644
index 0000000..f78f613
--- /dev/null
+++ b/chrome/browser/ui/views/crostini/crostini_app_restart_view.cc
@@ -0,0 +1,105 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/views/crostini/crostini_app_restart_view.h"
+
+#include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
+#include "chrome/browser/ui/browser_dialogs.h"
+#include "chrome/browser/ui/views/chrome_layout_provider.h"
+#include "services/ws/public/cpp/property_type_converters.h"
+#include "services/ws/public/mojom/window_manager.mojom.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/ui_base_features.h"
+#include "ui/chromeos/devicetype_utils.h"
+#include "ui/display/screen.h"
+#include "ui/strings/grit/ui_strings.h"
+#include "ui/views/controls/label.h"
+#include "ui/views/layout/box_layout.h"
+#include "ui/views/layout/layout_provider.h"
+
+namespace {
+
+gfx::NativeWindow GetNativeWindowFromDisplayId(int64_t display_id) {
+  display::Screen* screen = display::Screen::GetScreen();
+  display::Display display;
+  screen->GetDisplayWithDisplayId(display_id, &display);
+  return screen->GetWindowAtScreenPoint(display.bounds().origin());
+}
+
+}  // namespace
+
+// static
+void CrostiniAppRestartView::Show(const ash::ShelfID& id, int64_t display_id) {
+  CrostiniAppRestartView* view = new CrostiniAppRestartView(id, display_id);
+  if (features::IsUsingWindowService()) {
+    // TODO(mash): Simplify specifying |display_id| via CreateDialogWidget, etc.
+    views::Widget* widget = new views::Widget;
+    views::Widget::InitParams params =
+        views::DialogDelegate::GetDialogWidgetInitParams(view, nullptr, nullptr,
+                                                         gfx::Rect());
+    params.mus_properties[ws::mojom::WindowManager::kDisplayId_InitProperty] =
+        mojo::ConvertTo<std::vector<uint8_t>>(display_id);
+    widget->Init(params);
+  } else {
+    // TODO(timzheng): Remove this after single process mash is enabled.
+    views::DialogDelegate::CreateDialogWidget(
+        view, GetNativeWindowFromDisplayId(display_id), nullptr);
+  }
+  view->GetWidget()->Show();
+  chrome::RecordDialogCreation(chrome::DialogIdentifier::CROSTINI_APP_RESTART);
+}
+
+int CrostiniAppRestartView::GetDialogButtons() const {
+  return ui::DIALOG_BUTTON_CANCEL | ui::DIALOG_BUTTON_OK;
+}
+
+base::string16 CrostiniAppRestartView::GetDialogButtonLabel(
+    ui::DialogButton button) const {
+  if (button == ui::DIALOG_BUTTON_OK)
+    return l10n_util::GetStringUTF16(IDS_CROSTINI_APP_RESTART_BUTTON);
+  DCHECK_EQ(button, ui::DIALOG_BUTTON_CANCEL);
+  return l10n_util::GetStringUTF16(IDS_CROSTINI_NOT_NOW_BUTTON);
+}
+
+bool CrostiniAppRestartView::ShouldShowCloseButton() const {
+  return false;
+}
+
+bool CrostiniAppRestartView::Accept() {
+  ChromeLauncherController::instance()
+      ->crostini_app_window_shelf_controller()
+      ->Restart(id_, display_id_);
+  return true;  // Should close the dialog
+}
+
+gfx::Size CrostiniAppRestartView::CalculatePreferredSize() const {
+  const int dialog_width = ChromeLayoutProvider::Get()->GetDistanceMetric(
+                               DISTANCE_MODAL_DIALOG_PREFERRED_WIDTH) -
+                           margins().width();
+  return gfx::Size(dialog_width, GetHeightForWidth(dialog_width));
+}
+
+CrostiniAppRestartView::CrostiniAppRestartView(const ash::ShelfID& id,
+                                               int64_t display_id)
+    : id_(id), display_id_(display_id) {
+  views::LayoutProvider* provider = views::LayoutProvider::Get();
+  SetLayoutManager(std::make_unique<views::BoxLayout>(
+      views::BoxLayout::kVertical,
+      provider->GetInsetsMetric(views::InsetsMetric::INSETS_DIALOG),
+      provider->GetDistanceMetric(views::DISTANCE_RELATED_CONTROL_VERTICAL)));
+  set_margins(provider->GetDialogInsetsForContentType(
+      views::DialogContentType::TEXT, views::DialogContentType::TEXT));
+
+  const base::string16 device_type = ui::GetChromeOSDeviceName();
+  const base::string16 message =
+      l10n_util::GetStringFUTF16(IDS_CROSTINI_APP_RESTART_BODY, device_type);
+  views::Label* message_label = new views::Label(message);
+  message_label->SetMultiLine(true);
+  message_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
+  AddChildView(message_label);
+}
+
+ui::ModalType CrostiniAppRestartView::GetModalType() const {
+  return ui::MODAL_TYPE_SYSTEM;
+}
diff --git a/chrome/browser/ui/views/crostini/crostini_app_restart_view.h b/chrome/browser/ui/views/crostini/crostini_app_restart_view.h
new file mode 100644
index 0000000..394b0e2e
--- /dev/null
+++ b/chrome/browser/ui/views/crostini/crostini_app_restart_view.h
@@ -0,0 +1,35 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_VIEWS_CROSTINI_CROSTINI_APP_RESTART_VIEW_H_
+#define CHROME_BROWSER_UI_VIEWS_CROSTINI_CROSTINI_APP_RESTART_VIEW_H_
+
+#include "ash/public/cpp/shelf_types.h"
+#include "ui/views/window/dialog_delegate.h"
+
+// Provide user a choice to restart the app after display density change.
+class CrostiniAppRestartView : public views::DialogDelegateView {
+ public:
+  // Create and show a new dialog.
+  static void Show(const ash::ShelfID& id, int64_t display_id);
+
+  // views::DialogDelegateView:
+  int GetDialogButtons() const override;
+  base::string16 GetDialogButtonLabel(ui::DialogButton button) const override;
+  bool ShouldShowCloseButton() const override;
+  bool Accept() override;
+  gfx::Size CalculatePreferredSize() const override;
+  ui::ModalType GetModalType() const override;
+
+ private:
+  CrostiniAppRestartView(const ash::ShelfID& id, int64_t display_id);
+  ~CrostiniAppRestartView() override = default;
+
+  ash::ShelfID id_;
+  int64_t display_id_;
+
+  DISALLOW_COPY_AND_ASSIGN(CrostiniAppRestartView);
+};
+
+#endif  // CHROME_BROWSER_UI_VIEWS_CROSTINI_CROSTINI_APP_RESTART_VIEW_H_
diff --git a/chrome/browser/ui/views/frame/browser_frame.cc b/chrome/browser/ui/views/frame/browser_frame.cc
index 490f208..3691441b 100644
--- a/chrome/browser/ui/views/frame/browser_frame.cc
+++ b/chrome/browser/ui/views/frame/browser_frame.cc
@@ -253,7 +253,7 @@
   menu_runner_.reset();
 }
 
-void BrowserFrame::OnMdModeChanged() {
+void BrowserFrame::OnTouchUiChanged() {
   client_view()->InvalidateLayout();
   non_client_view()->InvalidateLayout();
   GetRootView()->Layout();
diff --git a/chrome/browser/ui/views/frame/browser_frame.h b/chrome/browser/ui/views/frame/browser_frame.h
index c2728ed5..7281e86 100644
--- a/chrome/browser/ui/views/frame/browser_frame.h
+++ b/chrome/browser/ui/views/frame/browser_frame.h
@@ -125,7 +125,7 @@
 
  protected:
   // ui::MaterialDesignControllerObserver:
-  void OnMdModeChanged() override;
+  void OnTouchUiChanged() override;
 
  private:
   // Callback for MenuRunner.
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 d042ab2..9c1ec40 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
@@ -409,7 +409,7 @@
   AnimationEnded(animation);
 }
 
-void IconLabelBubbleView::OnMdModeChanged() {
+void IconLabelBubbleView::OnTouchUiChanged() {
   UpdateBorder();
 
   // PreferredSizeChanged() incurs an expensive layout of the location bar, so
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 d4c8f72..cc256bd8 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
@@ -154,7 +154,7 @@
   void AnimationCanceled(const gfx::Animation* animation) override;
 
   // ui::MaterialDesignControllerObserver:
-  void OnMdModeChanged() override;
+  void OnTouchUiChanged() override;
 
   const gfx::FontList& font_list() const { return label_->font_list(); }
 
diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.cc b/chrome/browser/ui/views/location_bar/location_bar_view.cc
index ed48a91..c26a4bf9 100644
--- a/chrome/browser/ui/views/location_bar/location_bar_view.cc
+++ b/chrome/browser/ui/views/location_bar/location_bar_view.cc
@@ -1297,7 +1297,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 // LocationBarView, private ui::MaterialDesignControllerObserver implementation:
 
-void LocationBarView::OnMdModeChanged() {
+void LocationBarView::OnTouchUiChanged() {
   const gfx::FontList& font_list = views::style::GetFont(
       CONTEXT_OMNIBOX_PRIMARY, views::style::STYLE_PRIMARY);
   location_icon_view_->SetFontList(font_list);
diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.h b/chrome/browser/ui/views/location_bar/location_bar_view.h
index ee22dbb..f198fd8 100644
--- a/chrome/browser/ui/views/location_bar/location_bar_view.h
+++ b/chrome/browser/ui/views/location_bar/location_bar_view.h
@@ -391,7 +391,7 @@
   void SetFocusAndSelection(bool select_all) override;
 
   // ui::MaterialDesignControllerObserver:
-  void OnMdModeChanged() override;
+  void OnTouchUiChanged() override;
 
   // The Browser this LocationBarView is in.  Note that at least
   // chromeos::SimpleWebViewDialog uses a LocationBarView outside any browser
diff --git a/chrome/browser/ui/views/media_router/cast_dialog_sink_button.cc b/chrome/browser/ui/views/media_router/cast_dialog_sink_button.cc
index 9972369..61dc3e6 100644
--- a/chrome/browser/ui/views/media_router/cast_dialog_sink_button.cc
+++ b/chrome/browser/ui/views/media_router/cast_dialog_sink_button.cc
@@ -194,15 +194,17 @@
 
 void CastDialogSinkButton::OverrideStatusText(
     const base::string16& status_text) {
-  if (!saved_status_text_) {
-    saved_status_text_ = subtitle()->text();
+  if (subtitle()) {
+    if (!saved_status_text_)
+      saved_status_text_ = subtitle()->text();
+    subtitle()->SetText(status_text);
   }
-  subtitle()->SetText(status_text);
 }
 
 void CastDialogSinkButton::RestoreStatusText() {
   if (saved_status_text_) {
-    subtitle()->SetText(*saved_status_text_);
+    if (subtitle())
+      subtitle()->SetText(*saved_status_text_);
     saved_status_text_.reset();
   }
 }
diff --git a/chrome/browser/ui/views/page_action/page_action_icon_view.cc b/chrome/browser/ui/views/page_action/page_action_icon_view.cc
index 1fc2cf4..b03d190 100644
--- a/chrome/browser/ui/views/page_action/page_action_icon_view.cc
+++ b/chrome/browser/ui/views/page_action/page_action_icon_view.cc
@@ -228,10 +228,10 @@
   IconLabelBubbleView::OnBoundsChanged(previous_bounds);
 }
 
-void PageActionIconView::OnMdModeChanged() {
+void PageActionIconView::OnTouchUiChanged() {
   icon_size_ = GetLayoutConstant(LOCATION_BAR_ICON_SIZE);
   UpdateIconImage();
-  IconLabelBubbleView::OnMdModeChanged();
+  IconLabelBubbleView::OnTouchUiChanged();
 }
 
 void PageActionIconView::UpdateBorder() {
diff --git a/chrome/browser/ui/views/page_action/page_action_icon_view.h b/chrome/browser/ui/views/page_action/page_action_icon_view.h
index 897614d..cdc7318 100644
--- a/chrome/browser/ui/views/page_action/page_action_icon_view.h
+++ b/chrome/browser/ui/views/page_action/page_action_icon_view.h
@@ -123,7 +123,7 @@
 
   // IconLabelBubbleView:
   void OnBoundsChanged(const gfx::Rect& previous_bounds) override;
-  void OnMdModeChanged() override;
+  void OnTouchUiChanged() override;
   void UpdateBorder() override;
 
   // Updates the icon image after some state has changed.
diff --git a/chrome/browser/ui/views/profiles/avatar_toolbar_button.cc b/chrome/browser/ui/views/profiles/avatar_toolbar_button.cc
index cd3859a4..b7b4bb6 100644
--- a/chrome/browser/ui/views/profiles/avatar_toolbar_button.cc
+++ b/chrome/browser/ui/views/profiles/avatar_toolbar_button.cc
@@ -219,7 +219,7 @@
   UpdateIcon();
 }
 
-void AvatarToolbarButton::OnMdModeChanged() {
+void AvatarToolbarButton::OnTouchUiChanged() {
   SetInsets();
   PreferredSizeChanged();
 }
diff --git a/chrome/browser/ui/views/profiles/avatar_toolbar_button.h b/chrome/browser/ui/views/profiles/avatar_toolbar_button.h
index 56d13d1..3837f7a 100644
--- a/chrome/browser/ui/views/profiles/avatar_toolbar_button.h
+++ b/chrome/browser/ui/views/profiles/avatar_toolbar_button.h
@@ -72,7 +72,7 @@
   void OnAccountRemoved(const AccountInfo& info) override;
 
   // ui::MaterialDesignControllerObserver:
-  void OnMdModeChanged() override;
+  void OnTouchUiChanged() override;
 
   bool IsIncognito() const;
   bool IsIncognitoCounterActive() const;
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
index f1ce561..cd3ab11 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
@@ -77,6 +77,7 @@
 #include "chrome/browser/ui/views/frame/immersive_mode_controller_ash.h"
 #include "ui/aura/client/screen_position_client.h"
 #include "ui/aura/test/event_generator_delegate_aura.h"
+#include "ui/aura/test/mus/change_completion_waiter.h"
 #include "ui/aura/window_event_dispatcher.h"
 #include "ui/base/ui_base_features.h"
 #include "ui/display/manager/display_manager.h"
@@ -255,10 +256,6 @@
   InProcessBrowserTest::SetUp();
 }
 
-void TabDragControllerTest::SetUpCommandLine(base::CommandLine* command_line) {
-  command_line->AppendSwitch(switches::kDisableResizeLock);
-}
-
 namespace {
 
 enum InputSource {
@@ -2006,6 +2003,10 @@
   display::Screen* screen = display::Screen::GetScreen();
   Display second_display = ui_test_utils::GetSecondaryDisplay(screen);
   browser2->window()->SetBounds(second_display.work_area());
+  // In Mash, the display change as the result of the bounds change is processed
+  // asynchronously in the window server, it should wait for those changes to
+  // complete.
+  aura::test::WaitForAllChangesToComplete();
   EXPECT_EQ(
       second_display.id(),
       screen->GetDisplayNearestWindow(browser2->window()->GetNativeWindow())
@@ -2112,6 +2113,8 @@
   browser()->window()->SetBounds(work_area);
   work_area.set_x(work_area.right());
   browser2->window()->SetBounds(work_area);
+  // Wait for the display changes. See the ealier comments for the details.
+  aura::test::WaitForAllChangesToComplete();
   EXPECT_EQ(
       second_display.id(),
       screen->GetDisplayNearestWindow(browser()->window()->GetNativeWindow())
@@ -2236,6 +2239,8 @@
   display::Screen* screen = display::Screen::GetScreen();
   const std::pair<Display, Display> displays = GetDisplays(screen);
   browser2->window()->SetBounds(displays.second.work_area());
+  // Wait for the display changes. See the ealier comments for the details.
+  aura::test::WaitForAllChangesToComplete();
   EXPECT_EQ(
       displays.second.id(),
       screen->GetDisplayNearestWindow(browser2->window()->GetNativeWindow())
@@ -2530,6 +2535,8 @@
           .id());
 
   browser()->window()->SetBounds(displays.second.work_area());
+  // Wait for the display changes. See the ealier comments for the details.
+  aura::test::WaitForAllChangesToComplete();
   EXPECT_EQ(
       displays.second.id(),
       screen->GetDisplayNearestWindow(browser()->window()->GetNativeWindow())
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.h b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.h
index 577fa27..9b9b9d2 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.h
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.h
@@ -52,7 +52,6 @@
 
   // InProcessBrowserTest:
   void SetUp() override;
-  void SetUpCommandLine(base::CommandLine* command_line) override;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(TabDragControllerTest);
diff --git a/chrome/browser/ui/views/tabs/tab_strip.cc b/chrome/browser/ui/views/tabs/tab_strip.cc
index e084b78..3f09fbcd 100644
--- a/chrome/browser/ui/views/tabs/tab_strip.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip.cc
@@ -2610,7 +2610,7 @@
   return this;
 }
 
-void TabStrip::OnMdModeChanged() {
+void TabStrip::OnTouchUiChanged() {
   UpdateNewTabButtonBorder();
   new_tab_button_bounds_.set_size(new_tab_button_->GetPreferredSize());
   new_tab_button_->SetBoundsRect(new_tab_button_bounds_);
diff --git a/chrome/browser/ui/views/tabs/tab_strip.h b/chrome/browser/ui/views/tabs/tab_strip.h
index 3b4f5c8..e10ac2b2 100644
--- a/chrome/browser/ui/views/tabs/tab_strip.h
+++ b/chrome/browser/ui/views/tabs/tab_strip.h
@@ -580,7 +580,7 @@
   views::View* TargetForRect(views::View* root, const gfx::Rect& rect) override;
 
   // ui::MaterialDesignControllerObserver:
-  void OnMdModeChanged() override;
+  void OnTouchUiChanged() override;
 
   // -- Member Variables ------------------------------------------------------
 
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 c82ab906..ab35105 100644
--- a/chrome/browser/ui/views/toolbar/browser_app_menu_button.cc
+++ b/chrome/browser/ui/views/toolbar/browser_app_menu_button.cc
@@ -238,7 +238,7 @@
   InvalidateLayout();
 }
 
-void BrowserAppMenuButton::OnMdModeChanged() {
+void BrowserAppMenuButton::OnTouchUiChanged() {
   UpdateIcon(false);
   PreferredSizeChanged();
 }
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 1a0bed5..9a0b823 100644
--- a/chrome/browser/ui/views/toolbar/browser_app_menu_button.h
+++ b/chrome/browser/ui/views/toolbar/browser_app_menu_button.h
@@ -74,7 +74,7 @@
 
  protected:
   // ui::MaterialDesignControllerObserver:
-  void OnMdModeChanged() override;
+  void OnTouchUiChanged() override;
 
  private:
   // Animates the icon if possible. The icon will not animate if the severity
diff --git a/chrome/browser/ui/views/toolbar/toolbar_view.cc b/chrome/browser/ui/views/toolbar/toolbar_view.cc
index c39a6b6..20a136c 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_view.cc
+++ b/chrome/browser/ui/views/toolbar/toolbar_view.cc
@@ -664,7 +664,7 @@
 }
 
 // ui::MaterialDesignControllerObserver:
-void ToolbarView::OnMdModeChanged() {
+void ToolbarView::OnTouchUiChanged() {
   if (is_display_mode_normal()) {
     LoadImages();
     PreferredSizeChanged();
diff --git a/chrome/browser/ui/views/toolbar/toolbar_view.h b/chrome/browser/ui/views/toolbar/toolbar_view.h
index e98e424..56abed7 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_view.h
+++ b/chrome/browser/ui/views/toolbar/toolbar_view.h
@@ -175,7 +175,7 @@
   bool SetPaneFocusAndFocusDefault() override;
 
   // ui::MaterialDesignControllerObserver:
-  void OnMdModeChanged() override;
+  void OnTouchUiChanged() override;
 
   bool is_display_mode_normal() const {
     return display_mode_ == DISPLAYMODE_NORMAL;
diff --git a/chrome/browser/ui/views/webauthn/authenticator_request_dialog_view.cc b/chrome/browser/ui/views/webauthn/authenticator_request_dialog_view.cc
index dc42cad..11b47ed 100644
--- a/chrome/browser/ui/views/webauthn/authenticator_request_dialog_view.cc
+++ b/chrome/browser/ui/views/webauthn/authenticator_request_dialog_view.cc
@@ -123,6 +123,12 @@
   // invoked straight after, which destroys child views. views::View subclasses
   // shouldn't be doing anything interesting in their destructors, so it should
   // be okay to destroy the |sheet_| immediately after this line.
+  //
+  // However, as AuthenticatorRequestDialogModel is owned by |this|, and
+  // ObservableAuthenticatorList is owned by AuthenticatorRequestDialogModel,
+  // destroy all view components that might own models observing the list prior
+  // to destroying AuthenticatorRequestDialogModel.
+  RemoveAllChildViews(true /* delete_children */);
 }
 
 gfx::Size AuthenticatorRequestDialogView::CalculatePreferredSize() const {
diff --git a/chrome/browser/ui/views/webauthn/ble_device_selection_sheet_view.cc b/chrome/browser/ui/views/webauthn/ble_device_selection_sheet_view.cc
new file mode 100644
index 0000000..34d6152
--- /dev/null
+++ b/chrome/browser/ui/views/webauthn/ble_device_selection_sheet_view.cc
@@ -0,0 +1,52 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/views/webauthn/ble_device_selection_sheet_view.h"
+
+#include <utility>
+
+#include "chrome/browser/ui/views/webauthn/hover_list_view.h"
+#include "chrome/grit/generated_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/gfx/geometry/insets.h"
+#include "ui/views/controls/label.h"
+#include "ui/views/layout/box_layout.h"
+#include "ui/views/layout/layout_provider.h"
+#include "ui/views/style/typography.h"
+#include "ui/views/view.h"
+
+BleDeviceSelectionSheetView::BleDeviceSelectionSheetView(
+    std::unique_ptr<AuthenticatorBleDeviceSelectionSheetModel> model)
+    : AuthenticatorRequestSheetView(std::move(model)) {}
+
+BleDeviceSelectionSheetView::~BleDeviceSelectionSheetView() = default;
+
+std::unique_ptr<views::View>
+BleDeviceSelectionSheetView::BuildStepSpecificContent() {
+  auto device_selection_view = std::make_unique<views::View>();
+  device_selection_view->SetLayoutManager(std::make_unique<views::BoxLayout>(
+      views::BoxLayout::kVertical, gfx::Insets(),
+      views::LayoutProvider::Get()->GetDistanceMetric(
+          views::DISTANCE_RELATED_CONTROL_VERTICAL)));
+  auto device_list_view =
+      std::make_unique<HoverListView>(std::make_unique<BleDeviceHoverListModel>(
+          &model()->dialog_model()->saved_authenticators(), this));
+
+  auto bottom_suggestion_label = std::make_unique<views::Label>(
+      l10n_util::GetStringUTF16(
+          IDS_WEBAUTHN_BLE_DEVICE_SELECTION_REMINDER_LABEL),
+      views::style::CONTEXT_LABEL, views::style::STYLE_DISABLED);
+  bottom_suggestion_label->SetMultiLine(true);
+  bottom_suggestion_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
+
+  device_selection_view->AddChildView(device_list_view.release());
+  device_selection_view->AddChildView(bottom_suggestion_label.release());
+
+  return device_selection_view;
+}
+
+void BleDeviceSelectionSheetView::OnItemSelected(
+    base::StringPiece authenticator_id) {
+  model()->dialog_model()->InitiatePairingDevice(authenticator_id);
+}
diff --git a/chrome/browser/ui/views/webauthn/ble_device_selection_sheet_view.h b/chrome/browser/ui/views/webauthn/ble_device_selection_sheet_view.h
new file mode 100644
index 0000000..35a4450
--- /dev/null
+++ b/chrome/browser/ui/views/webauthn/ble_device_selection_sheet_view.h
@@ -0,0 +1,40 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_VIEWS_WEBAUTHN_BLE_DEVICE_SELECTION_SHEET_VIEW_H_
+#define CHROME_BROWSER_UI_VIEWS_WEBAUTHN_BLE_DEVICE_SELECTION_SHEET_VIEW_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "chrome/browser/ui/views/webauthn/authenticator_request_sheet_view.h"
+#include "chrome/browser/ui/webauthn/ble_device_hover_list_model.h"
+#include "chrome/browser/ui/webauthn/sheet_models.h"
+
+// Represents a sheet in the Web Authentication request dialog that allows the
+// user to pick the Bluetooth security key to which they wish to connect to
+// in order to service the Web Authentication request.
+class BleDeviceSelectionSheetView : public AuthenticatorRequestSheetView,
+                                    public BleDeviceHoverListModel::Delegate {
+ public:
+  explicit BleDeviceSelectionSheetView(
+      std::unique_ptr<AuthenticatorBleDeviceSelectionSheetModel> model);
+  ~BleDeviceSelectionSheetView() override;
+
+ private:
+  AuthenticatorBleDeviceSelectionSheetModel* model() {
+    return static_cast<AuthenticatorBleDeviceSelectionSheetModel*>(
+        AuthenticatorRequestSheetView::model());
+  }
+
+  // AuthenticatorRequestSheetView:
+  std::unique_ptr<views::View> BuildStepSpecificContent() override;
+
+  // BleDeviceHoverListModel::Delegate:
+  void OnItemSelected(base::StringPiece authenticator_id) override;
+
+  DISALLOW_COPY_AND_ASSIGN(BleDeviceSelectionSheetView);
+};
+
+#endif  // CHROME_BROWSER_UI_VIEWS_WEBAUTHN_BLE_DEVICE_SELECTION_SHEET_VIEW_H_
diff --git a/chrome/browser/ui/views/webauthn/hover_list_view.cc b/chrome/browser/ui/views/webauthn/hover_list_view.cc
index fab615a..baf993a 100644
--- a/chrome/browser/ui/views/webauthn/hover_list_view.cc
+++ b/chrome/browser/ui/views/webauthn/hover_list_view.cc
@@ -103,12 +103,9 @@
       views::BoxLayout::kVertical, gfx::Insets(), 0));
   AddSeparatorAsChild(this);
 
-  for (size_t index = 0; index < model_->GetItemCount(); ++index) {
-    int item_tag = model_->GetItemTag(index);
-    if (model_->ShouldShowItemInView(item_tag)) {
-      AppendListItemView(*model_->GetItemIcon(item_tag),
-                         model_->GetItemText(item_tag), item_tag);
-    }
+  for (const auto item_tag : model_->GetItemTags()) {
+    AppendListItemView(model_->GetItemIcon(item_tag),
+                       model_->GetItemText(item_tag), item_tag);
   }
 
   if (tags_to_list_item_views_.empty() &&
@@ -119,7 +116,7 @@
 }
 
 HoverListView::~HoverListView() {
-  model_->RemoveObserver(this);
+  model_->RemoveObserver();
 }
 
 void HoverListView::AppendListItemView(const gfx::VectorIcon& icon,
@@ -139,38 +136,23 @@
 }
 
 void HoverListView::CreateAndAppendPlaceholderItem() {
-  const auto* placeholder_item_icon = model_->GetPlaceholderIcon();
-  DCHECK(placeholder_item_icon);
   auto placeholder_item = CreateHoverButtonForListItem(
-      kPlaceHolderItemTag, *placeholder_item_icon, model_->GetPlaceholderText(),
-      nullptr, true /* is_placeholder_item */);
+      kPlaceHolderItemTag, model_->GetPlaceholderIcon(),
+      model_->GetPlaceholderText(), nullptr, true /* is_placeholder_item */);
   AddChildView(placeholder_item.get());
   auto* separator = AddSeparatorAsChild(this);
   placeholder_list_item_view_.emplace(
       ListItemViews{placeholder_item.release(), separator});
 }
 
-void HoverListView::RemoveListItemView(ListItemViews list_item) {
-  DCHECK(Contains(list_item.item_view));
-  DCHECK(Contains(list_item.separator_view));
-  RemoveChildView(list_item.item_view);
-  RemoveChildView(list_item.separator_view);
-}
-
-void HoverListView::RequestFocus() {
-  if (!first_list_item_view_)
-    return;
-
-  first_list_item_view_->RequestFocus();
-}
-
-void HoverListView::OnListItemAdded(int item_tag) {
+void HoverListView::AddListItemView(int item_tag) {
+  CHECK(!base::ContainsKey(tags_to_list_item_views_, item_tag));
   if (placeholder_list_item_view_) {
     RemoveListItemView(*placeholder_list_item_view_);
     placeholder_list_item_view_.emplace();
   }
 
-  AppendListItemView(*model_->GetItemIcon(item_tag),
+  AppendListItemView(model_->GetItemIcon(item_tag),
                      model_->GetItemText(item_tag), item_tag);
 
   // TODO(hongjunchoi): The enclosing dialog may also need to be resized,
@@ -179,9 +161,10 @@
   Layout();
 }
 
-void HoverListView::OnListItemRemoved(int removed_item_tag) {
-  auto view_it = tags_to_list_item_views_.find(removed_item_tag);
-  CHECK(view_it != tags_to_list_item_views_.end());
+void HoverListView::RemoveListItemView(int item_tag) {
+  auto view_it = tags_to_list_item_views_.find(item_tag);
+  if (view_it == tags_to_list_item_views_.end())
+    return;
 
   auto* list_item_ptr = view_it->second.item_view;
   if (list_item_ptr == first_list_item_view_)
@@ -201,6 +184,37 @@
   Layout();
 }
 
+void HoverListView::RemoveListItemView(ListItemViews list_item) {
+  DCHECK(Contains(list_item.item_view));
+  DCHECK(Contains(list_item.separator_view));
+  RemoveChildView(list_item.item_view);
+  RemoveChildView(list_item.separator_view);
+}
+
+void HoverListView::RequestFocus() {
+  if (!first_list_item_view_)
+    return;
+
+  first_list_item_view_->RequestFocus();
+}
+
+void HoverListView::OnListItemAdded(int item_tag) {
+  AddListItemView(item_tag);
+}
+
+void HoverListView::OnListItemRemoved(int removed_item_tag) {
+  RemoveListItemView(removed_item_tag);
+}
+
+void HoverListView::OnListItemChanged(int changed_list_item_tag,
+                                      HoverListModel::ListItemChangeType type) {
+  if (type == HoverListModel::ListItemChangeType::kAddToViewComponent) {
+    AddListItemView(changed_list_item_tag);
+  } else {
+    RemoveListItemView(changed_list_item_tag);
+  }
+}
+
 void HoverListView::ButtonPressed(views::Button* sender,
                                   const ui::Event& event) {
   model_->OnListItemSelected(sender->tag());
diff --git a/chrome/browser/ui/views/webauthn/hover_list_view.h b/chrome/browser/ui/views/webauthn/hover_list_view.h
index 2404e66f..51bbae5 100644
--- a/chrome/browser/ui/views/webauthn/hover_list_view.h
+++ b/chrome/browser/ui/views/webauthn/hover_list_view.h
@@ -53,6 +53,8 @@
                           base::string16 item_text,
                           int item_tag);
   void CreateAndAppendPlaceholderItem();
+  void AddListItemView(int item_tag);
+  void RemoveListItemView(int item_tag);
   void RemoveListItemView(ListItemViews list_item);
 
   // views::View:
@@ -61,6 +63,8 @@
   // HoverListModel::Observer:
   void OnListItemAdded(int item_tag) override;
   void OnListItemRemoved(int removed_item_view_tag) override;
+  void OnListItemChanged(int changed_list_item_tag,
+                         HoverListModel::ListItemChangeType type) override;
 
   // views::ButtonListener:
   void ButtonPressed(views::Button* sender, const ui::Event& event) override;
diff --git a/chrome/browser/ui/views/webauthn/sheet_view_factory.cc b/chrome/browser/ui/views/webauthn/sheet_view_factory.cc
index 607e257d..9f4ac8b 100644
--- a/chrome/browser/ui/views/webauthn/sheet_view_factory.cc
+++ b/chrome/browser/ui/views/webauthn/sheet_view_factory.cc
@@ -8,6 +8,7 @@
 #include "chrome/browser/ui/views/webauthn/authenticator_ble_pin_entry_sheet_view.h"
 #include "chrome/browser/ui/views/webauthn/authenticator_request_sheet_view.h"
 #include "chrome/browser/ui/views/webauthn/authenticator_transport_selector_sheet_view.h"
+#include "chrome/browser/ui/views/webauthn/ble_device_selection_sheet_view.h"
 #include "chrome/browser/ui/webauthn/sheet_models.h"
 #include "chrome/browser/webauthn/authenticator_request_dialog_model.h"
 
@@ -93,7 +94,7 @@
               dialog_model));
       break;
     case Step::kBleDeviceSelection:
-      sheet_view = std::make_unique<AuthenticatorRequestSheetView>(
+      sheet_view = std::make_unique<BleDeviceSelectionSheetView>(
           std::make_unique<AuthenticatorBleDeviceSelectionSheetModel>(
               dialog_model));
       break;
diff --git a/chrome/browser/ui/webauthn/authenticator_dialog_browsertest.cc b/chrome/browser/ui/webauthn/authenticator_dialog_browsertest.cc
index 17a9bd0..e9621f6 100644
--- a/chrome/browser/ui/webauthn/authenticator_dialog_browsertest.cc
+++ b/chrome/browser/ui/webauthn/authenticator_dialog_browsertest.cc
@@ -69,12 +69,10 @@
       model->SetCurrentStep(
           AuthenticatorRequestDialogModel::Step::kBleDeviceSelection);
     } else if (name == "ble_pin_entry") {
-      model->SetSelectedAuthenticatorForTesting(
-          std::make_unique<AuthenticatorReference>(
-              "test_authenticator_id" /* authenticator_id */,
-              base::string16() /* authenticator_display_name */,
-              AuthenticatorTransport::kInternal,
-              false /* is_in_pairing_mode */));
+      model->SetSelectedAuthenticatorForTesting(AuthenticatorReference(
+          "test_authenticator_id" /* authenticator_id */,
+          base::string16() /* authenticator_display_name */,
+          AuthenticatorTransport::kInternal, false /* is_in_pairing_mode */));
       model->SetCurrentStep(
           AuthenticatorRequestDialogModel::Step::kBlePinEntry);
     } else if (name == "ble_verifying") {
diff --git a/chrome/browser/ui/webauthn/ble_device_hover_list_model.cc b/chrome/browser/ui/webauthn/ble_device_hover_list_model.cc
new file mode 100644
index 0000000..866b1856
--- /dev/null
+++ b/chrome/browser/ui/webauthn/ble_device_hover_list_model.cc
@@ -0,0 +1,142 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/webauthn/ble_device_hover_list_model.h"
+
+#include <algorithm>
+#include <iterator>
+#include <numeric>
+#include <utility>
+
+#include "chrome/browser/ui/webauthn/transport_utils.h"
+#include "chrome/browser/webauthn/authenticator_transport.h"
+#include "chrome/grit/generated_resources.h"
+#include "ui/base/l10n/l10n_util.h"
+
+namespace {
+
+const std::map<int, std::string>::const_iterator FindElementByValue(
+    const std::map<int, std::string>& item_map,
+    base::StringPiece value) {
+  return std::find_if(item_map.begin(), item_map.end(),
+                      [value](const auto& key_value_pair) {
+                        return key_value_pair.second == value;
+                      });
+}
+
+bool ShouldShowItemInView(const AuthenticatorReference& authenticator) {
+  return authenticator.is_in_pairing_mode() &&
+         authenticator.transport() ==
+             AuthenticatorTransport::kBluetoothLowEnergy;
+}
+
+}  // namespace
+
+BleDeviceHoverListModel::BleDeviceHoverListModel(
+    ObservableAuthenticatorList* authenticator_list,
+    Delegate* delegate)
+    : authenticator_list_(authenticator_list), delegate_(delegate) {
+  int tag_counter = 0;
+  for (const auto& authenticator : authenticator_list_->authenticator_list()) {
+    authenticator_tags_.emplace(++tag_counter,
+                                authenticator.authenticator_id());
+  }
+
+  authenticator_list_->SetObserver(this);
+}
+
+BleDeviceHoverListModel::~BleDeviceHoverListModel() {
+  authenticator_list_->RemoveObserver();
+}
+
+const AuthenticatorReference* BleDeviceHoverListModel::GetAuthenticator(
+    int tag) const {
+  auto it = authenticator_tags_.find(tag);
+  CHECK(it != authenticator_tags_.end());
+  return authenticator_list_->GetAuthenticator(it->second);
+}
+
+bool BleDeviceHoverListModel::ShouldShowPlaceholderForEmptyList() const {
+  return true;
+}
+
+base::string16 BleDeviceHoverListModel::GetPlaceholderText() const {
+  return l10n_util::GetStringUTF16(
+      IDS_WEBAUTHN_BLE_DEVICE_SELECTION_SEARCHING_LABEL);
+}
+
+const gfx::VectorIcon& BleDeviceHoverListModel::GetPlaceholderIcon() const {
+  return GetTransportVectorIcon(AuthenticatorTransport::kBluetoothLowEnergy);
+}
+
+base::string16 BleDeviceHoverListModel::GetItemText(int item_tag) const {
+  return GetAuthenticator(item_tag)->authenticator_display_name();
+}
+
+const gfx::VectorIcon& BleDeviceHoverListModel::GetItemIcon(
+    int item_tag) const {
+  return GetTransportVectorIcon(AuthenticatorTransport::kBluetoothLowEnergy);
+}
+
+std::vector<int> BleDeviceHoverListModel::GetItemTags() const {
+  std::vector<int> tag_list;
+  tag_list.reserve(authenticator_tags_.size());
+
+  for (const auto& item : authenticator_tags_) {
+    const auto* authenticator =
+        authenticator_list_->GetAuthenticator(item.second);
+    CHECK(authenticator);
+    if (ShouldShowItemInView(*authenticator)) {
+      tag_list.emplace_back(item.first);
+    }
+  }
+
+  return tag_list;
+}
+
+void BleDeviceHoverListModel::OnListItemSelected(int item_tag) {
+  auto authenticator_item = authenticator_tags_.find(item_tag);
+  CHECK(authenticator_item != authenticator_tags_.end());
+  delegate_->OnItemSelected(authenticator_item->second);
+}
+
+void BleDeviceHoverListModel::OnAuthenticatorAdded(
+    const AuthenticatorReference& authenticator) {
+  auto item_tag = authenticator_tags_.empty()
+                      ? 0
+                      : (--authenticator_tags_.end())->first + 1;
+  authenticator_tags_.emplace(item_tag, authenticator.authenticator_id());
+
+  if (ShouldShowItemInView(authenticator) && observer())
+    observer()->OnListItemAdded(item_tag);
+}
+
+void BleDeviceHoverListModel::OnAuthenticatorRemoved(
+    const AuthenticatorReference& removed_authenticator) {
+  const auto& authenticator_id = removed_authenticator.authenticator_id();
+  auto it = FindElementByValue(authenticator_tags_, authenticator_id);
+  CHECK(it != authenticator_tags_.end());
+  const auto item_tag = it->first;
+  authenticator_tags_.erase(it);
+  if (observer() && ShouldShowItemInView(removed_authenticator))
+    observer()->OnListItemRemoved(item_tag);
+}
+
+void BleDeviceHoverListModel::OnAuthenticatorPairingModeChanged(
+    const AuthenticatorReference& changed_authenticator) {
+  if (!observer())
+    return;
+
+  auto it = FindElementByValue(authenticator_tags_,
+                               changed_authenticator.authenticator_id());
+  CHECK(it != authenticator_tags_.end());
+  const auto changed_item_tag = it->first;
+  if (ShouldShowItemInView(changed_authenticator)) {
+    observer()->OnListItemChanged(changed_item_tag,
+                                  ListItemChangeType::kAddToViewComponent);
+  } else {
+    observer()->OnListItemChanged(changed_item_tag,
+                                  ListItemChangeType::kRemoveFromViewComponent);
+  }
+}
diff --git a/chrome/browser/ui/webauthn/ble_device_hover_list_model.h b/chrome/browser/ui/webauthn/ble_device_hover_list_model.h
new file mode 100644
index 0000000..c1cd99c0a
--- /dev/null
+++ b/chrome/browser/ui/webauthn/ble_device_hover_list_model.h
@@ -0,0 +1,72 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_WEBAUTHN_BLE_DEVICE_HOVER_LIST_MODEL_H_
+#define CHROME_BROWSER_UI_WEBAUTHN_BLE_DEVICE_HOVER_LIST_MODEL_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/strings/string16.h"
+#include "chrome/browser/ui/webauthn/hover_list_model.h"
+#include "chrome/browser/webauthn/authenticator_list_observer.h"
+#include "chrome/browser/webauthn/observable_authenticator_list.h"
+#include "ui/gfx/vector_icon_types.h"
+
+class BleDeviceHoverListModel : public HoverListModel,
+                                public AuthenticatorListObserver {
+ public:
+  // Interface that the client should implement to learn when the user selects
+  // an authenticator.
+  class Delegate {
+   public:
+    virtual void OnItemSelected(base::StringPiece authenticator_id) = 0;
+  };
+
+  // |authenticator_list_| and |delegate_| must outlive |this|, and |delegate_|
+  // may be nullptr.
+  explicit BleDeviceHoverListModel(
+      ObservableAuthenticatorList* authenticator_list,
+      Delegate* delegate);
+  ~BleDeviceHoverListModel() override;
+
+ private:
+  const AuthenticatorReference* GetAuthenticator(int tag) const;
+
+  // HoverListModel:
+  bool ShouldShowPlaceholderForEmptyList() const override;
+  base::string16 GetPlaceholderText() const override;
+  const gfx::VectorIcon& GetPlaceholderIcon() const override;
+  base::string16 GetItemText(int item_tag) const override;
+  const gfx::VectorIcon& GetItemIcon(int item_tag) const override;
+  std::vector<int> GetItemTags() const override;
+  void OnListItemSelected(int item_tag) override;
+
+  // AuthenticatorListObserver:
+  void OnAuthenticatorAdded(
+      const AuthenticatorReference& authenticator) override;
+  void OnAuthenticatorRemoved(
+      const AuthenticatorReference& removed_authenticator) override;
+  // Invoked when Bluetooth authenticator already included in
+  // |authenticator_list_| changes from being in non-pairable state to pairable
+  // state.
+  void OnAuthenticatorPairingModeChanged(
+      const AuthenticatorReference& changed_authenticator) override;
+
+  ObservableAuthenticatorList* const authenticator_list_;
+  Delegate* const delegate_;  // Weak, may be nullptr.
+
+  // Map where key corresponds to the tags attached to elements in above
+  // |authenticator_list_| and value is the corresponding authenticator id.
+  // Elements in authenticator_tags_ are filtered and added to the view
+  // component, but the size of the list should be sync with that of
+  // |authenticator_list_|.
+  std::map<int, std::string> authenticator_tags_;
+
+  DISALLOW_COPY_AND_ASSIGN(BleDeviceHoverListModel);
+};
+
+#endif  // CHROME_BROWSER_UI_WEBAUTHN_BLE_DEVICE_HOVER_LIST_MODEL_H_
diff --git a/chrome/browser/ui/webauthn/hover_list_model.h b/chrome/browser/ui/webauthn/hover_list_model.h
index 19560f83..5e56911 100644
--- a/chrome/browser/ui/webauthn/hover_list_model.h
+++ b/chrome/browser/ui/webauthn/hover_list_model.h
@@ -7,6 +7,8 @@
 
 #include <stddef.h>
 
+#include <vector>
+
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/strings/string16.h"
@@ -17,10 +19,17 @@
 // UI view component.
 class HoverListModel {
  public:
+  enum class ListItemChangeType {
+    kAddToViewComponent,
+    kRemoveFromViewComponent,
+  };
+
   class Observer {
    public:
     virtual void OnListItemAdded(int item_tag) = 0;
     virtual void OnListItemRemoved(int removed_list_item_tag) = 0;
+    virtual void OnListItemChanged(int changed_list_item_tag,
+                                   ListItemChangeType type) = 0;
   };
 
   HoverListModel() = default;
@@ -28,20 +37,18 @@
 
   virtual bool ShouldShowPlaceholderForEmptyList() const = 0;
   virtual base::string16 GetPlaceholderText() const = 0;
-  virtual const gfx::VectorIcon* GetPlaceholderIcon() const = 0;
-
-  virtual size_t GetItemCount() const = 0;
-  virtual bool ShouldShowItemInView(int item_tag) const = 0;
+  virtual const gfx::VectorIcon& GetPlaceholderIcon() const = 0;
+  virtual std::vector<int> GetItemTags() const = 0;
   virtual base::string16 GetItemText(int item_tag) const = 0;
-  virtual const gfx::VectorIcon* GetItemIcon(int item_tag) const = 0;
-  virtual int GetItemTag(size_t index) const = 0;
+  virtual const gfx::VectorIcon& GetItemIcon(int item_tag) const = 0;
   virtual void OnListItemSelected(int item_tag) = 0;
 
   void SetObserver(Observer* observer) {
     DCHECK(!observer_);
     observer_ = observer;
   }
-  void RemoveObserver(Observer* observer) { observer_ = nullptr; }
+
+  void RemoveObserver() { observer_ = nullptr; }
 
  protected:
   Observer* observer() { return observer_; }
diff --git a/chrome/browser/ui/webauthn/sheet_models.cc b/chrome/browser/ui/webauthn/sheet_models.cc
index b465b5189..9ea87ca7 100644
--- a/chrome/browser/ui/webauthn/sheet_models.cc
+++ b/chrome/browser/ui/webauthn/sheet_models.cc
@@ -491,8 +491,8 @@
 
 base::string16 AuthenticatorBlePinEntrySheetModel::GetStepTitle() const {
   const auto& authenticator_id = dialog_model()->selected_authenticator_id();
-  const auto* const ble_authenticator =
-      dialog_model()->GetAuthenticator(authenticator_id);
+  const auto* ble_authenticator =
+      dialog_model()->saved_authenticators().GetAuthenticator(authenticator_id);
   DCHECK(ble_authenticator);
   return l10n_util::GetStringFUTF16(
       IDS_WEBAUTHN_BLE_PIN_ENTRY_TITLE,
diff --git a/chrome/browser/ui/webauthn/transport_hover_list_model.cc b/chrome/browser/ui/webauthn/transport_hover_list_model.cc
index 5f2f0f1..9bcef32 100644
--- a/chrome/browser/ui/webauthn/transport_hover_list_model.cc
+++ b/chrome/browser/ui/webauthn/transport_hover_list_model.cc
@@ -7,6 +7,7 @@
 #include <utility>
 
 #include "chrome/browser/ui/webauthn/transport_utils.h"
+#include "ui/gfx/paint_vector_icon.h"
 
 TransportHoverListModel::TransportHoverListModel(
     std::vector<AuthenticatorTransport> transport_list,
@@ -23,16 +24,16 @@
   return base::string16();
 }
 
-const gfx::VectorIcon* TransportHoverListModel::GetPlaceholderIcon() const {
-  return nullptr;
+const gfx::VectorIcon& TransportHoverListModel::GetPlaceholderIcon() const {
+  return gfx::kNoneIcon;
 }
 
-size_t TransportHoverListModel::GetItemCount() const {
-  return transport_list_.size();
-}
-
-bool TransportHoverListModel::ShouldShowItemInView(int item_tag) const {
-  return true;
+std::vector<int> TransportHoverListModel::GetItemTags() const {
+  std::vector<int> tag_list(transport_list_.size());
+  std::transform(
+      transport_list_.begin(), transport_list_.end(), tag_list.begin(),
+      [](const auto& transport) { return base::strict_cast<int>(transport); });
+  return tag_list;
 }
 
 base::string16 TransportHoverListModel::GetItemText(int item_tag) const {
@@ -41,14 +42,9 @@
       TransportSelectionContext::kTransportSelectionSheet);
 }
 
-const gfx::VectorIcon* TransportHoverListModel::GetItemIcon(
+const gfx::VectorIcon& TransportHoverListModel::GetItemIcon(
     int item_tag) const {
-  return &GetTransportVectorIcon(static_cast<AuthenticatorTransport>(item_tag));
-}
-
-int TransportHoverListModel::GetItemTag(size_t item_index) const {
-  DCHECK_GT(transport_list_.size(), item_index);
-  return base::strict_cast<int>(transport_list_.at(item_index));
+  return GetTransportVectorIcon(static_cast<AuthenticatorTransport>(item_tag));
 }
 
 void TransportHoverListModel::OnListItemSelected(int item_tag) {
diff --git a/chrome/browser/ui/webauthn/transport_hover_list_model.h b/chrome/browser/ui/webauthn/transport_hover_list_model.h
index aa12c2fa..2d53c67 100644
--- a/chrome/browser/ui/webauthn/transport_hover_list_model.h
+++ b/chrome/browser/ui/webauthn/transport_hover_list_model.h
@@ -29,12 +29,10 @@
   // HoverListModel:
   bool ShouldShowPlaceholderForEmptyList() const override;
   base::string16 GetPlaceholderText() const override;
-  const gfx::VectorIcon* GetPlaceholderIcon() const override;
-  size_t GetItemCount() const override;
-  bool ShouldShowItemInView(int item_tag) const override;
+  const gfx::VectorIcon& GetPlaceholderIcon() const override;
+  std::vector<int> GetItemTags() const override;
   base::string16 GetItemText(int item_tag) const override;
-  const gfx::VectorIcon* GetItemIcon(int item_tag) const override;
-  int GetItemTag(size_t item_index) const override;
+  const gfx::VectorIcon& GetItemIcon(int item_tag) const override;
   void OnListItemSelected(int item_tag) override;
 
  private:
diff --git a/chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.cc
index dbc2b1e3..9a63d3a5 100644
--- a/chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.cc
@@ -27,6 +27,7 @@
 constexpr char kSkipPressed[] = "skip-pressed";
 constexpr char kNextPressed[] = "next-pressed";
 constexpr char kFlowFinished[] = "flow-finished";
+constexpr char kReloadRequested[] = "reload-requested";
 
 }  // namespace
 
@@ -338,6 +339,12 @@
     OnActivityControlOptInResult(false);
   } else if (action == kNextPressed) {
     OnActivityControlOptInResult(true);
+  } else if (action == kReloadRequested) {
+    if (settings_manager_.is_bound()) {
+      SendGetSettingsRequest();
+    } else {
+      LOG(ERROR) << "Settings mojom failed to setup. Check Assistant service.";
+    }
   }
 }
 
diff --git a/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc b/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc
index 6d29d83..e485a43a 100644
--- a/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc
@@ -10,6 +10,7 @@
 
 #include "ash/public/cpp/ash_features.h"
 #include "ash/public/cpp/ash_switches.h"
+#include "ash/public/cpp/resources/grit/ash_public_unscaled_resources.h"
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/logging.h"
@@ -224,6 +225,8 @@
 void AddDiscoverDisplayTypeDefaultResources(content::WebUIDataSource* source) {
   source->SetDefaultResource(IDR_CHROMEOS_DISCOVER_APP_HTML);
   source->AddResourcePath(kDiscoverJSPath, IDR_CHROMEOS_DISCOVER_APP_JS);
+  source->AddResourcePath("manifest.json", IDR_CHROMEOS_DISCOVER_MANIFEST);
+  source->AddResourcePath("logo.png", IDR_DISCOVER_APP_192);
 }
 
 // Default and non-shared resource definition for kLoginDisplay display type.
diff --git a/chrome/browser/ui/webui/extensions/extensions_ui.cc b/chrome/browser/ui/webui/extensions/extensions_ui.cc
index 3ddbaf3..b347eff 100644
--- a/chrome/browser/ui/webui/extensions/extensions_ui.cc
+++ b/chrome/browser/ui/webui/extensions/extensions_ui.cc
@@ -321,7 +321,7 @@
   source->AddBoolean(kInDevModeKey, in_dev_mode);
   source->AddBoolean(kShowActivityLogKey,
                      base::CommandLine::ForCurrentProcess()->HasSwitch(
-                         switches::kEnableExtensionActivityLogging));
+                         ::switches::kEnableExtensionActivityLogging));
   source->AddString(kLoadTimeClassesKey, GetLoadTimeClasses(in_dev_mode));
 
 #if BUILDFLAG(OPTIMIZE_WEBUI)
diff --git a/chrome/browser/ui/webui/settings/md_settings_ui.cc b/chrome/browser/ui/webui/settings/md_settings_ui.cc
index cb9b7f53..ad94f46 100644
--- a/chrome/browser/ui/webui/settings/md_settings_ui.cc
+++ b/chrome/browser/ui/webui/settings/md_settings_ui.cc
@@ -70,6 +70,7 @@
 #endif  // defined(OS_WIN) || defined(OS_CHROMEOS)
 
 #if defined(OS_CHROMEOS)
+#include "ash/public/cpp/resources/grit/ash_public_unscaled_resources.h"
 #include "ash/public/cpp/stylus_utils.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/arc/arc_util.h"
@@ -97,7 +98,9 @@
 #include "chrome/browser/ui/webui/settings/chromeos/internet_handler.h"
 #include "chrome/browser/ui/webui/settings/chromeos/multidevice_handler.h"
 #include "chrome/browser/ui/webui/settings/chromeos/smb_handler.h"
+#include "chrome/browser/web_applications/bookmark_apps/system_web_app_manager.h"
 #include "chrome/common/chrome_switches.h"
+#include "chrome/grit/browser_resources.h"
 #include "chromeos/account_manager/account_manager.h"
 #include "chromeos/account_manager/account_manager_factory.h"
 #include "chromeos/chromeos_features.h"
@@ -374,6 +377,18 @@
   // Add the metrics handler to write uma stats.
   web_ui->AddMessageHandler(std::make_unique<MetricsHandler>());
 
+#if defined(OS_CHROMEOS)
+  // Add the System Web App resources for Settings.
+  if (web_app::SystemWebAppManager::ShouldEnableForProfile(profile)) {
+    html_source->AddResourcePath("icon-192.png", IDR_SETTINGS_LOGO_192);
+    html_source->AddResourcePath("pwa.html", IDR_PWA_HTML);
+#if BUILDFLAG(OPTIMIZE_WEBUI)
+    exclude_from_gzip.push_back("icon-192.png");
+    exclude_from_gzip.push_back("pwa.html");
+#endif  // BUILDFLAG(OPTIMIZE_WEBUI)
+  }
+#endif  // defined (OS_CHROMEOS)
+
 #if BUILDFLAG(OPTIMIZE_WEBUI)
   const bool use_polymer_2 =
       base::FeatureList::IsEnabled(features::kWebUIPolymer2);
@@ -388,6 +403,9 @@
                                       ? IDR_MD_SETTINGS_VULCANIZED_P2_HTML
                                       : IDR_MD_SETTINGS_VULCANIZED_HTML);
   html_source->UseGzip(exclude_from_gzip);
+#if defined(OS_CHROMEOS)
+  html_source->AddResourcePath("manifest.json", IDR_MD_SETTINGS_MANIFEST);
+#endif  // defined (OS_CHROMEOS)
 #else
   // Add all settings resources.
   for (size_t i = 0; i < kSettingsResourcesSize; ++i) {
diff --git a/chrome/browser/web_applications/bookmark_apps/system_web_app_manager.cc b/chrome/browser/web_applications/bookmark_apps/system_web_app_manager.cc
index 8583ec9..83686b7 100644
--- a/chrome/browser/web_applications/bookmark_apps/system_web_app_manager.cc
+++ b/chrome/browser/web_applications/bookmark_apps/system_web_app_manager.cc
@@ -85,7 +85,8 @@
 // TODO(calamity): Split this into per-platform functions.
 #if defined(OS_CHROMEOS)
   urls.emplace_back(chrome::kChromeUIDiscoverURL);
-  urls.emplace_back(chrome::kChromeUISettingsURL);
+  constexpr char kChromeSettingsPWAURL[] = "chrome://settings/pwa.html";
+  urls.emplace_back(kChromeSettingsPWAURL);
 #endif  // OS_CHROMEOS
 
   return urls;
diff --git a/chrome/browser/web_applications/bookmark_apps/system_web_app_manager_browsertest.cc b/chrome/browser/web_applications/bookmark_apps/system_web_app_manager_browsertest.cc
index 08d11bd7..90806d93 100644
--- a/chrome/browser/web_applications/bookmark_apps/system_web_app_manager_browsertest.cc
+++ b/chrome/browser/web_applications/bookmark_apps/system_web_app_manager_browsertest.cc
@@ -18,6 +18,7 @@
 #include "chrome/browser/web_applications/web_app_provider_factory.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/extensions/manifest_handlers/app_theme_color_info.h"
+#include "chrome/grit/browser_resources.h"
 #include "chrome/grit/chrome_unscaled_resources.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_ui.h"
@@ -46,9 +47,6 @@
       "theme_color": "#00FF00"
     })";
 
-constexpr char kSystemAppHTMLText[] =
-    R"(<html><head><link rel="manifest" href="manifest.json"></head></html>)";
-
 // WebUIController that serves a System PWA.
 class TestWebUIController : public content::WebUIController {
  public:
@@ -57,20 +55,17 @@
     content::WebUIDataSource* data_source =
         content::WebUIDataSource::Create("test-system-app");
     data_source->AddResourcePath("icon-256.png", IDR_PRODUCT_LOGO_256);
+    data_source->AddResourcePath("pwa.html", IDR_PWA_HTML);
     data_source->SetRequestFilter(base::BindRepeating(
         [](const std::string& id,
            const content::WebUIDataSource::GotDataCallback& callback) {
           scoped_refptr<base::RefCountedString> ref_contents(
               new base::RefCountedString);
-          if (id == "manifest.json")
-            ref_contents->data() = kSystemAppManifestText;
-
-          if (id == "pwa.html")
-            ref_contents->data() = kSystemAppHTMLText;
-
-          if (ref_contents->data().empty())
+          if (id != "manifest.json")
             return false;
 
+          ref_contents->data() = kSystemAppManifestText;
+
           callback.Run(ref_contents);
           return true;
         }));
@@ -115,7 +110,8 @@
     : public extensions::ExtensionBrowserTest {
  public:
   SystemWebAppManagerIntegrationTest() {
-    scoped_feature_list_.InitWithFeatures({features::kSystemWebApps}, {});
+    scoped_feature_list_.InitWithFeatures(
+        {features::kDesktopPWAWindowing, features::kSystemWebApps}, {});
     content::WebUIControllerFactory::RegisterFactory(&factory_);
   }
   ~SystemWebAppManagerIntegrationTest() override {
@@ -137,15 +133,8 @@
   DISALLOW_COPY_AND_ASSIGN(SystemWebAppManagerIntegrationTest);
 };
 
-// Crashes on Mac only. https://crbug.com/898184
-#if defined(OS_MACOSX)
-#define MAYBE_WithManifest DISABLED_WithManifest
-#else
-#define MAYBE_WithManifest WithManifest
-#endif
-
 // Test that System Apps install correctly with a manifest.
-IN_PROC_BROWSER_TEST_F(SystemWebAppManagerIntegrationTest, MAYBE_WithManifest) {
+IN_PROC_BROWSER_TEST_F(SystemWebAppManagerIntegrationTest, WithManifest) {
   std::vector<GURL> system_apps;
   system_apps.emplace_back(GURL("chrome://test-system-app/pwa.html"));
   extensions::PendingBookmarkAppManager pending_app_manager(profile());
diff --git a/chrome/browser/webauthn/authenticator_list_observer.h b/chrome/browser/webauthn/authenticator_list_observer.h
new file mode 100644
index 0000000..b13d6e6
--- /dev/null
+++ b/chrome/browser/webauthn/authenticator_list_observer.h
@@ -0,0 +1,27 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_WEBAUTHN_AUTHENTICATOR_LIST_OBSERVER_H_
+#define CHROME_BROWSER_WEBAUTHN_AUTHENTICATOR_LIST_OBSERVER_H_
+
+#include "chrome/browser/webauthn/authenticator_reference.h"
+
+// Interface to observe mutations to an ObservableAuthenticatorList.
+//
+// This is currently only implemented by the the BleDeviceHoverListModel that is
+// used by HoverListView to visualize an ObservableAuthenticatorList.
+class AuthenticatorListObserver {
+ public:
+  AuthenticatorListObserver() = default;
+  virtual ~AuthenticatorListObserver() = default;
+
+  virtual void OnAuthenticatorAdded(
+      const AuthenticatorReference& added_authenticator) = 0;
+  virtual void OnAuthenticatorRemoved(
+      const AuthenticatorReference& removed_authenticator) = 0;
+  virtual void OnAuthenticatorPairingModeChanged(
+      const AuthenticatorReference& changed_authenticator) = 0;
+};
+
+#endif  // CHROME_BROWSER_WEBAUTHN_AUTHENTICATOR_LIST_OBSERVER_H_
diff --git a/chrome/browser/webauthn/authenticator_request_dialog_model.cc b/chrome/browser/webauthn/authenticator_request_dialog_model.cc
index 7b83110..3c6a28a 100644
--- a/chrome/browser/webauthn/authenticator_request_dialog_model.cc
+++ b/chrome/browser/webauthn/authenticator_request_dialog_model.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/webauthn/authenticator_request_dialog_model.h"
 
+#include <iterator>
 #include <utility>
 
 #include "base/bind.h"
@@ -185,10 +186,10 @@
 }
 
 void AuthenticatorRequestDialogModel::InitiatePairingDevice(
-    const std::string& authenticator_id) {
+    base::StringPiece authenticator_id) {
   DCHECK_EQ(current_step(), Step::kBleDeviceSelection);
-  CHECK(GetAuthenticator(authenticator_id));
-  selected_authenticator_id_ = authenticator_id;
+  DCHECK(saved_authenticators_.GetAuthenticator(authenticator_id));
+  selected_authenticator_id_ = authenticator_id.as_string();
   SetCurrentStep(Step::kBlePinEntry);
 }
 
@@ -196,7 +197,7 @@
     const base::string16& pin) {
   DCHECK_EQ(current_step(), Step::kBlePinEntry);
   const auto* selected_authenticator =
-      GetAuthenticator(selected_authenticator_id_);
+      saved_authenticators_.GetAuthenticator(selected_authenticator_id_);
   if (!selected_authenticator) {
     // TODO(hongjunchoi): Implement an error screen for error encountered when
     // pairing.
@@ -218,7 +219,8 @@
 void AuthenticatorRequestDialogModel::OnPairingSuccess(
     base::StringPiece authenticator_id) {
   DCHECK_EQ(current_step(), Step::kBleVerifying);
-  auto* authenticator = GetAuthenticator(authenticator_id);
+  auto* authenticator =
+      saved_authenticators_.GetAuthenticator(authenticator_id);
   if (authenticator)
     return;
 
@@ -246,19 +248,20 @@
 
   SetCurrentStep(Step::kTouchId);
 
+  auto& authenticators = saved_authenticators_.authenticator_list();
   auto touch_id_authenticator_it =
-      std::find_if(saved_authenticators_.begin(), saved_authenticators_.end(),
+      std::find_if(authenticators.begin(), authenticators.end(),
                    [](const auto& authenticator) {
-                     return authenticator->transport() ==
+                     return authenticator.transport() ==
                             device::FidoTransportProtocol::kInternal;
                    });
 
-  if (touch_id_authenticator_it == saved_authenticators_.end())
+  if (touch_id_authenticator_it == authenticators.end())
     return;
 
   static base::TimeDelta kTouchIdDispatchDelay =
       base::TimeDelta::FromMilliseconds(1250);
-  DispatchRequestAsync(touch_id_authenticator_it->get(), kTouchIdDispatchDelay);
+  DispatchRequestAsync(&*touch_id_authenticator_it, kTouchIdDispatchDelay);
 }
 
 void AuthenticatorRequestDialogModel::Cancel() {
@@ -340,29 +343,20 @@
 void AuthenticatorRequestDialogModel::UpdateAuthenticatorReferenceId(
     base::StringPiece old_authenticator_id,
     std::string new_authenticator_id) {
-  auto it = std::find_if(
-      saved_authenticators_.begin(), saved_authenticators_.end(),
-      [old_authenticator_id](const auto& authenticator) {
-        return authenticator->authenticator_id() == old_authenticator_id;
-      });
-  if (it != saved_authenticators_.end())
-    (*it)->SetAuthenticatorId(std::move(new_authenticator_id));
+  saved_authenticators_.ChangeAuthenticatorId(old_authenticator_id,
+                                              std::move(new_authenticator_id));
 }
 
 void AuthenticatorRequestDialogModel::AddAuthenticator(
     const device::FidoAuthenticator& authenticator) {
-  saved_authenticators_.emplace_back(std::make_unique<AuthenticatorReference>(
+  saved_authenticators_.AddAuthenticator(AuthenticatorReference(
       authenticator.GetId(), authenticator.GetDisplayName(),
       authenticator.AuthenticatorTransport(), authenticator.IsInPairingMode()));
 }
 
 void AuthenticatorRequestDialogModel::RemoveAuthenticator(
     base::StringPiece authenticator_id) {
-  base::EraseIf(saved_authenticators_,
-                [authenticator_id](const auto& authenticator_reference) {
-                  return authenticator_reference->authenticator_id() ==
-                         authenticator_id;
-                });
+  saved_authenticators_.RemoveAuthenticator(authenticator_id);
 }
 
 void AuthenticatorRequestDialogModel::DispatchRequestAsync(
@@ -386,31 +380,13 @@
 void AuthenticatorRequestDialogModel::UpdateAuthenticatorReferencePairingMode(
     base::StringPiece authenticator_id,
     bool is_in_pairing_mode) {
-  auto it = std::find_if(
-      saved_authenticators_.begin(), saved_authenticators_.end(),
-      [authenticator_id](const auto& authenticator) {
-        return authenticator->authenticator_id() == authenticator_id;
-      });
-  if (it != saved_authenticators_.end())
-    (*it)->SetIsInPairingMode(is_in_pairing_mode);
+  saved_authenticators_.ChangeAuthenticatorPairingMode(authenticator_id,
+                                                       is_in_pairing_mode);
 }
 
 void AuthenticatorRequestDialogModel::SetSelectedAuthenticatorForTesting(
-    std::unique_ptr<AuthenticatorReference> test_authenticator) {
-  selected_authenticator_id_ = test_authenticator->authenticator_id();
-  saved_authenticators_.emplace_back(std::move(test_authenticator));
+    AuthenticatorReference test_authenticator) {
+  selected_authenticator_id_ = test_authenticator.authenticator_id();
+  saved_authenticators_.AddAuthenticator(std::move(test_authenticator));
 }
 
-AuthenticatorReference* AuthenticatorRequestDialogModel::GetAuthenticator(
-    base::StringPiece authenticator_id) const {
-  auto authenticator = std::find_if(
-      saved_authenticators_.begin(), saved_authenticators_.end(),
-      [authenticator_id](const auto& authenticator) {
-        return authenticator->authenticator_id() == authenticator_id;
-      });
-
-  if (authenticator == saved_authenticators_.end())
-    return nullptr;
-
-  return authenticator->get();
-}
diff --git a/chrome/browser/webauthn/authenticator_request_dialog_model.h b/chrome/browser/webauthn/authenticator_request_dialog_model.h
index 6e3a7781..1e42cd2 100644
--- a/chrome/browser/webauthn/authenticator_request_dialog_model.h
+++ b/chrome/browser/webauthn/authenticator_request_dialog_model.h
@@ -16,6 +16,7 @@
 #include "base/strings/string_piece.h"
 #include "chrome/browser/webauthn/authenticator_reference.h"
 #include "chrome/browser/webauthn/authenticator_transport.h"
+#include "chrome/browser/webauthn/observable_authenticator_list.h"
 #include "device/fido/fido_request_handler_base.h"
 #include "device/fido/fido_transport_protocol.h"
 
@@ -186,7 +187,7 @@
   // Initiates pairing of the device that the user has chosen.
   //
   // Valid action when at step: kBleDeviceSelection.
-  void InitiatePairingDevice(const std::string& authenticator_id);
+  void InitiatePairingDevice(base::StringPiece authenticator_id);
 
   // Finishes pairing of the previously chosen device with the |pin| code
   // entered.
@@ -267,13 +268,9 @@
       base::StringPiece authenticator_id,
       bool is_in_pairing_mode);
 
-  void SetSelectedAuthenticatorForTesting(
-      std::unique_ptr<AuthenticatorReference> authenticator);
+  void SetSelectedAuthenticatorForTesting(AuthenticatorReference authenticator);
 
-  AuthenticatorReference* GetAuthenticator(
-      base::StringPiece authenticator_id) const;
-
-  std::vector<std::unique_ptr<AuthenticatorReference>>& saved_authenticators() {
+  ObservableAuthenticatorList& saved_authenticators() {
     return saved_authenticators_;
   }
 
@@ -303,11 +300,12 @@
   // Transport type and id of Mac TouchId and BLE authenticators are cached so
   // that the WebAuthN request for the corresponding authenticators can be
   // dispatched lazily after the user interacts with the UI element.
-  std::vector<std::unique_ptr<AuthenticatorReference>> saved_authenticators_;
+  ObservableAuthenticatorList saved_authenticators_;
 
   // Represents the id of the Bluetooth authenticator that the user is trying to
   // connect to or conduct WebAuthN request to via the WebAuthN UI.
   std::string selected_authenticator_id_;
+
   RequestCallback request_callback_;
   BlePairingCallback ble_pairing_callback_;
   base::RepeatingClosure bluetooth_adapter_power_on_callback_;
diff --git a/chrome/browser/webauthn/authenticator_request_dialog_model_unittest.cc b/chrome/browser/webauthn/authenticator_request_dialog_model_unittest.cc
index c5d835a..6138768b5 100644
--- a/chrome/browser/webauthn/authenticator_request_dialog_model_unittest.cc
+++ b/chrome/browser/webauthn/authenticator_request_dialog_model_unittest.cc
@@ -472,11 +472,10 @@
   model.SetRequestCallback(base::BindRepeating(
       [](int* i, const std::string& authenticator_id) { ++(*i); },
       &num_called));
-  model.saved_authenticators().emplace_back(
-      std::make_unique<AuthenticatorReference>(
-          "authenticator" /* authenticator_id */,
-          base::string16() /* authenticator_display_name */,
-          AuthenticatorTransport::kInternal, false /* is_in_pairing_mode */));
+  model.saved_authenticators().AddAuthenticator(AuthenticatorReference(
+      "authenticator" /* authenticator_id */,
+      base::string16() /* authenticator_display_name */,
+      AuthenticatorTransport::kInternal, false /* is_in_pairing_mode */));
 
   model.StartFlow(std::move(transports_info), base::nullopt);
   EXPECT_EQ(AuthenticatorRequestDialogModel::Step::kTransportSelection,
diff --git a/chrome/browser/webauthn/observable_authenticator_list.cc b/chrome/browser/webauthn/observable_authenticator_list.cc
new file mode 100644
index 0000000..9799d7c
--- /dev/null
+++ b/chrome/browser/webauthn/observable_authenticator_list.cc
@@ -0,0 +1,90 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/webauthn/observable_authenticator_list.h"
+
+#include <algorithm>
+#include <utility>
+
+#include "chrome/browser/webauthn/authenticator_list_observer.h"
+
+ObservableAuthenticatorList::ObservableAuthenticatorList() = default;
+
+ObservableAuthenticatorList::~ObservableAuthenticatorList() = default;
+
+void ObservableAuthenticatorList::AddAuthenticator(
+    AuthenticatorReference authenticator) {
+  authenticator_list_.emplace_back(std::move(authenticator));
+  if (observer_)
+    observer_->OnAuthenticatorAdded(authenticator_list_.back());
+}
+
+void ObservableAuthenticatorList::RemoveAuthenticator(
+    base::StringPiece authenticator_id) {
+  auto it = GetAuthenticatorIterator(authenticator_id);
+  if (it == authenticator_list_.end())
+    return;
+
+  auto removed_authenticator = std::move(*it);
+  authenticator_list_.erase(it);
+
+  if (observer_)
+    observer_->OnAuthenticatorRemoved(removed_authenticator);
+}
+
+void ObservableAuthenticatorList::ChangeAuthenticatorId(
+    base::StringPiece previous_id,
+    std::string new_id) {
+  auto* authenticator = GetAuthenticator(previous_id);
+  if (!authenticator)
+    return;
+
+  if (observer_)
+    observer_->OnAuthenticatorRemoved(*authenticator);
+
+  authenticator->SetAuthenticatorId(std::move(new_id));
+  if (observer_)
+    observer_->OnAuthenticatorAdded(*authenticator);
+}
+
+void ObservableAuthenticatorList::ChangeAuthenticatorPairingMode(
+    base::StringPiece authenticator_id,
+    bool is_in_pairing_mode) {
+  auto it = GetAuthenticatorIterator(authenticator_id);
+  if (it == authenticator_list_.end())
+    return;
+
+  it->SetIsInPairingMode(is_in_pairing_mode);
+  if (observer_)
+    observer_->OnAuthenticatorPairingModeChanged(*it);
+}
+
+AuthenticatorReference* ObservableAuthenticatorList::GetAuthenticator(
+    base::StringPiece authenticator_id) {
+  auto it = GetAuthenticatorIterator(authenticator_id);
+  if (it == authenticator_list_.end())
+    return nullptr;
+
+  return &*it;
+}
+
+void ObservableAuthenticatorList::SetObserver(
+    AuthenticatorListObserver* observer) {
+  DCHECK(!observer_);
+  observer_ = observer;
+}
+
+void ObservableAuthenticatorList::RemoveObserver() {
+  observer_ = nullptr;
+}
+
+ObservableAuthenticatorList::AuthenticatorListIterator
+ObservableAuthenticatorList::GetAuthenticatorIterator(
+    base::StringPiece authenticator_id) {
+  return std::find_if(authenticator_list_.begin(), authenticator_list_.end(),
+                      [authenticator_id](const auto& authenticator) {
+                        return authenticator.authenticator_id() ==
+                               authenticator_id;
+                      });
+}
diff --git a/chrome/browser/webauthn/observable_authenticator_list.h b/chrome/browser/webauthn/observable_authenticator_list.h
new file mode 100644
index 0000000..d30c1aa
--- /dev/null
+++ b/chrome/browser/webauthn/observable_authenticator_list.h
@@ -0,0 +1,56 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_WEBAUTHN_OBSERVABLE_AUTHENTICATOR_LIST_H_
+#define CHROME_BROWSER_WEBAUTHN_OBSERVABLE_AUTHENTICATOR_LIST_H_
+
+#include <stddef.h>
+
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/strings/string_piece.h"
+#include "chrome/browser/webauthn/authenticator_reference.h"
+
+class AuthenticatorListObserver;
+
+// List of AuthenticatorReference maintained by AuthenticatorRequestDialogModel
+// that BleDeviceHoverListModel observes to add views to WebAuthN UI modal
+// dialog views.
+class ObservableAuthenticatorList {
+ public:
+  ObservableAuthenticatorList();
+  ~ObservableAuthenticatorList();
+
+  void AddAuthenticator(AuthenticatorReference authenticator);
+  void RemoveAuthenticator(base::StringPiece authenticator_id);
+  void ChangeAuthenticatorId(base::StringPiece previous_id, std::string new_id);
+  void ChangeAuthenticatorPairingMode(base::StringPiece authenticator_id,
+                                      bool is_in_pairing_mode);
+  AuthenticatorReference* GetAuthenticator(base::StringPiece authenticator_id);
+
+  void SetObserver(AuthenticatorListObserver* observer);
+  void RemoveObserver();
+
+  std::vector<AuthenticatorReference>& authenticator_list() {
+    return authenticator_list_;
+  }
+
+  size_t size() const { return authenticator_list_.size(); }
+
+ private:
+  using AuthenticatorListIterator =
+      std::vector<AuthenticatorReference>::iterator;
+
+  AuthenticatorListIterator GetAuthenticatorIterator(
+      base::StringPiece authenticator_id);
+
+  std::vector<AuthenticatorReference> authenticator_list_;
+  AuthenticatorListObserver* observer_ = nullptr;
+
+  DISALLOW_COPY_AND_ASSIGN(ObservableAuthenticatorList);
+};
+
+#endif  // CHROME_BROWSER_WEBAUTHN_OBSERVABLE_AUTHENTICATOR_LIST_H_
diff --git a/chrome/common/BUILD.gn b/chrome/common/BUILD.gn
index f0d95a70..3c5f821 100644
--- a/chrome/common/BUILD.gn
+++ b/chrome/common/BUILD.gn
@@ -323,8 +323,6 @@
       "extensions/api/system_indicator/system_indicator_handler.h",
       "extensions/api/url_handlers/url_handlers_parser.cc",
       "extensions/api/url_handlers/url_handlers_parser.h",
-      "extensions/api/webstore/webstore_api_constants.cc",
-      "extensions/api/webstore/webstore_api_constants.h",
       "extensions/chrome_extension_messages.h",
       "extensions/chrome_extensions_api_provider.cc",
       "extensions/chrome_extensions_api_provider.h",
diff --git a/chrome/common/chrome_content_client.cc b/chrome/common/chrome_content_client.cc
index d93b738..310971a 100644
--- a/chrome/common/chrome_content_client.cc
+++ b/chrome/common/chrome_content_client.cc
@@ -364,6 +364,9 @@
       // This list must match the CDM that is being bundled with Chrome.
       capability->video_codecs.push_back(media::VideoCodec::kCodecVP8);
       capability->video_codecs.push_back(media::VideoCodec::kCodecVP9);
+      // TODO(xhwang): Update this and tests after Widevine CDM supports VP9
+      // profile 2.
+      capability->supports_vp9_profile2 = false;
 #if BUILDFLAG(USE_PROPRIETARY_CODECS)
       capability->video_codecs.push_back(media::VideoCodec::kCodecH264);
 #endif  // BUILDFLAG(USE_PROPRIETARY_CODECS)
diff --git a/chrome/common/extensions/api/webstore/webstore_api_constants.cc b/chrome/common/extensions/api/webstore/webstore_api_constants.cc
deleted file mode 100644
index 09b0b76..0000000
--- a/chrome/common/extensions/api/webstore/webstore_api_constants.cc
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/common/extensions/api/webstore/webstore_api_constants.h"
-
-#include "base/macros.h"
-#include "chrome/common/extensions/webstore_install_result.h"
-
-namespace extensions {
-namespace api {
-namespace webstore {
-
-// IMPORTANT: Keep this list in sync with both the definition in
-// chrome/common/extensions/api/webstore.json and
-// chrome/common/extensions/webstore_install_result.h!
-const char* const kInstallResultCodes[] = {
-  "success",
-  "otherError",
-  "aborted",
-  "installInProgress",
-  "notPermitted",
-  "invalidId",
-  "webstoreRequestError",
-  "invalidWebstoreResponse",
-  "invalidManifest",
-  "iconError",
-  "userCancelled",
-  "blacklisted",
-  "missingDependencies",
-  "requirementViolations",
-  "blockedByPolicy",
-  "launchFeatureDisabled",
-  "launchUnsupportedExtensionType",
-  "launchInProgress",
-};
-
-static_assert(arraysize(kInstallResultCodes) ==
-                  webstore_install::RESULT_LAST + 1,
-              "kInstallResultCodes should equal RESULT_LAST + 1");
-
-// The "downloading" stage begins when the installer starts downloading modules
-// for the extension.
-const char kInstallStageDownloading[] = "downloading";
-
-// The "installing" stage begins once all downloads are complete, and the
-// CrxInstaller begins.
-const char kInstallStageInstalling[] = "installing";
-
-// The method in custom_webstore_bindings.js triggered when we enter a new
-// install stage ("downloading" or "installing").
-const char kOnInstallStageChangedMethodName[] = "onInstallStageChanged";
-
-// The method in custom_webstore_bindings.js triggered when we update
-// download progress.
-const char kOnDownloadProgressMethodName[] = "onDownloadProgress";
-
-}  // namespace webstore
-}  // namespace api
-}  // namespace extensions
diff --git a/chrome/common/extensions/api/webstore/webstore_api_constants.h b/chrome/common/extensions/api/webstore/webstore_api_constants.h
deleted file mode 100644
index 8a6b490..0000000
--- a/chrome/common/extensions/api/webstore/webstore_api_constants.h
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_COMMON_EXTENSIONS_API_WEBSTORE_WEBSTORE_API_CONSTANTS_H_
-#define CHROME_COMMON_EXTENSIONS_API_WEBSTORE_WEBSTORE_API_CONSTANTS_H_
-
-namespace extensions {
-namespace api {
-namespace webstore {
-
-// An enum for listener types. This is used when creating/reading the mask for
-// IPC messages.
-enum ListenerType {
-  INSTALL_STAGE_LISTENER = 1,
-  DOWNLOAD_PROGRESS_LISTENER = 1 << 1
-};
-
-// An enum to represent which stage the installation is in.
-enum InstallStage {
-  INSTALL_STAGE_DOWNLOADING = 0,
-  INSTALL_STAGE_INSTALLING,
-};
-
-// Result codes returned by WebstoreStandaloneInstaller and its subclasses.
-// IMPORTANT: Keep this list in sync with both the definition in
-// chrome/common/extensions/api/webstore.json and
-// chrome/common/extensions/webstore_install_result.h!
-extern const char* const kInstallResultCodes[];
-
-extern const char kInstallStageDownloading[];
-extern const char kInstallStageInstalling[];
-extern const char kOnInstallStageChangedMethodName[];
-extern const char kOnDownloadProgressMethodName[];
-
-}  // namespace webstore
-}  // namespace api
-}  // namespace extensions
-
-#endif  // CHROME_COMMON_EXTENSIONS_API_WEBSTORE_WEBSTORE_API_CONSTANTS_H_
diff --git a/chrome/common/trace_event_args_whitelist.cc b/chrome/common/trace_event_args_whitelist.cc
index 83a7449..ca972938 100644
--- a/chrome/common/trace_event_args_whitelist.cc
+++ b/chrome/common/trace_event_args_whitelist.cc
@@ -37,7 +37,7 @@
     {"shutdown", "*", nullptr},
     {"task_scheduler", "*", nullptr},
     {"toplevel", "*", nullptr},
-    {TRACE_DISABLED_BY_DEFAULT("cpu_profiler"), "StackCpuSampling", nullptr},
+    {TRACE_DISABLED_BY_DEFAULT("cpu_profiler"), "*", nullptr},
     // Redefined the string since MemoryDumpManager::kTraceCategory causes
     // static initialization of this struct.
     {TRACE_DISABLED_BY_DEFAULT("memory-infra"), "*", kMemoryDumpAllowedArgs},
diff --git a/chrome/renderer/media/chrome_key_systems.cc b/chrome/renderer/media/chrome_key_systems.cc
index 7a2a291..0ef05ece 100644
--- a/chrome/renderer/media/chrome_key_systems.cc
+++ b/chrome/renderer/media/chrome_key_systems.cc
@@ -144,6 +144,7 @@
 #if BUILDFLAG(ENABLE_WIDEVINE)
 static SupportedCodecs GetSupportedCodecs(
     const std::vector<media::VideoCodec>& supported_video_codecs,
+    bool supports_vp9_profile2,
     bool is_secure) {
   SupportedCodecs supported_codecs = media::EME_CODEC_NONE;
 
@@ -169,8 +170,9 @@
         supported_codecs |= media::EME_CODEC_VP8;
         break;
       case media::VideoCodec::kCodecVP9:
-        // TODO(crbug.com/707127): Support VP9 higher profiles.
         supported_codecs |= media::EME_CODEC_VP9_PROFILE0;
+        if (supports_vp9_profile2)
+          supported_codecs |= media::EME_CODEC_VP9_PROFILE2;
         break;
       case media::VideoCodec::kCodecAV1:
         supported_codecs |= media::EME_CODEC_AV1;
@@ -251,10 +253,13 @@
   }
 
   // Codecs and encryption schemes.
-  auto codecs =
-      GetSupportedCodecs(capability->video_codecs, /*is_secure=*/false);
+  auto codecs = GetSupportedCodecs(capability->video_codecs,
+                                   capability->supports_vp9_profile2,
+                                   /*is_secure=*/false);
   const auto& encryption_schemes = capability->encryption_schemes;
+  // TODO(xhwang): Investigate whether hardware VP9 profile 2 is supported.
   auto hw_secure_codecs = GetSupportedCodecs(capability->hw_secure_video_codecs,
+                                             /*supports_vp9_profile2=*/false,
                                              /*is_secure=*/true);
   const auto& hw_secure_encryption_schemes =
       capability->hw_secure_encryption_schemes;
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 751dcc9..4ed6bd7 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -3406,7 +3406,6 @@
       "../browser/chromeos/crostini/crostini_mime_types_service_unittest.cc",
       "../browser/chromeos/crostini/crostini_registry_service_unittest.cc",
       "../browser/chromeos/crostini/crostini_reporting_util_unittest.cc",
-      "../browser/chromeos/policy/policy_cert_verifier_unittest.cc",
       "../browser/component_updater/cros_component_installer_chromeos_unittest.cc",
       "../browser/component_updater/metadata_table_chromeos_unittest.cc",
       "../browser/google/google_brand_code_map_chromeos_unittest.cc",
diff --git a/chrome/test/data/navigation_predictor/simple_page_with_anchors.html b/chrome/test/data/navigation_predictor/simple_page_with_anchors.html
index 1951958..9b4362e 100644
--- a/chrome/test/data/navigation_predictor/simple_page_with_anchors.html
+++ b/chrome/test/data/navigation_predictor/simple_page_with_anchors.html
@@ -4,5 +4,6 @@
   <body>
     <a id="google" href="https://google.com">Google</a>
     <a id="example" href="https://example.com">Example</a>
+    <a id="example" href="simple_page_with_anchors.html">Same page</a>
   </body>
 </html>
\ No newline at end of file
diff --git a/chrome/test/data/webui/cr_elements/cr_elements_browsertest.js b/chrome/test/data/webui/cr_elements/cr_elements_browsertest.js
index 4c1c383..b9f4fec 100644
--- a/chrome/test/data/webui/cr_elements/cr_elements_browsertest.js
+++ b/chrome/test/data/webui/cr_elements/cr_elements_browsertest.js
@@ -153,6 +153,7 @@
 
   /** @override */
   extraLibraries: CrElementsBrowserTest.prototype.extraLibraries.concat([
+    '../settings/test_util.js',
     'cr_scrollable_behavior_tests.js',
   ]),
 };
diff --git a/chrome/test/data/webui/cr_elements/cr_scrollable_behavior_tests.js b/chrome/test/data/webui/cr_elements/cr_scrollable_behavior_tests.js
index f919ef5..7eca66b 100644
--- a/chrome/test/data/webui/cr_elements/cr_scrollable_behavior_tests.js
+++ b/chrome/test/data/webui/cr_elements/cr_scrollable_behavior_tests.js
@@ -52,10 +52,10 @@
     container = testElement.$$('#container');
     ironList = testElement.$$('iron-list');
 
-    // Wait for requestAnimationFrame for CrScrollableBehavior to set the
-    // initial scrollable class properties.
-    window.requestAnimationFrame(function() {
-      done();
+    // Wait for CrScrollableBehavior to set the initial scrollable class
+    // properties.
+    window.requestAnimationFrame(() => {
+      test_util.waitForRender().then(done);
     });
   });
 
diff --git a/chrome/test/data/webui/settings/cr_settings_browsertest.js b/chrome/test/data/webui/settings/cr_settings_browsertest.js
index 17ada260..5f9b886 100644
--- a/chrome/test/data/webui/settings/cr_settings_browsertest.js
+++ b/chrome/test/data/webui/settings/cr_settings_browsertest.js
@@ -1960,6 +1960,33 @@
 });
 
 /**
+ * Test fixture for the multidevice Smart Lock subpage.
+ * @constructor
+ * @extends {CrSettingsBrowserTest}
+ */
+function CrSettingsMultideviceSmartLockSubpageTest() {}
+
+CrSettingsMultideviceSmartLockSubpageTest.prototype = {
+  __proto__: CrSettingsBrowserTest.prototype,
+
+  /** @override */
+  browsePreload:
+      'chrome://settings/multidevice_page/multidevice_smartlock_subpage.html',
+
+  /** @override */
+  extraLibraries: CrSettingsBrowserTest.prototype.extraLibraries.concat([
+    '../test_browser_proxy.js',
+    'test_multidevice_browser_proxy.js',
+    'test_util.js',
+    'multidevice_smartlock_subpage_test.js',
+  ]),
+};
+
+TEST_F('CrSettingsMultideviceSmartLockSubpageTest', 'All', function() {
+  mocha.run();
+});
+
+/**
  * Test fixture for the multidevice settings subpage.
  * @constructor
  * @extends {CrSettingsBrowserTest}
diff --git a/chrome/test/data/webui/settings/multidevice_smartlock_subpage_test.js b/chrome/test/data/webui/settings/multidevice_smartlock_subpage_test.js
new file mode 100644
index 0000000..d76ff9f
--- /dev/null
+++ b/chrome/test/data/webui/settings/multidevice_smartlock_subpage_test.js
@@ -0,0 +1,352 @@
+// 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.
+
+suite('Multidevice', function() {
+  let smartLockSubPage = null;
+  let browserProxy = null;
+
+  function createSmartLockSubPage() {
+    let smartLockSubPage =
+        document.createElement('settings-multidevice-smartlock-subpage');
+    document.body.appendChild(smartLockSubPage);
+    Polymer.dom.flush();
+
+    return smartLockSubPage;
+  }
+
+  function setSuiteState(newState) {
+    smartLockSubPage.pageContentData = Object.assign(
+        {}, smartLockSubPage.pageContentData, {betterTogetherState: newState});
+  }
+
+  function setSmartLockFeatureState(newState) {
+    smartLockSubPage.pageContentData = Object.assign(
+        {}, smartLockSubPage.pageContentData, {smartLockState: newState});
+  }
+
+  function getSmartLockFeatureToggle() {
+    let smartLockFeatureToggle =
+        smartLockSubPage.$$('settings-multidevice-feature-toggle');
+    assertTrue(!!smartLockFeatureToggle);
+    return smartLockFeatureToggle;
+  }
+
+  function getSmartLockFeatureToggleControl() {
+    let smartLockFeatureToggle = getSmartLockFeatureToggle();
+    let toggleControl = smartLockFeatureToggle.$$('#toggle');
+    assertTrue(!!toggleControl);
+    return toggleControl;
+  }
+
+  function getScreenLockOptionsContent() {
+    let optionsContent = smartLockSubPage.$$('iron-collapse');
+    assertTrue(!!optionsContent);
+    return optionsContent;
+  }
+
+  function getSmartLockSignInRadio() {
+    let smartLockSignInRadio = smartLockSubPage.$$('cr-radio-group');
+    assertTrue(!!smartLockSignInRadio);
+    return smartLockSignInRadio;
+  }
+
+  setup(function() {
+    PolymerTest.clearBody();
+
+    browserProxy = new multidevice.TestMultideviceBrowserProxy();
+    settings.MultiDeviceBrowserProxyImpl.instance_ = browserProxy;
+
+    // Each test must create a settings-multidevice-smartlock-subpage element.
+    smartLockSubPage = null;
+  });
+
+  teardown(function() {
+    assertTrue(!!smartLockSubPage);
+    smartLockSubPage.remove();
+
+    browserProxy.reset();
+  });
+
+  test('Smart Lock enabled', function() {
+    smartLockSubPage = createSmartLockSubPage();
+    setSmartLockFeatureState(settings.MultiDeviceFeatureState.ENABLED_BY_USER);
+
+    // Feature toggle is checked.
+    let toggleControl = getSmartLockFeatureToggleControl();
+    assertTrue(toggleControl.checked);
+
+    // Screen lock options are visible.
+    let optionsContent = getScreenLockOptionsContent();
+    assertTrue(optionsContent.opened);
+  });
+
+  test('Smart Lock disabled by user', function() {
+    smartLockSubPage = createSmartLockSubPage();
+    setSmartLockFeatureState(settings.MultiDeviceFeatureState.DISABLED_BY_USER);
+
+    // Feature toggle is not checked.
+    let toggleControl = getSmartLockFeatureToggleControl();
+    assertFalse(toggleControl.checked);
+
+    // Screen lock options are not visible.
+    let optionsContent = getScreenLockOptionsContent();
+    assertFalse(optionsContent.opened);
+  });
+
+  test('Smart Lock prohibited by policy', function() {
+    smartLockSubPage = createSmartLockSubPage();
+    setSmartLockFeatureState(
+        settings.MultiDeviceFeatureState.PROHIBITED_BY_POLICY);
+
+    // Feature toggle is not checked.
+    let toggleControl = getSmartLockFeatureToggleControl();
+    assertFalse(toggleControl.checked);
+
+    // Screen lock options are not visible.
+    let optionsContent = getScreenLockOptionsContent();
+    assertFalse(optionsContent.opened);
+  });
+
+  test('Smart Lock enable feature toggle', function() {
+    smartLockSubPage = createSmartLockSubPage();
+    setSuiteState(settings.MultiDeviceFeatureState.ENABLED_BY_USER);
+    setSmartLockFeatureState(settings.MultiDeviceFeatureState.DISABLED_BY_USER);
+
+    // Feature toggle is not checked.
+    let toggleControl = getSmartLockFeatureToggleControl();
+    assertFalse(toggleControl.checked);
+
+    // In the case of Smart Lock, the multidevice-feature-toggle depends on the
+    // top-level settings-multidevice-page handling the authentication process
+    // and feature toggling.
+    //
+    // This code simulates the authentication and toggling by directly toggling
+    // the feature to enabled when the feature toggle is clicked.
+    let featureToggle = getSmartLockFeatureToggle();
+    const whenFeatureClicked = test_util.eventToPromise(
+        'feature-toggle-clicked', featureToggle).then(() => {
+      setSmartLockFeatureState(
+        settings.MultiDeviceFeatureState.ENABLED_BY_USER);
+    });
+
+    // Toggle the feature to enabled.
+    toggleControl.click();
+
+    // Verify the feature control is toggled to enabled after the user clicks on
+    // the feature toggle.
+    return whenFeatureClicked.then(() => {
+      assertTrue(toggleControl.checked);
+    });
+  });
+
+  test('Smart Lock enable feature toggle without authentication', function()
+  {
+    smartLockSubPage = createSmartLockSubPage();
+    setSuiteState(settings.MultiDeviceFeatureState.ENABLED_BY_USER);
+    setSmartLockFeatureState(settings.MultiDeviceFeatureState.DISABLED_BY_USER);
+
+    // Feature toggle is not checked.
+    let toggleControl = getSmartLockFeatureToggleControl();
+    assertFalse(toggleControl.checked);
+
+    // In the case of Smart Lock, the multidevice-feature-toggle depends on the
+    // top-level settings-multidevice-page handling the authentication process
+    // and feature toggling.
+    //
+    // This code simulates the user cancelling authentication by ignoring the
+    // toggle being clicked.
+    let featureToggle = getSmartLockFeatureToggle();
+    const whenFeatureClicked = test_util.eventToPromise(
+        'feature-toggle-clicked', featureToggle).then(() => {
+      // Do not enable the feature (simulating the user cancelling auth).
+    });
+
+    // Toggle the feature to enabled.
+    toggleControl.click();
+
+    // Verify the feature control is not toggled to enabled after the user
+    // cancels authenticating with the password dialog.
+    return whenFeatureClicked.then(() => {
+      assertFalse(toggleControl.checked);
+    });
+  });
+
+  test('Smart Lock signin disabled by default', function() {
+    smartLockSubPage = createSmartLockSubPage();
+
+    let smartLockSignInRadio = getSmartLockSignInRadio();
+    assertEquals(settings.SignInEnabledState.DISABLED,
+                 smartLockSignInRadio.selected);
+  });
+
+  test('Smart Lock signin enabled', function() {
+    let whenSignInEnabledSet =
+        browserProxy.whenCalled('getSmartLockSignInEnabled');
+
+    smartLockSubPage = createSmartLockSubPage();
+
+    let smartLockSignInRadio = getSmartLockSignInRadio();
+    assertEquals(settings.SignInEnabledState.DISABLED,
+                 smartLockSignInRadio.selected);
+
+    return whenSignInEnabledSet.then(() => {
+      assertEquals(settings.SignInEnabledState.ENABLED,
+                  smartLockSignInRadio.selected);
+    });
+  });
+
+  test('Smart Lock signin enabled changed', function() {
+    smartLockSubPage = createSmartLockSubPage();
+
+    let smartLockSignInRadio = getSmartLockSignInRadio();
+    assertEquals(settings.SignInEnabledState.DISABLED,
+                 smartLockSignInRadio.selected);
+
+    cr.webUIListenerCallback('smart-lock-signin-enabled-changed', true);
+    Polymer.dom.flush();
+
+    assertEquals(settings.SignInEnabledState.ENABLED,
+                 smartLockSignInRadio.selected);
+  });
+
+  test('Smart Lock sign in successful authentication', function() {
+    smartLockSubPage = createSmartLockSubPage();
+
+    let smartLockSignInRadio = getSmartLockSignInRadio();
+    assertEquals(settings.SignInEnabledState.DISABLED,
+                 smartLockSignInRadio.selected);
+
+    // The password dialog is not visible.
+    let passwordDialog =
+    smartLockSubPage.$$('settings-password-prompt-dialog');
+    assertTrue(!passwordDialog);
+
+    // Click the 'Enable sign in' radio.
+    let enableSmartLockControl =
+        smartLockSubPage.$$('multidevice-radio-button[name="enabled"]');
+    assertTrue(!!enableSmartLockControl);
+    enableSmartLockControl.click();
+    Polymer.dom.flush();
+
+    // The password dialog is now visible.
+    passwordDialog = smartLockSubPage.$$('settings-password-prompt-dialog');
+    assertTrue(!!passwordDialog);
+
+    // Sign in radio is still disabled because the user has not authenticated
+    // using the password dialog.
+    assertEquals(settings.SignInEnabledState.DISABLED,
+                 smartLockSignInRadio.selected);
+
+    // Simulate the user entering a valid password.
+    smartLockSubPage.fire('auth-token-changed', {value: 'validAuthToken'});
+
+    assertEquals(settings.SignInEnabledState.ENABLED,
+                  smartLockSignInRadio.selected);
+  });
+
+  test('Smart Lock sign in cancel authentication', function() {
+    smartLockSubPage = createSmartLockSubPage();
+
+    let smartLockSignInRadio = getSmartLockSignInRadio();
+    assertEquals(settings.SignInEnabledState.DISABLED,
+                 smartLockSignInRadio.selected);
+
+    // The password dialog is not visible.
+    let passwordDialog = smartLockSubPage.$$('settings-password-prompt-dialog');
+    assertTrue(!passwordDialog);
+
+    // Click the 'Enable sign in' radio.
+    let enableSmartLockControl =
+        smartLockSubPage.$$('multidevice-radio-button[name="enabled"]');
+    assertTrue(!!enableSmartLockControl);
+    enableSmartLockControl.click();
+    Polymer.dom.flush();
+
+    // The password dialog is now visible.
+    passwordDialog = smartLockSubPage.$$('settings-password-prompt-dialog');
+    assertTrue(!!passwordDialog);
+
+    // Sign in radio is still disabled because the user has not authenticated
+    // using the password dialog.
+    assertEquals(settings.SignInEnabledState.DISABLED,
+                 smartLockSignInRadio.selected);
+
+    // Simulate the user closing the password dialog.
+    passwordDialog.dispatchEvent(new CustomEvent('close'));
+    Polymer.dom.flush();
+
+    // Verify the password dialog is closed.
+    passwordDialog = smartLockSubPage.$$('settings-password-prompt-dialog');
+    assert(!passwordDialog);
+
+    // The password dialog is closed and unauthenticated, so sign in is still
+    // disabled.
+    assertEquals(settings.SignInEnabledState.DISABLED,
+                 smartLockSignInRadio.selected);
+  });
+
+  test(
+      'Smart Lock disabling sign in does not show password dialog', function() {
+    smartLockSubPage = createSmartLockSubPage();
+
+    // Set sign in as enabled.
+    cr.webUIListenerCallback('smart-lock-signin-enabled-changed', true);
+    Polymer.dom.flush();
+
+    let smartLockSignInRadio = getSmartLockSignInRadio();
+    assertEquals(settings.SignInEnabledState.ENABLED,
+                 smartLockSignInRadio.selected);
+
+    // The password dialog is not visible.
+    let passwordDialog = smartLockSubPage.$$('settings-password-prompt-dialog');
+    assertTrue(!passwordDialog);
+
+    // Click the 'Disable sign in' radio.
+    let disableSmartLockControl =
+        smartLockSubPage.$$('multidevice-radio-button[name="disabled"]');
+    assertTrue(!!disableSmartLockControl);
+    disableSmartLockControl.click();
+    Polymer.dom.flush();
+
+    // The password dialog is not shown.
+    passwordDialog = smartLockSubPage.$$('settings-password-prompt-dialog');
+    assertTrue(!passwordDialog);
+
+    // Sign in radio is now disabled.
+    assertEquals(settings.SignInEnabledState.DISABLED,
+                 smartLockSignInRadio.selected);
+  });
+
+  test('Smart Lock sign in control enabled by default', function() {
+    smartLockSubPage = createSmartLockSubPage();
+
+    let smartLockSignInRadio = getSmartLockSignInRadio();
+    assertFalse(smartLockSignInRadio.disabled);
+  });
+
+  test('Smart Lock sign in control disabled by policy', function() {
+    browserProxy.smartLockSignInAllowed = false;
+    let whenSignInAllowedSet =
+        browserProxy.whenCalled('getSmartLockSignInAllowed');
+
+    smartLockSubPage = createSmartLockSubPage();
+
+    return whenSignInAllowedSet.then(() => {
+      let smartLockSignInRadio = getSmartLockSignInRadio();
+      assertTrue(smartLockSignInRadio.disabled);
+    });
+  });
+
+  test('Smart Lock sign in control allowed state changes', function() {
+    smartLockSubPage = createSmartLockSubPage();
+
+    let smartLockSignInRadio = getSmartLockSignInRadio();
+    assertFalse(smartLockSignInRadio.disabled);
+
+    cr.webUIListenerCallback('smart-lock-signin-allowed-changed', false);
+    Polymer.dom.flush();
+
+    assertTrue(smartLockSignInRadio.disabled);
+  });
+});
diff --git a/chrome/test/data/webui/settings/test_multidevice_browser_proxy.js b/chrome/test/data/webui/settings/test_multidevice_browser_proxy.js
index d64e9e1..31346cf 100644
--- a/chrome/test/data/webui/settings/test_multidevice_browser_proxy.js
+++ b/chrome/test/data/webui/settings/test_multidevice_browser_proxy.js
@@ -47,11 +47,15 @@
         'getPageContentData',
         'setFeatureEnabledState',
         'setUpAndroidSms',
+        'getSmartLockSignInEnabled',
+        'setSmartLockSignInEnabled',
+        'getSmartLockSignInAllowed',
         'getAndroidSmsInfo',
       ]);
       this.data = createFakePageContentData(
           settings.MultiDeviceSettingsMode.NO_HOST_SET);
       this.androidSmsInfo = {origin: TEST_ANDROID_SMS_ORIGIN, enabled: true};
+      this.smartLockSignInAllowed = true;
     }
 
     /** @override */
@@ -82,6 +86,24 @@
     }
 
     /** @override */
+    getSmartLockSignInEnabled() {
+      this.methodCalled('getSmartLockSignInEnabled');
+      return Promise.resolve(true);
+    }
+
+    /** @override */
+    setSmartLockSignInEnabled(enabled, opt_authToken) {
+      this.methodCalled('setSmartLockSignInEnabled', [enabled, opt_authToken]);
+      cr.webUIListenerCallback('smart-lock-signin-enabled-changed', enabled);
+    }
+
+    /** @override */
+    getSmartLockSignInAllowed() {
+      this.methodCalled('getSmartLockSignInAllowed');
+      return Promise.resolve(this.smartLockSignInAllowed);
+    }
+
+    /** @override */
     getAndroidSmsInfo() {
       this.methodCalled('getAndroidSmsInfo');
       return Promise.resolve(this.androidSmsInfo);
diff --git a/chrome/tools/build/win/FILES.cfg b/chrome/tools/build/win/FILES.cfg
index 888b3f1d..b3288fb 100644
--- a/chrome/tools/build/win/FILES.cfg
+++ b/chrome/tools/build/win/FILES.cfg
@@ -508,6 +508,31 @@
     'buildtype': ['official'],
     'archive': 'remoting-win32.zip',
   },
+  # Credential Provider:
+  {
+    'filename': 'gcp_setup.exe',
+    'buildtype': ['dev', 'official'],
+    'optional': ['dev', 'official'],
+    'filegroup': ['symsrc'],
+  },
+  {
+    'filename': 'gcp_setup.exe.pdb',
+    'buildtype': ['dev', 'official'],
+    'optional': ['dev', 'official'],
+    'archive': 'chrome-win32-syms.zip',
+  },
+  {
+    'filename': 'gaia1_0.dll',
+    'buildtype': ['dev', 'official'],
+    'optional': ['dev', 'official'],
+    'filegroup': ['symsrc'],
+  },
+  {
+    'filename': 'gaia1_0.dll.pdb',
+    'buildtype': ['dev', 'official'],
+    'optional': ['dev', 'official'],
+    'archive': 'chrome-win32-syms.zip',
+  },
   # Cloud Print files:
   {
     'filename': 'gcp_portmon.dll',
diff --git a/chromecast/BUILD.gn b/chromecast/BUILD.gn
index 5557577..45d2799 100644
--- a/chromecast/BUILD.gn
+++ b/chromecast/BUILD.gn
@@ -135,6 +135,15 @@
         "--enable-local-file-accesses",
         "--test-launcher-jobs=1",
       ]
+
+      gtest_excludes = []
+
+      # TODO(b/112440248): This test was failing:
+      #   * On v1 and Cast Audio devices since 2017-03-15.
+      #   * On desktop builds since 2018-08-22
+      # Also see: b/36238710, b/36239051, hotlist/461351
+      gtest_excludes += [ "RendererPrelauncherTest.ReusedRenderer" ]
+
       if (!is_cast_desktop_build) {
         args += [ "--use-gpu-in-tests" ]
 
@@ -142,19 +151,10 @@
         #    Once all of the CastMediaBlockerTest.* have been un-DISABLEd and
         #    are running successfully, revisit these tests and see if they pass
         #    on devices. (crbug/665118, internal b/32023194)
-        gtest_excludes = [
+        gtest_excludes += [
           "CastMediaBlockerBrowserTest.Video_BlockUnblock",
           "CastMediaBlockerBrowserTest.Audio_BlockUnblock",
         ]
-
-        # TODO(mbjorge): The ReusedRenderer test is failing on v1 and cast audio
-        # devices. Temporarily disable them as part of an effort_to re-green
-        # the unittests. Current failures (2017-03-15) are being disabled to get
-        # back to a green state. Re-enable once the tests have been fixed.
-        # Limitations in the build mean this unfortunately is getting disabled
-        # across all devices, even though it is only failing on some.
-        # b/36238710, b/36239051, hotlist/461351
-        gtest_excludes += [ "RendererPrelauncherTest.ReusedRenderer" ]
       }
 
       if (!is_cast_desktop_build && !is_cast_audio_only && !enable_assistant) {
@@ -202,11 +202,8 @@
     gtest_excludes = []
     if (target_os == "linux") {
       if (is_cast_desktop_build) {
-        # Disable PartitionAllocDeathTest.Repeated*ReturnNullDirect (b/67975693)
-        gtest_excludes += [
-          "PartitionAllocDeathTest.RepeatedAllocReturnNullDirect",
-          "PartitionAllocDeathTest.RepeatedReallocReturnNullDirect",
-        ]
+        # Disable PartitionAllocDeathTest.* (b/67975693)
+        gtest_excludes += [ "PartitionAllocDeathTest.*" ]
       } else {
         # Disable ProcessMetricsTest.GetNumberOfThreads (b/15610509)
         # Disable ProcessUtilTest.* (need to define OS_ANDROID)
@@ -235,11 +232,15 @@
 
   cc_unittests_filter = {
     test_name = "cc_unittests"
+
+    # Temporarily disable all test cases (b/113324890)
+    gtest_excludes = [ "*" ]
+
     if (!is_cast_desktop_build) {
       #Disable ToColorSpace/ColorTransformPixelTest*  (b/64346790)
       #Disable ImageBackgroundFilter* (b/64346875)
       #Disable LayerTreeHostTilesTestPartialInvalidation* (b/65844132)
-      gtest_excludes = [
+      gtest_excludes += [
         "ToColorSpace/ColorTransformPixelTest.*",
         "ImageBackgroundFilter.*",
         "LayerTreeHostTilesTestPartialInvalidation.*",
diff --git a/chromecast/base/cast_sys_info_android_things.cc b/chromecast/base/cast_sys_info_android_things.cc
index 70028eb..04d77b3 100644
--- a/chromecast/base/cast_sys_info_android_things.cc
+++ b/chromecast/base/cast_sys_info_android_things.cc
@@ -62,7 +62,7 @@
 #if BUILDFLAG(IS_ANDROID_THINGS_NON_PUBLIC)
   JNIEnv* env = base::android::AttachCurrentThread();
   base::android::AppendJavaStringArrayToStringVector(
-      env, Java_CastSysInfoAndroidThings_getFactoryLocaleList(env).obj(),
+      env, Java_CastSysInfoAndroidThings_getFactoryLocaleList(env),
       &locale_list);
 #endif
   return locale_list;
diff --git a/chromecast/browser/cast_content_browser_client.cc b/chromecast/browser/cast_content_browser_client.cc
index cff4cab9..1689f49d 100644
--- a/chromecast/browser/cast_content_browser_client.cc
+++ b/chromecast/browser/cast_content_browser_client.cc
@@ -149,7 +149,7 @@
   PrefService* pref_service = CastBrowserProcess::GetInstance()->pref_service();
   DCHECK(pref_service);
 
-  if (render_frame_host->GetLastCommittedOrigin().unique()) {
+  if (render_frame_host->GetLastCommittedOrigin().opaque()) {
     DVLOG(1) << __func__ << ": Unique origin.";
     return;
   }
diff --git a/chromecast/browser/cast_media_blocker_browsertest.cc b/chromecast/browser/cast_media_blocker_browsertest.cc
index 7483ddd..f37cc6b 100644
--- a/chromecast/browser/cast_media_blocker_browsertest.cc
+++ b/chromecast/browser/cast_media_blocker_browsertest.cc
@@ -54,10 +54,11 @@
 
     // Changing states is not instant, but should be timely (< 0.5s).
     for (size_t i = 0; i < 5; i++) {
+      LOG(INFO) << "Checking media blocking, re-try = " << i;
       base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
       base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
           FROM_HERE, run_loop.QuitClosure(),
-          base::TimeDelta::FromMilliseconds(50));
+          base::TimeDelta::FromMilliseconds(100));
       run_loop.Run();
 
       const std::string command =
diff --git a/chromecast/browser/network_context_manager.cc b/chromecast/browser/network_context_manager.cc
index 2179635e..988c234 100644
--- a/chromecast/browser/network_context_manager.cc
+++ b/chromecast/browser/network_context_manager.cc
@@ -27,20 +27,22 @@
       network_service_for_test_(std::move(network_service)),
       weak_factory_(this) {
   DCHECK(url_request_context_getter_);
+  weak_ptr_ = weak_factory_.GetWeakPtr();
+
   // The NetworkContext must be initialized on the browser's IO thread. Posting
   // this task from the constructor ensures that |network_context_| will
   // be initialized for subsequent calls to BindRequestOnIOThread().
   base::PostTaskWithTraits(
       FROM_HERE, {content::BrowserThread::IO},
-      base::BindOnce(&NetworkContextManager::InitializeOnIoThread,
-                     weak_factory_.GetWeakPtr()));
+      base::BindOnce(&NetworkContextManager::InitializeOnIOThread,
+                     GetWeakPtr()));
 }
 
 NetworkContextManager::~NetworkContextManager() {
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
 }
 
-void NetworkContextManager::InitializeOnIoThread() {
+void NetworkContextManager::InitializeOnIOThread() {
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
 
   network::NetworkService* network_service =
@@ -62,17 +64,31 @@
       std::move(request), std::move(url_loader_factory_params));
 }
 
+void NetworkContextManager::GetProxyResolvingSocketFactoryOnIOThread(
+    network::mojom::ProxyResolvingSocketFactoryRequest request) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+  network_context_->CreateProxyResolvingSocketFactory(std::move(request));
+}
+
 network::mojom::URLLoaderFactoryPtr
 NetworkContextManager::GetURLLoaderFactory() {
   network::mojom::URLLoaderFactoryPtr loader_factory;
   base::PostTaskWithTraits(
       FROM_HERE, {content::BrowserThread::IO},
       base::BindOnce(&NetworkContextManager::BindRequestOnIOThread,
-                     weak_factory_.GetWeakPtr(),
-                     mojo::MakeRequest(&loader_factory)));
+                     GetWeakPtr(), mojo::MakeRequest(&loader_factory)));
   return loader_factory;
 }
 
+void NetworkContextManager::GetProxyResolvingSocketFactory(
+    network::mojom::ProxyResolvingSocketFactoryRequest request) {
+  base::PostTaskWithTraits(
+      FROM_HERE, {content::BrowserThread::IO},
+      base::BindOnce(
+          &NetworkContextManager::GetProxyResolvingSocketFactoryOnIOThread,
+          GetWeakPtr(), std::move(request)));
+}
+
 //  static
 NetworkContextManager* NetworkContextManager::CreateForTest(
     scoped_refptr<net::URLRequestContextGetter> url_request_context_getter,
diff --git a/chromecast/browser/network_context_manager.h b/chromecast/browser/network_context_manager.h
index b73574a..2730f2a 100644
--- a/chromecast/browser/network_context_manager.h
+++ b/chromecast/browser/network_context_manager.h
@@ -53,6 +53,14 @@
   // calling thread. The caller owns the returned interface pointer.
   network::mojom::URLLoaderFactoryPtr GetURLLoaderFactory();
 
+  // Creates a ProxyResolvingSocketFactory asynchronously on the IO thread, and
+  // binds it to |request|. This may be called from any thread.
+  void GetProxyResolvingSocketFactory(
+      network::mojom::ProxyResolvingSocketFactoryRequest request);
+
+  // Get a WeakPtr to this object.
+  base::WeakPtr<NetworkContextManager> GetWeakPtr() { return weak_ptr_; }
+
   // Creates a NetworkContextManager for testing, so that a fake NetworkService
   // can be created on the IO thread and injected into this class. Caller owns
   // the returned instance. Returns the object unwrapped so that it can be
@@ -70,12 +78,18 @@
       std::unique_ptr<network::NetworkService> network_service);
 
   // Initializes the NetworkContext. Posted to the IO thread from the ctor.
-  void InitializeOnIoThread();
+  void InitializeOnIOThread();
 
   // Posted to the IO thread whenever GetURLLoaderFactoryPtr() is called.
   // Guaranteed to be called after InitializeOnIoThread().
   void BindRequestOnIOThread(network::mojom::URLLoaderFactoryRequest request);
 
+  // Create a proxy-resolving socket factory using the |network_context_| on the
+  // IO thread. Posted from RequestProxyResolvingSocketFactory(). Guaranteed to
+  // be called after InitializeOnIoThread().
+  void GetProxyResolvingSocketFactoryOnIOThread(
+      network::mojom::ProxyResolvingSocketFactoryRequest request);
+
   // The underlying URLRequestContextGetter. The reference may only be released
   // after the NetworkContext has been destroyed.
   const scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_;
@@ -89,6 +103,7 @@
   std::unique_ptr<network::NetworkContext> network_context_;
   network::mojom::NetworkContextPtr network_context_ptr_;
 
+  base::WeakPtr<NetworkContextManager> weak_ptr_;
   base::WeakPtrFactory<NetworkContextManager> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(NetworkContextManager);
diff --git a/chromecast/device/bluetooth/le/mock_remote_characteristic.h b/chromecast/device/bluetooth/le/mock_remote_characteristic.h
index 8b7beddf..05156ae 100644
--- a/chromecast/device/bluetooth/le/mock_remote_characteristic.h
+++ b/chromecast/device/bluetooth/le/mock_remote_characteristic.h
@@ -39,10 +39,16 @@
     std::move(callback).Run(res.first, std::move(res.second));
   }
 
+  MOCK_METHOD3(WriteAuth,
+               bool(bluetooth_v2_shlib::Gatt::Client::AuthReq auth_req,
+                    bluetooth_v2_shlib::Gatt::WriteType write_type,
+                    const std::vector<uint8_t>& value));
   void WriteAuth(bluetooth_v2_shlib::Gatt::Client::AuthReq auth_req,
                  bluetooth_v2_shlib::Gatt::WriteType write_type,
                  const std::vector<uint8_t>& value,
-                 StatusCallback callback) override {}
+                 StatusCallback callback) override {
+    std::move(callback).Run(WriteAuth(auth_req, write_type, value));
+  }
 
   MOCK_METHOD1(Write, bool(const std::vector<uint8_t>& value));
   void Write(const std::vector<uint8_t>& value,
diff --git a/chromecast/media/cma/backend/android/java/src/org/chromium/chromecast/cma/backend/android/VolumeMap.java b/chromecast/media/cma/backend/android/java/src/org/chromium/chromecast/cma/backend/android/VolumeMap.java
index 8f71bddf..b49a72f3 100644
--- a/chromecast/media/cma/backend/android/java/src/org/chromium/chromecast/cma/backend/android/VolumeMap.java
+++ b/chromecast/media/cma/backend/android/java/src/org/chromium/chromecast/cma/backend/android/VolumeMap.java
@@ -28,7 +28,7 @@
 
     private static final int DEVICE_TYPE = AudioDeviceInfo.TYPE_BUILTIN_SPEAKER;
 
-    private static AudioManager sAudioManager = null;
+    private static AudioManager sAudioManager;
 
     // Mapping from Android's stream_type to Cast's AudioContentType (used for callback).
     private static final SparseIntArray ANDROID_TYPE_TO_CAST_TYPE_MAP = new SparseIntArray(4) {
diff --git a/chromecast/media/cma/backend/media_pipeline_backend_for_mixer.cc b/chromecast/media/cma/backend/media_pipeline_backend_for_mixer.cc
index bc686ff..3078b2eb 100644
--- a/chromecast/media/cma/backend/media_pipeline_backend_for_mixer.cc
+++ b/chromecast/media/cma/backend/media_pipeline_backend_for_mixer.cc
@@ -190,11 +190,14 @@
 int64_t MediaPipelineBackendForMixer::GetCurrentPts() {
   int64_t timestamp = 0;
   int64_t pts = 0;
+  int64_t video_pts = INT64_MIN;
+  int64_t audio_pts = INT64_MIN;
+
   if (video_decoder_ && video_decoder_->GetCurrentPts(&timestamp, &pts))
-    return pts;
+    video_pts = pts;
   if (audio_decoder_)
-    return audio_decoder_->GetCurrentPts();
-  return std::numeric_limits<int64_t>::min();
+    audio_pts = audio_decoder_->GetCurrentPts();
+  return std::max(audio_pts, video_pts);
 }
 
 bool MediaPipelineBackendForMixer::Primary() const {
diff --git a/chromecast/media/cma/backend/post_processing_pipeline_impl.h b/chromecast/media/cma/backend/post_processing_pipeline_impl.h
index efe143b3..21f29e0 100644
--- a/chromecast/media/cma/backend/post_processing_pipeline_impl.h
+++ b/chromecast/media/cma/backend/post_processing_pipeline_impl.h
@@ -61,13 +61,13 @@
   void UpdateCastVolume(float multiplier);
 
   std::string name_;
-  int sample_rate_;
+  int sample_rate_ = 0;
   int ringing_time_in_frames_ = 0;
   int silence_frames_processed_ = 0;
   int total_delay_frames_ = 0;
-  float current_multiplier_;
-  float cast_volume_;
-  float current_dbfs_;
+  float current_multiplier_ = 0.0;
+  float cast_volume_ = 0.0;
+  float current_dbfs_ = 0.0;
   int num_output_channels_ = 0;
   float* output_buffer_ = nullptr;
 
diff --git a/chromecast/media/cma/base/BUILD.gn b/chromecast/media/cma/base/BUILD.gn
index 220286d..6fd5c78 100644
--- a/chromecast/media/cma/base/BUILD.gn
+++ b/chromecast/media/cma/base/BUILD.gn
@@ -47,5 +47,6 @@
     "//chromecast/media/base:media_codec_support",
     "//media",
     "//media:shared_memory_support",
+    "//ui/gfx",
   ]
 }
diff --git a/chromecast/renderer/media/key_systems_cast.cc b/chromecast/renderer/media/key_systems_cast.cc
index f7870c94..65e0115 100644
--- a/chromecast/renderer/media/key_systems_cast.cc
+++ b/chromecast/renderer/media/key_systems_cast.cc
@@ -84,7 +84,7 @@
                                        : EmeSessionTypeSupport::NOT_SUPPORTED;
   }
 
-  EmeSessionTypeSupport GetPersistentReleaseMessageSessionSupport()
+  EmeSessionTypeSupport GetPersistentUsageRecordSessionSupport()
       const override {
     return EmeSessionTypeSupport::NOT_SUPPORTED;
   }
@@ -96,9 +96,11 @@
     return EmeFeatureSupport::ALWAYS_ENABLED;
   }
 
-  bool IsEncryptionSchemeSupported(
+  EmeConfigRule GetEncryptionSchemeConfigRule(
       ::media::EncryptionMode encryption_mode) const override {
-    return encryption_mode == ::media::EncryptionMode::kCenc;
+    if (encryption_mode == ::media::EncryptionMode::kCenc)
+      return EmeConfigRule::SUPPORTED;
+    return EmeConfigRule::NOT_SUPPORTED;
   }
 
  private:
diff --git a/chromeos/chromeos_features.cc b/chromeos/chromeos_features.cc
index be49881..1d2c3313 100644
--- a/chromeos/chromeos_features.cc
+++ b/chromeos/chromeos_features.cc
@@ -16,6 +16,11 @@
 const base::Feature kAndroidMessagesProdEndpoint{
     "AndroidMessagesProdEndpoint", base::FEATURE_ENABLED_BY_DEFAULT};
 
+// Enables or disables auto screen-brightness adjustment when ambient light
+// changes.
+const base::Feature kAutoScreenBrightness{"AutoScreenBrightness",
+                                          base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Enables or disables native ChromeVox support for Arc.
 const base::Feature kChromeVoxArcSupport{"ChromeVoxArcSupport",
                                          base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/chromeos/chromeos_features.h b/chromeos/chromeos_features.h
index 728c61a6..4000190e5 100644
--- a/chromeos/chromeos_features.h
+++ b/chromeos/chromeos_features.h
@@ -17,6 +17,7 @@
 
 CHROMEOS_EXPORT extern const base::Feature kAndroidMessagesIntegration;
 CHROMEOS_EXPORT extern const base::Feature kAndroidMessagesProdEndpoint;
+CHROMEOS_EXPORT extern const base::Feature kAutoScreenBrightness;
 CHROMEOS_EXPORT extern const base::Feature kChromeVoxArcSupport;
 CHROMEOS_EXPORT extern const base::Feature kDriveFs;
 CHROMEOS_EXPORT extern const base::Feature kMyFilesVolume;
diff --git a/chromeos/components/drivefs/drivefs_host.cc b/chromeos/components/drivefs/drivefs_host.cc
index 1fe34e5e..43904b2 100644
--- a/chromeos/components/drivefs/drivefs_host.cc
+++ b/chromeos/components/drivefs/drivefs_host.cc
@@ -291,7 +291,11 @@
     DCHECK_CALLED_ON_VALID_SEQUENCE(host_->sequence_checker_);
     drivefs_has_mounted_ = false;
     drivefs_has_terminated_ = true;
-    host_->mount_observer_->OnMountFailed(std::move(remount_delay));
+    bool needs_restart = remount_delay.has_value();
+    host_->mount_observer_->OnMountFailed(
+        needs_restart ? MountObserver::MountFailure::kNeedsRestart
+                      : MountObserver::MountFailure::kUnknown,
+        std::move(remount_delay));
   }
 
   void OnUnmounted(base::Optional<base::TimeDelta> remount_delay) override {
@@ -351,17 +355,23 @@
   void OnConnectionError() {
     DCHECK_CALLED_ON_VALID_SEQUENCE(host_->sequence_checker_);
     if (!drivefs_has_terminated_) {
-      if (mounted())
+      if (mounted()) {
         host_->mount_observer_->OnUnmounted({});
-      else
-        host_->mount_observer_->OnMountFailed({});
+      } else {
+        host_->mount_observer_->OnMountFailed(
+            MountObserver::MountFailure::kIpcDisconnect, {});
+      }
       drivefs_has_terminated_ = true;
     }
   }
 
   void OnTimedOut() {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(host_->sequence_checker_);
     host_->timer_->Stop();
-    OnMountFailed({});
+    drivefs_has_mounted_ = false;
+    drivefs_has_terminated_ = true;
+    host_->mount_observer_->OnMountFailed(MountObserver::MountFailure::kTimeout,
+                                          {});
   }
 
   void MaybeNotifyDelegateOnMounted() {
@@ -387,7 +397,7 @@
 
       // Deletes |this|.
       host_->Unmount();
-      observer->OnMountFailed({});
+      observer->OnMountFailed(MountObserver::MountFailure::kInvocation, {});
       return;
     }
     DCHECK(!mount_info.mount_path.empty());
diff --git a/chromeos/components/drivefs/drivefs_host.h b/chromeos/components/drivefs/drivefs_host.h
index 7c9e6649..859f824 100644
--- a/chromeos/components/drivefs/drivefs_host.h
+++ b/chromeos/components/drivefs/drivefs_host.h
@@ -64,11 +64,20 @@
 
   class MountObserver {
    public:
+    enum class MountFailure {
+      kUnknown,
+      kNeedsRestart,
+      kIpcDisconnect,
+      kInvocation,
+      kTimeout,
+    };
+
     MountObserver() = default;
     virtual ~MountObserver() = default;
     virtual void OnMounted(const base::FilePath& mount_path) = 0;
     virtual void OnUnmounted(base::Optional<base::TimeDelta> remount_delay) = 0;
     virtual void OnMountFailed(
+        MountFailure failure,
         base::Optional<base::TimeDelta> remount_delay) = 0;
 
    private:
diff --git a/chromeos/components/drivefs/drivefs_host_unittest.cc b/chromeos/components/drivefs/drivefs_host_unittest.cc
index 3018e7d..e9165e0f7 100644
--- a/chromeos/components/drivefs/drivefs_host_unittest.cc
+++ b/chromeos/components/drivefs/drivefs_host_unittest.cc
@@ -36,6 +36,7 @@
 namespace {
 
 using testing::_;
+using MountFailure = DriveFsHost::MountObserver::MountFailure;
 
 class TestingMojoConnectionDelegate
     : public DriveFsHost::MojoConnectionDelegate {
@@ -159,7 +160,8 @@
 
   // DriveFsHost::MountObserver:
   MOCK_METHOD1(OnMounted, void(const base::FilePath&));
-  MOCK_METHOD1(OnMountFailed, void(base::Optional<base::TimeDelta>));
+  MOCK_METHOD2(OnMountFailed,
+               void(MountFailure, base::Optional<base::TimeDelta>));
   MOCK_METHOD1(OnUnmounted, void(base::Optional<base::TimeDelta>));
 
   drive::DriveNotificationManager& GetDriveNotificationManager() override {
@@ -501,7 +503,7 @@
   ASSERT_NO_FATAL_FAILURE(EstablishConnection());
   base::RunLoop run_loop;
   base::OnceClosure quit_closure = run_loop.QuitClosure();
-  EXPECT_CALL(*host_delegate_, OnMountFailed(_))
+  EXPECT_CALL(*host_delegate_, OnMountFailed(MountFailure::kUnknown, _))
       .WillOnce(RunQuitClosure(&quit_closure));
   SendMountFailed({});
   run_loop.Run();
@@ -515,7 +517,7 @@
 
   base::RunLoop run_loop;
   base::OnceClosure quit_closure = run_loop.QuitClosure();
-  EXPECT_CALL(*host_delegate_, OnMountFailed(_))
+  EXPECT_CALL(*host_delegate_, OnMountFailed(MountFailure::kInvocation, _))
       .WillOnce(RunQuitClosure(&quit_closure));
   DispatchMountEvent(chromeos::disks::DiskMountManager::MOUNTING,
                      chromeos::MOUNT_ERROR_INVALID_MOUNT_OPTIONS,
@@ -535,7 +537,7 @@
 
   base::RunLoop run_loop;
   base::OnceClosure quit_closure = run_loop.QuitClosure();
-  EXPECT_CALL(*host_delegate_, OnMountFailed(_))
+  EXPECT_CALL(*host_delegate_, OnMountFailed(MountFailure::kInvocation, _))
       .WillOnce(testing::InvokeWithoutArgs([&]() {
         std::move(quit_closure).Run();
         host_->Unmount();
@@ -635,7 +637,7 @@
 TEST_F(DriveFsHostTest, MountError) {
   auto token = StartMount();
   EXPECT_CALL(*disk_manager_, UnmountPath(_, _, _)).Times(0);
-  EXPECT_CALL(*host_delegate_, OnMountFailed(_));
+  EXPECT_CALL(*host_delegate_, OnMountFailed(MountFailure::kInvocation, _));
 
   DispatchMountEvent(chromeos::disks::DiskMountManager::MOUNTING,
                      chromeos::MOUNT_ERROR_DIRECTORY_CREATION_FAILED,
@@ -674,7 +676,8 @@
   EXPECT_FALSE(host_->IsMounted());
 
   base::Optional<base::TimeDelta> empty;
-  EXPECT_CALL(*host_delegate_, OnMountFailed(empty));
+  EXPECT_CALL(*host_delegate_,
+              OnMountFailed(MountFailure::kIpcDisconnect, empty));
   delegate_ptr_.reset();
   base::RunLoop().RunUntilIdle();
 }
@@ -685,7 +688,7 @@
   EXPECT_FALSE(host_->IsMounted());
 
   base::Optional<base::TimeDelta> empty;
-  EXPECT_CALL(*host_delegate_, OnMountFailed(empty));
+  EXPECT_CALL(*host_delegate_, OnMountFailed(MountFailure::kTimeout, empty));
   timer_->Fire();
 }
 
diff --git a/chromeos/components/proximity_auth/notification_controller.h b/chromeos/components/proximity_auth/notification_controller.h
index 152ee90..60a014ce 100644
--- a/chromeos/components/proximity_auth/notification_controller.h
+++ b/chromeos/components/proximity_auth/notification_controller.h
@@ -26,9 +26,6 @@
   // should be used for EasyUnlock from now on.
   virtual void ShowPairingChangeAppliedNotification(
       const std::string& phone_name) = 0;
-
-  // Shows the notification to promote EasyUnlock to the user.
-  virtual void ShowPromotionNotification() = 0;
 };
 
 }  // namespace proximity_auth
diff --git a/chromeos/network/client_cert_resolver.cc b/chromeos/network/client_cert_resolver.cc
index 6f3caf95..0f7525d 100644
--- a/chromeos/network/client_cert_resolver.cc
+++ b/chromeos/network/client_cert_resolver.cc
@@ -27,6 +27,7 @@
 #include "chromeos/network/network_state.h"
 #include "chromeos/tools/variable_expander.h"
 #include "components/onc/onc_constants.h"
+#include "crypto/scoped_nss_types.h"
 #include "dbus/object_path.h"
 #include "net/cert/scoped_nss_types.h"
 #include "net/cert/x509_certificate.h"
@@ -67,10 +68,10 @@
 };
 
 // Describes a network that is configured with |client_cert_config|, which
-// includes the certificate pattern.
-struct NetworkAndCertPattern {
-  NetworkAndCertPattern(const std::string& network_path,
-                        const client_cert::ClientCertConfig& client_cert_config)
+// includes the certificate config.
+struct NetworkAndCertConfig {
+  NetworkAndCertConfig(const std::string& network_path,
+                       const client_cert::ClientCertConfig& client_cert_config)
       : service_path(network_path), cert_config(client_cert_config) {}
 
   std::string service_path;
@@ -114,6 +115,14 @@
   return substitutions;
 }
 
+// Returns true if |client_cert_config| specifies a pattern or reference, i.e.
+// if client certificate resolution should be attempted.
+bool ShouldResolveCert(
+    const client_cert::ClientCertConfig& client_cert_config) {
+  return client_cert_config.client_cert_type == ::onc::client_cert::kPattern ||
+         client_cert_config.client_cert_type == ::onc::client_cert::kRef;
+}
+
 }  // namespace
 
 namespace internal {
@@ -134,10 +143,10 @@
 
 // Describes a network |network_path| and the client cert resolution result.
 struct NetworkAndMatchingCert {
-  NetworkAndMatchingCert(const NetworkAndCertPattern& network_and_pattern,
+  NetworkAndMatchingCert(const NetworkAndCertConfig& network_and_cert_config,
                          base::Optional<MatchingCert> matching_cert)
-      : service_path(network_and_pattern.service_path),
-        cert_config_type(network_and_pattern.cert_config.location),
+      : service_path(network_and_cert_config.service_path),
+        cert_config_type(network_and_cert_config.cert_config.location),
         matching_cert(matching_cert) {}
 
   std::string service_path;
@@ -155,27 +164,45 @@
 
 namespace {
 
-// Returns true if a private key for certificate |cert| is installed.
-// Note that HasPrivateKey is not a cheap operation: it iterates all tokens and
-// attempts to look up the private key.
-bool HasPrivateKey(CERTCertificate* cert) {
-  PK11SlotInfo* slot = PK11_KeyForCertExists(cert, nullptr, nullptr);
-  if (!slot)
-    return false;
+// Returns the nickname of the private key for certificate |cert|, if such a
+// private key is installed. Note that this is not a cheap operation: it
+// iterates all tokens and attempts to look up the private key.
+// A return value of |base::nullopt| means that no private key could be found
+// for |cert|.
+// If a private key could be found for |cert| but it did not have a nickname,
+// will return the empty string.
+base::Optional<std::string> GetPrivateKeyNickname(CERTCertificate* cert) {
+  crypto::ScopedSECKEYPrivateKey key(
+      PK11_FindKeyByAnyCert(cert, nullptr /* wincx */));
+  if (!key)
+    return base::nullopt;
 
-  PK11_FreeSlot(slot);
-  return true;
+  std::string key_nickname;
+  char* nss_key_nickname = PK11_GetPrivateKeyNickname(key.get());
+  if (nss_key_nickname) {
+    key_nickname = nss_key_nickname;
+    PORT_Free(nss_key_nickname);
+  }
+  return key_nickname;
 }
 
 // Describes a certificate which is issued by |issuer| (encoded as PEM).
 // |issuer| can be empty if no issuer certificate is found in the database.
 struct CertAndIssuer {
   CertAndIssuer(net::ScopedCERTCertificate certificate,
-                const std::string& issuer)
-      : cert(std::move(certificate)), pem_encoded_issuer(issuer) {}
+                const std::string& issuer,
+                const std::string& key_nickname)
+      : cert(std::move(certificate)),
+        pem_encoded_issuer(issuer),
+        private_key_nickname(key_nickname) {}
 
   net::ScopedCERTCertificate cert;
   std::string pem_encoded_issuer;
+  // The nickname of the private key associated with |cert|. This is used
+  // for resolving ClientCertRef ONC references, using the fact that
+  // |CertificateImporterImpl| sets the private key nickname to the
+  // ONC-specified GUID.
+  std::string private_key_nickname;
 };
 
 bool CompareCertExpiration(const CertAndIssuer& a, const CertAndIssuer& b) {
@@ -187,12 +214,28 @@
 }
 
 // A unary predicate that returns true if the given CertAndIssuer matches the
-// given certificate pattern.
-struct MatchCertWithPattern {
-  explicit MatchCertWithPattern(const CertificatePattern& cert_pattern)
-      : pattern(cert_pattern) {}
+// given certificate config.
+struct MatchCertWithCertConfig {
+  explicit MatchCertWithCertConfig(
+      const client_cert::ClientCertConfig& client_cert_config)
+      : cert_config(client_cert_config) {}
 
   bool operator()(const CertAndIssuer& cert_and_issuer) {
+    if (cert_config.client_cert_type == ::onc::client_cert::kPattern)
+      return MatchByPattern(cert_config.pattern, cert_and_issuer);
+
+    if (cert_config.client_cert_type == ::onc::client_cert::kRef) {
+      // This relies on the fact that |CertificateImporterImpl| sets the
+      // nickname for the imported private key to the GUID.
+      return cert_config.guid == cert_and_issuer.private_key_nickname;
+    }
+
+    NOTREACHED();
+    return false;
+  }
+
+  static bool MatchByPattern(const CertificatePattern& pattern,
+                             const CertAndIssuer& cert_and_issuer) {
     if (!pattern.issuer().Empty() || !pattern.subject().Empty()) {
       // Allow UTF-8 inside PrintableStrings in client certificates. See
       // crbug.com/770323 and crbug.com/788655.
@@ -223,8 +266,7 @@
     }
     return true;
   }
-
-  const CertificatePattern pattern;
+  const client_cert::ClientCertConfig cert_config;
 };
 
 // Lookup the issuer certificate of |cert|. If it is available, return the PEM
@@ -267,17 +309,23 @@
   for (net::ScopedCERTCertificate& scoped_cert : certs) {
     CERTCertificate* cert = scoped_cert.get();
     base::Time not_after;
-    // HasPrivateKey should be invoked after IsCertificateHardwareBacked for
-    // performance reasons.
     if (!net::x509_util::GetValidityTimes(cert, nullptr, &not_after) ||
         now > not_after ||
-        !NetworkCertLoader::IsCertificateHardwareBacked(cert) ||
-        !HasPrivateKey(cert)) {
+        !NetworkCertLoader::IsCertificateHardwareBacked(cert)) {
+      continue;
+    }
+    // GetPrivateKeyNickname should be invoked after the checks above for
+    // performance reasons.
+    base::Optional<std::string> private_key_nickname =
+        GetPrivateKeyNickname(cert);
+    if (!private_key_nickname.has_value()) {
+      // No private key has been found for this certificate.
       continue;
     }
     std::string pem_encoded_issuer = GetPEMEncodedIssuer(cert);
-    client_certs.push_back(
-        CertAndIssuer(std::move(scoped_cert), pem_encoded_issuer));
+    client_certs.push_back(CertAndIssuer(std::move(scoped_cert),
+                                         pem_encoded_issuer,
+                                         private_key_nickname.value()));
   }
 
   std::sort(client_certs.begin(), client_certs.end(), &CompareCertExpiration);
@@ -292,7 +340,7 @@
 std::vector<NetworkAndMatchingCert> FindCertificateMatches(
     net::ScopedCERTCertificateList all_certs,
     net::ScopedCERTCertificateList system_token_client_certs,
-    const std::vector<NetworkAndCertPattern>& networks,
+    const std::vector<NetworkAndCertConfig>& networks,
     base::Time now) {
   std::vector<NetworkAndMatchingCert> matches;
 
@@ -301,22 +349,22 @@
   std::vector<CertAndIssuer> system_client_certs(
       CreateSortedCertAndIssuerList(std::move(system_token_client_certs), now));
 
-  for (const NetworkAndCertPattern& network_and_pattern : networks) {
+  for (const NetworkAndCertConfig& network_and_cert_config : networks) {
     // Use only certs from the system token if the source of the client cert
     // pattern is device policy.
     std::vector<CertAndIssuer>* client_certs =
-        network_and_pattern.cert_config.onc_source ==
+        network_and_cert_config.cert_config.onc_source ==
                 ::onc::ONC_SOURCE_DEVICE_POLICY
             ? &system_client_certs
             : &all_client_certs;
     auto cert_it = std::find_if(
         client_certs->begin(), client_certs->end(),
-        MatchCertWithPattern(network_and_pattern.cert_config.pattern));
+        MatchCertWithCertConfig(network_and_cert_config.cert_config));
     if (cert_it == client_certs->end()) {
       VLOG(1) << "Couldn't find a matching client cert for network "
-              << network_and_pattern.service_path;
+              << network_and_cert_config.service_path;
       matches.push_back(
-          NetworkAndMatchingCert(network_and_pattern, base::nullopt));
+          NetworkAndMatchingCert(network_and_cert_config, base::nullopt));
       continue;
     }
 
@@ -336,13 +384,13 @@
     // client certificate.
     VariableExpander variable_expander(
         GetSubstitutionsForCert(cert_it->cert.get()));
-    std::string identity = network_and_pattern.cert_config.policy_identity;
+    std::string identity = network_and_cert_config.cert_config.policy_identity;
     const bool success = variable_expander.ExpandString(&identity);
     LOG_IF(ERROR, !success)
         << "Error during variable expansion in ONC-configured identity";
 
     matches.push_back(NetworkAndMatchingCert(
-        network_and_pattern, MatchingCert(pkcs11_id, slot_id, identity)));
+        network_and_cert_config, MatchingCert(pkcs11_id, slot_id, identity)));
   }
   return matches;
 }
@@ -419,12 +467,15 @@
 }
 
 // static
-bool ClientCertResolver::ResolveCertificatePatternSync(
+bool ClientCertResolver::ResolveClientCertificateSync(
     const client_cert::ConfigType client_cert_type,
     const client_cert::ClientCertConfig& client_cert_config,
     base::DictionaryValue* shill_properties) {
+  if (!ShouldResolveCert(client_cert_config))
+    return false;
+
   // Prepare and sort the list of known client certs. Use only certs from the
-  // system token if the source of the client cert pattern is device policy.
+  // system token if the source of the client cert config is device policy.
   std::vector<CertAndIssuer> client_certs;
   if (client_cert_config.onc_source == ::onc::ONC_SOURCE_DEVICE_POLICY) {
     client_certs = CreateSortedCertAndIssuerList(
@@ -438,10 +489,10 @@
         base::Time::Now());
   }
 
-  // Search for a certificate matching the pattern.
+  // Search for a certificate matching the pattern or reference.
   std::vector<CertAndIssuer>::iterator cert_it =
       std::find_if(client_certs.begin(), client_certs.end(),
-                   MatchCertWithPattern(client_cert_config.pattern));
+                   MatchCertWithCertConfig(client_cert_config));
 
   if (cert_it == client_certs.end()) {
     VLOG(1) << "Couldn't find a matching client cert";
@@ -558,10 +609,10 @@
 void ClientCertResolver::ResolveNetworks(
     const NetworkStateHandler::NetworkStateList& networks) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  std::vector<NetworkAndCertPattern> networks_to_resolve;
+  std::vector<NetworkAndCertConfig> networks_to_resolve;
 
-  // Filter networks with ClientCertPattern. As ClientCertPatterns can only be
-  // set by policy, we check there.
+  // Filter networks with ClientCertPattern or ClientCertRef. As these can only
+  // be set by policy, we check there.
   for (const NetworkState* network : networks) {
     // If the network was not known before, mark it as known but with resolving
     // pending.
@@ -569,7 +620,8 @@
       networks_status_.insert_or_assign(network->path(),
                                         MatchingCertAndResolveStatus());
 
-    // If this network is not configured, it cannot have a ClientCertPattern.
+    // If this network is not configured, it cannot have a
+    // ClientCertPattern/ClientCertRef.
     if (network->profile_path().empty())
       continue;
 
@@ -590,12 +642,12 @@
     client_cert::ClientCertConfig cert_config;
     OncToClientCertConfig(onc_source, *policy, &cert_config);
 
-    // Skip networks that don't have a ClientCertPattern.
-    if (cert_config.client_cert_type != ::onc::client_cert::kPattern)
+    // Skip networks that don't have a ClientCertPattern or ClientCertRef.
+    if (!ShouldResolveCert(cert_config))
       continue;
 
     networks_to_resolve.push_back(
-        NetworkAndCertPattern(network->path(), cert_config));
+        NetworkAndCertConfig(network->path(), cert_config));
   }
 
   if (networks_to_resolve.empty()) {
@@ -609,10 +661,8 @@
 
   if (resolve_task_running_) {
     VLOG(1) << "A resolve task is already running. Queue this request.";
-    for (const NetworkAndCertPattern& network_and_pattern :
-         networks_to_resolve) {
-      queued_networks_to_resolve_.insert(network_and_pattern.service_path);
-    }
+    for (const NetworkAndCertConfig& network_to_resolve : networks_to_resolve)
+      queued_networks_to_resolve_.insert(network_to_resolve.service_path);
     return;
   }
 
diff --git a/chromeos/network/client_cert_resolver.h b/chromeos/network/client_cert_resolver.h
index 85777b0..f92d930f 100644
--- a/chromeos/network/client_cert_resolver.h
+++ b/chromeos/network/client_cert_resolver.h
@@ -77,12 +77,13 @@
   void SetClockForTesting(base::Clock* clock);
 
   // Returns true and sets the Shill properties that have to be configured in
-  // |shill_properties| if the certificate pattern |pattern| could be resolved.
+  // |shill_properties| if the client certificate could be resolved according to
+  // |client_cert_config|.
   // Returns false otherwise and sets empty Shill properties to clear the
   // certificate configuration.
   // Note that it uses the global clock when checking the certificates for
   // expiration.
-  static bool ResolveCertificatePatternSync(
+  static bool ResolveClientCertificateSync(
       const client_cert::ConfigType client_cert_type,
       const client_cert::ClientCertConfig& client_cert_config,
       base::DictionaryValue* shill_properties);
diff --git a/chromeos/network/client_cert_resolver_unittest.cc b/chromeos/network/client_cert_resolver_unittest.cc
index 2041c6c..722eabf5 100644
--- a/chromeos/network/client_cert_resolver_unittest.cc
+++ b/chromeos/network/client_cert_resolver_unittest.cc
@@ -8,12 +8,15 @@
 
 #include <memory>
 
+#include "base/base64.h"
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/json/json_reader.h"
 #include "base/macros.h"
+#include "base/run_loop.h"
 #include "base/strings/stringprintf.h"
 #include "base/test/scoped_task_environment.h"
 #include "base/test/simple_test_clock.h"
@@ -27,6 +30,8 @@
 #include "chromeos/network/network_configuration_handler.h"
 #include "chromeos/network/network_profile_handler.h"
 #include "chromeos/network/network_state_handler.h"
+#include "chromeos/network/onc/onc_certificate_importer_impl.h"
+#include "chromeos/network/onc/onc_test_utils.h"
 #include "components/onc/onc_constants.h"
 #include "crypto/scoped_nss_types.h"
 #include "crypto/scoped_test_nss_db.h"
@@ -49,6 +54,40 @@
 constexpr char kUserProfilePath[] = "user_profile";
 constexpr char kUserHash[] = "user_hash";
 
+void OnImportCompleted(base::OnceClosure loop_quit_closure, bool success) {
+  EXPECT_TRUE(success);
+  std::move(loop_quit_closure).Run();
+}
+
+void OnListCertsDone(base::OnceClosure loop_quit_closure,
+                     net::ScopedCERTCertificateList* out_cert_list,
+                     net::ScopedCERTCertificateList cert_list) {
+  out_cert_list->swap(cert_list);
+  std::move(loop_quit_closure).Run();
+}
+
+// Returns a |OncParsedCertificates| which contains exactly one client
+// certificate with the contents of |client_cert_pkcs12_file| and the GUID
+// |guid|. Returns nullptr if the file could not be read.
+std::unique_ptr<onc::OncParsedCertificates> OncParsedCertificatesForPkcs12File(
+    const base::FilePath& client_cert_pkcs12_file,
+    base::StringPiece guid) {
+  std::string pkcs12_raw;
+  if (!base::ReadFileToString(client_cert_pkcs12_file, &pkcs12_raw))
+    return nullptr;
+
+  std::string pkcs12_base64_encoded;
+  base::Base64Encode(pkcs12_raw, &pkcs12_base64_encoded);
+
+  base::Value onc_certificate(base::Value::Type::DICTIONARY);
+  onc_certificate.SetKey("GUID", base::Value(guid));
+  onc_certificate.SetKey("Type", base::Value("Client"));
+  onc_certificate.SetKey("PKCS12", base::Value(pkcs12_base64_encoded));
+  base::Value onc_certificates(base::Value::Type::LIST);
+  onc_certificates.GetList().push_back(std::move(onc_certificate));
+  return std::make_unique<onc::OncParsedCertificates>(onc_certificates);
+}
+
 }  // namespace
 
 class ClientCertResolverTest : public testing::Test,
@@ -224,91 +263,63 @@
   // Sets up a policy with a certificate pattern that matches any client cert
   // with a certain Issuer CN. It will match the test client cert imported by
   // SetupTestCerts.
-  void SetupPolicyMatchingIssuerCN(onc::ONCSource onc_source) {
-    const char* test_policy =
-        "[ { \"GUID\": \"wifi_stub\","
-        "    \"Name\": \"wifi_stub\","
-        "    \"Type\": \"WiFi\","
-        "    \"WiFi\": {"
-        "      \"Security\": \"WPA-EAP\","
-        "      \"SSID\": \"wifi_ssid\","
-        "      \"EAP\": {"
-        "        \"Outer\": \"EAP-TLS\","
-        "        \"ClientCertType\": \"Pattern\","
-        "        \"ClientCertPattern\": {"
-        "          \"Issuer\": {"
-        "            \"CommonName\": \"B CA\""
-        "          }"
-        "        }"
-        "      }"
-        "    }"
-        "} ]";
-
-    std::string error;
-    std::unique_ptr<base::Value> policy_value =
-        base::JSONReader::ReadAndReturnError(
-            test_policy, base::JSON_ALLOW_TRAILING_COMMAS, nullptr, &error);
-    ASSERT_TRUE(policy_value) << error;
-
-    base::ListValue* policy = nullptr;
-    ASSERT_TRUE(policy_value->GetAsList(&policy));
-
-    std::string user_hash =
-        onc_source == onc::ONC_SOURCE_USER_POLICY ? kUserHash : "";
-    managed_config_handler_->SetPolicy(
-        onc_source, user_hash, *policy,
-        base::DictionaryValue() /* no global network config */);
+  void SetupPolicyMatchingIssuerCN(::onc::ONCSource onc_source) {
+    const char* test_policy = R"(
+        [ { "GUID": "wifi_stub",
+            "Name": "wifi_stub",
+            "Type": "WiFi",
+            "WiFi": {
+              "Security": "WPA-EAP",
+              "SSID": "wifi_ssid",
+              "EAP": {
+                "Outer": "EAP-TLS",
+                "ClientCertType": "Pattern",
+                "ClientCertPattern": {
+                  "Issuer": {
+                    "CommonName": "B CA"
+                  }
+                }
+              }
+            }
+        } ])";
+    ASSERT_NO_FATAL_FAILURE(SetManagedNetworkPolicy(onc_source, test_policy));
   }
 
   // Sets up a policy with a certificate pattern that matches any client cert
   // with a Subject Organization set to "Blar". It will match the test client
   // cert imported by SetupTestCertWithBadPrintableString.
   void SetupPolicyMatchingSubjectOrgForBadPrintableStringCert(
-      onc::ONCSource onc_source) {
-    const char* test_policy =
-        "[ { \"GUID\": \"wifi_stub\","
-        "    \"Name\": \"wifi_stub\","
-        "    \"Type\": \"WiFi\","
-        "    \"WiFi\": {"
-        "      \"Security\": \"WPA-EAP\","
-        "      \"SSID\": \"wifi_ssid\","
-        "      \"EAP\": {"
-        "        \"Outer\": \"EAP-TLS\","
-        "        \"ClientCertType\": \"Pattern\","
-        "        \"ClientCertPattern\": {"
-        "          \"Subject\": {"
-        "            \"Organization\": \"Blar\""
-        "          }"
-        "        }"
-        "      }"
-        "    }"
-        "} ]";
-
-    std::string error;
-    std::unique_ptr<base::Value> policy_value =
-        base::JSONReader::ReadAndReturnError(
-            test_policy, base::JSON_ALLOW_TRAILING_COMMAS, nullptr, &error);
-    ASSERT_TRUE(policy_value) << error;
-
-    base::ListValue* policy = nullptr;
-    ASSERT_TRUE(policy_value->GetAsList(&policy));
-
-    std::string user_hash =
-        onc_source == onc::ONC_SOURCE_USER_POLICY ? kUserHash : "";
-    managed_config_handler_->SetPolicy(
-        onc_source, user_hash, *policy,
-        base::DictionaryValue() /* no global network config */);
+      ::onc::ONCSource onc_source) {
+    const char* test_policy = R"(
+        [ { "GUID": "wifi_stub",
+            "Name": "wifi_stub",
+            "Type": "WiFi",
+            "WiFi": {
+              "Security": "WPA-EAP",
+              "SSID": "wifi_ssid",
+              "EAP": {
+                "Outer": "EAP-TLS",
+                "ClientCertType": "Pattern",
+                "ClientCertPattern": {
+                  "Subject": {
+                    "Organization": "Blar"
+                  }
+                }
+              }
+            }
+        } ])";
+    ASSERT_NO_FATAL_FAILURE(SetManagedNetworkPolicy(onc_source, test_policy));
   }
 
   void SetupCertificateConfigMatchingIssuerCN(
-      onc::ONCSource onc_source,
+      ::onc::ONCSource onc_source,
       client_cert::ClientCertConfig* client_cert_config) {
-    const char* test_onc_pattern =
-        "{"
-        "  \"Issuer\": {"
-        "    \"CommonName\": \"B CA\""
-        "  }"
-        "}";
+    const char* test_onc_pattern = R"(
+        {
+          "Issuer": {
+            "CommonName": "B CA"
+          }
+        })";
     std::string error;
     std::unique_ptr<base::Value> onc_pattern_value =
         base::JSONReader::ReadAndReturnError(test_onc_pattern,
@@ -320,34 +331,39 @@
     onc_pattern_value->GetAsDictionary(&onc_pattern_dict);
 
     client_cert_config->onc_source = onc_source;
+    client_cert_config->client_cert_type = ::onc::client_cert::kPattern;
     client_cert_config->pattern.ReadFromONCDictionary(*onc_pattern_dict);
   }
 
   // Sets up a policy with a certificate pattern that matches any client cert
   // that is signed by the test CA cert (stored in |test_ca_cert_pem_|). In
   // particular it will match the test client cert.
-  void SetupPolicyMatchingIssuerPEM(onc::ONCSource onc_source,
+  void SetupPolicyMatchingIssuerPEM(::onc::ONCSource onc_source,
                                     const std::string& identity) {
-    const char* test_policy_template =
-        "[ { \"GUID\": \"wifi_stub\","
-        "    \"Name\": \"wifi_stub\","
-        "    \"Type\": \"WiFi\","
-        "    \"WiFi\": {"
-        "      \"Security\": \"WPA-EAP\","
-        "      \"SSID\": \"wifi_ssid\","
-        "      \"EAP\": {"
-        "        \"Identity\": \"%s\","
-        "        \"Outer\": \"EAP-TLS\","
-        "        \"ClientCertType\": \"Pattern\","
-        "        \"ClientCertPattern\": {"
-        "          \"IssuerCAPEMs\": [ \"%s\" ]"
-        "        }"
-        "      }"
-        "    }"
-        "} ]";
+    const char* test_policy_template = R"(
+        [ { "GUID": "wifi_stub",
+            "Name": "wifi_stub",
+            "Type": "WiFi",
+            "WiFi": {
+              "Security": "WPA-EAP",
+              "SSID": "wifi_ssid",
+              "EAP": {
+                "Identity": "%s",
+                "Outer": "EAP-TLS",
+                "ClientCertType": "Pattern",
+                "ClientCertPattern": {
+                  "IssuerCAPEMs": [ "%s" ]
+                }
+              }
+            }
+        } ])";
     std::string policy_json = base::StringPrintf(
         test_policy_template, identity.c_str(), test_ca_cert_pem_.c_str());
+    ASSERT_NO_FATAL_FAILURE(SetManagedNetworkPolicy(onc_source, policy_json));
+  }
 
+  void SetManagedNetworkPolicy(::onc::ONCSource onc_source,
+                               base::StringPiece policy_json) {
     std::string error;
     std::unique_ptr<base::Value> policy_value =
         base::JSONReader::ReadAndReturnError(
@@ -358,7 +374,7 @@
     ASSERT_TRUE(policy_value->GetAsList(&policy));
 
     std::string user_hash =
-        onc_source == onc::ONC_SOURCE_USER_POLICY ? kUserHash : "";
+        onc_source == ::onc::ONC_SOURCE_USER_POLICY ? kUserHash : "";
     managed_config_handler_->SetPolicy(
         onc_source, user_hash, *policy,
         base::DictionaryValue() /* no global network config */);
@@ -379,12 +395,26 @@
     properties->GetStringWithoutPathExpansion(prop_name, prop_value);
   }
 
+  // Returns a list of all certificates that are stored on |test_nsscertdb_|'s
+  // private slot.
+  net::ScopedCERTCertificateList ListCertsOnPrivateSlot() {
+    net::ScopedCERTCertificateList certs;
+    base::RunLoop run_loop;
+    test_nsscertdb_->ListCertsInSlot(
+        base::AdaptCallbackForRepeating(
+            base::BindOnce(&OnListCertsDone, run_loop.QuitClosure(), &certs)),
+        test_nsscertdb_->GetPrivateSlot().get());
+    run_loop.Run();
+    return certs;
+  }
+
   base::test::ScopedTaskEnvironment scoped_task_environment_;
   int network_properties_changed_count_ = 0;
   std::string test_cert_id_;
   std::unique_ptr<base::SimpleTestClock> test_clock_;
   std::unique_ptr<ClientCertResolver> client_cert_resolver_;
   NetworkCertLoader* network_cert_loader_ = nullptr;
+  std::unique_ptr<net::NSSCertDatabaseChromeOS> test_nsscertdb_;
 
  private:
   // ClientCertResolver::Observer:
@@ -404,7 +434,6 @@
   std::string test_ca_cert_pem_;
   crypto::ScopedTestNSSDB test_nssdb_;
   crypto::ScopedTestNSSDB test_system_nssdb_;
-  std::unique_ptr<net::NSSCertDatabaseChromeOS> test_nsscertdb_;
 
   DISALLOW_COPY_AND_ASSIGN(ClientCertResolverTest);
 };
@@ -416,7 +445,8 @@
   scoped_task_environment_.RunUntilIdle();
   network_properties_changed_count_ = 0;
   SetupNetworkHandlers();
-  SetupPolicyMatchingIssuerPEM(onc::ONC_SOURCE_USER_POLICY, "");
+  ASSERT_NO_FATAL_FAILURE(
+      SetupPolicyMatchingIssuerPEM(::onc::ONC_SOURCE_USER_POLICY, ""));
   scoped_task_environment_.RunUntilIdle();
 
   // Verify that no client certificate was configured.
@@ -433,7 +463,8 @@
   scoped_task_environment_.RunUntilIdle();
 
   SetupNetworkHandlers();
-  SetupPolicyMatchingIssuerCN(onc::ONC_SOURCE_USER_POLICY);
+  ASSERT_NO_FATAL_FAILURE(
+      SetupPolicyMatchingIssuerCN(::onc::ONC_SOURCE_USER_POLICY));
   scoped_task_environment_.RunUntilIdle();
 
   network_properties_changed_count_ = 0;
@@ -459,7 +490,7 @@
   SetupNetworkHandlers();
   ASSERT_NO_FATAL_FAILURE(
       SetupPolicyMatchingSubjectOrgForBadPrintableStringCert(
-          onc::ONC_SOURCE_USER_POLICY));
+          ::onc::ONC_SOURCE_USER_POLICY));
   scoped_task_environment_.RunUntilIdle();
 
   network_properties_changed_count_ = 0;
@@ -480,7 +511,8 @@
   scoped_task_environment_.RunUntilIdle();
 
   SetupNetworkHandlers();
-  SetupPolicyMatchingIssuerPEM(onc::ONC_SOURCE_USER_POLICY, "");
+  ASSERT_NO_FATAL_FAILURE(
+      SetupPolicyMatchingIssuerPEM(::onc::ONC_SOURCE_USER_POLICY, ""));
   scoped_task_environment_.RunUntilIdle();
 
   network_properties_changed_count_ = 0;
@@ -505,7 +537,8 @@
 
   // Policy application will trigger the ClientCertResolver.
   network_properties_changed_count_ = 0;
-  SetupPolicyMatchingIssuerPEM(onc::ONC_SOURCE_USER_POLICY, "");
+  ASSERT_NO_FATAL_FAILURE(
+      SetupPolicyMatchingIssuerPEM(::onc::ONC_SOURCE_USER_POLICY, ""));
   scoped_task_environment_.RunUntilIdle();
 
   // Verify that the resolver positively matched the pattern in the policy with
@@ -522,7 +555,8 @@
   scoped_task_environment_.RunUntilIdle();
 
   SetupNetworkHandlers();
-  SetupPolicyMatchingIssuerPEM(onc::ONC_SOURCE_USER_POLICY, "");
+  ASSERT_NO_FATAL_FAILURE(
+      SetupPolicyMatchingIssuerPEM(::onc::ONC_SOURCE_USER_POLICY, ""));
   scoped_task_environment_.RunUntilIdle();
 
   StartNetworkCertLoader();
@@ -559,7 +593,8 @@
   scoped_task_environment_.RunUntilIdle();
 
   SetupNetworkHandlers();
-  SetupPolicyMatchingIssuerPEM(onc::ONC_SOURCE_USER_POLICY, "");
+  ASSERT_NO_FATAL_FAILURE(
+      SetupPolicyMatchingIssuerPEM(::onc::ONC_SOURCE_USER_POLICY, ""));
   scoped_task_environment_.RunUntilIdle();
 
   StartNetworkCertLoader();
@@ -591,7 +626,8 @@
   scoped_task_environment_.RunUntilIdle();
 
   SetupNetworkHandlers();
-  SetupPolicyMatchingIssuerCN(onc::ONC_SOURCE_USER_POLICY);
+  ASSERT_NO_FATAL_FAILURE(
+      SetupPolicyMatchingIssuerCN(::onc::ONC_SOURCE_USER_POLICY));
   scoped_task_environment_.RunUntilIdle();
 
   StartNetworkCertLoader();
@@ -611,11 +647,11 @@
   scoped_task_environment_.RunUntilIdle();
 
   client_cert::ClientCertConfig client_cert_config;
-  SetupCertificateConfigMatchingIssuerCN(onc::ONC_SOURCE_USER_POLICY,
+  SetupCertificateConfigMatchingIssuerCN(::onc::ONC_SOURCE_USER_POLICY,
                                          &client_cert_config);
 
   base::DictionaryValue shill_properties;
-  ClientCertResolver::ResolveCertificatePatternSync(
+  ClientCertResolver::ResolveClientCertificateSync(
       client_cert::CONFIG_TYPE_EAP, client_cert_config, &shill_properties);
   std::string pkcs11_id;
   shill_properties.GetStringWithoutPathExpansion(shill::kEapCertIdProperty,
@@ -629,7 +665,8 @@
   scoped_task_environment_.RunUntilIdle();
 
   SetupNetworkHandlers();
-  SetupPolicyMatchingIssuerCN(onc::ONC_SOURCE_USER_POLICY);
+  ASSERT_NO_FATAL_FAILURE(
+      SetupPolicyMatchingIssuerCN(::onc::ONC_SOURCE_USER_POLICY));
   scoped_task_environment_.RunUntilIdle();
 
   StartNetworkCertLoader();
@@ -649,11 +686,11 @@
   scoped_task_environment_.RunUntilIdle();
 
   client_cert::ClientCertConfig client_cert_config;
-  SetupCertificateConfigMatchingIssuerCN(onc::ONC_SOURCE_DEVICE_POLICY,
+  SetupCertificateConfigMatchingIssuerCN(::onc::ONC_SOURCE_DEVICE_POLICY,
                                          &client_cert_config);
 
   base::DictionaryValue shill_properties;
-  ClientCertResolver::ResolveCertificatePatternSync(
+  ClientCertResolver::ResolveClientCertificateSync(
       client_cert::CONFIG_TYPE_EAP, client_cert_config, &shill_properties);
   std::string pkcs11_id;
   shill_properties.GetStringWithoutPathExpansion(shill::kEapCertIdProperty,
@@ -667,7 +704,8 @@
   scoped_task_environment_.RunUntilIdle();
 
   SetupNetworkHandlers();
-  SetupPolicyMatchingIssuerCN(onc::ONC_SOURCE_DEVICE_POLICY);
+  ASSERT_NO_FATAL_FAILURE(
+      SetupPolicyMatchingIssuerCN(::onc::ONC_SOURCE_DEVICE_POLICY));
   scoped_task_environment_.RunUntilIdle();
 
   network_properties_changed_count_ = 0;
@@ -689,11 +727,11 @@
   scoped_task_environment_.RunUntilIdle();
 
   client_cert::ClientCertConfig client_cert_config;
-  SetupCertificateConfigMatchingIssuerCN(onc::ONC_SOURCE_DEVICE_POLICY,
+  SetupCertificateConfigMatchingIssuerCN(::onc::ONC_SOURCE_DEVICE_POLICY,
                                          &client_cert_config);
 
   base::DictionaryValue shill_properties;
-  ClientCertResolver::ResolveCertificatePatternSync(
+  ClientCertResolver::ResolveClientCertificateSync(
       client_cert::CONFIG_TYPE_EAP, client_cert_config, &shill_properties);
   std::string pkcs11_id;
   shill_properties.GetStringWithoutPathExpansion(shill::kEapCertIdProperty,
@@ -707,8 +745,8 @@
   scoped_task_environment_.RunUntilIdle();
 
   SetupNetworkHandlers();
-  SetupPolicyMatchingIssuerPEM(onc::ONC_SOURCE_USER_POLICY,
-                               "${CERT_SAN_EMAIL}");
+  ASSERT_NO_FATAL_FAILURE(SetupPolicyMatchingIssuerPEM(
+      ::onc::ONC_SOURCE_USER_POLICY, "${CERT_SAN_EMAIL}"));
   scoped_task_environment_.RunUntilIdle();
 
   network_properties_changed_count_ = 0;
@@ -725,8 +763,8 @@
   // Verify that after changing the ONC policy to request a variant of the
   // Microsoft Universal Principal Name field instead, the correct value is
   // substituted into the shill service entry.
-  SetupPolicyMatchingIssuerPEM(onc::ONC_SOURCE_USER_POLICY,
-                               "upn-${CERT_SAN_UPN}-suffix");
+  ASSERT_NO_FATAL_FAILURE(SetupPolicyMatchingIssuerPEM(
+      ::onc::ONC_SOURCE_USER_POLICY, "upn-${CERT_SAN_UPN}-suffix"));
   scoped_task_environment_.RunUntilIdle();
 
   GetServiceProperty(shill::kEapIdentityProperty, &identity);
@@ -735,8 +773,9 @@
 
   // Verify that after changing the ONC policy to request the subject CommonName
   // field, the correct value is substituted into the shill service entry.
-  SetupPolicyMatchingIssuerPEM(onc::ONC_SOURCE_USER_POLICY,
-                               "subject-cn-${CERT_SUBJECT_COMMON_NAME}-suffix");
+  ASSERT_NO_FATAL_FAILURE(SetupPolicyMatchingIssuerPEM(
+      ::onc::ONC_SOURCE_USER_POLICY,
+      "subject-cn-${CERT_SUBJECT_COMMON_NAME}-suffix"));
   scoped_task_environment_.RunUntilIdle();
 
   GetServiceProperty(shill::kEapIdentityProperty, &identity);
@@ -752,7 +791,8 @@
   StartNetworkCertLoader();
   SetupWifi();
   SetupNetworkHandlers();
-  SetupPolicyMatchingIssuerPEM(onc::ONC_SOURCE_USER_POLICY, "");
+  ASSERT_NO_FATAL_FAILURE(
+      SetupPolicyMatchingIssuerPEM(::onc::ONC_SOURCE_USER_POLICY, ""));
   scoped_task_environment_.RunUntilIdle();
 
   // Pretend that policy was applied, this shall queue a resolving task.
@@ -779,4 +819,82 @@
   EXPECT_EQ(test_cert_id_, pkcs11_id);
 }
 
+// Tests that a ClientCertRef reference is resolved by |ClientCertResolver|.
+// Uses the |CertificateImporterImpl| to import the client certificate from ONC
+// policy, ensuring that setting the cert's key's nickname (in the import step)
+// and evaluating it (in the matching step) work well together.
+TEST_F(ClientCertResolverTest, ResolveClientCertRef) {
+  const char* test_policy_network =
+      R"([ { "GUID": "wifi_stub",
+               "Name": "wifi_stub",
+               "Type": "WiFi",
+               "WiFi": {
+                 "Security": "WPA-EAP",
+                 "SSID": "wifi_ssid",
+                 "EAP": {
+                   "Identity": "TestIdentity",
+                   "Outer": "EAP-TLS",
+                   "ClientCertType": "Ref",
+                   "ClientCertRef": "{some-unique-guid}"
+                 }
+               }
+           } ])";
+
+  SetupWifi();
+  scoped_task_environment_.RunUntilIdle();
+  StartNetworkCertLoader();
+  scoped_task_environment_.RunUntilIdle();
+  SetupNetworkHandlers();
+  scoped_task_environment_.RunUntilIdle();
+
+  // Make sure that expiring client certs don't cause issues.
+  test_clock_->SetNow(base::Time::Min());
+
+  // Apply the network policy.
+  network_properties_changed_count_ = 0;
+  ASSERT_NO_FATAL_FAILURE(SetManagedNetworkPolicy(::onc::ONC_SOURCE_USER_POLICY,
+                                                  test_policy_network));
+  scoped_task_environment_.RunUntilIdle();
+
+  // The referenced client cert does not exist yet, so expect that it has not
+  // been resolved.
+  std::string pkcs11_id;
+  GetServiceProperty(shill::kEapCertIdProperty, &pkcs11_id);
+  EXPECT_TRUE(pkcs11_id.empty());
+  EXPECT_EQ(1, network_properties_changed_count_);
+
+  // Now import a client certificate which has the GUID required using the
+  // |CertificateImporterImpl|.
+  auto onc_parsed_certificates = OncParsedCertificatesForPkcs12File(
+      net::GetTestCertsDirectory().AppendASCII("client-empty-password.p12"),
+      "{some-unique-guid}");
+  ASSERT_TRUE(onc_parsed_certificates);
+
+  onc::CertificateImporterImpl importer(
+      scoped_task_environment_.GetMainThreadTaskRunner(),
+      test_nsscertdb_.get());
+  base::RunLoop import_loop;
+  importer.ImportClientCertificates(
+      onc_parsed_certificates->client_certificates(),
+      base::BindOnce(&OnImportCompleted, import_loop.QuitClosure()));
+  import_loop.Run();
+  scoped_task_environment_.RunUntilIdle();
+
+  // Find the imported cert and get its id.
+  net::ScopedCERTCertificateList private_slot_certs = ListCertsOnPrivateSlot();
+  ASSERT_EQ(1u, private_slot_certs.size());
+  int slot_id = 0;
+  const std::string imported_cert_pkcs11_id =
+      NetworkCertLoader::GetPkcs11IdAndSlotForCert(private_slot_certs[0].get(),
+                                                   &slot_id);
+  std::string imported_cert_formatted_pkcs11_id =
+      base::StringPrintf("%i:%s", slot_id, imported_cert_pkcs11_id.c_str());
+
+  // Verify that the resolver positively matched the pattern in the policy with
+  // the test client cert and configured the network.
+  GetServiceProperty(shill::kEapCertIdProperty, &pkcs11_id);
+  EXPECT_EQ(imported_cert_formatted_pkcs11_id, pkcs11_id);
+  EXPECT_EQ(2, network_properties_changed_count_);
+}
+
 }  // namespace chromeos
diff --git a/chromeos/network/client_cert_util.cc b/chromeos/network/client_cert_util.cc
index 4f4e3ad..07a827522 100644
--- a/chromeos/network/client_cert_util.cc
+++ b/chromeos/network/client_cert_util.cc
@@ -31,7 +31,10 @@
 
 namespace {
 
-void GetClientCertTypeAndPattern(
+// Extracts the type and descriptor (referenced GUID or client cert pattern) of
+// a ONC-specified client certificate specification for a network
+// (|dict_with_client_cert|) and stores it in |cert_config|.
+void GetClientCertTypeAndDescriptor(
     onc::ONCSource onc_source,
     const base::DictionaryValue& dict_with_client_cert,
     ClientCertConfig* cert_config) {
@@ -52,6 +55,12 @@
       bool success = cert_config->pattern.ReadFromONCDictionary(*pattern);
       DCHECK(success);
     }
+  } else if (cert_config->client_cert_type == kRef) {
+    const base::Value* client_cert_ref_key =
+        dict_with_client_cert.FindKeyOfType(kClientCertRef,
+                                            base::Value::Type::STRING);
+    if (client_cert_ref_key)
+      cert_config->guid = client_cert_ref_key->GetString();
   }
 }
 
@@ -257,6 +266,8 @@
 
 ClientCertConfig::ClientCertConfig(const ClientCertConfig& other) = default;
 
+ClientCertConfig::~ClientCertConfig() = default;
+
 void OncToClientCertConfig(::onc::ONCSource onc_source,
                            const base::DictionaryValue& network_config,
                            ClientCertConfig* cert_config) {
@@ -310,8 +321,8 @@
   }
 
   if (dict_with_client_cert) {
-    GetClientCertTypeAndPattern(onc_source, *dict_with_client_cert,
-                                cert_config);
+    GetClientCertTypeAndDescriptor(onc_source, *dict_with_client_cert,
+                                   cert_config);
   }
 }
 
diff --git a/chromeos/network/client_cert_util.h b/chromeos/network/client_cert_util.h
index 0f2eb045..50d7206 100644
--- a/chromeos/network/client_cert_util.h
+++ b/chromeos/network/client_cert_util.h
@@ -40,19 +40,24 @@
 struct CHROMEOS_EXPORT ClientCertConfig {
   ClientCertConfig();
   ClientCertConfig(const ClientCertConfig& other);
+  ~ClientCertConfig();
 
   // Independent of whether the client cert (pattern or reference) is
   // configured, the location determines whether this network configuration
   // supports client certs and what kind of configuration it requires.
   ConfigType location;
 
-  // One of the ClientCertTypes defined in ONC: kNone, kRef, or kPattern.
+  // One of the ClientCertTypes defined in ONC: |kNone|, |kRef|, or |kPattern|.
   std::string client_cert_type;
 
-  // If |client_cert_type| equals kPattern, this contains the pattern.
+  // If |client_cert_type| equals |kPattern|, this contains the pattern.
   CertificatePattern pattern;
 
-  // The value of kIdentity, to enable substitutions.
+  // If |client_cert_type| equals |kRef|, this contains the GUID of the
+  // referenced certificate.
+  std::string guid;
+
+  // The value of |kIdentity|, to enable substitutions.
   std::string policy_identity;
 
   // source of this ClientCertConfig.
@@ -67,8 +72,8 @@
                           const net::CertPrincipal& principal);
 
 // Returns the PKCS11 and slot ID of |cert_id|, which is expected to be a
-// value of the Shill property kEapCertIdProperty or kEapKeyIdProperty, either
-// of format "<pkcs11_id>" or "<slot_id>:<pkcs11_id>".
+// value of the Shill property |kEapCertIdProperty| or |kEapKeyIdProperty|,
+// either of format "<pkcs11_id>" or "<slot_id>:<pkcs11_id>".
 CHROMEOS_EXPORT std::string GetPkcs11AndSlotIdFromEapCertId(
     const std::string& cert_id,
     int* slot_id);
diff --git a/chromeos/network/network_connection_handler_impl.cc b/chromeos/network/network_connection_handler_impl.cc
index 43216ba..6f57705 100644
--- a/chromeos/network/network_connection_handler_impl.cc
+++ b/chromeos/network/network_connection_handler_impl.cc
@@ -537,7 +537,7 @@
     // Check certificate properties from policy.
     if (cert_config_from_policy.client_cert_type ==
         onc::client_cert::kPattern) {
-      if (!ClientCertResolver::ResolveCertificatePatternSync(
+      if (!ClientCertResolver::ResolveClientCertificateSync(
               client_cert_type, cert_config_from_policy, &config_properties)) {
         NET_LOG(ERROR) << "Non matching certificate for: " << service_path;
         ErrorCallbackForPendingRequest(service_path, kErrorCertificateRequired);
diff --git a/chromeos/network/onc/onc_certificate_importer_impl.cc b/chromeos/network/onc/onc_certificate_importer_impl.cc
index 1a01775..4c8abe8 100644
--- a/chromeos/network/onc/onc_certificate_importer_impl.cc
+++ b/chromeos/network/onc/onc_certificate_importer_impl.cc
@@ -243,7 +243,8 @@
   CERTCertificate* cert_result = imported_certs[0].get();
 
   // Find the private key associated with this certificate, and set the
-  // nickname on it.
+  // nickname on it. This is used by |ClientCertResolver| as a handle to resolve
+  // onc ClientCertRef GUID references.
   SECKEYPrivateKey* private_key = PK11_FindPrivateKeyFromCert(
       cert_result->slot, cert_result, nullptr /* wincx */);
   if (private_key) {
diff --git a/components/BUILD.gn b/components/BUILD.gn
index 4abde54..c1f38af 100644
--- a/components/BUILD.gn
+++ b/components/BUILD.gn
@@ -284,6 +284,7 @@
       "//components/signin/core/browser",
       "//components/signin/core/browser/android:java",
       "//components/spellcheck/browser/android:java",
+      "//components/tracing:tracing_test_helper_java",
       "//components/variations/android:variations_java",
       "//components/web_restrictions:test_support",
       "//components/web_restrictions:test_support_java",
diff --git a/components/arc/BUILD.gn b/components/arc/BUILD.gn
index e8efb43..b8862f9 100644
--- a/components/arc/BUILD.gn
+++ b/components/arc/BUILD.gn
@@ -66,6 +66,7 @@
     "volume_mounter/arc_volume_mounter_bridge.h",
     "wake_lock/arc_wake_lock_bridge.cc",
     "wake_lock/arc_wake_lock_bridge.h",
+    "wake_lock/wake_lock_observer.h",
   ]
 
   public_deps = [
diff --git a/components/arc/common/notifications.mojom b/components/arc/common/notifications.mojom
index 8d616f1..48e8dce 100644
--- a/components/arc/common/notifications.mojom
+++ b/components/arc/common/notifications.mojom
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 //
-// Next MinVersion: 22
+// Next MinVersion: 23
 
 module arc.mojom;
 
@@ -187,6 +187,13 @@
   bool show_private_notification;
 };
 
+[MinVersion=22]
+struct NotificationConfiguration {
+  // Flag to enable notification expansion animations on arc.
+  // See b/35786193.
+  bool expansion_animation;
+};
+
 // Next Method ID: 11
 interface NotificationsHost {
   // Set the Do-Not-Disturb status on Chrome side from Android side.
@@ -225,7 +232,7 @@
   OnLockScreenSettingUpdated@10(ArcLockScreenNotificationSetting setting);
 };
 
-// Next Method ID: 12
+// Next Method ID: 13
 // TODO(lhchavez): Migrate all request/response messages to Mojo.
 interface NotificationsInstance {
   // DEPRECATED: Please use Init@5 instead.
@@ -283,4 +290,8 @@
   // Sets the lock screen notification setting on Android side from Chrome side.
   [MinVersion=21]
   SetLockScreenSettingOnAndroid@11(ArcLockScreenNotificationSetting setting);
+
+  // Set configuration variables for notifications.
+  [MinVersion=22]
+  SetNotificationConfiguration@12(NotificationConfiguration configuration);
 };
diff --git a/components/arc/common/video_encode_accelerator.mojom b/components/arc/common/video_encode_accelerator.mojom
index 18d00f6..92a8a98 100644
--- a/components/arc/common/video_encode_accelerator.mojom
+++ b/components/arc/common/video_encode_accelerator.mojom
@@ -9,13 +9,19 @@
 
 import "components/arc/common/video_common.mojom";
 
-// Next MinVersion: 2
+// Next MinVersion: 3
 
 [Extensible]
 enum VideoPixelFormat {
   // The values must match to the values in media::VideoPixelFormat
   PIXEL_FORMAT_UNKNOWN = 0,
   PIXEL_FORMAT_I420 = 1,
+  [MinVersion=2] PIXEL_FORMAT_YV12 = 2,
+  [MinVersion=2] PIXEL_FORMAT_NV12 = 6,
+  [MinVersion=2] PIXEL_FORMAT_NV21 = 7,
+  [MinVersion=2] PIXEL_FORMAT_ARGB = 10,
+  [MinVersion=2] PIXEL_FORMAT_ABGR = 27,
+  [MinVersion=2] PIXEL_FORMAT_XBGR = 28,
 };
 
 // Specification of an encoding profile supported by an encoder.
diff --git a/components/arc/common/video_encode_accelerator_struct_traits.cc b/components/arc/common/video_encode_accelerator_struct_traits.cc
index 9601ca3..c6eaea8 100644
--- a/components/arc/common/video_encode_accelerator_struct_traits.cc
+++ b/components/arc/common/video_encode_accelerator_struct_traits.cc
@@ -73,6 +73,12 @@
       "enum ##value mismatch")
 
 CHECK_PIXEL_FORMAT_ENUM(PIXEL_FORMAT_I420);
+CHECK_PIXEL_FORMAT_ENUM(PIXEL_FORMAT_YV12);
+CHECK_PIXEL_FORMAT_ENUM(PIXEL_FORMAT_NV12);
+CHECK_PIXEL_FORMAT_ENUM(PIXEL_FORMAT_NV21);
+CHECK_PIXEL_FORMAT_ENUM(PIXEL_FORMAT_ARGB);
+CHECK_PIXEL_FORMAT_ENUM(PIXEL_FORMAT_ABGR);
+CHECK_PIXEL_FORMAT_ENUM(PIXEL_FORMAT_XBGR);
 
 #undef CHECK_PXIEL_FORMAT_ENUM
 
@@ -89,13 +95,19 @@
     FromMojom(arc::mojom::VideoPixelFormat input,
               media::VideoPixelFormat* output) {
   switch (input) {
+    case arc::mojom::VideoPixelFormat::PIXEL_FORMAT_UNKNOWN:
     case arc::mojom::VideoPixelFormat::PIXEL_FORMAT_I420:
+    case arc::mojom::VideoPixelFormat::PIXEL_FORMAT_YV12:
+    case arc::mojom::VideoPixelFormat::PIXEL_FORMAT_NV12:
+    case arc::mojom::VideoPixelFormat::PIXEL_FORMAT_NV21:
+    case arc::mojom::VideoPixelFormat::PIXEL_FORMAT_ARGB:
+    case arc::mojom::VideoPixelFormat::PIXEL_FORMAT_ABGR:
+    case arc::mojom::VideoPixelFormat::PIXEL_FORMAT_XBGR:
       *output = static_cast<media::VideoPixelFormat>(input);
       return true;
-    default:
-      DLOG(ERROR) << "Unknown VideoPixelFormat: " << input;
-      return false;
   }
+  NOTREACHED();
+  return false;
 }
 
 // static
diff --git a/components/arc/test/fake_notifications_instance.cc b/components/arc/test/fake_notifications_instance.cc
index e43922b1..31f322f 100644
--- a/components/arc/test/fake_notifications_instance.cc
+++ b/components/arc/test/fake_notifications_instance.cc
@@ -61,5 +61,7 @@
 void FakeNotificationsInstance::CancelDeferredUserAction(uint32_t action_id) {}
 void FakeNotificationsInstance::SetLockScreenSettingOnAndroid(
     mojom::ArcLockScreenNotificationSettingPtr setting) {}
+void FakeNotificationsInstance::SetNotificationConfiguration(
+    mojom::NotificationConfigurationPtr configuration) {}
 
 }  // namespace arc
diff --git a/components/arc/test/fake_notifications_instance.h b/components/arc/test/fake_notifications_instance.h
index 08c44a68a..389f60d 100644
--- a/components/arc/test/fake_notifications_instance.h
+++ b/components/arc/test/fake_notifications_instance.h
@@ -37,6 +37,8 @@
   void CancelDeferredUserAction(uint32_t action_id) override;
   void SetLockScreenSettingOnAndroid(
       mojom::ArcLockScreenNotificationSettingPtr setting) override;
+  void SetNotificationConfiguration(
+      mojom::NotificationConfigurationPtr configuration) override;
 
   const std::vector<std::pair<std::string, mojom::ArcNotificationEvent>>&
   events() const;
diff --git a/components/arc/wake_lock/arc_wake_lock_bridge.cc b/components/arc/wake_lock/arc_wake_lock_bridge.cc
index bea34b2f..2fe9e39 100644
--- a/components/arc/wake_lock/arc_wake_lock_bridge.cc
+++ b/components/arc/wake_lock/arc_wake_lock_bridge.cc
@@ -7,6 +7,9 @@
 
 #include "base/logging.h"
 #include "base/memory/singleton.h"
+#include "base/observer_list.h"
+#include "base/task/post_task.h"
+#include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/power_policy_controller.h"
 #include "components/arc/arc_bridge_service.h"
 #include "components/arc/arc_browser_context_keyed_service_factory_base.h"
@@ -46,7 +49,8 @@
 
 // WakeLockRequester requests a wake lock from the device service in response
 // to wake lock requests of a given type from Android. A count is kept of
-// outstanding Android requests so that only a single actual wake lock is used.
+// outstanding Android requests so that only a single actual wake lock is
+// used.
 class ArcWakeLockBridge::WakeLockRequester {
  public:
   WakeLockRequester(device::mojom::WakeLockType type,
@@ -76,6 +80,9 @@
     }
 
     wake_lock_->RequestWakeLock();
+
+    for (auto& observer : observers_)
+      observer.OnWakeLockAcquire();
   }
 
   // Decrements the number of outstanding Android requests. Cancels the device
@@ -94,10 +101,27 @@
     }
 
     DCHECK(wake_lock_);
-    DVLOG(1) << "Partial wake force release. Count: " << wake_lock_count_;
+    DVLOG(1) << "Partial wake lock force release. Count: " << wake_lock_count_;
     wake_lock_->CancelWakeLock();
+
+    for (auto& observer : observers_)
+      observer.OnWakeLockRelease();
   }
 
+  bool IsWakeLockHeld() const { return wake_lock_count_ > 0; }
+
+  void AddObserver(WakeLockObserver* observer) {
+    DCHECK(observer);
+    observers_.AddObserver(observer);
+  }
+
+  void RemoveObserver(WakeLockObserver* observer) {
+    DCHECK(observer);
+    observers_.RemoveObserver(observer);
+  }
+
+  bool HasObservers() const { return observers_.might_have_observers(); }
+
   // Runs the message loop until replies have been received for all pending
   // requests on |wake_lock_|.
   void FlushForTesting() {
@@ -118,6 +142,8 @@
   // Lazily initialized in response to first request.
   device::mojom::WakeLockPtr wake_lock_;
 
+  base::ObserverList<WakeLockObserver>::Unchecked observers_;
+
   DISALLOW_COPY_AND_ASSIGN(WakeLockRequester);
 };
 
@@ -138,6 +164,9 @@
   return ArcWakeLockBridgeFactory::GetForBrowserContextForTesting(context);
 }
 
+constexpr base::TimeDelta ArcWakeLockBridge::kDarkResumeWakeLockCheckTimeout;
+constexpr base::TimeDelta ArcWakeLockBridge::kDarkResumeHardTimeout;
+
 ArcWakeLockBridge::ArcWakeLockBridge(content::BrowserContext* context,
                                      ArcBridgeService* bridge_service)
     : arc_bridge_service_(bridge_service),
@@ -145,11 +174,16 @@
       weak_ptr_factory_(this) {
   arc_bridge_service_->wake_lock()->SetHost(this);
   arc_bridge_service_->wake_lock()->AddObserver(this);
+  chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->AddObserver(
+      this);
 }
 
 ArcWakeLockBridge::~ArcWakeLockBridge() {
   arc_bridge_service_->wake_lock()->RemoveObserver(this);
   arc_bridge_service_->wake_lock()->SetHost(nullptr);
+  // In case some this wasn't cleared while handling a dark resume.
+  GetWakeLockRequester(device::mojom::WakeLockType::kPreventAppSuspension)
+      ->RemoveObserver(this);
 }
 
 void ArcWakeLockBridge::OnConnectionClosed() {
@@ -157,11 +191,6 @@
   wake_lock_requesters_.clear();
 }
 
-void ArcWakeLockBridge::FlushWakeLocksForTesting() {
-  for (const auto& it : wake_lock_requesters_)
-    it.second->FlushForTesting();
-}
-
 void ArcWakeLockBridge::AcquirePartialWakeLock(
     AcquirePartialWakeLockCallback callback) {
   GetWakeLockRequester(device::mojom::WakeLockType::kPreventAppSuspension)
@@ -176,6 +205,104 @@
   std::move(callback).Run(true);
 }
 
+void ArcWakeLockBridge::DarkSuspendImminent() {
+  DVLOG(1) << __func__;
+  suspend_readiness_cb_ = chromeos::DBusThreadManager::Get()
+                              ->GetPowerManagerClient()
+                              ->GetSuspendReadinessCallback(FROM_HERE);
+  // Post task that will check for any wake locks acquired in dark resume.
+  base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE,
+      base::BindOnce(&ArcWakeLockBridge::HandleDarkResumeWakeLockCheckTimeout,
+                     dark_resume_weak_ptr_factory_.GetWeakPtr()),
+      kDarkResumeWakeLockCheckTimeout);
+}
+
+void ArcWakeLockBridge::SuspendDone(const base::TimeDelta& sleep_duration) {
+  DVLOG(1) << __func__;
+  // Clear any dark resume state when the device resumes.
+  ClearDarkResumeState();
+}
+
+void ArcWakeLockBridge::OnWakeLockRelease() {
+  // This observer is only registered once dark resume starts.
+  DCHECK(suspend_readiness_cb_);
+  DVLOG(1) << __func__;
+
+  // At this point the instance has done its work, tell the power daemon to
+  // re-suspend.
+  std::move(suspend_readiness_cb_).Run();
+  ClearDarkResumeState();
+}
+
+void ArcWakeLockBridge::FlushWakeLocksForTesting() {
+  for (const auto& it : wake_lock_requesters_)
+    it.second->FlushForTesting();
+}
+
+bool ArcWakeLockBridge::IsSuspendReadinessStateSetForTesting() const {
+  return !suspend_readiness_cb_.is_null();
+}
+
+bool ArcWakeLockBridge::WakeLockHasObserversForTesting(
+    device::mojom::WakeLockType type) {
+  return GetWakeLockRequester(
+             device::mojom::WakeLockType::kPreventAppSuspension)
+      ->HasObservers();
+}
+
+void ArcWakeLockBridge::HandleDarkResumeWakeLockCheckTimeout() {
+  DVLOG(1) << __func__;
+  DCHECK_CALLED_ON_VALID_SEQUENCE(dark_resume_tasks_sequence_checker_);
+  // Check if any wake locks are held at this point. If not, then it's assumed
+  // the instance either acquired and released one or had no reason to acquire
+  // one in the first place. If it wants to after this then too bad, tell the
+  // power daemon to re-suspend and invalidate any other state associated with
+  // dark resume.
+  if (!GetWakeLockRequester(device::mojom::WakeLockType::kPreventAppSuspension)
+           ->IsWakeLockHeld()) {
+    DVLOG(1) << "Wake lock not held during check";
+    std::move(suspend_readiness_cb_).Run();
+    ClearDarkResumeState();
+    return;
+  }
+
+  DVLOG(1) << "Wake lock held during check";
+  // If a wake lock is held then register for a wake lock release
+  // notification. As soon as it's released tell power daemon to re-suspend.
+  // If the instance takes a long time then tell powerd daemon to re-suspend
+  // after a hard timeout irrespective of wake locks held.
+  GetWakeLockRequester(device::mojom::WakeLockType::kPreventAppSuspension)
+      ->AddObserver(this);
+
+  // Post task that will tell the power daemon to re-suspend after a dark
+  // resume irrespective of any state. This is a last resort timeout to ensure
+  // the device doesn't stay up indefinitely in dark resume.
+  base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE,
+      base::BindOnce(&ArcWakeLockBridge::HandleDarkResumeHardTimeout,
+                     dark_resume_weak_ptr_factory_.GetWeakPtr()),
+      kDarkResumeHardTimeout);
+}
+
+void ArcWakeLockBridge::HandleDarkResumeHardTimeout() {
+  DVLOG(1) << __func__;
+  DCHECK_CALLED_ON_VALID_SEQUENCE(dark_resume_tasks_sequence_checker_);
+  // Enough is enough. Tell power daemon it's okay to suspend.
+  DCHECK(suspend_readiness_cb_);
+  std::move(suspend_readiness_cb_).Run();
+  ClearDarkResumeState();
+}
+
+void ArcWakeLockBridge::ClearDarkResumeState() {
+  DVLOG(1) << __func__;
+  // Invalidate all other state associated with dark resume.
+  suspend_readiness_cb_.Reset();
+  GetWakeLockRequester(device::mojom::WakeLockType::kPreventAppSuspension)
+      ->RemoveObserver(this);
+  dark_resume_weak_ptr_factory_.InvalidateWeakPtrs();
+}
+
 ArcWakeLockBridge::WakeLockRequester* ArcWakeLockBridge::GetWakeLockRequester(
     device::mojom::WakeLockType type) {
   auto it = wake_lock_requesters_.find(type);
diff --git a/components/arc/wake_lock/arc_wake_lock_bridge.h b/components/arc/wake_lock/arc_wake_lock_bridge.h
index 67ce3ee..545b9b0 100644
--- a/components/arc/wake_lock/arc_wake_lock_bridge.h
+++ b/components/arc/wake_lock/arc_wake_lock_bridge.h
@@ -10,8 +10,11 @@
 
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "base/sequence_checker.h"
+#include "chromeos/dbus/power_manager_client.h"
 #include "components/arc/common/wake_lock.mojom.h"
 #include "components/arc/connection_observer.h"
+#include "components/arc/wake_lock/wake_lock_observer.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "content/public/common/service_manager_connection.h"
 #include "mojo/public/cpp/bindings/binding.h"
@@ -30,7 +33,9 @@
 // Sets wake up timers / alarms based on calls from the instance.
 class ArcWakeLockBridge : public KeyedService,
                           public ConnectionObserver<mojom::WakeLockInstance>,
-                          public mojom::WakeLockHost {
+                          public mojom::WakeLockHost,
+                          public chromeos::PowerManagerClient::Observer,
+                          public WakeLockObserver {
  public:
   // Returns the factory instance for this class.
   static BrowserContextKeyedServiceFactory* GetFactory();
@@ -54,13 +59,36 @@
   // ConnectionObserver<mojom::WakeLockInstance>::Observer overrides.
   void OnConnectionClosed() override;
 
+  // mojom::WakeLockHost overrides.
+  void AcquirePartialWakeLock(AcquirePartialWakeLockCallback callback) override;
+  void ReleasePartialWakeLock(ReleasePartialWakeLockCallback callback) override;
+
+  // chromeos::PowerManagerClient::Observer overrides.
+  void DarkSuspendImminent() override;
+  void SuspendDone(const base::TimeDelta& sleep_duration) override;
+
+  // WakeLockObserver override.
+  void OnWakeLockRelease() override;
+
   // Runs the message loop until replies have been received for all pending
   // device service requests in |wake_lock_requesters_|.
   void FlushWakeLocksForTesting();
 
-  // mojom::WakeLockHost overrides.
-  void AcquirePartialWakeLock(AcquirePartialWakeLockCallback callback) override;
-  void ReleasePartialWakeLock(ReleasePartialWakeLockCallback callback) override;
+  // Checks if |suspend_readiness_cb_| is set.
+  bool IsSuspendReadinessStateSetForTesting() const;
+
+  // Returns true iff wake lock of |type| has observers.
+  bool WakeLockHasObserversForTesting(device::mojom::WakeLockType type);
+
+  // Time after a dark resume when wake lock count is checked and a decision is
+  // made to re-suspend or wait for wake lock release.
+  static constexpr base::TimeDelta kDarkResumeWakeLockCheckTimeout =
+      base::TimeDelta::FromSeconds(3);
+
+  // Max time to wait for wake lock release after a wake lock check after a dark
+  // resume. After this time the system is asked to re-suspend.
+  static constexpr base::TimeDelta kDarkResumeHardTimeout =
+      base::TimeDelta::FromSeconds(10);
 
  private:
   class WakeLockRequester;
@@ -68,6 +96,20 @@
   // Returns the WakeLockRequester for |type|, creating one if needed.
   WakeLockRequester* GetWakeLockRequester(device::mojom::WakeLockType type);
 
+  // Runs |kDarkResumeWakeLockCheckTimeout| time delta after a dark resume.
+  // Checks if app suspension wake locks (partial wake locks for Android) are
+  // held. If no wake locks are held then re-suspends the device else schedules
+  // |HandleDarkResumeHardTimeout|.
+  void HandleDarkResumeWakeLockCheckTimeout();
+
+  // Runs |kDarkResumeHardTimeout| time delta after a
+  // |HandleDarkResumeWakeLockCheckTimeout|. Clears all dark resume state and
+  // re-suspends the device.
+  void HandleDarkResumeHardTimeout();
+
+  // Clears all state associated with dark resume.
+  void ClearDarkResumeState();
+
   ArcBridgeService* const arc_bridge_service_;  // Owned by ArcServiceManager.
 
   // If non-null, used instead of the process-wide connector to fetch services.
@@ -78,8 +120,21 @@
   std::map<device::mojom::WakeLockType, std::unique_ptr<WakeLockRequester>>
       wake_lock_requesters_;
 
+  // Called when system is ready to supend after a |DarkSupendImminent| i.e.
+  // after a dark resume.
+  base::OnceClosure suspend_readiness_cb_;
+
   mojo::Binding<mojom::WakeLockHost> binding_;
 
+  // Used for checking if |DarkResumeWakeLockCheckTimeout| and
+  // |DarkResumeHardTimeout| run on the same sequence.
+  SEQUENCE_CHECKER(dark_resume_tasks_sequence_checker_);
+
+  // Factory used to schedule and cancel
+  // |HandleDarkResumeWakeLockCheckTimeout| and |HandleDarkResumeHardTimeout|.
+  // At any point either none or one of these tasks is in flight.
+  base::WeakPtrFactory<ArcWakeLockBridge> dark_resume_weak_ptr_factory_{this};
+
   base::WeakPtrFactory<ArcWakeLockBridge> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(ArcWakeLockBridge);
diff --git a/components/arc/wake_lock/arc_wake_lock_bridge_unittest.cc b/components/arc/wake_lock/arc_wake_lock_bridge_unittest.cc
index 7a2c46e..8f1e4e93 100644
--- a/components/arc/wake_lock/arc_wake_lock_bridge_unittest.cc
+++ b/components/arc/wake_lock/arc_wake_lock_bridge_unittest.cc
@@ -9,6 +9,8 @@
 
 #include "base/run_loop.h"
 #include "base/test/scoped_task_environment.h"
+#include "chromeos/dbus/dbus_thread_manager.h"
+#include "chromeos/dbus/fake_power_manager_client.h"
 #include "components/arc/arc_bridge_service.h"
 #include "components/arc/common/power.mojom.h"
 #include "components/arc/test/connection_holder_util.h"
@@ -24,7 +26,9 @@
 
 class ArcWakeLockBridgeTest : public testing::Test {
  public:
-  ArcWakeLockBridgeTest() {
+  ArcWakeLockBridgeTest()
+      : scoped_task_environment_(
+            base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME) {
     auto wake_lock_provider_ptr =
         std::make_unique<device::TestWakeLockProvider>();
     wake_lock_provider_ = wake_lock_provider_ptr.get();
@@ -34,6 +38,10 @@
             std::move(wake_lock_provider_ptr));
     connector_ = connector_factory_->CreateConnector();
 
+    fake_power_manager_client_ = new chromeos::FakePowerManagerClient;
+    chromeos::DBusThreadManager::GetSetterForTesting()->SetPowerManagerClient(
+        base::WrapUnique(fake_power_manager_client_));
+
     bridge_service_ = std::make_unique<ArcBridgeService>();
     wake_lock_bridge_ =
         std::make_unique<ArcWakeLockBridge>(nullptr, bridge_service_.get());
@@ -44,6 +52,27 @@
   ~ArcWakeLockBridgeTest() override { DestroyWakeLockInstance(); }
 
  protected:
+  // Creates a FakeWakeLockInstance for |bridge_service_|. This results in
+  // ArcWakeLockBridge::OnInstanceReady() being called.
+  void CreateWakeLockInstance() {
+    instance_ = std::make_unique<FakeWakeLockInstance>();
+    bridge_service_->wake_lock()->SetInstance(instance_.get());
+    WaitForInstanceReady(bridge_service_->wake_lock());
+  }
+
+  // Destroys the FakeWakeLockInstance. This results in
+  // ArcWakeLockBridge::OnInstanceClosed() being called.
+  void DestroyWakeLockInstance() {
+    if (!instance_)
+      return;
+    bridge_service_->wake_lock()->CloseInstance(instance_.get());
+    instance_.reset();
+  }
+
+  device::TestWakeLockProvider* GetWakeLockProvider() const {
+    return wake_lock_provider_;
+  }
+
   // Returns true iff there is no failure acquiring a system wake lock.
   bool AcquirePartialWakeLock() {
     base::RunLoop loop;
@@ -66,30 +95,29 @@
     return result;
   }
 
-  // Creates a FakeWakeLockInstance for |bridge_service_|. This results in
-  // ArcWakeLockBridge::OnInstanceReady() being called.
-  void CreateWakeLockInstance() {
-    instance_ = std::make_unique<FakeWakeLockInstance>();
-    bridge_service_->wake_lock()->SetInstance(instance_.get());
-    WaitForInstanceReady(bridge_service_->wake_lock());
+  // Return true iff all dark resume related state is set i.e the suspend
+  // readiness callback is set and wake lock release event has observers.
+  bool IsDarkResumeStateSet() const {
+    return wake_lock_bridge_->IsSuspendReadinessStateSetForTesting() &&
+           wake_lock_bridge_->WakeLockHasObserversForTesting(
+               WakeLockType::kPreventAppSuspension);
   }
 
-  // Destroys the FakeWakeLockInstance. This results in
-  // ArcWakeLockBridge::OnInstanceClosed() being called.
-  void DestroyWakeLockInstance() {
-    if (!instance_)
-      return;
-    bridge_service_->wake_lock()->CloseInstance(instance_.get());
-    instance_.reset();
+  // Return true iff all dark resume related state is reset. This should be true
+  // when device exits dark resume either by re-suspending or transitioning to
+  // full resume.
+  bool IsDarkResumeStateReset() const {
+    return !wake_lock_bridge_->WakeLockHasObserversForTesting(
+               WakeLockType::kPreventAppSuspension) &&
+           !wake_lock_bridge_->IsSuspendReadinessStateSetForTesting();
   }
 
-  device::TestWakeLockProvider* GetWakeLockProvider() {
-    return wake_lock_provider_;
-  }
-
- private:
   base::test::ScopedTaskEnvironment scoped_task_environment_;
 
+  // Owned by chromeos::DBusThreadManager.
+  chromeos::FakePowerManagerClient* fake_power_manager_client_;
+
+ private:
   std::unique_ptr<service_manager::TestConnectorFactory> connector_factory_;
   std::unique_ptr<service_manager::Connector> connector_;
   device::TestWakeLockProvider* wake_lock_provider_;
@@ -155,4 +183,94 @@
                    WakeLockType::kPreventAppSuspension));
 }
 
+TEST_F(ArcWakeLockBridgeTest, CheckSuspendAfterDarkResumeNoWakeLocksHeld) {
+  // Trigger a dark resume event, move time forward to trigger a wake lock check
+  // and check if a re-suspend happened if no wake locks were acquired.
+  fake_power_manager_client_->SendDarkSuspendImminent();
+  scoped_task_environment_.FastForwardBy(
+      ArcWakeLockBridge::kDarkResumeWakeLockCheckTimeout);
+  base::RunLoop run_loop;
+  run_loop.RunUntilIdle();
+  EXPECT_TRUE(IsDarkResumeStateReset());
+
+  // Trigger a dark resume event, acquire and release a wake lock and move time
+  // forward to trigger a wake lock check. The device should re-suspend in this
+  // case since no wake locks were held at the time of the wake lock check.
+  fake_power_manager_client_->SendDarkSuspendImminent();
+  EXPECT_TRUE(AcquirePartialWakeLock());
+  EXPECT_TRUE(ReleasePartialWakeLock());
+  scoped_task_environment_.FastForwardBy(
+      ArcWakeLockBridge::kDarkResumeWakeLockCheckTimeout);
+  base::RunLoop run_loop2;
+  run_loop2.RunUntilIdle();
+  EXPECT_TRUE(IsDarkResumeStateReset());
+}
+
+TEST_F(ArcWakeLockBridgeTest, CheckSuspendAfterDarkResumeWakeLocksHeld) {
+  // Trigger a dark resume event, acquire a wake lock and move time forward to a
+  // wake lock check. At this point the system shouldn't re-suspend i.e. the
+  // suspend readiness callback should be set and wake lock release should have
+  // observers.
+  fake_power_manager_client_->SendDarkSuspendImminent();
+  EXPECT_TRUE(AcquirePartialWakeLock());
+  scoped_task_environment_.FastForwardBy(
+      ArcWakeLockBridge::kDarkResumeWakeLockCheckTimeout);
+  base::RunLoop run_loop;
+  run_loop.RunUntilIdle();
+  EXPECT_TRUE(IsDarkResumeStateSet());
+
+  // Move time forward by < |kDarkResumeHardTimeout| and release the
+  // partial wake lock.This should instantaneously re-suspend the device.
+  scoped_task_environment_.FastForwardBy(
+      ArcWakeLockBridge::kDarkResumeHardTimeout -
+      base::TimeDelta::FromSeconds(1));
+  EXPECT_TRUE(ReleasePartialWakeLock());
+  base::RunLoop run_loop2;
+  run_loop2.RunUntilIdle();
+  EXPECT_TRUE(IsDarkResumeStateReset());
+}
+
+TEST_F(ArcWakeLockBridgeTest, CheckSuspendAfterDarkResumeHardTimeout) {
+  // Trigger a dark resume event, acquire a wake lock and move time forward to a
+  // wake lock check. At this point the system shouldn't re-suspend i.e. the
+  // suspend readiness callback should be set and wake lock release should have
+  // observers.
+  fake_power_manager_client_->SendDarkSuspendImminent();
+  EXPECT_TRUE(AcquirePartialWakeLock());
+  scoped_task_environment_.FastForwardBy(
+      ArcWakeLockBridge::kDarkResumeWakeLockCheckTimeout);
+  base::RunLoop run_loop;
+  run_loop.RunUntilIdle();
+  EXPECT_TRUE(IsDarkResumeStateSet());
+
+  // Move time forward by |kDarkResumeHardTimeout|. At this point the
+  // device should re-suspend even though the wake lock is acquired.
+  scoped_task_environment_.FastForwardBy(
+      ArcWakeLockBridge::kDarkResumeHardTimeout);
+  EXPECT_EQ(1, GetWakeLockProvider()->GetActiveWakeLocksOfType(
+                   WakeLockType::kPreventAppSuspension));
+  base::RunLoop run_loop2;
+  run_loop2.RunUntilIdle();
+  EXPECT_TRUE(IsDarkResumeStateReset());
+}
+
+TEST_F(ArcWakeLockBridgeTest, CheckStateResetAfterSuspendDone) {
+  // Trigger a dark resume event, acquire a wake lock and move time forward to a
+  // wake lock check. At this point the system shouldn't re-suspend i.e. the
+  // suspend readiness callback should be set and wake lock release should have
+  // observers.
+  fake_power_manager_client_->SendDarkSuspendImminent();
+  EXPECT_TRUE(AcquirePartialWakeLock());
+  scoped_task_environment_.FastForwardBy(
+      ArcWakeLockBridge::kDarkResumeWakeLockCheckTimeout);
+  base::RunLoop run_loop;
+  run_loop.RunUntilIdle();
+  EXPECT_TRUE(IsDarkResumeStateSet());
+
+  // Trigger suspend done event. Check if state is reset as dark resume would be
+  // exited.
+  fake_power_manager_client_->SendSuspendDone();
+  EXPECT_TRUE(IsDarkResumeStateReset());
+}
+
 }  // namespace arc
diff --git a/components/arc/wake_lock/wake_lock_observer.h b/components/arc/wake_lock/wake_lock_observer.h
new file mode 100644
index 0000000..45072a67
--- /dev/null
+++ b/components/arc/wake_lock/wake_lock_observer.h
@@ -0,0 +1,28 @@
+// 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_ARC_WAKE_LOCK_WAKE_LOCK_OBSERVER_H_
+#define COMPONENTS_ARC_WAKE_LOCK_WAKE_LOCK_OBSERVER_H_
+
+namespace arc {
+
+// This is an interface for classes that want to learn when Android wake locks
+// are acquired or released. Observer should register themselves by calling the
+// overriding class's AddObserver() method.
+class WakeLockObserver {
+ public:
+  virtual ~WakeLockObserver() = default;
+
+  // Called when the tracked wake lock is acquired the first time i.e.
+  // number of holders increases to 1.
+  virtual void OnWakeLockAcquire() {}
+
+  // Called when the tracked wake lock is released the last time i.e. the number
+  // of holders goes to 0.
+  virtual void OnWakeLockRelease() {}
+};
+
+}  // namespace arc
+
+#endif  // COMPONENTS_ARC_WAKE_LOCK_WAKE_LOCK_OBSERVER_H_
diff --git a/components/autofill/android/java/res/layout/autofill_dropdown_footer_item_refresh.xml b/components/autofill/android/java/res/layout/autofill_dropdown_footer_item_refresh.xml
index da6e127e..b97c548 100644
--- a/components/autofill/android/java/res/layout/autofill_dropdown_footer_item_refresh.xml
+++ b/components/autofill/android/java/res/layout/autofill_dropdown_footer_item_refresh.xml
@@ -14,6 +14,7 @@
     android:paddingStart="@dimen/autofill_dropdown_refresh_horizontal_padding"
     android:gravity="center_vertical"
     android:orientation="horizontal"
+    android:background="?android:attr/selectableItemBackground"
     tools:ignore="UseCompoundDrawables" >
 
     <TextView
@@ -29,8 +30,9 @@
 
     <ImageView
         android:id="@+id/dropdown_icon"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
+        android:layout_width="@dimen/autofill_dropdown_refresh_icon_width"
+        android:layout_height="@dimen/autofill_dropdown_refresh_footer_icon_height"
+        android:scaleType="centerInside"
         android:layout_marginStart="@dimen/autofill_dropdown_refresh_icon_margin"
         android:layout_marginEnd="0dp"
         tools:ignore="ContentDescription" />
diff --git a/components/autofill/android/java/res/layout/autofill_dropdown_item_refresh.xml b/components/autofill/android/java/res/layout/autofill_dropdown_item_refresh.xml
index 4287074..8977b68e 100644
--- a/components/autofill/android/java/res/layout/autofill_dropdown_item_refresh.xml
+++ b/components/autofill/android/java/res/layout/autofill_dropdown_item_refresh.xml
@@ -46,8 +46,9 @@
 
     <ImageView
         android:id="@+id/end_dropdown_icon"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
+        android:layout_width="@dimen/autofill_dropdown_refresh_icon_width"
+        android:layout_height="@dimen/autofill_dropdown_refresh_icon_height"
+        android:scaleType="centerInside"
         android:layout_marginStart="@dimen/autofill_dropdown_refresh_icon_margin"
         android:layout_marginEnd="0dp"
         tools:ignore="ContentDescription" />
diff --git a/components/autofill/android/java/res/values/dimens.xml b/components/autofill/android/java/res/values/dimens.xml
index 3f01bcb1..1e1b660 100644
--- a/components/autofill/android/java/res/values/dimens.xml
+++ b/components/autofill/android/java/res/values/dimens.xml
@@ -15,6 +15,12 @@
     <!-- Dimens for refresh UI -->
     <dimen name="autofill_dropdown_refresh_item_height">48dp</dimen>
     <dimen name="autofill_dropdown_refresh_footer_item_height">40dp</dimen>
+
+    <dimen name="autofill_dropdown_refresh_icon_height">16dp</dimen>
+    <dimen name="autofill_dropdown_refresh_icon_width">38dp</dimen>
+    <dimen name="autofill_dropdown_refresh_footer_icon_height">14dp</dimen>
+
     <dimen name="autofill_dropdown_refresh_horizontal_padding">16dp</dimen>
+    <dimen name="autofill_dropdown_refresh_vertical_padding">12dp</dimen>
     <dimen name="autofill_dropdown_refresh_icon_margin">24dp</dimen>
 </resources>
diff --git a/components/autofill/android/java/src/org/chromium/components/autofill/AutofillDropdownAdapter.java b/components/autofill/android/java/src/org/chromium/components/autofill/AutofillDropdownAdapter.java
index 9b73485..384040e 100644
--- a/components/autofill/android/java/src/org/chromium/components/autofill/AutofillDropdownAdapter.java
+++ b/components/autofill/android/java/src/org/chromium/components/autofill/AutofillDropdownAdapter.java
@@ -83,13 +83,27 @@
         DropdownItem item = getItem(position);
 
         if (mIsRefresh) {
-            populateLabelView(item, layout);
+            TextView labelView = populateLabelView(item, layout);
             populateSublabelView(item, layout);
             ImageView iconView =
                     populateIconView((ImageView) layout.findViewById(R.id.end_dropdown_icon), item);
             if (iconView != null) {
                 iconView.setLayoutParams(getSizeParamsForIconView(iconView, item));
             }
+
+            if (item.isMultilineLabel()) {
+                labelView.setSingleLine(false);
+
+                LinearLayout wrapper =
+                        (LinearLayout) layout.findViewById(R.id.dropdown_label_wrapper);
+
+                int paddingHeight = mContext.getResources().getDimensionPixelSize(
+                        R.dimen.autofill_dropdown_refresh_vertical_padding);
+
+                wrapper.setPadding(
+                        /*left=*/0, /*top=*/paddingHeight, /*right=*/0, /*bottom=*/paddingHeight);
+            }
+
             return layout;
         }
 
diff --git a/components/autofill/core/browser/autofill_profile_validation_util.cc b/components/autofill/core/browser/autofill_profile_validation_util.cc
index 0d6bca3..3932749 100644
--- a/components/autofill/core/browser/autofill_profile_validation_util.cc
+++ b/components/autofill/core/browser/autofill_profile_validation_util.cc
@@ -4,6 +4,7 @@
 
 #include "components/autofill/core/browser/autofill_profile_validation_util.h"
 
+#include <string>
 #include <utility>
 
 #include "base/i18n/case_conversion.h"
@@ -125,6 +126,41 @@
                               AutofillProfile::CLIENT);
 }
 
+void SetInvalidIfUnvalidated(AutofillProfile* profile) {
+  if (profile->GetValidityState(ADDRESS_HOME_COUNTRY,
+                                AutofillProfile::CLIENT) ==
+      AutofillProfile::UNVALIDATED) {
+    profile->SetValidityState(ADDRESS_HOME_COUNTRY, AutofillProfile::INVALID,
+                              AutofillProfile::CLIENT);
+  }
+
+  if (profile->GetValidityState(ADDRESS_HOME_STATE, AutofillProfile::CLIENT) ==
+      AutofillProfile::UNVALIDATED) {
+    profile->SetValidityState(ADDRESS_HOME_STATE, AutofillProfile::INVALID,
+                              AutofillProfile::CLIENT);
+  }
+
+  if (profile->GetValidityState(ADDRESS_HOME_CITY, AutofillProfile::CLIENT) ==
+      AutofillProfile::UNVALIDATED) {
+    profile->SetValidityState(ADDRESS_HOME_CITY, AutofillProfile::INVALID,
+                              AutofillProfile::CLIENT);
+  }
+
+  if (profile->GetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
+                                AutofillProfile::CLIENT) ==
+      AutofillProfile::UNVALIDATED) {
+    profile->SetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
+                              AutofillProfile::INVALID,
+                              AutofillProfile::CLIENT);
+  }
+
+  if (profile->GetValidityState(ADDRESS_HOME_ZIP, AutofillProfile::CLIENT) ==
+      AutofillProfile::UNVALIDATED) {
+    profile->SetValidityState(ADDRESS_HOME_ZIP, AutofillProfile::INVALID,
+                              AutofillProfile::CLIENT);
+  }
+}
+
 void MaybeApplyValidToFields(AutofillProfile* profile) {
   // The metadata works from top to bottom. Therefore, a so far UNVALIDATED
   // subregion can only be validated if its super-region is VALID. In  this
@@ -162,6 +198,29 @@
   }
 }
 
+void ApplyValidOnlyIfAllChildrenNotInvalid(AutofillProfile* profile) {
+  if (profile->GetValidityState(ADDRESS_HOME_STATE, AutofillProfile::CLIENT) ==
+          AutofillProfile::INVALID &&
+      profile->GetValidityState(ADDRESS_HOME_ZIP, AutofillProfile::CLIENT) ==
+          AutofillProfile::INVALID) {
+    profile->SetValidityState(ADDRESS_HOME_COUNTRY, AutofillProfile::INVALID,
+                              AutofillProfile::CLIENT);
+  }
+
+  if (profile->GetValidityState(ADDRESS_HOME_CITY, AutofillProfile::CLIENT) ==
+      AutofillProfile::INVALID) {
+    profile->SetValidityState(ADDRESS_HOME_STATE, AutofillProfile::INVALID,
+                              AutofillProfile::CLIENT);
+  }
+
+  if (profile->GetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
+                                AutofillProfile::CLIENT) ==
+      AutofillProfile::INVALID) {
+    profile->SetValidityState(ADDRESS_HOME_CITY, AutofillProfile::INVALID,
+                              AutofillProfile::CLIENT);
+  }
+}
+
 }  // namespace
 
 namespace profile_validation_util {
@@ -170,13 +229,13 @@
                      AddressValidator* address_validator) {
   DCHECK(address_validator);
   DCHECK(profile);
-  ValidateAddress(profile, address_validator);
+  ValidateAddressStrictly(profile, address_validator);
   ValidatePhoneNumber(profile);
   ValidateEmailAddress(profile);
 }
 
-void ValidateAddress(AutofillProfile* profile,
-                     AddressValidator* address_validator) {
+AddressValidator::Status ValidateAddress(AutofillProfile* profile,
+                                         AddressValidator* address_validator) {
   DCHECK(address_validator);
   DCHECK(profile);
 
@@ -190,7 +249,7 @@
     // unclear which, if any, rule should apply.
     SetValidityStateForAddressField(profile, COUNTRY, AutofillProfile::INVALID);
     SetEmptyValidityIfEmpty(profile);
-    return;
+    return AddressValidator::SUCCESS;
   }
 
   // The COUNTRY was already listed in the CountryDataMap, therefore it's valid.
@@ -212,6 +271,31 @@
   // Fields (except COUNTRY) could be VALID, only if the rules were available.
   if (status == AddressValidator::SUCCESS)
     MaybeApplyValidToFields(profile);
+
+  return status;
+}
+
+void ValidateAddressStrictly(AutofillProfile* profile,
+                             AddressValidator* address_validator) {
+  DCHECK(address_validator);
+  DCHECK(profile);
+
+  // If the rules were loaded successfully, add a second layer of validation:
+  // 1. For a field to stay valid after the first run, all the fields that
+  // depend on that field for validation need to not be invalid on the first
+  // run, otherwise there is a chance that the data on that field was also
+  // invalid (incorrect.)
+  // Example: 1225 Notre-Dame Ouest, Montreal, Quebec, H3C 2A3, United States.
+  // A human validator can see that the country is most probably the invalid
+  // field. The first step helps us validate the rules interdependently.
+  // 2. All the address fields that could not be validated (UNVALIDATED),
+  // should be considered as invalid.
+
+  if (ValidateAddress(profile, address_validator) ==
+      AddressValidator::SUCCESS) {
+    ApplyValidOnlyIfAllChildrenNotInvalid(profile);
+    SetInvalidIfUnvalidated(profile);
+  }
 }
 
 void ValidateEmailAddress(AutofillProfile* profile) {
diff --git a/components/autofill/core/browser/autofill_profile_validation_util.h b/components/autofill/core/browser/autofill_profile_validation_util.h
index 84c8931..60c84d4 100644
--- a/components/autofill/core/browser/autofill_profile_validation_util.h
+++ b/components/autofill/core/browser/autofill_profile_validation_util.h
@@ -16,8 +16,14 @@
                      AddressValidator* address_validator);
 
 // Sets the validity state of the address fields of the |profile|.
-void ValidateAddress(AutofillProfile* profile,
-                     AddressValidator* address_validator);
+AddressValidator::Status ValidateAddress(AutofillProfile* profile,
+                                         AddressValidator* address_validator);
+
+// Sets the validity state of the address fields of the |profile| in two passes.
+// First runs the ValidateAddress, then adds a second layer of validation based
+// on the results.
+void ValidateAddressStrictly(AutofillProfile* profile,
+                             AddressValidator* address_validator);
 
 // Sets the validity state of the phone number field of the |profile|.
 void ValidatePhoneNumber(AutofillProfile* profile);
diff --git a/components/autofill/core/browser/autofill_profile_validation_util_unittest.cc b/components/autofill/core/browser/autofill_profile_validation_util_unittest.cc
index 1fb11af..6b609ed 100644
--- a/components/autofill/core/browser/autofill_profile_validation_util_unittest.cc
+++ b/components/autofill/core/browser/autofill_profile_validation_util_unittest.cc
@@ -54,7 +54,7 @@
   }
 
   void ValidateAddressTest(AutofillProfile* profile) {
-    profile_validation_util::ValidateAddress(profile, validator_.get());
+    profile_validation_util::ValidateAddressStrictly(profile, validator_.get());
   }
 
   void ValidatePhoneTest(AutofillProfile* profile) {
@@ -115,17 +115,19 @@
   EXPECT_EQ(
       AutofillProfile::INVALID,
       profile.GetValidityState(ADDRESS_HOME_COUNTRY, AutofillProfile::CLIENT));
+  // The zip, the state and the city can't be validated, because we don't know
+  // the country, in the strict validation this is considered as invalid.
   EXPECT_EQ(
-      AutofillProfile::UNVALIDATED,
+      AutofillProfile::INVALID,
       profile.GetValidityState(ADDRESS_HOME_STATE, AutofillProfile::CLIENT));
   EXPECT_EQ(
-      AutofillProfile::UNVALIDATED,
+      AutofillProfile::INVALID,
       profile.GetValidityState(ADDRESS_HOME_CITY, AutofillProfile::CLIENT));
   EXPECT_EQ(AutofillProfile::EMPTY,
             profile.GetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
                                      AutofillProfile::CLIENT));
   EXPECT_EQ(
-      AutofillProfile::UNVALIDATED,
+      AutofillProfile::INVALID,
       profile.GetValidityState(ADDRESS_HOME_ZIP, AutofillProfile::CLIENT));
 }
 
@@ -139,17 +141,19 @@
   EXPECT_EQ(
       AutofillProfile::EMPTY,
       profile.GetValidityState(ADDRESS_HOME_COUNTRY, AutofillProfile::CLIENT));
+  // The zip, the state and the city can't be validated, because we don't know
+  // the country, in the strict validation this is considered as invalid.
   EXPECT_EQ(
-      AutofillProfile::UNVALIDATED,
+      AutofillProfile::INVALID,
       profile.GetValidityState(ADDRESS_HOME_STATE, AutofillProfile::CLIENT));
   EXPECT_EQ(
-      AutofillProfile::UNVALIDATED,
+      AutofillProfile::INVALID,
       profile.GetValidityState(ADDRESS_HOME_CITY, AutofillProfile::CLIENT));
   EXPECT_EQ(AutofillProfile::EMPTY,
             profile.GetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
                                      AutofillProfile::CLIENT));
   EXPECT_EQ(
-      AutofillProfile::UNVALIDATED,
+      AutofillProfile::INVALID,
       profile.GetValidityState(ADDRESS_HOME_ZIP, AutofillProfile::CLIENT));
 }
 
@@ -190,8 +194,10 @@
   EXPECT_EQ(
       AutofillProfile::INVALID,
       profile.GetValidityState(ADDRESS_HOME_STATE, AutofillProfile::CLIENT));
+  // The city can't be validated, because we don't know the state, in the strict
+  // validation this is considered as invalid.
   EXPECT_EQ(
-      AutofillProfile::UNVALIDATED,
+      AutofillProfile::INVALID,
       profile.GetValidityState(ADDRESS_HOME_CITY, AutofillProfile::CLIENT));
   EXPECT_EQ(AutofillProfile::EMPTY,
             profile.GetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
@@ -212,8 +218,10 @@
   EXPECT_EQ(
       AutofillProfile::EMPTY,
       profile.GetValidityState(ADDRESS_HOME_STATE, AutofillProfile::CLIENT));
+  // The city can't be validated, because we don't know the state, in the strict
+  // validation this is considered as invalid.
   EXPECT_EQ(
-      AutofillProfile::UNVALIDATED,
+      AutofillProfile::INVALID,
       profile.GetValidityState(ADDRESS_HOME_CITY, AutofillProfile::CLIENT));
   EXPECT_EQ(AutofillProfile::EMPTY,
             profile.GetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
@@ -499,13 +507,17 @@
   EXPECT_EQ(
       AutofillProfile::VALID,
       profile.GetValidityState(ADDRESS_HOME_COUNTRY, AutofillProfile::CLIENT));
+  // The city which is the only dependent field on state is invalid, in the
+  // strict validation the state would also be considered as invalid.
   EXPECT_EQ(
-      AutofillProfile::VALID,
+      AutofillProfile::INVALID,
       profile.GetValidityState(ADDRESS_HOME_STATE, AutofillProfile::CLIENT));
   EXPECT_EQ(
       AutofillProfile::INVALID,
       profile.GetValidityState(ADDRESS_HOME_CITY, AutofillProfile::CLIENT));
-  EXPECT_EQ(AutofillProfile::UNVALIDATED,
+  // The dependent locality can't be validated, because we don't know the city,
+  // in the strict validation this is considered as invalid.
+  EXPECT_EQ(AutofillProfile::INVALID,
             profile.GetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
                                      AutofillProfile::CLIENT));
   EXPECT_EQ(
@@ -526,13 +538,17 @@
   EXPECT_EQ(
       AutofillProfile::VALID,
       profile.GetValidityState(ADDRESS_HOME_COUNTRY, AutofillProfile::CLIENT));
+  // The city which is the only dependent field on state is invalid, in the
+  // strict validation the state would also be considered as invalid.
   EXPECT_EQ(
-      AutofillProfile::VALID,
+      AutofillProfile::INVALID,
       profile.GetValidityState(ADDRESS_HOME_STATE, AutofillProfile::CLIENT));
   EXPECT_EQ(
       AutofillProfile::INVALID,
       profile.GetValidityState(ADDRESS_HOME_CITY, AutofillProfile::CLIENT));
-  EXPECT_EQ(AutofillProfile::UNVALIDATED,
+  // The dependent locality can't be validated, because we don't know the city,
+  // in the strict validation this is considered as invalid.
+  EXPECT_EQ(AutofillProfile::INVALID,
             profile.GetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
                                      AutofillProfile::CLIENT));
   EXPECT_EQ(
@@ -609,8 +625,10 @@
   EXPECT_EQ(
       AutofillProfile::VALID,
       profile.GetValidityState(ADDRESS_HOME_STATE, AutofillProfile::CLIENT));
+  // The dependent locality which is the only dependent field on city is
+  // invalid, in the strict validation the city would also be invalid.
   EXPECT_EQ(
-      AutofillProfile::VALID,
+      AutofillProfile::INVALID,
       profile.GetValidityState(ADDRESS_HOME_CITY, AutofillProfile::CLIENT));
   EXPECT_EQ(AutofillProfile::INVALID,
             profile.GetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
@@ -636,8 +654,10 @@
   EXPECT_EQ(
       AutofillProfile::VALID,
       profile.GetValidityState(ADDRESS_HOME_STATE, AutofillProfile::CLIENT));
+  // The only that depend on city (dependent locality) is invalid,
+  //  in the strict validation city would also be considered as invalid.
   EXPECT_EQ(
-      AutofillProfile::VALID,
+      AutofillProfile::INVALID,
       profile.GetValidityState(ADDRESS_HOME_CITY, AutofillProfile::CLIENT));
   EXPECT_EQ(AutofillProfile::INVALID,
             profile.GetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
@@ -946,16 +966,19 @@
   profile.SetRawInfo(ADDRESS_HOME_COUNTRY, base::ASCIIToUTF16("CN"));
 
   ValidateProfileTest(&profile);
-  // The country is validated independently, so it's considered as valid.
+  // The fields that depend on country (state and zip) are both invalid,
+  // therefore in the strict validation this is considered as invalid.
   EXPECT_EQ(
-      AutofillProfile::VALID,
+      AutofillProfile::INVALID,
       profile.GetValidityState(ADDRESS_HOME_COUNTRY, AutofillProfile::CLIENT));
   // The state is not a Chinese state, so it's considered as invalid.
   EXPECT_EQ(
       AutofillProfile::INVALID,
       profile.GetValidityState(ADDRESS_HOME_STATE, AutofillProfile::CLIENT));
+  // The city can't be validated, because the state value is not
+  // valid, in the strict validation this is considered as invalid.
   EXPECT_EQ(
-      AutofillProfile::UNVALIDATED,
+      AutofillProfile::INVALID,
       profile.GetValidityState(ADDRESS_HOME_CITY, AutofillProfile::CLIENT));
 
   EXPECT_EQ(AutofillProfile::EMPTY,
@@ -985,17 +1008,19 @@
 
   ValidateProfileTest(&profile);
 
-  // The country is validated independently, so it's considered as valid.
+  // The fields that depend on Country (state and zip) are both invalid,
+  // therefore in the strict validation this is considered as invalid.
   EXPECT_EQ(
-      AutofillProfile::VALID,
+      AutofillProfile::INVALID,
       profile.GetValidityState(ADDRESS_HOME_COUNTRY, AutofillProfile::CLIENT));
   // The state is not a Canadian state, so it's considered as invalid.
   EXPECT_EQ(
       AutofillProfile::INVALID,
       profile.GetValidityState(ADDRESS_HOME_STATE, AutofillProfile::CLIENT));
-  // We can't validate city, because state is not valid.
+  // We can't validate city, because state is not valid, in the strict
+  // validation this is considered as invalid.
   EXPECT_EQ(
-      AutofillProfile::UNVALIDATED,
+      AutofillProfile::INVALID,
       profile.GetValidityState(ADDRESS_HOME_CITY, AutofillProfile::CLIENT));
   // The dependent locality is not a Canadian field, so it's considered as
   // invalid.
@@ -1030,17 +1055,18 @@
   EXPECT_EQ(
       AutofillProfile::VALID,
       profile.GetValidityState(ADDRESS_HOME_COUNTRY, AutofillProfile::CLIENT));
-  // Considered as valid because of the top to bottom approach.
+  // The only field that depends on state (city) is invalid, in the strict
+  // validation this makes state also invalid.
   EXPECT_EQ(
-      AutofillProfile::VALID,
+      AutofillProfile::INVALID,
       profile.GetValidityState(ADDRESS_HOME_STATE, AutofillProfile::CLIENT));
   // The city is in another province.
   EXPECT_EQ(
       AutofillProfile::INVALID,
       profile.GetValidityState(ADDRESS_HOME_CITY, AutofillProfile::CLIENT));
   // The dependent locality can't be validated, because the city value is not
-  // valid.
-  EXPECT_EQ(AutofillProfile::UNVALIDATED,
+  // valid, in the strict validation this is considered as invalid.
+  EXPECT_EQ(AutofillProfile::INVALID,
             profile.GetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
                                      AutofillProfile::CLIENT));
   EXPECT_EQ(AutofillProfile::UNSUPPORTED,
@@ -1058,7 +1084,7 @@
 
 TEST_F(AutofillProfileValidationUtilTest,
        ValidateProfile_TopToBottomValidationChina_StateMissing) {
-  // This is a full valid profile, with the wrong province:
+  // This is a full valid profile, with the empty province:
   // Address Address: "100 Century Avenue",
   // District: "赫章县", City: "毕节地区", Province: "",
   // Postal Code: "200120", Country Code: "CN",
@@ -1073,12 +1099,14 @@
   EXPECT_EQ(
       AutofillProfile::EMPTY,
       profile.GetValidityState(ADDRESS_HOME_STATE, AutofillProfile::CLIENT));
-  // City can't be validated, because the state is missing.
+  // City can't be validated, because the state is missing, in the strict
+  // validation this is considered as invalid.
   EXPECT_EQ(
-      AutofillProfile::UNVALIDATED,
+      AutofillProfile::INVALID,
       profile.GetValidityState(ADDRESS_HOME_CITY, AutofillProfile::CLIENT));
-  // The dependent locality can't be validated, because we don't know the city.
-  EXPECT_EQ(AutofillProfile::UNVALIDATED,
+  // The dependent locality can't be validated, because we don't know the city,
+  // in the strict validation this is considered as invalid.
+  EXPECT_EQ(AutofillProfile::INVALID,
             profile.GetValidityState(ADDRESS_HOME_DEPENDENT_LOCALITY,
                                      AutofillProfile::CLIENT));
   EXPECT_EQ(AutofillProfile::UNSUPPORTED,
diff --git a/components/autofill/core/browser/autofill_profile_validator_unittest.cc b/components/autofill/core/browser/autofill_profile_validator_unittest.cc
index 61f4483..f70fe93 100644
--- a/components/autofill/core/browser/autofill_profile_validator_unittest.cc
+++ b/components/autofill/core/browser/autofill_profile_validator_unittest.cc
@@ -165,8 +165,8 @@
 
   // Set up the test expectations.
   expected_validity_ = {{ADDRESS_HOME_COUNTRY, AutofillProfile::INVALID},
-                        {ADDRESS_HOME_STATE, AutofillProfile::UNVALIDATED},
-                        {ADDRESS_HOME_ZIP, AutofillProfile::UNVALIDATED},
+                        {ADDRESS_HOME_STATE, AutofillProfile::INVALID},
+                        {ADDRESS_HOME_ZIP, AutofillProfile::INVALID},
                         {PHONE_HOME_WHOLE_NUMBER, AutofillProfile::UNVALIDATED},
                         {EMAIL_ADDRESS, AutofillProfile::VALID}};
 
@@ -205,8 +205,8 @@
   // Set up the test expectations.
   // The phone is validated for the US.
   expected_validity_ = {{ADDRESS_HOME_COUNTRY, AutofillProfile::EMPTY},
-                        {ADDRESS_HOME_STATE, AutofillProfile::UNVALIDATED},
-                        {ADDRESS_HOME_ZIP, AutofillProfile::UNVALIDATED},
+                        {ADDRESS_HOME_STATE, AutofillProfile::INVALID},
+                        {ADDRESS_HOME_ZIP, AutofillProfile::INVALID},
                         {PHONE_HOME_WHOLE_NUMBER, AutofillProfile::UNVALIDATED},
                         {EMAIL_ADDRESS, AutofillProfile::VALID}};
 
diff --git a/components/autofill/core/browser/payments/payments_client.cc b/components/autofill/core/browser/payments/payments_client.cc
index 97d5c12..70d7ad9 100644
--- a/components/autofill/core/browser/payments/payments_client.cc
+++ b/components/autofill/core/browser/payments/payments_client.cc
@@ -886,7 +886,7 @@
 
   DCHECK(account_info_getter_);
 
-  OAuth2TokenService::ScopeSet payments_scopes;
+  identity::ScopeSet payments_scopes;
   payments_scopes.insert(kPaymentsOAuth2Scope);
   std::string account_id =
       account_info_getter_->GetAccountInfoForPaymentsServer().account_id;
diff --git a/components/autofill/core/browser/personal_data_manager_unittest.cc b/components/autofill/core/browser/personal_data_manager_unittest.cc
index 5278183..82bf681 100644
--- a/components/autofill/core/browser/personal_data_manager_unittest.cc
+++ b/components/autofill/core/browser/personal_data_manager_unittest.cc
@@ -6752,7 +6752,7 @@
   EXPECT_EQ(
       AutofillProfile::VALID,
       profiles[2]->GetValidityState(ADDRESS_HOME_ZIP, AutofillProfile::CLIENT));
-  EXPECT_EQ(AutofillProfile::UNVALIDATED,
+  EXPECT_EQ(AutofillProfile::INVALID,
             profiles[2]->GetValidityState(ADDRESS_HOME_CITY,
                                           AutofillProfile::CLIENT));
   EXPECT_EQ(AutofillProfile::EMPTY,
diff --git a/components/autofill/core/browser/ui/local_card_migration_dialog_controller.h b/components/autofill/core/browser/ui/local_card_migration_dialog_controller.h
index 4696d2606..c58d92bfe 100644
--- a/components/autofill/core/browser/ui/local_card_migration_dialog_controller.h
+++ b/components/autofill/core/browser/ui/local_card_migration_dialog_controller.h
@@ -11,6 +11,7 @@
 #include "base/macros.h"
 #include "base/strings/string16.h"
 #include "components/autofill/core/browser/legal_message_line.h"
+#include "url/gurl.h"
 
 namespace autofill {
 
@@ -31,7 +32,7 @@
       const std::vector<std::string>& selected_cards_guids) = 0;
   virtual void OnCancelButtonClicked() = 0;
   virtual void OnViewCardsButtonClicked() = 0;
-  virtual void OnLegalMessageLinkClicked() = 0;
+  virtual void OnLegalMessageLinkClicked(const GURL& url) = 0;
   virtual void OnDialogClosed() = 0;
 
  private:
diff --git a/components/autofill_assistant/browser/BUILD.gn b/components/autofill_assistant/browser/BUILD.gn
index a629ca7..480cae2 100644
--- a/components/autofill_assistant/browser/BUILD.gn
+++ b/components/autofill_assistant/browser/BUILD.gn
@@ -13,6 +13,7 @@
 
 jumbo_static_library("browser") {
   sources = [
+    "access_token_fetcher.h",
     "actions/action.cc",
     "actions/action.h",
     "actions/action_delegate.h",
diff --git a/components/autofill_assistant/browser/access_token_fetcher.h b/components/autofill_assistant/browser/access_token_fetcher.h
new file mode 100644
index 0000000..9800def
--- /dev/null
+++ b/components/autofill_assistant/browser/access_token_fetcher.h
@@ -0,0 +1,31 @@
+// 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_ASSISTANT_BROWSER_ACCESS_TOKEN_FETCHER_H_
+#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ACCESS_TOKEN_FETCHER_H_
+
+#include <string>
+
+namespace autofill_assistant {
+
+// An interface that abstracts the steps needed to choose a user to sign in,
+// authenticate and fetch an appropriate oauth token.
+class AccessTokenFetcher {
+ public:
+  virtual ~AccessTokenFetcher() = default;
+
+  // Gets an oauth token, for the appropriate user and scope.
+  //
+  // If successful, |callback| is called with true and a token.
+  virtual void FetchAccessToken(
+      base::OnceCallback<void(bool, const std::string&)>) = 0;
+
+  // Invalidates the given oauth token.
+  virtual void InvalidateAccessToken(const std::string& access_token) = 0;
+
+ protected:
+  AccessTokenFetcher() = default;
+};
+}  // namespace autofill_assistant
+#endif  // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ACCESS_TOKEN_FETCHER_H_
diff --git a/components/autofill_assistant/browser/actions/action.cc b/components/autofill_assistant/browser/actions/action.cc
index 22e87f5..8b7d46be 100644
--- a/components/autofill_assistant/browser/actions/action.cc
+++ b/components/autofill_assistant/browser/actions/action.cc
@@ -2,14 +2,29 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <utility>
+
+#include "base/callback.h"
 #include "components/autofill_assistant/browser/actions/action.h"
+#include "components/autofill_assistant/browser/actions/action_delegate.h"
 
 namespace autofill_assistant {
 
-Action::Action(const ActionProto& proto) : proto_(proto) {}
+Action::Action(const ActionProto& proto) : proto_(proto), show_overlay_(true) {}
 
 Action::~Action() {}
 
+void Action::ProcessAction(ActionDelegate* delegate,
+                           ProcessActionCallback callback) {
+  if (show_overlay_) {
+    delegate->ShowOverlay();
+  } else {
+    delegate->HideOverlay();
+  }
+  processed_action_proto_ = std::make_unique<ProcessedActionProto>();
+  InternalProcessAction(delegate, std::move(callback));
+}
+
 void Action::UpdateProcessedAction(ProcessedActionStatusProto status) {
   // Safety check in case process action is run twice.
   *processed_action_proto_->mutable_action() = proto_;
diff --git a/components/autofill_assistant/browser/actions/action.h b/components/autofill_assistant/browser/actions/action.h
index e674f89..dab72979 100644
--- a/components/autofill_assistant/browser/actions/action.h
+++ b/components/autofill_assistant/browser/actions/action.h
@@ -26,16 +26,18 @@
   // Delegate should outlive this object.
   using ProcessActionCallback =
       base::OnceCallback<void(std::unique_ptr<ProcessedActionProto>)>;
-  // ProcessAction should create a processed_action_proto_ to be passed to the
-  // callback.
-  virtual void ProcessAction(ActionDelegate* delegate,
-                             ProcessActionCallback callback) = 0;
+
+  void ProcessAction(ActionDelegate* delegate, ProcessActionCallback callback);
 
   const ActionProto& proto() const { return proto_; }
 
  protected:
   explicit Action(const ActionProto& proto);
 
+  // Subclasses must implement this method.
+  virtual void InternalProcessAction(ActionDelegate* delegate,
+                                     ProcessActionCallback callback) = 0;
+
   // Returns selectors as a string from a repeated proto field.
   static std::vector<std::string> ExtractSelectors(
       const google::protobuf::RepeatedPtrField<std::string>& selectors_proto);
@@ -43,6 +45,7 @@
   void UpdateProcessedAction(ProcessedActionStatusProto status);
 
   const ActionProto proto_;
+  bool show_overlay_;
 
   // Accumulate any result of this action during ProcessAction. Is only valid
   // during a run of ProcessAction.
diff --git a/components/autofill_assistant/browser/actions/action_delegate.h b/components/autofill_assistant/browser/actions/action_delegate.h
index 6700f76..75cbb7f 100644
--- a/components/autofill_assistant/browser/actions/action_delegate.h
+++ b/components/autofill_assistant/browser/actions/action_delegate.h
@@ -68,8 +68,8 @@
   // UseCreditCardAction.
   virtual void GetPaymentInformation(
       payments::mojom::PaymentOptionsPtr payment_options,
-      base::OnceCallback<void(std::unique_ptr<PaymentInformation>)>
-          callback) = 0;
+      base::OnceCallback<void(std::unique_ptr<PaymentInformation>)> callback,
+      const std::string& title) = 0;
 
   // Fill the address form given by |selectors| with the given address |guid| in
   // personal data manager.
@@ -153,6 +153,12 @@
   // Hide the progress bar.
   virtual void HideProgressBar() = 0;
 
+  // Show the overlay.
+  virtual void ShowOverlay() = 0;
+
+  // Hide the overlay.
+  virtual void HideOverlay() = 0;
+
  protected:
   ActionDelegate() = default;
 };
diff --git a/components/autofill_assistant/browser/actions/autofill_action.cc b/components/autofill_assistant/browser/actions/autofill_action.cc
index d9e53be..7090b94 100644
--- a/components/autofill_assistant/browser/actions/autofill_action.cc
+++ b/components/autofill_assistant/browser/actions/autofill_action.cc
@@ -101,6 +101,7 @@
     check_form_message_ = proto.use_address().strings().check_form();
     required_fields_value_status_.resize(
         proto_.use_address().required_fields_size(), UNKNOWN);
+    show_overlay_ = proto.use_address().show_overlay();
   } else {
     DCHECK(proto.has_use_card());
     is_autofill_card_ = true;
@@ -110,15 +111,16 @@
         ExtractSelectors(proto.use_card().form_field_element().selectors());
     fill_form_message_ = proto.use_card().strings().fill_form();
     check_form_message_ = proto.use_card().strings().check_form();
+    show_overlay_ = proto.use_card().show_overlay();
   }
 }
 
 AutofillAction::~AutofillAction() = default;
 
-void AutofillAction::ProcessAction(ActionDelegate* delegate,
-                                   ProcessActionCallback action_callback) {
+void AutofillAction::InternalProcessAction(
+    ActionDelegate* delegate,
+    ProcessActionCallback action_callback) {
   process_action_callback_ = std::move(action_callback);
-  processed_action_proto_ = std::make_unique<ProcessedActionProto>();
   // Check data already selected in a previous action.
   base::Optional<std::string> selected_data;
   if (is_autofill_card_) {
diff --git a/components/autofill_assistant/browser/actions/autofill_action.h b/components/autofill_assistant/browser/actions/autofill_action.h
index 4885f1b..04a0ea5 100644
--- a/components/autofill_assistant/browser/actions/autofill_action.h
+++ b/components/autofill_assistant/browser/actions/autofill_action.h
@@ -27,13 +27,13 @@
   explicit AutofillAction(const ActionProto& proto);
   ~AutofillAction() override;
 
-  // Overrides Action:
-  void ProcessAction(ActionDelegate* delegate,
-                     ProcessActionCallback callback) override;
-
  private:
   enum FieldValueStatus { UNKNOWN, EMPTY, NOT_EMPTY };
 
+  // Overrides Action:
+  void InternalProcessAction(ActionDelegate* delegate,
+                             ProcessActionCallback callback) override;
+
   void EndAction(bool successful);
 
   // Called when the user selected the data.
diff --git a/components/autofill_assistant/browser/actions/autofill_action_unittest.cc b/components/autofill_assistant/browser/actions/autofill_action_unittest.cc
index b22eb5c..85cc640 100644
--- a/components/autofill_assistant/browser/actions/autofill_action_unittest.cc
+++ b/components/autofill_assistant/browser/actions/autofill_action_unittest.cc
@@ -314,6 +314,5 @@
   }
   EXPECT_TRUE(ProcessAction(action_proto));
 }
-
 }  // namespace
 }  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/actions/click_action.cc b/components/autofill_assistant/browser/actions/click_action.cc
index e1128e1..7362fbf 100644
--- a/components/autofill_assistant/browser/actions/click_action.cc
+++ b/components/autofill_assistant/browser/actions/click_action.cc
@@ -19,9 +19,8 @@
 
 ClickAction::~ClickAction() {}
 
-void ClickAction::ProcessAction(ActionDelegate* delegate,
-                                ProcessActionCallback callback) {
-  processed_action_proto_ = std::make_unique<ProcessedActionProto>();
+void ClickAction::InternalProcessAction(ActionDelegate* delegate,
+                                        ProcessActionCallback callback) {
   DCHECK_GT(proto_.click().element_to_click().selectors_size(), 0);
   delegate->WaitForElement(
       ExtractSelectors(proto_.click().element_to_click().selectors()),
diff --git a/components/autofill_assistant/browser/actions/click_action.h b/components/autofill_assistant/browser/actions/click_action.h
index 7bc62d6..df7d886 100644
--- a/components/autofill_assistant/browser/actions/click_action.h
+++ b/components/autofill_assistant/browser/actions/click_action.h
@@ -5,13 +5,12 @@
 #ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ACTIONS_CLICK_ACTION_H_
 #define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ACTIONS_CLICK_ACTION_H_
 
-#include "components/autofill_assistant/browser/actions/action.h"
-
 #include <string>
 #include <vector>
 
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "components/autofill_assistant/browser/actions/action.h"
 
 namespace autofill_assistant {
 // An action to perform a mouse left button click on a given element on Web.
@@ -20,11 +19,11 @@
   explicit ClickAction(const ActionProto& proto);
   ~ClickAction() override;
 
-  // Overrides Action:
-  void ProcessAction(ActionDelegate* delegate,
-                     ProcessActionCallback callback) override;
-
  private:
+  // Overrides Action:
+  void InternalProcessAction(ActionDelegate* delegate,
+                             ProcessActionCallback callback) override;
+
   void OnWaitForElement(ActionDelegate* delegate,
                         ProcessActionCallback callback,
                         bool element_found);
diff --git a/components/autofill_assistant/browser/actions/focus_element_action.cc b/components/autofill_assistant/browser/actions/focus_element_action.cc
index 996d7a5..593f8dcf 100644
--- a/components/autofill_assistant/browser/actions/focus_element_action.cc
+++ b/components/autofill_assistant/browser/actions/focus_element_action.cc
@@ -4,6 +4,9 @@
 
 #include "components/autofill_assistant/browser/actions/focus_element_action.h"
 
+#include <memory>
+#include <utility>
+
 #include "base/bind.h"
 #include "base/callback.h"
 #include "components/autofill_assistant/browser/actions/action_delegate.h"
@@ -13,13 +16,13 @@
 FocusElementAction::FocusElementAction(const ActionProto& proto)
     : Action(proto), weak_ptr_factory_(this) {
   DCHECK(proto_.has_focus_element());
+  show_overlay_ = false;
 }
 
 FocusElementAction::~FocusElementAction() {}
 
-void FocusElementAction::ProcessAction(ActionDelegate* delegate,
-                                       ProcessActionCallback callback) {
-  processed_action_proto_ = std::make_unique<ProcessedActionProto>();
+void FocusElementAction::InternalProcessAction(ActionDelegate* delegate,
+                                               ProcessActionCallback callback) {
   const FocusElementProto& focus_element = proto_.focus_element();
   DCHECK_GT(focus_element.element().selectors_size(), 0);
 
diff --git a/components/autofill_assistant/browser/actions/focus_element_action.h b/components/autofill_assistant/browser/actions/focus_element_action.h
index b2b2f74..7a19d08 100644
--- a/components/autofill_assistant/browser/actions/focus_element_action.h
+++ b/components/autofill_assistant/browser/actions/focus_element_action.h
@@ -17,11 +17,11 @@
   explicit FocusElementAction(const ActionProto& proto);
   ~FocusElementAction() override;
 
-  // Overrides Action:
-  void ProcessAction(ActionDelegate* delegate,
-                     ProcessActionCallback callback) override;
-
  private:
+  // Overrides Action:
+  void InternalProcessAction(ActionDelegate* delegate,
+                             ProcessActionCallback callback) override;
+
   void OnWaitForElement(ActionDelegate* delegate,
                         ProcessActionCallback callback,
                         bool element_found);
diff --git a/components/autofill_assistant/browser/actions/get_payment_information_action.cc b/components/autofill_assistant/browser/actions/get_payment_information_action.cc
index 5caa509..9795b15 100644
--- a/components/autofill_assistant/browser/actions/get_payment_information_action.cc
+++ b/components/autofill_assistant/browser/actions/get_payment_information_action.cc
@@ -22,10 +22,9 @@
 
 GetPaymentInformationAction::~GetPaymentInformationAction() {}
 
-void GetPaymentInformationAction::ProcessAction(
+void GetPaymentInformationAction::InternalProcessAction(
     ActionDelegate* delegate,
     ProcessActionCallback callback) {
-  processed_action_proto_ = std::make_unique<ProcessedActionProto>();
   const GetPaymentInformationProto& get_payment_information =
       proto_.get_payment_information();
 
@@ -43,7 +42,8 @@
       std::move(payment_options),
       base::BindOnce(&GetPaymentInformationAction::OnGetPaymentInformation,
                      weak_ptr_factory_.GetWeakPtr(), delegate,
-                     std::move(get_payment_information), std::move(callback)));
+                     std::move(get_payment_information), std::move(callback)),
+      get_payment_information.prompt());
 }
 
 void GetPaymentInformationAction::OnGetPaymentInformation(
diff --git a/components/autofill_assistant/browser/actions/get_payment_information_action.h b/components/autofill_assistant/browser/actions/get_payment_information_action.h
index 053d0cb1..cce34f8 100644
--- a/components/autofill_assistant/browser/actions/get_payment_information_action.h
+++ b/components/autofill_assistant/browser/actions/get_payment_information_action.h
@@ -5,13 +5,13 @@
 #ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ACTIONS_GET_PAYMENT_INFORMATION_ACTION_H_
 #define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ACTIONS_GET_PAYMENT_INFORMATION_ACTION_H_
 
-#include "components/autofill_assistant/browser/actions/action.h"
-
+#include <memory>
 #include <string>
 #include <vector>
 
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "components/autofill_assistant/browser/actions/action.h"
 #include "components/autofill_assistant/browser/payment_information.h"
 
 namespace autofill_assistant {
@@ -22,10 +22,10 @@
   explicit GetPaymentInformationAction(const ActionProto& proto);
   ~GetPaymentInformationAction() override;
 
-  void ProcessAction(ActionDelegate* delegate,
-                     ProcessActionCallback callback) override;
-
  private:
+  void InternalProcessAction(ActionDelegate* delegate,
+                             ProcessActionCallback callback) override;
+
   void OnGetPaymentInformation(
       ActionDelegate* delegate,
       const GetPaymentInformationProto& get_payment_information,
diff --git a/components/autofill_assistant/browser/actions/highlight_element_action.cc b/components/autofill_assistant/browser/actions/highlight_element_action.cc
index f19268e2..1503c4c 100644
--- a/components/autofill_assistant/browser/actions/highlight_element_action.cc
+++ b/components/autofill_assistant/browser/actions/highlight_element_action.cc
@@ -19,9 +19,9 @@
 
 HighlightElementAction::~HighlightElementAction() {}
 
-void HighlightElementAction::ProcessAction(ActionDelegate* delegate,
-                                           ProcessActionCallback callback) {
-  processed_action_proto_ = std::make_unique<ProcessedActionProto>();
+void HighlightElementAction::InternalProcessAction(
+    ActionDelegate* delegate,
+    ProcessActionCallback callback) {
   DCHECK_GT(proto_.highlight_element().element().selectors_size(), 0);
   delegate->WaitForElement(
       ExtractSelectors(proto_.highlight_element().element().selectors()),
diff --git a/components/autofill_assistant/browser/actions/highlight_element_action.h b/components/autofill_assistant/browser/actions/highlight_element_action.h
index c55dd34..d83bb663 100644
--- a/components/autofill_assistant/browser/actions/highlight_element_action.h
+++ b/components/autofill_assistant/browser/actions/highlight_element_action.h
@@ -5,13 +5,12 @@
 #ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ACTIONS_HIGHLIGHT_ELEMENT_ACTION_H_
 #define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ACTIONS_HIGHLIGHT_ELEMENT_ACTION_H_
 
-#include "components/autofill_assistant/browser/actions/action.h"
-
 #include <string>
 #include <vector>
 
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "components/autofill_assistant/browser/actions/action.h"
 
 namespace autofill_assistant {
 // An action to highlight an element on Web.
@@ -22,11 +21,11 @@
   explicit HighlightElementAction(const ActionProto& proto);
   ~HighlightElementAction() override;
 
-  // Overrides Action:
-  void ProcessAction(ActionDelegate* delegate,
-                     ProcessActionCallback callback) override;
-
  private:
+  // Overrides Action:
+  void InternalProcessAction(ActionDelegate* delegate,
+                             ProcessActionCallback callback) override;
+
   void OnWaitForElement(ActionDelegate* delegate,
                         ProcessActionCallback callback,
                         bool element_found);
diff --git a/components/autofill_assistant/browser/actions/mock_action_delegate.h b/components/autofill_assistant/browser/actions/mock_action_delegate.h
index 9dd3c0dd..1153400 100644
--- a/components/autofill_assistant/browser/actions/mock_action_delegate.h
+++ b/components/autofill_assistant/browser/actions/mock_action_delegate.h
@@ -87,11 +87,12 @@
                void(const std::vector<std::string>& selectors,
                     base::OnceCallback<void(bool)> callback));
 
-  MOCK_METHOD2(
+  MOCK_METHOD3(
       GetPaymentInformation,
       void(payments::mojom::PaymentOptionsPtr payment_options,
            base::OnceCallback<void(std::unique_ptr<PaymentInformation>)>
-               callback));
+               callback,
+           const std::string& title));
 
   void SetFieldValue(const std::vector<std::string>& selectors,
                      const std::string& value,
@@ -119,6 +120,8 @@
   MOCK_METHOD1(ShowDetails, void(const DetailsProto& details));
   MOCK_METHOD2(ShowProgressBar, void(int progress, const std::string& message));
   MOCK_METHOD0(HideProgressBar, void());
+  MOCK_METHOD0(ShowOverlay, void());
+  MOCK_METHOD0(HideOverlay, void());
 };
 
 }  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/actions/navigate_action.cc b/components/autofill_assistant/browser/actions/navigate_action.cc
index 78b677be..731f3e80 100644
--- a/components/autofill_assistant/browser/actions/navigate_action.cc
+++ b/components/autofill_assistant/browser/actions/navigate_action.cc
@@ -19,11 +19,10 @@
 
 NavigateAction::~NavigateAction() {}
 
-void NavigateAction::ProcessAction(ActionDelegate* delegate,
-                                   ProcessActionCallback callback) {
+void NavigateAction::InternalProcessAction(ActionDelegate* delegate,
+                                           ProcessActionCallback callback) {
   GURL url(proto_.navigate().url());
   delegate->LoadURL(url);
-  processed_action_proto_ = std::make_unique<ProcessedActionProto>();
   UpdateProcessedAction(ACTION_APPLIED);
   std::move(callback).Run(std::move(processed_action_proto_));
 }
diff --git a/components/autofill_assistant/browser/actions/navigate_action.h b/components/autofill_assistant/browser/actions/navigate_action.h
index 72114b8..6dceb591 100644
--- a/components/autofill_assistant/browser/actions/navigate_action.h
+++ b/components/autofill_assistant/browser/actions/navigate_action.h
@@ -17,11 +17,11 @@
   explicit NavigateAction(const ActionProto& proto);
   ~NavigateAction() override;
 
-  // Overrides Action:
-  void ProcessAction(ActionDelegate* delegate,
-                     ProcessActionCallback callback) override;
-
  private:
+  // Overrides Action:
+  void InternalProcessAction(ActionDelegate* delegate,
+                             ProcessActionCallback callback) override;
+
   DISALLOW_COPY_AND_ASSIGN(NavigateAction);
 };
 
diff --git a/components/autofill_assistant/browser/actions/reset_action.cc b/components/autofill_assistant/browser/actions/reset_action.cc
index 2a83e54..c8705ec 100644
--- a/components/autofill_assistant/browser/actions/reset_action.cc
+++ b/components/autofill_assistant/browser/actions/reset_action.cc
@@ -18,10 +18,9 @@
 
 ResetAction::~ResetAction() {}
 
-void ResetAction::ProcessAction(ActionDelegate* delegate,
-                                ProcessActionCallback callback) {
+void ResetAction::InternalProcessAction(ActionDelegate* delegate,
+                                        ProcessActionCallback callback) {
   delegate->Restart();
-  processed_action_proto_ = std::make_unique<ProcessedActionProto>();
   UpdateProcessedAction(ACTION_APPLIED);
   std::move(callback).Run(std::move(processed_action_proto_));
 }
diff --git a/components/autofill_assistant/browser/actions/reset_action.h b/components/autofill_assistant/browser/actions/reset_action.h
index 564c2ad..ee26c94c 100644
--- a/components/autofill_assistant/browser/actions/reset_action.h
+++ b/components/autofill_assistant/browser/actions/reset_action.h
@@ -17,11 +17,11 @@
   explicit ResetAction(const ActionProto& proto);
   ~ResetAction() override;
 
-  // Overrides Action:
-  void ProcessAction(ActionDelegate* delegate,
-                     ProcessActionCallback callback) override;
-
  private:
+  // Overrides Action:
+  void InternalProcessAction(ActionDelegate* delegate,
+                             ProcessActionCallback callback) override;
+
   DISALLOW_COPY_AND_ASSIGN(ResetAction);
 };
 
diff --git a/components/autofill_assistant/browser/actions/select_option_action.cc b/components/autofill_assistant/browser/actions/select_option_action.cc
index b14eb8f8..224f4211a 100644
--- a/components/autofill_assistant/browser/actions/select_option_action.cc
+++ b/components/autofill_assistant/browser/actions/select_option_action.cc
@@ -19,9 +19,8 @@
 
 SelectOptionAction::~SelectOptionAction() {}
 
-void SelectOptionAction::ProcessAction(ActionDelegate* delegate,
-                                       ProcessActionCallback callback) {
-  processed_action_proto_ = std::make_unique<ProcessedActionProto>();
+void SelectOptionAction::InternalProcessAction(ActionDelegate* delegate,
+                                               ProcessActionCallback callback) {
   const SelectOptionProto& select_option = proto_.select_option();
 
   // A non prefilled |select_option| is not supported.
diff --git a/components/autofill_assistant/browser/actions/select_option_action.h b/components/autofill_assistant/browser/actions/select_option_action.h
index 49f5e8c..1d68e73 100644
--- a/components/autofill_assistant/browser/actions/select_option_action.h
+++ b/components/autofill_assistant/browser/actions/select_option_action.h
@@ -5,13 +5,12 @@
 #ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ACTIONS_SELECT_OPTION_ACTION_H_
 #define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ACTIONS_SELECT_OPTION_ACTION_H_
 
-#include "components/autofill_assistant/browser/actions/action.h"
-
 #include <string>
 #include <vector>
 
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "components/autofill_assistant/browser/actions/action.h"
 
 namespace autofill_assistant {
 // An action to select an option on a given element on Web.
@@ -20,11 +19,11 @@
   explicit SelectOptionAction(const ActionProto& proto);
   ~SelectOptionAction() override;
 
-  // Overrides Action:
-  void ProcessAction(ActionDelegate* delegate,
-                     ProcessActionCallback callback) override;
-
  private:
+  // Overrides Action:
+  void InternalProcessAction(ActionDelegate* delegate,
+                             ProcessActionCallback callback) override;
+
   void OnWaitForElement(ActionDelegate* delegate,
                         ProcessActionCallback callback,
                         bool element_found);
diff --git a/components/autofill_assistant/browser/actions/set_form_field_value_action.cc b/components/autofill_assistant/browser/actions/set_form_field_value_action.cc
index ae6726f..2baf391 100644
--- a/components/autofill_assistant/browser/actions/set_form_field_value_action.cc
+++ b/components/autofill_assistant/browser/actions/set_form_field_value_action.cc
@@ -22,9 +22,9 @@
 
 SetFormFieldValueAction::~SetFormFieldValueAction() {}
 
-void SetFormFieldValueAction::ProcessAction(ActionDelegate* delegate,
-                                            ProcessActionCallback callback) {
-  processed_action_proto_ = std::make_unique<ProcessedActionProto>();
+void SetFormFieldValueAction::InternalProcessAction(
+    ActionDelegate* delegate,
+    ProcessActionCallback callback) {
   delegate->WaitForElement(
       ExtractSelectors(proto_.set_form_value().element().selectors()),
       base::BindOnce(&SetFormFieldValueAction::OnWaitForElement,
diff --git a/components/autofill_assistant/browser/actions/set_form_field_value_action.h b/components/autofill_assistant/browser/actions/set_form_field_value_action.h
index 562365988..be0aec9f 100644
--- a/components/autofill_assistant/browser/actions/set_form_field_value_action.h
+++ b/components/autofill_assistant/browser/actions/set_form_field_value_action.h
@@ -5,13 +5,12 @@
 #ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ACTIONS_SET_FORM_FIELD_VALUE_ACTION_H_
 #define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_ACTIONS_SET_FORM_FIELD_VALUE_ACTION_H_
 
-#include "components/autofill_assistant/browser/actions/action.h"
-
 #include <string>
 #include <vector>
 
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "components/autofill_assistant/browser/actions/action.h"
 
 namespace autofill_assistant {
 // An action to set the value of a form input element.
@@ -20,11 +19,11 @@
   explicit SetFormFieldValueAction(const ActionProto& proto);
   ~SetFormFieldValueAction() override;
 
-  // Overrides Action:
-  void ProcessAction(ActionDelegate* delegate,
-                     ProcessActionCallback callback) override;
-
  private:
+  // Overrides Action:
+  void InternalProcessAction(ActionDelegate* delegate,
+                             ProcessActionCallback callback) override;
+
   void OnWaitForElement(ActionDelegate* delegate,
                         ProcessActionCallback callback,
                         bool element_found);
diff --git a/components/autofill_assistant/browser/actions/show_details_action.cc b/components/autofill_assistant/browser/actions/show_details_action.cc
index 6dbc6ec1..783ab42 100644
--- a/components/autofill_assistant/browser/actions/show_details_action.cc
+++ b/components/autofill_assistant/browser/actions/show_details_action.cc
@@ -4,6 +4,8 @@
 
 #include "components/autofill_assistant/browser/actions/show_details_action.h"
 
+#include <utility>
+
 #include "base/callback.h"
 #include "components/autofill_assistant/browser/actions/action_delegate.h"
 
@@ -15,15 +17,14 @@
 
 ShowDetailsAction::~ShowDetailsAction() {}
 
-void ShowDetailsAction::ProcessAction(ActionDelegate* delegate,
-                                      ProcessActionCallback callback) {
+void ShowDetailsAction::InternalProcessAction(ActionDelegate* delegate,
+                                              ProcessActionCallback callback) {
   if (!proto_.show_details().has_details()) {
     delegate->HideDetails();
   } else {
     delegate->ShowDetails(proto_.show_details().details());
   }
 
-  processed_action_proto_ = std::make_unique<ProcessedActionProto>();
   UpdateProcessedAction(ACTION_APPLIED);
   std::move(callback).Run(std::move(processed_action_proto_));
 }
diff --git a/components/autofill_assistant/browser/actions/show_details_action.h b/components/autofill_assistant/browser/actions/show_details_action.h
index 0446327..1b66148b 100644
--- a/components/autofill_assistant/browser/actions/show_details_action.h
+++ b/components/autofill_assistant/browser/actions/show_details_action.h
@@ -15,11 +15,11 @@
   explicit ShowDetailsAction(const ActionProto& proto);
   ~ShowDetailsAction() override;
 
-  // Overrides Action:
-  void ProcessAction(ActionDelegate* delegate,
-                     ProcessActionCallback callback) override;
-
  private:
+  // Overrides Action:
+  void InternalProcessAction(ActionDelegate* delegate,
+                             ProcessActionCallback callback) override;
+
   DISALLOW_COPY_AND_ASSIGN(ShowDetailsAction);
 };
 
diff --git a/components/autofill_assistant/browser/actions/show_progress_bar_action.cc b/components/autofill_assistant/browser/actions/show_progress_bar_action.cc
index 06ffc46..0edef98 100644
--- a/components/autofill_assistant/browser/actions/show_progress_bar_action.cc
+++ b/components/autofill_assistant/browser/actions/show_progress_bar_action.cc
@@ -4,6 +4,10 @@
 
 #include "components/autofill_assistant/browser/actions/show_progress_bar_action.h"
 
+#include <algorithm>
+#include <memory>
+#include <utility>
+
 #include "base/bind.h"
 #include "base/callback.h"
 #include "components/autofill_assistant/browser/actions/action_delegate.h"
@@ -17,8 +21,9 @@
 
 ShowProgressBarAction::~ShowProgressBarAction() {}
 
-void ShowProgressBarAction::ProcessAction(ActionDelegate* delegate,
-                                          ProcessActionCallback callback) {
+void ShowProgressBarAction::InternalProcessAction(
+    ActionDelegate* delegate,
+    ProcessActionCallback callback) {
   int progress =
       std::min(100, std::max(0, proto_.show_progress_bar().progress()));
   if (proto_.show_progress_bar().done() || progress == 100) {
@@ -27,7 +32,6 @@
     delegate->ShowProgressBar(progress, proto_.show_progress_bar().message());
   }
 
-  processed_action_proto_ = std::make_unique<ProcessedActionProto>();
   UpdateProcessedAction(ACTION_APPLIED);
   std::move(callback).Run(std::move(processed_action_proto_));
 }
diff --git a/components/autofill_assistant/browser/actions/show_progress_bar_action.h b/components/autofill_assistant/browser/actions/show_progress_bar_action.h
index 4655a87..6010ddec 100644
--- a/components/autofill_assistant/browser/actions/show_progress_bar_action.h
+++ b/components/autofill_assistant/browser/actions/show_progress_bar_action.h
@@ -17,11 +17,11 @@
   explicit ShowProgressBarAction(const ActionProto& proto);
   ~ShowProgressBarAction() override;
 
-  // Overrides Action:
-  void ProcessAction(ActionDelegate* delegate,
-                     ProcessActionCallback callback) override;
-
  private:
+  // Overrides Action:
+  void InternalProcessAction(ActionDelegate* delegate,
+                             ProcessActionCallback callback) override;
+
   DISALLOW_COPY_AND_ASSIGN(ShowProgressBarAction);
 };
 
diff --git a/components/autofill_assistant/browser/actions/stop_action.cc b/components/autofill_assistant/browser/actions/stop_action.cc
index 1a670eb..4ff6cd5 100644
--- a/components/autofill_assistant/browser/actions/stop_action.cc
+++ b/components/autofill_assistant/browser/actions/stop_action.cc
@@ -18,10 +18,9 @@
 
 StopAction::~StopAction() {}
 
-void StopAction::ProcessAction(ActionDelegate* delegate,
-                               ProcessActionCallback callback) {
+void StopAction::InternalProcessAction(ActionDelegate* delegate,
+                                       ProcessActionCallback callback) {
   delegate->Shutdown();
-  processed_action_proto_ = std::make_unique<ProcessedActionProto>();
   UpdateProcessedAction(ACTION_APPLIED);
   std::move(callback).Run(std::move(processed_action_proto_));
 }
diff --git a/components/autofill_assistant/browser/actions/stop_action.h b/components/autofill_assistant/browser/actions/stop_action.h
index f51bce70..6de488f 100644
--- a/components/autofill_assistant/browser/actions/stop_action.h
+++ b/components/autofill_assistant/browser/actions/stop_action.h
@@ -17,11 +17,11 @@
   explicit StopAction(const ActionProto& proto);
   ~StopAction() override;
 
-  // Overrides Action:
-  void ProcessAction(ActionDelegate* delegate,
-                     ProcessActionCallback callback) override;
-
  private:
+  // Overrides Action:
+  void InternalProcessAction(ActionDelegate* delegate,
+                             ProcessActionCallback callback) override;
+
   DISALLOW_COPY_AND_ASSIGN(StopAction);
 };
 
diff --git a/components/autofill_assistant/browser/actions/tell_action.cc b/components/autofill_assistant/browser/actions/tell_action.cc
index fd97359f..11c9fc1 100644
--- a/components/autofill_assistant/browser/actions/tell_action.cc
+++ b/components/autofill_assistant/browser/actions/tell_action.cc
@@ -17,9 +17,8 @@
 
 TellAction::~TellAction() {}
 
-void TellAction::ProcessAction(ActionDelegate* delegate,
-                               ProcessActionCallback callback) {
-  processed_action_proto_ = std::make_unique<ProcessedActionProto>();
+void TellAction::InternalProcessAction(ActionDelegate* delegate,
+                                       ProcessActionCallback callback) {
   // tell.message in the proto is localized.
   delegate->ShowStatusMessage(proto_.tell().message());
   UpdateProcessedAction(ACTION_APPLIED);
diff --git a/components/autofill_assistant/browser/actions/tell_action.h b/components/autofill_assistant/browser/actions/tell_action.h
index a1eab82..8131db42 100644
--- a/components/autofill_assistant/browser/actions/tell_action.h
+++ b/components/autofill_assistant/browser/actions/tell_action.h
@@ -17,11 +17,11 @@
   explicit TellAction(const ActionProto& proto);
   ~TellAction() override;
 
-  // Overrides Action:
-  void ProcessAction(ActionDelegate* delegate,
-                     ProcessActionCallback callback) override;
-
  private:
+  // Overrides Action:
+  void InternalProcessAction(ActionDelegate* delegate,
+                             ProcessActionCallback callback) override;
+
   DISALLOW_COPY_AND_ASSIGN(TellAction);
 };
 
diff --git a/components/autofill_assistant/browser/actions/unsupported_action.cc b/components/autofill_assistant/browser/actions/unsupported_action.cc
index 4f806e1..5105db0 100644
--- a/components/autofill_assistant/browser/actions/unsupported_action.cc
+++ b/components/autofill_assistant/browser/actions/unsupported_action.cc
@@ -4,7 +4,7 @@
 
 #include "components/autofill_assistant/browser/actions/unsupported_action.h"
 
-#include <memory>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/callback.h"
@@ -16,9 +16,8 @@
 
 UnsupportedAction::~UnsupportedAction() {}
 
-void UnsupportedAction::ProcessAction(ActionDelegate* delegate,
-                                      ProcessActionCallback callback) {
-  processed_action_proto_ = std::make_unique<ProcessedActionProto>();
+void UnsupportedAction::InternalProcessAction(ActionDelegate* delegate,
+                                              ProcessActionCallback callback) {
   // TODO(crbug.com/806868): Add 'unsupported action' status to the protocol.
   UpdateProcessedAction(UNKNOWN_ACTION_STATUS);
   std::move(callback).Run(std::move(processed_action_proto_));
diff --git a/components/autofill_assistant/browser/actions/unsupported_action.h b/components/autofill_assistant/browser/actions/unsupported_action.h
index 956b648..a372e5b7 100644
--- a/components/autofill_assistant/browser/actions/unsupported_action.h
+++ b/components/autofill_assistant/browser/actions/unsupported_action.h
@@ -15,11 +15,11 @@
   explicit UnsupportedAction(const ActionProto& proto);
   ~UnsupportedAction() override;
 
-  // Overrides Action:
-  void ProcessAction(ActionDelegate* delegate,
-                     ProcessActionCallback callback) override;
-
  private:
+  // Overrides Action:
+  void InternalProcessAction(ActionDelegate* delegate,
+                             ProcessActionCallback callback) override;
+
   void OnUnsupported(ProcessActionCallback callback, bool status);
 
   DISALLOW_COPY_AND_ASSIGN(UnsupportedAction);
diff --git a/components/autofill_assistant/browser/actions/upload_dom_action.cc b/components/autofill_assistant/browser/actions/upload_dom_action.cc
index 322f966..a949380 100644
--- a/components/autofill_assistant/browser/actions/upload_dom_action.cc
+++ b/components/autofill_assistant/browser/actions/upload_dom_action.cc
@@ -19,10 +19,8 @@
 
 UploadDomAction::~UploadDomAction() {}
 
-void UploadDomAction::ProcessAction(ActionDelegate* delegate,
-                                    ProcessActionCallback callback) {
-  processed_action_proto_ = std::make_unique<ProcessedActionProto>();
-
+void UploadDomAction::InternalProcessAction(ActionDelegate* delegate,
+                                            ProcessActionCallback callback) {
   DCHECK_GT(proto_.upload_dom().tree_root().selectors_size(), 0);
   delegate->WaitForElement(
       ExtractSelectors(proto_.upload_dom().tree_root().selectors()),
diff --git a/components/autofill_assistant/browser/actions/upload_dom_action.h b/components/autofill_assistant/browser/actions/upload_dom_action.h
index 3c4e1bdc..630db32 100644
--- a/components/autofill_assistant/browser/actions/upload_dom_action.h
+++ b/components/autofill_assistant/browser/actions/upload_dom_action.h
@@ -18,11 +18,11 @@
   explicit UploadDomAction(const ActionProto& proto);
   ~UploadDomAction() override;
 
-  // Overrides Action:
-  void ProcessAction(ActionDelegate* delegate,
-                     ProcessActionCallback callback) override;
-
  private:
+  // Overrides Action:
+  void InternalProcessAction(ActionDelegate* delegate,
+                             ProcessActionCallback callback) override;
+
   void OnWaitForElement(ActionDelegate* delegate,
                         ProcessActionCallback callback,
                         bool element_found);
diff --git a/components/autofill_assistant/browser/actions/wait_for_dom_action.cc b/components/autofill_assistant/browser/actions/wait_for_dom_action.cc
index b4c6cc0..b5162a03 100644
--- a/components/autofill_assistant/browser/actions/wait_for_dom_action.cc
+++ b/components/autofill_assistant/browser/actions/wait_for_dom_action.cc
@@ -25,8 +25,8 @@
 
 WaitForDomAction::~WaitForDomAction() {}
 
-void WaitForDomAction::ProcessAction(ActionDelegate* delegate,
-                                     ProcessActionCallback callback) {
+void WaitForDomAction::InternalProcessAction(ActionDelegate* delegate,
+                                             ProcessActionCallback callback) {
   DCHECK_GT(proto_.wait_for_dom().selectors_size(), 0);
   batch_element_checker_ = delegate->CreateBatchElementChecker();
   batch_element_checker_->AddElementExistenceCheck(
@@ -47,7 +47,6 @@
 }
 
 void WaitForDomAction::OnCheckDone(ProcessActionCallback callback) {
-  processed_action_proto_ = std::make_unique<ProcessedActionProto>();
   UpdateProcessedAction(batch_element_checker_->all_found()
                             ? ACTION_APPLIED
                             : ELEMENT_RESOLUTION_FAILED);
diff --git a/components/autofill_assistant/browser/actions/wait_for_dom_action.h b/components/autofill_assistant/browser/actions/wait_for_dom_action.h
index 3d6c4c3..7a5dd0e 100644
--- a/components/autofill_assistant/browser/actions/wait_for_dom_action.h
+++ b/components/autofill_assistant/browser/actions/wait_for_dom_action.h
@@ -21,11 +21,11 @@
   explicit WaitForDomAction(const ActionProto& proto);
   ~WaitForDomAction() override;
 
-  // Overrides Action:
-  void ProcessAction(ActionDelegate* delegate,
-                     ProcessActionCallback callback) override;
-
  private:
+  // Overrides Action:
+  void InternalProcessAction(ActionDelegate* delegate,
+                             ProcessActionCallback callback) override;
+
   void OnCheckDone(ProcessActionCallback callback);
 
   std::unique_ptr<BatchElementChecker> batch_element_checker_;
diff --git a/components/autofill_assistant/browser/client.h b/components/autofill_assistant/browser/client.h
index a677bc68..e4b5b1a 100644
--- a/components/autofill_assistant/browser/client.h
+++ b/components/autofill_assistant/browser/client.h
@@ -7,16 +7,13 @@
 
 #include <string>
 
-namespace identity {
-class IdentityManager;
-}  // namespace identity
-
 namespace autofill {
 class PersonalDataManager;
 }  // namespace autofill
 
 namespace autofill_assistant {
 class UiController;
+class AccessTokenFetcher;
 
 // A client interface that needs to be supplied to the controller by the
 // embedder.
@@ -27,9 +24,8 @@
   // Returns the API key to be used for requests to the backend.
   virtual std::string GetApiKey() = 0;
 
-  // Gets the identity manager to use to make authenticated calls or nullptr if
-  // no identity is available.
-  virtual identity::IdentityManager* GetIdentityManagerForPrimaryAccount() = 0;
+  // Returns the AccessTokenFetcher to use to get oauth credentials.
+  virtual AccessTokenFetcher* GetAccessTokenFetcher() = 0;
 
   // Returns the current active personal data manager.
   virtual autofill::PersonalDataManager* GetPersonalDataManager() = 0;
diff --git a/components/autofill_assistant/browser/controller.cc b/components/autofill_assistant/browser/controller.cc
index 8520179..2d10d5f7 100644
--- a/components/autofill_assistant/browser/controller.cc
+++ b/components/autofill_assistant/browser/controller.cc
@@ -42,16 +42,17 @@
 void Controller::CreateAndStartForWebContents(
     content::WebContents* web_contents,
     std::unique_ptr<Client> client,
-    std::unique_ptr<std::map<std::string, std::string>> parameters) {
+    std::unique_ptr<std::map<std::string, std::string>> parameters,
+    const GURL& initialUrl) {
   // Get the key early since |client| will be invalidated when moved below.
   GURL server_url(client->GetServerUrl());
   DCHECK(server_url.is_valid());
   std::unique_ptr<Service> service = std::make_unique<Service>(
       client->GetApiKey(), server_url, web_contents->GetBrowserContext(),
-      client->GetIdentityManagerForPrimaryAccount());
+      client->GetAccessTokenFetcher());
   new Controller(web_contents, std::move(client),
                  WebController::CreateForWebContents(web_contents),
-                 std::move(service), std::move(parameters));
+                 std::move(service), std::move(parameters), initialUrl);
 }
 
 Service* Controller::GetService() {
@@ -87,7 +88,8 @@
     std::unique_ptr<Client> client,
     std::unique_ptr<WebController> web_controller,
     std::unique_ptr<Service> service,
-    std::unique_ptr<std::map<std::string, std::string>> parameters)
+    std::unique_ptr<std::map<std::string, std::string>> parameters,
+    const GURL& initialUrl)
     : content::WebContentsObserver(web_contents),
       client_(std::move(client)),
       web_controller_(std::move(web_controller)),
@@ -110,9 +112,8 @@
   }
 
   GetUiController()->SetUiDelegate(this);
-  if (!web_contents->IsLoading()) {
-    GetOrCheckScripts(web_contents->GetLastCommittedURL());
-  }
+  if (initialUrl.is_valid())
+    GetOrCheckScripts(initialUrl);
 
   if (allow_autostart_) {
     auto iter = parameters_->find(kCallerScriptParameterName);
diff --git a/components/autofill_assistant/browser/controller.h b/components/autofill_assistant/browser/controller.h
index 00550330..30bcffd 100644
--- a/components/autofill_assistant/browser/controller.h
+++ b/components/autofill_assistant/browser/controller.h
@@ -42,7 +42,8 @@
   static void CreateAndStartForWebContents(
       content::WebContents* web_contents,
       std::unique_ptr<Client> client,
-      std::unique_ptr<std::map<std::string, std::string>> parameters);
+      std::unique_ptr<std::map<std::string, std::string>> parameters,
+      const GURL& initialUrl);
 
   // Overrides ScriptExecutorDelegate:
   Service* GetService() override;
@@ -60,7 +61,8 @@
              std::unique_ptr<Client> client,
              std::unique_ptr<WebController> web_controller,
              std::unique_ptr<Service> service,
-             std::unique_ptr<std::map<std::string, std::string>> parameters);
+             std::unique_ptr<std::map<std::string, std::string>> parameters,
+             const GURL& initialUrl);
   ~Controller() override;
 
   void GetOrCheckScripts(const GURL& url);
diff --git a/components/autofill_assistant/browser/controller_unittest.cc b/components/autofill_assistant/browser/controller_unittest.cc
index 641ba236a..cc9a8df3 100644
--- a/components/autofill_assistant/browser/controller_unittest.cc
+++ b/components/autofill_assistant/browser/controller_unittest.cc
@@ -41,9 +41,7 @@
 
   // Implements Client
   std::string GetApiKey() override { return ""; }
-  identity::IdentityManager* GetIdentityManagerForPrimaryAccount() override {
-    return nullptr;
-  }
+  AccessTokenFetcher* GetAccessTokenFetcher() override { return nullptr; }
   autofill::PersonalDataManager* GetPersonalDataManager() override {
     return nullptr;
   }
@@ -61,6 +59,22 @@
   ControllerTest() {}
   ~ControllerTest() override {}
 
+  static Controller* CreateController(
+      content::WebContents* web_contents,
+      std::unique_ptr<Client> client,
+      std::unique_ptr<WebController> web_controller,
+      std::unique_ptr<Service> service,
+      std::unique_ptr<std::map<std::string, std::string>> parameters,
+      const GURL& initialUrl) {
+    return new Controller(web_contents, std::move(client),
+                          std::move(web_controller), std::move(service),
+                          std::move(parameters), initialUrl);
+  }
+
+  static void DestroyController(Controller* controller) {
+    controller->OnDestroy();
+  }
+
   void SetUp() override {
     content::RenderViewHostTestHarness::SetUp();
 
@@ -72,10 +86,12 @@
     mock_service_ = service.get();
     auto parameters = std::make_unique<std::map<std::string, std::string>>();
     parameters->insert(std::make_pair("a", "b"));
+    GURL initialUrl("");
 
     controller_ = new Controller(
         web_contents(), std::make_unique<FakeClient>(std::move(ui_controller)),
-        std::move(web_controller), std::move(service), std::move(parameters));
+        std::move(web_controller), std::move(service), std::move(parameters),
+        initialUrl);
 
     // Fetching scripts succeeds for all URLs, but return nothing.
     ON_CALL(*mock_service_, OnGetScriptsForUrl(_, _, _))
@@ -92,7 +108,7 @@
   }
 
   void TearDown() override {
-    controller_->OnDestroy();  // deletes the controller and mocks
+    DestroyController(controller_);  // deletes the controller and mocks
     content::RenderViewHostTestHarness::TearDown();
   }
 
@@ -348,4 +364,20 @@
   SimulateProgressChanged(0.4);
 }
 
+TEST_F(ControllerTest, InitialUrlLoads) {
+  GURL initialUrl("http://a.example.com/path");
+  auto service = std::make_unique<NiceMock<MockService>>();
+
+  EXPECT_CALL(*service.get(), OnGetScriptsForUrl(Eq(initialUrl), _, _))
+      .WillOnce(RunOnceCallback<2>(true, ""));
+
+  Controller* controller = ControllerTest::CreateController(
+      web_contents(),
+      std::make_unique<FakeClient>(
+          std::make_unique<NiceMock<MockUiController>>()),
+      std::make_unique<NiceMock<MockWebController>>(), std::move(service),
+      std::make_unique<std::map<std::string, std::string>>(), initialUrl);
+  ControllerTest::DestroyController(controller);
+}
+
 }  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/mock_ui_controller.h b/components/autofill_assistant/browser/mock_ui_controller.h
index e7000b68..23899ef 100644
--- a/components/autofill_assistant/browser/mock_ui_controller.h
+++ b/components/autofill_assistant/browser/mock_ui_controller.h
@@ -40,11 +40,12 @@
   }
   MOCK_METHOD1(OnChooseCard,
                void(base::OnceCallback<void(const std::string&)>& callback));
-  MOCK_METHOD2(
+  MOCK_METHOD3(
       GetPaymentInformation,
       void(payments::mojom::PaymentOptionsPtr payment_options,
            base::OnceCallback<void(std::unique_ptr<PaymentInformation>)>
-               callback));
+               callback,
+           const std::string& title));
   MOCK_METHOD0(HideDetails, void());
   MOCK_METHOD1(ShowDetails, void(const DetailsProto& details));
   MOCK_METHOD2(ShowProgressBar, void(int progress, const std::string& message));
diff --git a/components/autofill_assistant/browser/mock_web_controller.h b/components/autofill_assistant/browser/mock_web_controller.h
index 3a20940..660c7d21d 100644
--- a/components/autofill_assistant/browser/mock_web_controller.h
+++ b/components/autofill_assistant/browser/mock_web_controller.h
@@ -33,6 +33,14 @@
                void(const std::vector<std::string>& selectors,
                     base::OnceCallback<void(bool)>& callback));
 
+  void FocusElement(const std::vector<std::string>& selectors,
+                    base::OnceCallback<void(bool)> callback) override {
+    OnFocusElement(selectors, callback);
+  }
+  MOCK_METHOD2(OnFocusElement,
+               void(const std::vector<std::string>& selectors,
+                    base::OnceCallback<void(bool)>& callback));
+
   void ElementExists(const std::vector<std::string>& selectors,
                      base::OnceCallback<void(bool)> callback) override {
     OnElementExists(selectors, callback);
diff --git a/components/autofill_assistant/browser/script_executor.cc b/components/autofill_assistant/browser/script_executor.cc
index eac9609..3558f04 100644
--- a/components/autofill_assistant/browser/script_executor.cc
+++ b/components/autofill_assistant/browser/script_executor.cc
@@ -87,9 +87,10 @@
 
 void ScriptExecutor::GetPaymentInformation(
     payments::mojom::PaymentOptionsPtr payment_options,
-    base::OnceCallback<void(std::unique_ptr<PaymentInformation>)> callback) {
+    base::OnceCallback<void(std::unique_ptr<PaymentInformation>)> callback,
+    const std::string& title) {
   delegate_->GetUiController()->GetPaymentInformation(
-      std::move(payment_options), std::move(callback));
+      std::move(payment_options), std::move(callback), title);
 }
 
 void ScriptExecutor::ChooseAddress(
@@ -143,6 +144,14 @@
   delegate_->GetUiController()->HideProgressBar();
 }
 
+void ScriptExecutor::ShowOverlay() {
+  delegate_->GetUiController()->ShowOverlay();
+}
+
+void ScriptExecutor::HideOverlay() {
+  delegate_->GetUiController()->HideOverlay();
+}
+
 void ScriptExecutor::SetFieldValue(const std::vector<std::string>& selectors,
                                    const std::string& value,
                                    bool simulate_key_presses,
diff --git a/components/autofill_assistant/browser/script_executor.h b/components/autofill_assistant/browser/script_executor.h
index 1c7703c..5efa844 100644
--- a/components/autofill_assistant/browser/script_executor.h
+++ b/components/autofill_assistant/browser/script_executor.h
@@ -71,8 +71,8 @@
                     base::OnceCallback<void(bool)> callback) override;
   void GetPaymentInformation(
       payments::mojom::PaymentOptionsPtr payment_options,
-      base::OnceCallback<void(std::unique_ptr<PaymentInformation>)> callback)
-      override;
+      base::OnceCallback<void(std::unique_ptr<PaymentInformation>)> callback,
+      const std::string& title) override;
   void ChooseAddress(
       base::OnceCallback<void(const std::string&)> callback) override;
   void FillAddressForm(const std::string& guid,
@@ -109,6 +109,8 @@
   void ShowDetails(const DetailsProto& details) override;
   void ShowProgressBar(int progress, const std::string& message) override;
   void HideProgressBar() override;
+  void ShowOverlay() override;
+  void HideOverlay() override;
 
  private:
   void OnGetActions(bool result, const std::string& response);
diff --git a/components/autofill_assistant/browser/script_executor_unittest.cc b/components/autofill_assistant/browser/script_executor_unittest.cc
index b232a7a..d55edf86 100644
--- a/components/autofill_assistant/browser/script_executor_unittest.cc
+++ b/components/autofill_assistant/browser/script_executor_unittest.cc
@@ -24,6 +24,7 @@
 using ::testing::Contains;
 using ::testing::DoAll;
 using ::testing::Field;
+using ::testing::Invoke;
 using ::testing::NiceMock;
 using ::testing::Pair;
 using ::testing::ReturnRef;
@@ -46,13 +47,22 @@
         .WillByDefault(RunOnceCallback<1>(true));
     ON_CALL(mock_web_controller_, OnClickElement(_, _))
         .WillByDefault(RunOnceCallback<1>(false));
+    ON_CALL(mock_web_controller_, OnFocusElement(_, _))
+        .WillByDefault(RunOnceCallback<1>(true));
     ON_CALL(mock_web_controller_, GetUrl()).WillByDefault(ReturnRef(url_));
+    ON_CALL(mock_ui_controller_, ShowOverlay()).WillByDefault(Invoke([this]() {
+      overlay_ = true;
+    }));
+    ON_CALL(mock_ui_controller_, HideOverlay()).WillByDefault(Invoke([this]() {
+      overlay_ = false;
+    }));
   }
 
  protected:
   ScriptExecutorTest()
       : scoped_task_environment_(
-            base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME) {}
+            base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME),
+        overlay_(false) {}
 
   Service* GetService() override { return &mock_service_; }
 
@@ -93,6 +103,7 @@
   StrictMock<base::MockCallback<ScriptExecutor::RunScriptCallback>>
       executor_callback_;
   GURL url_;
+  bool overlay_;
 };
 
 TEST_F(ScriptExecutorTest, GetActionsFails) {
@@ -302,7 +313,7 @@
   ActionProto click_with_clean_contextual_ui;
   click_with_clean_contextual_ui.set_clean_contextual_ui(true);
   click_with_clean_contextual_ui.mutable_tell()->set_message("clean");
-  ;
+
   *actions_response.add_actions() = click_with_clean_contextual_ui;
 
   EXPECT_CALL(mock_service_, OnGetActions(_, _, _))
@@ -352,5 +363,51 @@
   executor_->Run(executor_callback_.Get());
 }
 
+TEST_F(ScriptExecutorTest, HideOverlay) {
+  ActionsResponseProto actions_response;
+  actions_response.set_server_payload("payload");
+  actions_response.add_actions()->mutable_tell()->set_message("1");
+  // focus_element hides the overlay
+  actions_response.add_actions()
+      ->mutable_focus_element()
+      ->mutable_element()
+      ->add_selectors("exists");
+
+  EXPECT_CALL(mock_service_, OnGetActions(_, _, _))
+      .WillOnce(RunOnceCallback<2>(true, Serialize(actions_response)));
+
+  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _))
+      .WillOnce(RunOnceCallback<2>(true, ""));
+
+  EXPECT_CALL(executor_callback_, Run(_));
+
+  overlay_ = true;
+  executor_->Run(executor_callback_.Get());
+  ASSERT_FALSE(overlay_);
+}
+
+TEST_F(ScriptExecutorTest, ShowOverlayAgainAfterHiding) {
+  ActionsResponseProto actions_response;
+  actions_response.set_server_payload("payload");
+  actions_response.add_actions()
+      ->mutable_focus_element()
+      ->mutable_element()
+      ->add_selectors("exists");
+  // tell shows the overlay again, after it's been hidden by focus_element
+  actions_response.add_actions()->mutable_tell()->set_message("1");
+
+  EXPECT_CALL(mock_service_, OnGetActions(_, _, _))
+      .WillOnce(RunOnceCallback<2>(true, Serialize(actions_response)));
+
+  EXPECT_CALL(mock_service_, OnGetNextActions(_, _, _))
+      .WillOnce(RunOnceCallback<2>(true, ""));
+
+  EXPECT_CALL(executor_callback_, Run(_));
+
+  overlay_ = true;
+  executor_->Run(executor_callback_.Get());
+  ASSERT_TRUE(overlay_);
+}
+
 }  // namespace
 }  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/service.cc b/components/autofill_assistant/browser/service.cc
index 96a5491..b372f42 100644
--- a/components/autofill_assistant/browser/service.cc
+++ b/components/autofill_assistant/browser/service.cc
@@ -30,9 +30,6 @@
 // TODO(crbug.com/806868): Provide correct server and endpoint.
 const char* const kScriptEndpoint = "/v1/supportsSite2";
 const char* const kActionEndpoint = "/v1/actions2";
-const char* const kTokenFetchId = "autofill_assistant";
-const char* const kOAuthScope =
-    "https://www.googleapis.com/auth/userinfo.profile";
 
 net::NetworkTrafficAnnotationTag traffic_annotation =
     net::DefineNetworkTrafficAnnotation("autofill_service", R"(
@@ -59,15 +56,14 @@
 Service::Service(const std::string& api_key,
                  const GURL& server_url,
                  content::BrowserContext* context,
-                 identity::IdentityManager* identity_manager)
+                 AccessTokenFetcher* access_token_fetcher)
     : context_(context),
       api_key_(api_key),
-      identity_manager_(identity_manager),
-      auth_enabled_(
-          identity_manager_ &&
-          "false" !=
-              base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
-                  switches::kAutofillAssistantAuth)),
+      access_token_fetcher_(access_token_fetcher),
+      fetching_token_(false),
+      auth_enabled_("false" !=
+                    base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+                        switches::kAutofillAssistantAuth)),
       weak_ptr_factory_(this) {
   DCHECK(server_url.is_valid());
 
@@ -196,9 +192,7 @@
     loader->retried_with_fresh_access_token = true;
     loader->loader.reset();
     // Invalidate access token and load a new one.
-    OAuth2TokenService::ScopeSet scopes{kOAuthScope};
-    identity_manager_->RemoveAccessTokenFromCache(account_id_, scopes,
-                                                  access_token_);
+    access_token_fetcher_->InvalidateAccessToken(access_token_);
     access_token_.clear();
     SendRequest(loader);
     return;
@@ -225,31 +219,26 @@
 }
 
 void Service::FetchAccessToken() {
-  DCHECK(identity_manager_);
-  if (token_fetcher_)
+  if (fetching_token_)
     return;
 
-  OAuth2TokenService::ScopeSet scopes{kOAuthScope};
-  account_id_ = identity_manager_->GetPrimaryAccountId();
-  token_fetcher_ = std::make_unique<identity::PrimaryAccountAccessTokenFetcher>(
-      kTokenFetchId, identity_manager_, scopes,
-      base::BindOnce(&Service::OnFetchAccessToken, base::Unretained(this)),
-      identity::PrimaryAccountAccessTokenFetcher::Mode::kWaitUntilAvailable);
-  // Unretained, because token_fetcher_ is owned by this instance.
+  fetching_token_ = true;
+  access_token_fetcher_->FetchAccessToken(base::BindOnce(
+      &Service::OnFetchAccessToken, weak_ptr_factory_.GetWeakPtr()));
 }
 
-void Service::OnFetchAccessToken(GoogleServiceAuthError error,
-                                 identity::AccessTokenInfo access_token_info) {
-  token_fetcher_.reset();
+void Service::OnFetchAccessToken(bool success,
+                                 const std::string& access_token) {
+  fetching_token_ = false;
 
-  if (error.state() != GoogleServiceAuthError::NONE) {
+  if (!success) {
     auth_enabled_ = false;
     // Give up on authentication for this run. Let the pending requests through,
     // which might be rejected, depending on the server configuration.
     return;
   }
 
-  access_token_ = access_token_info.token;
+  access_token_ = access_token;
 
   // Start any pending requests with the access token.
   for (const auto& entry : loaders_) {
diff --git a/components/autofill_assistant/browser/service.h b/components/autofill_assistant/browser/service.h
index 371b931..7fa893a 100644
--- a/components/autofill_assistant/browser/service.h
+++ b/components/autofill_assistant/browser/service.h
@@ -12,6 +12,7 @@
 
 #include "base/callback.h"
 #include "base/memory/weak_ptr.h"
+#include "components/autofill_assistant/browser/access_token_fetcher.h"
 #include "components/autofill_assistant/browser/service.pb.h"
 #include "google_apis/gaia/google_service_auth_error.h"
 #include "services/identity/public/cpp/primary_account_access_token_fetcher.h"
@@ -22,21 +23,17 @@
 class BrowserContext;
 }  // namespace content
 
-namespace identity {
-class IdentityManager;
-}  // namespace identity
-
 namespace autofill_assistant {
 // Autofill assistant service to communicate with the server to get scripts and
 // client actions.
 class Service {
  public:
-  // |context| and |identity_manager| must remain valid for the lifetime of the
-  // service instance. |identity_manager| might be nullptr.
+  // |context| and |token_fetcher| must remain valid for the lifetime of the
+  // service instance.
   Service(const std::string& api_key,
           const GURL& server_url,
           content::BrowserContext* context,
-          identity::IdentityManager* identity_manager);
+          AccessTokenFetcher* token_fetcher);
   virtual ~Service();
 
   using ResponseCallback =
@@ -90,8 +87,7 @@
   // Fetches the access token and, once this is done, starts all pending loaders
   // in |loaders_|.
   void FetchAccessToken();
-  void OnFetchAccessToken(GoogleServiceAuthError error,
-                          identity::AccessTokenInfo access_token_info);
+  void OnFetchAccessToken(bool success, const std::string& access_token);
 
   content::BrowserContext* context_;
   GURL script_server_url_;
@@ -103,9 +99,11 @@
   // API key to add to the URL of unauthenticated requests.
   std::string api_key_;
 
-  // Pointer must remain valid for the lifetime of the Service instance. Might
-  // be nullptr, if auth_enabled_ is false.
-  identity::IdentityManager* const identity_manager_;
+  // Pointer must remain valid for the lifetime of the Service instance.
+  AccessTokenFetcher* access_token_fetcher_;
+
+  // True while waiting for a response from AccessTokenFetcher.
+  bool fetching_token_;
 
   // Whether requests should be authenticated.
   bool auth_enabled_;
@@ -114,12 +112,6 @@
   // invalidated.
   std::string access_token_;
 
-  // Account id |access_token_| is for.
-  std::string account_id_;
-
-  // Active OAuth2 token fetcher.
-  std::unique_ptr<identity::PrimaryAccountAccessTokenFetcher> token_fetcher_;
-
   base::WeakPtrFactory<Service> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(Service);
diff --git a/components/autofill_assistant/browser/service.proto b/components/autofill_assistant/browser/service.proto
index 360511f..5572d3e 100644
--- a/components/autofill_assistant/browser/service.proto
+++ b/components/autofill_assistant/browser/service.proto
@@ -329,6 +329,9 @@
   // An optional list of fields that should be filled by this action.
   repeated RequiredField required_fields = 6;
 
+  // If set to false, clear the overlay for the duration of the action.
+  optional bool show_overlay = 7 [default = true];
+
   optional AutofillStrings strings = 8;
 }
 
@@ -341,6 +344,9 @@
   // A reference to the card number field in the form that should be filled.
   optional ElementReferenceProto form_field_element = 3;
 
+  // If set to false, clear the overlay for the duration of the action.
+  optional bool show_overlay = 5 [default = true];
+
   optional AutofillStrings strings = 8;
 }
 
diff --git a/components/autofill_assistant/browser/ui_controller.h b/components/autofill_assistant/browser/ui_controller.h
index d8018cc..f106087 100644
--- a/components/autofill_assistant/browser/ui_controller.h
+++ b/components/autofill_assistant/browser/ui_controller.h
@@ -63,8 +63,8 @@
   // forms.
   virtual void GetPaymentInformation(
       payments::mojom::PaymentOptionsPtr payment_options,
-      base::OnceCallback<void(std::unique_ptr<PaymentInformation>)>
-          callback) = 0;
+      base::OnceCallback<void(std::unique_ptr<PaymentInformation>)> callback,
+      const std::string& title) = 0;
 
   // Hide contextual information.
   virtual void HideDetails() = 0;
diff --git a/components/browser_sync/profile_sync_service.cc b/components/browser_sync/profile_sync_service.cc
index 66a5d0b..61554d8 100644
--- a/components/browser_sync/profile_sync_service.cc
+++ b/components/browser_sync/profile_sync_service.cc
@@ -194,8 +194,8 @@
       unrecoverable_error_reason_(ERROR_REASON_UNSET),
       expect_sync_configuration_aborted_(false),
       gaia_cookie_manager_service_(init_params.gaia_cookie_manager_service),
-      invalidations_identity_provider_(
-          init_params.invalidations_identity_provider),
+      invalidations_identity_providers_(
+          init_params.invalidations_identity_providers),
       network_resources_(
           std::make_unique<syncer::HttpBridgeNetworkResources>()),
       start_behavior_(init_params.start_behavior),
@@ -279,9 +279,10 @@
 
   if (!IsLocalSyncEnabled()) {
     auth_manager_->RegisterForAuthNotifications();
-    if (invalidations_identity_provider_) {
-      invalidations_identity_provider_->SetActiveAccountId(
-          GetAuthenticatedAccountInfo().account_id);
+    for (auto* provider : invalidations_identity_providers_) {
+      if (provider) {
+        provider->SetActiveAccountId(GetAuthenticatedAccountInfo().account_id);
+      }
     }
 
     if (!IsSignedIn()) {
@@ -400,10 +401,10 @@
 #endif
     startup_controller_->TryStart(/*force_immediate=*/IsSetupInProgress());
   }
-
-  if (invalidations_identity_provider_) {
-    invalidations_identity_provider_->SetActiveAccountId(
-        GetAuthenticatedAccountInfo().account_id);
+  for (auto* provider : invalidations_identity_providers_) {
+    if (provider) {
+      provider->SetActiveAccountId(GetAuthenticatedAccountInfo().account_id);
+    }
   }
 }
 
@@ -641,6 +642,9 @@
 
   if (sync_thread_)
     sync_thread_->Stop();
+
+  DCHECK(!data_type_manager_);
+  data_type_controllers_.clear();
 }
 
 void ProfileSyncService::ShutdownImpl(syncer::ShutdownReason reason) {
diff --git a/components/browser_sync/profile_sync_service.h b/components/browser_sync/profile_sync_service.h
index cf7c3c3..385d919f 100644
--- a/components/browser_sync/profile_sync_service.h
+++ b/components/browser_sync/profile_sync_service.h
@@ -205,7 +205,8 @@
     identity::IdentityManager* identity_manager;
     SigninScopedDeviceIdCallback signin_scoped_device_id_callback;
     GaiaCookieManagerService* gaia_cookie_manager_service = nullptr;
-    invalidation::IdentityProvider* invalidations_identity_provider = nullptr;
+    std::vector<invalidation::IdentityProvider*>
+        invalidations_identity_providers;
     StartBehavior start_behavior = MANUAL_START;
     syncer::NetworkTimeUpdateCallback network_time_update_callback;
     scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory;
@@ -713,10 +714,11 @@
   // when the user signs out of the content area.
   GaiaCookieManagerService* const gaia_cookie_manager_service_;
 
-  // This provider tells the invalidations code which identity to register for.
+  // This providers tells the invalidations code which identity to register for.
   // The account that it registers for should be the same as the currently
   // syncing account, so we'll need to update this whenever the account changes.
-  invalidation::IdentityProvider* const invalidations_identity_provider_;
+  std::vector<invalidation::IdentityProvider*> const
+      invalidations_identity_providers_;
 
   std::unique_ptr<syncer::LocalDeviceInfoProvider> local_device_;
 
diff --git a/components/browser_sync/profile_sync_test_util.cc b/components/browser_sync/profile_sync_test_util.cc
index adbb202..9ed22ea 100644
--- a/components/browser_sync/profile_sync_test_util.cc
+++ b/components/browser_sync/profile_sync_test_util.cc
@@ -268,7 +268,8 @@
   init_params.identity_manager = identity_manager();
   init_params.signin_scoped_device_id_callback =
       base::BindRepeating([]() { return std::string(); });
-  init_params.invalidations_identity_provider = identity_provider_.get();
+  init_params.invalidations_identity_providers.push_back(
+      identity_provider_.get());
   init_params.network_time_update_callback = base::DoNothing();
   init_params.url_loader_factory =
       base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
diff --git a/components/browser_sync/sync_auth_manager.cc b/components/browser_sync/sync_auth_manager.cc
index 42aa561c..2826632 100644
--- a/components/browser_sync/sync_auth_manager.cc
+++ b/components/browser_sync/sync_auth_manager.cc
@@ -219,8 +219,7 @@
 
   identity_manager_->RemoveAccessTokenFromCache(
       sync_account_.account_info.account_id,
-      OAuth2TokenService::ScopeSet{GaiaConstants::kChromeSyncOAuth2Scope},
-      access_token_);
+      identity::ScopeSet{GaiaConstants::kChromeSyncOAuth2Scope}, access_token_);
 
   access_token_.clear();
   credentials_changed_callback_.Run();
@@ -426,7 +425,7 @@
     request_access_token_retry_timer_.Stop();
   }
 
-  const OAuth2TokenService::ScopeSet kOAuth2ScopeSet{
+  const identity::ScopeSet kOAuth2ScopeSet{
       GaiaConstants::kChromeSyncOAuth2Scope};
 
   // Invalidate any previous token, otherwise the token service will return the
diff --git a/components/cbor/cbor_reader.cc b/components/cbor/cbor_reader.cc
index dfebe92..7205ed9f 100644
--- a/components/cbor/cbor_reader.cc
+++ b/components/cbor/cbor_reader.cc
@@ -22,8 +22,8 @@
 
 namespace {
 
-CBORValue::Type GetMajorType(uint8_t initial_data_byte) {
-  return static_cast<CBORValue::Type>(
+Value::Type GetMajorType(uint8_t initial_data_byte) {
+  return static_cast<Value::Type>(
       (initial_data_byte & constants::kMajorTypeMask) >>
       constants::kMajorTypeBitShift);
 }
@@ -61,14 +61,14 @@
 
 }  // namespace
 
-CBORReader::CBORReader(base::span<const uint8_t> data)
+Reader::Reader(base::span<const uint8_t> data)
     : rest_(data), error_code_(DecoderError::CBOR_NO_ERROR) {}
-CBORReader::~CBORReader() {}
+Reader::~Reader() {}
 
 // static
-base::Optional<CBORValue> CBORReader::Read(base::span<uint8_t const> data,
-                                           DecoderError* error_code_out,
-                                           int max_nesting_level) {
+base::Optional<Value> Reader::Read(base::span<uint8_t const> data,
+                                   DecoderError* error_code_out,
+                                   int max_nesting_level) {
   size_t num_bytes_consumed;
   auto value =
       Read(data, &num_bytes_consumed, error_code_out, max_nesting_level);
@@ -84,12 +84,12 @@
 }
 
 // static
-base::Optional<CBORValue> CBORReader::Read(base::span<uint8_t const> data,
-                                           size_t* num_bytes_consumed,
-                                           DecoderError* error_code_out,
-                                           int max_nesting_level) {
-  CBORReader reader(data);
-  base::Optional<CBORValue> value =
+base::Optional<Value> Reader::Read(base::span<uint8_t const> data,
+                                   size_t* num_bytes_consumed,
+                                   DecoderError* error_code_out,
+                                   int max_nesting_level) {
+  Reader reader(data);
+  base::Optional<Value> value =
       reader.DecodeCompleteDataItem(max_nesting_level);
 
   auto error = reader.GetErrorCode();
@@ -105,8 +105,7 @@
   return value;
 }
 
-base::Optional<CBORValue> CBORReader::DecodeCompleteDataItem(
-    int max_nesting_level) {
+base::Optional<Value> Reader::DecodeCompleteDataItem(int max_nesting_level) {
   if (max_nesting_level < 0 || max_nesting_level > kCBORMaxDepth) {
     error_code_ = DecoderError::TOO_MUCH_NESTING;
     return base::nullopt;
@@ -118,22 +117,22 @@
   }
 
   switch (header->type) {
-    case CBORValue::Type::UNSIGNED:
+    case Value::Type::UNSIGNED:
       return DecodeValueToUnsigned(header->value);
-    case CBORValue::Type::NEGATIVE:
+    case Value::Type::NEGATIVE:
       return DecodeValueToNegative(header->value);
-    case CBORValue::Type::BYTE_STRING:
+    case Value::Type::BYTE_STRING:
       return ReadByteStringContent(*header);
-    case CBORValue::Type::STRING:
+    case Value::Type::STRING:
       return ReadStringContent(*header);
-    case CBORValue::Type::ARRAY:
+    case Value::Type::ARRAY:
       return ReadArrayContent(*header, max_nesting_level);
-    case CBORValue::Type::MAP:
+    case Value::Type::MAP:
       return ReadMapContent(*header, max_nesting_level);
-    case CBORValue::Type::SIMPLE_VALUE:
+    case Value::Type::SIMPLE_VALUE:
       return DecodeToSimpleValue(*header);
-    case CBORValue::Type::TAG:  // We explicitly don't support TAG.
-    case CBORValue::Type::NONE:
+    case Value::Type::TAG:  // We explicitly don't support TAG.
+    case Value::Type::NONE:
       break;
   }
 
@@ -141,7 +140,7 @@
   return base::nullopt;
 }
 
-base::Optional<CBORReader::DataItemHeader> CBORReader::DecodeDataItemHeader() {
+base::Optional<Reader::DataItemHeader> Reader::DecodeDataItemHeader() {
   const base::Optional<uint8_t> initial_byte = ReadByte();
   if (!initial_byte) {
     return base::nullopt;
@@ -156,7 +155,7 @@
                : base::nullopt;
 }
 
-base::Optional<uint64_t> CBORReader::ReadVariadicLengthInteger(
+base::Optional<uint64_t> Reader::ReadVariadicLengthInteger(
     uint8_t additional_info) {
   uint8_t additional_bytes = 0;
   if (additional_info < 24) {
@@ -191,25 +190,25 @@
              : base::nullopt;
 }
 
-base::Optional<CBORValue> CBORReader::DecodeValueToNegative(uint64_t value) {
+base::Optional<Value> Reader::DecodeValueToNegative(uint64_t value) {
   auto negative_value = -base::CheckedNumeric<int64_t>(value) - 1;
   if (!negative_value.IsValid()) {
     error_code_ = DecoderError::OUT_OF_RANGE_INTEGER_VALUE;
     return base::nullopt;
   }
-  return CBORValue(negative_value.ValueOrDie());
+  return Value(negative_value.ValueOrDie());
 }
 
-base::Optional<CBORValue> CBORReader::DecodeValueToUnsigned(uint64_t value) {
+base::Optional<Value> Reader::DecodeValueToUnsigned(uint64_t value) {
   auto unsigned_value = base::CheckedNumeric<int64_t>(value);
   if (!unsigned_value.IsValid()) {
     error_code_ = DecoderError::OUT_OF_RANGE_INTEGER_VALUE;
     return base::nullopt;
   }
-  return CBORValue(unsigned_value.ValueOrDie());
+  return Value(unsigned_value.ValueOrDie());
 }
 
-base::Optional<CBORValue> CBORReader::DecodeToSimpleValue(
+base::Optional<Value> Reader::DecodeToSimpleValue(
     const DataItemHeader& header) {
   // ReadVariadicLengthInteger provides this bound.
   CHECK_LE(header.additional_info, 27);
@@ -224,22 +223,22 @@
   CHECK_LE(header.value, 255u);
   // |SimpleValue| is an enum class and so the underlying type is specified to
   // be |int|. So this cast is safe.
-  CBORValue::SimpleValue possibly_unsupported_simple_value =
-      static_cast<CBORValue::SimpleValue>(static_cast<int>(header.value));
+  Value::SimpleValue possibly_unsupported_simple_value =
+      static_cast<Value::SimpleValue>(static_cast<int>(header.value));
   switch (possibly_unsupported_simple_value) {
-    case CBORValue::SimpleValue::FALSE_VALUE:
-    case CBORValue::SimpleValue::TRUE_VALUE:
-    case CBORValue::SimpleValue::NULL_VALUE:
-    case CBORValue::SimpleValue::UNDEFINED:
-      return CBORValue(possibly_unsupported_simple_value);
+    case Value::SimpleValue::FALSE_VALUE:
+    case Value::SimpleValue::TRUE_VALUE:
+    case Value::SimpleValue::NULL_VALUE:
+    case Value::SimpleValue::UNDEFINED:
+      return Value(possibly_unsupported_simple_value);
   }
 
   error_code_ = DecoderError::UNSUPPORTED_SIMPLE_VALUE;
   return base::nullopt;
 }
 
-base::Optional<CBORValue> CBORReader::ReadStringContent(
-    const CBORReader::DataItemHeader& header) {
+base::Optional<Value> Reader::ReadStringContent(
+    const Reader::DataItemHeader& header) {
   uint64_t num_bytes = header.value;
   const base::Optional<base::span<const uint8_t>> bytes = ReadBytes(num_bytes);
   if (!bytes) {
@@ -249,12 +248,12 @@
   std::string cbor_string(bytes->begin(), bytes->end());
 
   return HasValidUTF8Format(cbor_string)
-             ? base::make_optional<CBORValue>(CBORValue(std::move(cbor_string)))
+             ? base::make_optional<Value>(Value(std::move(cbor_string)))
              : base::nullopt;
 }
 
-base::Optional<CBORValue> CBORReader::ReadByteStringContent(
-    const CBORReader::DataItemHeader& header) {
+base::Optional<Value> Reader::ReadByteStringContent(
+    const Reader::DataItemHeader& header) {
   uint64_t num_bytes = header.value;
   const base::Optional<base::span<const uint8_t>> bytes = ReadBytes(num_bytes);
   if (!bytes) {
@@ -262,46 +261,44 @@
   }
 
   std::vector<uint8_t> cbor_byte_string(bytes->begin(), bytes->end());
-  return CBORValue(std::move(cbor_byte_string));
+  return Value(std::move(cbor_byte_string));
 }
 
-base::Optional<CBORValue> CBORReader::ReadArrayContent(
-    const CBORReader::DataItemHeader& header,
+base::Optional<Value> Reader::ReadArrayContent(
+    const Reader::DataItemHeader& header,
     int max_nesting_level) {
   const uint64_t length = header.value;
 
-  CBORValue::ArrayValue cbor_array;
+  Value::ArrayValue cbor_array;
   for (uint64_t i = 0; i < length; ++i) {
-    base::Optional<CBORValue> cbor_element =
+    base::Optional<Value> cbor_element =
         DecodeCompleteDataItem(max_nesting_level - 1);
     if (!cbor_element.has_value()) {
       return base::nullopt;
     }
     cbor_array.push_back(std::move(cbor_element.value()));
   }
-  return CBORValue(std::move(cbor_array));
+  return Value(std::move(cbor_array));
 }
 
-base::Optional<CBORValue> CBORReader::ReadMapContent(
-    const CBORReader::DataItemHeader& header,
+base::Optional<Value> Reader::ReadMapContent(
+    const Reader::DataItemHeader& header,
     int max_nesting_level) {
   const uint64_t length = header.value;
 
-  CBORValue::MapValue cbor_map;
+  Value::MapValue cbor_map;
   for (uint64_t i = 0; i < length; ++i) {
-    base::Optional<CBORValue> key =
-        DecodeCompleteDataItem(max_nesting_level - 1);
-    base::Optional<CBORValue> value =
-        DecodeCompleteDataItem(max_nesting_level - 1);
+    base::Optional<Value> key = DecodeCompleteDataItem(max_nesting_level - 1);
+    base::Optional<Value> value = DecodeCompleteDataItem(max_nesting_level - 1);
     if (!key.has_value() || !value.has_value()) {
       return base::nullopt;
     }
 
     switch (key.value().type()) {
-      case CBORValue::Type::UNSIGNED:
-      case CBORValue::Type::NEGATIVE:
-      case CBORValue::Type::STRING:
-      case CBORValue::Type::BYTE_STRING:
+      case Value::Type::UNSIGNED:
+      case Value::Type::NEGATIVE:
+      case Value::Type::STRING:
+      case Value::Type::BYTE_STRING:
         break;
       default:
         error_code_ = DecoderError::INCORRECT_MAP_KEY_TYPE;
@@ -313,15 +310,15 @@
 
     cbor_map.insert_or_assign(std::move(key.value()), std::move(value.value()));
   }
-  return CBORValue(std::move(cbor_map));
+  return Value(std::move(cbor_map));
 }
 
-base::Optional<uint8_t> CBORReader::ReadByte() {
+base::Optional<uint8_t> Reader::ReadByte() {
   const base::Optional<base::span<const uint8_t>> bytes = ReadBytes(1);
   return bytes ? base::make_optional(bytes.value()[0]) : base::nullopt;
 }
 
-base::Optional<base::span<const uint8_t>> CBORReader::ReadBytes(
+base::Optional<base::span<const uint8_t>> Reader::ReadBytes(
     uint64_t num_bytes) {
   if (base::strict_cast<uint64_t>(rest_.size()) < num_bytes) {
     error_code_ = DecoderError::INCOMPLETE_CBOR_DATA;
@@ -332,8 +329,7 @@
   return ret;
 }
 
-bool CBORReader::IsEncodingMinimal(uint8_t additional_bytes,
-                                   uint64_t uint_data) {
+bool Reader::IsEncodingMinimal(uint8_t additional_bytes, uint64_t uint_data) {
   if ((additional_bytes == 1 && uint_data < 24) ||
       uint_data <= (1ULL << 8 * (additional_bytes >> 1)) - 1) {
     error_code_ = DecoderError::NON_MINIMAL_CBOR_ENCODING;
@@ -342,7 +338,7 @@
   return true;
 }
 
-bool CBORReader::HasValidUTF8Format(const std::string& string_data) {
+bool Reader::HasValidUTF8Format(const std::string& string_data) {
   if (!base::IsStringUTF8(string_data)) {
     error_code_ = DecoderError::INVALID_UTF8;
     return false;
@@ -350,8 +346,7 @@
   return true;
 }
 
-bool CBORReader::IsKeyInOrder(const CBORValue& new_key,
-                              CBORValue::MapValue* map) {
+bool Reader::IsKeyInOrder(const Value& new_key, Value::MapValue* map) {
   if (map->empty()) {
     return true;
   }
@@ -366,7 +361,7 @@
 }
 
 // static
-const char* CBORReader::ErrorCodeToString(DecoderError error) {
+const char* Reader::ErrorCodeToString(DecoderError error) {
   switch (error) {
     case DecoderError::CBOR_NO_ERROR:
       return kNoError;
diff --git a/components/cbor/cbor_reader.h b/components/cbor/cbor_reader.h
index f2291e9..6463fed0 100644
--- a/components/cbor/cbor_reader.h
+++ b/components/cbor/cbor_reader.h
@@ -57,7 +57,7 @@
 
 namespace cbor {
 
-class CBOR_EXPORT CBORReader {
+class CBOR_EXPORT Reader {
  public:
   enum class DecoderError {
     CBOR_NO_ERROR = 0,
@@ -79,9 +79,9 @@
   // CBOR nested depth sufficient for most use cases.
   static const int kCBORMaxDepth = 16;
 
-  ~CBORReader();
+  ~Reader();
 
-  // Reads and parses |input_data| into a CBORValue. Returns an empty Optional
+  // Reads and parses |input_data| into a Value. Returns an empty Optional
   // if the input violates any one of the syntax requirements (including unknown
   // additional info and incomplete CBOR data).
   //
@@ -93,29 +93,29 @@
   //
   // Returns an empty Optional if not all the data was consumed, and sets
   // |error_code_out| to EXTRANEOUS_DATA in this case.
-  static base::Optional<CBORValue> Read(base::span<const uint8_t> input_data,
-                                        DecoderError* error_code_out = nullptr,
-                                        int max_nesting_level = kCBORMaxDepth);
+  static base::Optional<Value> Read(base::span<const uint8_t> input_data,
+                                    DecoderError* error_code_out = nullptr,
+                                    int max_nesting_level = kCBORMaxDepth);
 
   // Never fails with EXTRANEOUS_DATA, but informs the caller of how many bytes
   // were consumed through |num_bytes_consumed|.
-  static base::Optional<CBORValue> Read(base::span<const uint8_t> input_data,
-                                        size_t* num_bytes_consumed,
-                                        DecoderError* error_code_out = nullptr,
-                                        int max_nesting_level = kCBORMaxDepth);
+  static base::Optional<Value> Read(base::span<const uint8_t> input_data,
+                                    size_t* num_bytes_consumed,
+                                    DecoderError* error_code_out = nullptr,
+                                    int max_nesting_level = kCBORMaxDepth);
 
   // Translates errors to human-readable error messages.
   static const char* ErrorCodeToString(DecoderError error_code);
 
  private:
-  explicit CBORReader(base::span<const uint8_t> data);
+  explicit Reader(base::span<const uint8_t> data);
 
   // Encapsulates information extracted from the header of a CBOR data item,
   // which consists of the initial byte, and a variable-length-encoded integer
   // (if any).
   struct DataItemHeader {
     // The major type decoded from the initial byte.
-    CBORValue::Type type;
+    Value::Type type;
 
     // The raw 5-bit additional information from the initial byte.
     uint8_t additional_info;
@@ -126,24 +126,24 @@
   };
 
   base::Optional<DataItemHeader> DecodeDataItemHeader();
-  base::Optional<CBORValue> DecodeCompleteDataItem(int max_nesting_level);
-  base::Optional<CBORValue> DecodeValueToNegative(uint64_t value);
-  base::Optional<CBORValue> DecodeValueToUnsigned(uint64_t value);
-  base::Optional<CBORValue> DecodeToSimpleValue(const DataItemHeader& header);
+  base::Optional<Value> DecodeCompleteDataItem(int max_nesting_level);
+  base::Optional<Value> DecodeValueToNegative(uint64_t value);
+  base::Optional<Value> DecodeValueToUnsigned(uint64_t value);
+  base::Optional<Value> DecodeToSimpleValue(const DataItemHeader& header);
   base::Optional<uint64_t> ReadVariadicLengthInteger(uint8_t additional_info);
-  base::Optional<CBORValue> ReadByteStringContent(const DataItemHeader& header);
-  base::Optional<CBORValue> ReadStringContent(const DataItemHeader& header);
-  base::Optional<CBORValue> ReadArrayContent(const DataItemHeader& header,
-                                             int max_nesting_level);
-  base::Optional<CBORValue> ReadMapContent(const DataItemHeader& header,
-                                           int max_nesting_level);
+  base::Optional<Value> ReadByteStringContent(const DataItemHeader& header);
+  base::Optional<Value> ReadStringContent(const DataItemHeader& header);
+  base::Optional<Value> ReadArrayContent(const DataItemHeader& header,
+                                         int max_nesting_level);
+  base::Optional<Value> ReadMapContent(const DataItemHeader& header,
+                                       int max_nesting_level);
   base::Optional<uint8_t> ReadByte();
   base::Optional<base::span<const uint8_t>> ReadBytes(uint64_t num_bytes);
   // TODO(crbug/879237): This function's only caller has to make a copy of a
   // `span<uint8_t>` to satisfy this function's interface. Maybe we can make
   // this function take a `const span<const uint8_t>` and avoid copying?
   bool HasValidUTF8Format(const std::string& string_data);
-  bool IsKeyInOrder(const CBORValue& new_key, CBORValue::MapValue* map);
+  bool IsKeyInOrder(const Value& new_key, Value::MapValue* map);
   bool IsEncodingMinimal(uint8_t additional_bytes, uint64_t uint_data);
 
   DecoderError GetErrorCode() { return error_code_; }
@@ -153,7 +153,7 @@
   base::span<const uint8_t> rest_;
   DecoderError error_code_;
 
-  DISALLOW_COPY_AND_ASSIGN(CBORReader);
+  DISALLOW_COPY_AND_ASSIGN(Reader);
 };
 
 }  // namespace cbor
diff --git a/components/cbor/cbor_reader_fuzzer.cc b/components/cbor/cbor_reader_fuzzer.cc
index 4809e70..a3b8594 100644
--- a/components/cbor/cbor_reader_fuzzer.cc
+++ b/components/cbor/cbor_reader_fuzzer.cc
@@ -12,11 +12,11 @@
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
   std::vector<uint8_t> input(data, data + size);
-  base::Optional<CBORValue> cbor = CBORReader::Read(input);
+  base::Optional<Value> cbor = Reader::Read(input);
 
   if (cbor.has_value()) {
     base::Optional<std::vector<uint8_t>> serialized_cbor =
-        CBORWriter::Write(cbor.value());
+        Writer::Write(cbor.value());
     CHECK(serialized_cbor.has_value());
     if (serialized_cbor.has_value()) {
       CHECK(serialized_cbor.value().size() == input.size());
diff --git a/components/cbor/cbor_reader_unittest.cc b/components/cbor/cbor_reader_unittest.cc
index d86866d..2d72860 100644
--- a/components/cbor/cbor_reader_unittest.cc
+++ b/components/cbor/cbor_reader_unittest.cc
@@ -51,24 +51,24 @@
   for (const UintTestCase& test_case : kUintTestCases) {
     SCOPED_TRACE(testing::Message() << "testing uint: " << test_case.value);
 
-    base::Optional<CBORValue> cbor = CBORReader::Read(test_case.cbor_data);
+    base::Optional<Value> cbor = Reader::Read(test_case.cbor_data);
     ASSERT_TRUE(cbor.has_value());
-    ASSERT_EQ(cbor.value().type(), CBORValue::Type::UNSIGNED);
+    ASSERT_EQ(cbor.value().type(), Value::Type::UNSIGNED);
     EXPECT_EQ(cbor.value().GetInteger(), test_case.value);
 
     auto cbor_data_with_extra_byte = WithExtraneousData(test_case.cbor_data);
-    CBORReader::DecoderError error_code;
-    cbor = CBORReader::Read(cbor_data_with_extra_byte, &error_code);
+    Reader::DecoderError error_code;
+    cbor = Reader::Read(cbor_data_with_extra_byte, &error_code);
     EXPECT_FALSE(cbor.has_value());
-    EXPECT_EQ(error_code, CBORReader::DecoderError::EXTRANEOUS_DATA);
+    EXPECT_EQ(error_code, Reader::DecoderError::EXTRANEOUS_DATA);
 
     size_t num_bytes_consumed;
-    cbor = CBORReader::Read(cbor_data_with_extra_byte, &num_bytes_consumed,
-                            &error_code);
+    cbor = Reader::Read(cbor_data_with_extra_byte, &num_bytes_consumed,
+                        &error_code);
     ASSERT_TRUE(cbor.has_value());
-    ASSERT_EQ(cbor.value().type(), CBORValue::Type::UNSIGNED);
+    ASSERT_EQ(cbor.value().type(), Value::Type::UNSIGNED);
     EXPECT_EQ(cbor.value().GetInteger(), test_case.value);
-    EXPECT_EQ(error_code, CBORReader::DecoderError::CBOR_NO_ERROR);
+    EXPECT_EQ(error_code, Reader::DecoderError::CBOR_NO_ERROR);
     EXPECT_EQ(num_bytes_consumed, test_case.cbor_data.size());
   }
 }
@@ -111,15 +111,14 @@
   };
 
   int test_case_index = 0;
-  CBORReader::DecoderError error_code;
+  Reader::DecoderError error_code;
   for (const auto& non_minimal_uint : non_minimal_uint_encodings) {
     SCOPED_TRACE(testing::Message()
                  << "testing element at index : " << test_case_index++);
 
-    base::Optional<CBORValue> cbor =
-        CBORReader::Read(non_minimal_uint, &error_code);
+    base::Optional<Value> cbor = Reader::Read(non_minimal_uint, &error_code);
     EXPECT_FALSE(cbor.has_value());
-    EXPECT_EQ(error_code, CBORReader::DecoderError::NON_MINIMAL_CBOR_ENCODING);
+    EXPECT_EQ(error_code, Reader::DecoderError::NON_MINIMAL_CBOR_ENCODING);
   }
 }
 
@@ -144,24 +143,24 @@
     SCOPED_TRACE(testing::Message()
                  << "testing negative int : " << test_case.negative_int);
 
-    base::Optional<CBORValue> cbor = CBORReader::Read(test_case.cbor_data);
+    base::Optional<Value> cbor = Reader::Read(test_case.cbor_data);
     ASSERT_TRUE(cbor.has_value());
-    ASSERT_EQ(cbor.value().type(), CBORValue::Type::NEGATIVE);
+    ASSERT_EQ(cbor.value().type(), Value::Type::NEGATIVE);
     EXPECT_EQ(cbor.value().GetInteger(), test_case.negative_int);
 
     auto cbor_data_with_extra_byte = WithExtraneousData(test_case.cbor_data);
-    CBORReader::DecoderError error_code;
-    cbor = CBORReader::Read(cbor_data_with_extra_byte, &error_code);
+    Reader::DecoderError error_code;
+    cbor = Reader::Read(cbor_data_with_extra_byte, &error_code);
     EXPECT_FALSE(cbor.has_value());
-    EXPECT_EQ(error_code, CBORReader::DecoderError::EXTRANEOUS_DATA);
+    EXPECT_EQ(error_code, Reader::DecoderError::EXTRANEOUS_DATA);
 
     size_t num_bytes_consumed;
-    cbor = CBORReader::Read(cbor_data_with_extra_byte, &num_bytes_consumed,
-                            &error_code);
+    cbor = Reader::Read(cbor_data_with_extra_byte, &num_bytes_consumed,
+                        &error_code);
     ASSERT_TRUE(cbor.has_value());
-    ASSERT_EQ(cbor.value().type(), CBORValue::Type::NEGATIVE);
+    ASSERT_EQ(cbor.value().type(), Value::Type::NEGATIVE);
     EXPECT_EQ(cbor.value().GetInteger(), test_case.negative_int);
-    EXPECT_EQ(error_code, CBORReader::DecoderError::CBOR_NO_ERROR);
+    EXPECT_EQ(error_code, Reader::DecoderError::CBOR_NO_ERROR);
     EXPECT_EQ(num_bytes_consumed, test_case.cbor_data.size());
   }
 }
@@ -184,24 +183,24 @@
     SCOPED_TRACE(testing::Message()
                  << "testing string test case at : " << element_index++);
 
-    base::Optional<CBORValue> cbor = CBORReader::Read(test_case.cbor_data);
+    base::Optional<Value> cbor = Reader::Read(test_case.cbor_data);
     ASSERT_TRUE(cbor.has_value());
-    ASSERT_EQ(cbor.value().type(), CBORValue::Type::BYTE_STRING);
+    ASSERT_EQ(cbor.value().type(), Value::Type::BYTE_STRING);
     EXPECT_EQ(cbor.value().GetBytestring(), test_case.value);
 
     auto cbor_data_with_extra_byte = WithExtraneousData(test_case.cbor_data);
-    CBORReader::DecoderError error_code;
-    cbor = CBORReader::Read(cbor_data_with_extra_byte, &error_code);
+    Reader::DecoderError error_code;
+    cbor = Reader::Read(cbor_data_with_extra_byte, &error_code);
     EXPECT_FALSE(cbor.has_value());
-    EXPECT_EQ(error_code, CBORReader::DecoderError::EXTRANEOUS_DATA);
+    EXPECT_EQ(error_code, Reader::DecoderError::EXTRANEOUS_DATA);
 
     size_t num_bytes_consumed;
-    cbor = CBORReader::Read(cbor_data_with_extra_byte, &num_bytes_consumed,
-                            &error_code);
+    cbor = Reader::Read(cbor_data_with_extra_byte, &num_bytes_consumed,
+                        &error_code);
     ASSERT_TRUE(cbor.has_value());
-    ASSERT_EQ(cbor.value().type(), CBORValue::Type::BYTE_STRING);
+    ASSERT_EQ(cbor.value().type(), Value::Type::BYTE_STRING);
     EXPECT_EQ(cbor.value().GetBytestring(), test_case.value);
-    EXPECT_EQ(error_code, CBORReader::DecoderError::CBOR_NO_ERROR);
+    EXPECT_EQ(error_code, Reader::DecoderError::CBOR_NO_ERROR);
     EXPECT_EQ(num_bytes_consumed, test_case.cbor_data.size());
   }
 }
@@ -226,24 +225,24 @@
     SCOPED_TRACE(testing::Message()
                  << "testing string value : " << test_case.value);
 
-    base::Optional<CBORValue> cbor = CBORReader::Read(test_case.cbor_data);
+    base::Optional<Value> cbor = Reader::Read(test_case.cbor_data);
     ASSERT_TRUE(cbor.has_value());
-    ASSERT_EQ(cbor.value().type(), CBORValue::Type::STRING);
+    ASSERT_EQ(cbor.value().type(), Value::Type::STRING);
     EXPECT_EQ(cbor.value().GetString(), test_case.value);
 
     auto cbor_data_with_extra_byte = WithExtraneousData(test_case.cbor_data);
-    CBORReader::DecoderError error_code;
-    cbor = CBORReader::Read(cbor_data_with_extra_byte, &error_code);
+    Reader::DecoderError error_code;
+    cbor = Reader::Read(cbor_data_with_extra_byte, &error_code);
     EXPECT_FALSE(cbor.has_value());
-    EXPECT_EQ(error_code, CBORReader::DecoderError::EXTRANEOUS_DATA);
+    EXPECT_EQ(error_code, Reader::DecoderError::EXTRANEOUS_DATA);
 
     size_t num_bytes_consumed;
-    cbor = CBORReader::Read(cbor_data_with_extra_byte, &num_bytes_consumed,
-                            &error_code);
+    cbor = Reader::Read(cbor_data_with_extra_byte, &num_bytes_consumed,
+                        &error_code);
     ASSERT_TRUE(cbor.has_value());
-    ASSERT_EQ(cbor.value().type(), CBORValue::Type::STRING);
+    ASSERT_EQ(cbor.value().type(), Value::Type::STRING);
     EXPECT_EQ(cbor.value().GetString(), test_case.value);
-    EXPECT_EQ(error_code, CBORReader::DecoderError::CBOR_NO_ERROR);
+    EXPECT_EQ(error_code, Reader::DecoderError::CBOR_NO_ERROR);
     EXPECT_EQ(num_bytes_consumed, test_case.cbor_data.size());
   }
 }
@@ -271,24 +270,24 @@
     SCOPED_TRACE(testing::Message()
                  << "testing string with nul bytes :" << test_case.value);
 
-    base::Optional<CBORValue> cbor = CBORReader::Read(test_case.cbor_data);
+    base::Optional<Value> cbor = Reader::Read(test_case.cbor_data);
     ASSERT_TRUE(cbor.has_value());
-    ASSERT_EQ(cbor.value().type(), CBORValue::Type::STRING);
+    ASSERT_EQ(cbor.value().type(), Value::Type::STRING);
     EXPECT_EQ(cbor.value().GetString(), test_case.value);
 
     auto cbor_data_with_extra_byte = WithExtraneousData(test_case.cbor_data);
-    CBORReader::DecoderError error_code;
-    cbor = CBORReader::Read(cbor_data_with_extra_byte, &error_code);
+    Reader::DecoderError error_code;
+    cbor = Reader::Read(cbor_data_with_extra_byte, &error_code);
     EXPECT_FALSE(cbor.has_value());
-    EXPECT_EQ(error_code, CBORReader::DecoderError::EXTRANEOUS_DATA);
+    EXPECT_EQ(error_code, Reader::DecoderError::EXTRANEOUS_DATA);
 
     size_t num_bytes_consumed;
-    cbor = CBORReader::Read(cbor_data_with_extra_byte, &num_bytes_consumed,
-                            &error_code);
+    cbor = Reader::Read(cbor_data_with_extra_byte, &num_bytes_consumed,
+                        &error_code);
     ASSERT_TRUE(cbor.has_value());
-    ASSERT_EQ(cbor.value().type(), CBORValue::Type::STRING);
+    ASSERT_EQ(cbor.value().type(), Value::Type::STRING);
     EXPECT_EQ(cbor.value().GetString(), test_case.value);
-    EXPECT_EQ(error_code, CBORReader::DecoderError::CBOR_NO_ERROR);
+    EXPECT_EQ(error_code, Reader::DecoderError::CBOR_NO_ERROR);
     EXPECT_EQ(num_bytes_consumed, test_case.cbor_data.size());
   }
 }
@@ -300,11 +299,11 @@
   // characters. Here, 0xA6 is an unexpected continuation byte.
   static const std::vector<uint8_t> string_with_invalid_continuation_byte = {
       0x63, 0x00, 0x00, 0xA6};
-  CBORReader::DecoderError error_code;
-  base::Optional<CBORValue> cbor =
-      CBORReader::Read(string_with_invalid_continuation_byte, &error_code);
+  Reader::DecoderError error_code;
+  base::Optional<Value> cbor =
+      Reader::Read(string_with_invalid_continuation_byte, &error_code);
   EXPECT_FALSE(cbor.has_value());
-  EXPECT_EQ(error_code, CBORReader::DecoderError::INVALID_UTF8);
+  EXPECT_EQ(error_code, Reader::DecoderError::INVALID_UTF8);
 }
 
 TEST(CBORReaderTest, TestReadArray) {
@@ -317,34 +316,34 @@
       // clang-format on
   };
 
-  base::Optional<CBORValue> cbor = CBORReader::Read(kArrayTestCaseCbor);
+  base::Optional<Value> cbor = Reader::Read(kArrayTestCaseCbor);
   ASSERT_TRUE(cbor.has_value());
-  const CBORValue cbor_array = std::move(cbor.value());
-  ASSERT_EQ(cbor_array.type(), CBORValue::Type::ARRAY);
+  const Value cbor_array = std::move(cbor.value());
+  ASSERT_EQ(cbor_array.type(), Value::Type::ARRAY);
   ASSERT_THAT(cbor_array.GetArray(), testing::SizeIs(25));
 
-  std::vector<CBORValue> array;
+  std::vector<Value> array;
   for (int i = 0; i < 25; i++) {
     SCOPED_TRACE(testing::Message() << "testing array element at index " << i);
 
-    ASSERT_EQ(cbor_array.GetArray()[i].type(), CBORValue::Type::UNSIGNED);
+    ASSERT_EQ(cbor_array.GetArray()[i].type(), Value::Type::UNSIGNED);
     EXPECT_EQ(cbor_array.GetArray()[i].GetInteger(),
               static_cast<int64_t>(i + 1));
   }
 
   auto cbor_data_with_extra_byte = WithExtraneousData(kArrayTestCaseCbor);
-  CBORReader::DecoderError error_code;
-  cbor = CBORReader::Read(cbor_data_with_extra_byte, &error_code);
+  Reader::DecoderError error_code;
+  cbor = Reader::Read(cbor_data_with_extra_byte, &error_code);
   EXPECT_FALSE(cbor.has_value());
-  EXPECT_EQ(error_code, CBORReader::DecoderError::EXTRANEOUS_DATA);
+  EXPECT_EQ(error_code, Reader::DecoderError::EXTRANEOUS_DATA);
 
   size_t num_bytes_consumed;
-  cbor = CBORReader::Read(cbor_data_with_extra_byte, &num_bytes_consumed,
-                          &error_code);
+  cbor =
+      Reader::Read(cbor_data_with_extra_byte, &num_bytes_consumed, &error_code);
   ASSERT_TRUE(cbor.has_value());
-  ASSERT_EQ(cbor_array.type(), CBORValue::Type::ARRAY);
+  ASSERT_EQ(cbor_array.type(), Value::Type::ARRAY);
   ASSERT_THAT(cbor_array.GetArray(), testing::SizeIs(25));
-  EXPECT_EQ(error_code, CBORReader::DecoderError::CBOR_NO_ERROR);
+  EXPECT_EQ(error_code, Reader::DecoderError::CBOR_NO_ERROR);
   EXPECT_EQ(num_bytes_consumed, kArrayTestCaseCbor.size());
 }
 
@@ -366,49 +365,47 @@
       // clang-format on
   };
 
-  base::Optional<CBORValue> cbor = CBORReader::Read(kMapTestCaseCbor);
+  base::Optional<Value> cbor = Reader::Read(kMapTestCaseCbor);
   ASSERT_TRUE(cbor.has_value());
-  const CBORValue cbor_val = std::move(cbor.value());
-  ASSERT_EQ(cbor_val.type(), CBORValue::Type::MAP);
+  const Value cbor_val = std::move(cbor.value());
+  ASSERT_EQ(cbor_val.type(), Value::Type::MAP);
   ASSERT_EQ(cbor_val.GetMap().size(), 4u);
 
-  const CBORValue key_uint(24);
+  const Value key_uint(24);
   ASSERT_EQ(cbor_val.GetMap().count(key_uint), 1u);
   ASSERT_EQ(cbor_val.GetMap().find(key_uint)->second.type(),
-            CBORValue::Type::STRING);
+            Value::Type::STRING);
   EXPECT_EQ(cbor_val.GetMap().find(key_uint)->second.GetString(), "abc");
 
-  const CBORValue key_empty_string("");
+  const Value key_empty_string("");
   ASSERT_EQ(cbor_val.GetMap().count(key_empty_string), 1u);
   ASSERT_EQ(cbor_val.GetMap().find(key_empty_string)->second.type(),
-            CBORValue::Type::STRING);
+            Value::Type::STRING);
   EXPECT_EQ(cbor_val.GetMap().find(key_empty_string)->second.GetString(), ".");
 
-  const CBORValue key_b("b");
+  const Value key_b("b");
   ASSERT_EQ(cbor_val.GetMap().count(key_b), 1u);
-  ASSERT_EQ(cbor_val.GetMap().find(key_b)->second.type(),
-            CBORValue::Type::STRING);
+  ASSERT_EQ(cbor_val.GetMap().find(key_b)->second.type(), Value::Type::STRING);
   EXPECT_EQ(cbor_val.GetMap().find(key_b)->second.GetString(), "B");
 
-  const CBORValue key_aa("aa");
+  const Value key_aa("aa");
   ASSERT_EQ(cbor_val.GetMap().count(key_aa), 1u);
-  ASSERT_EQ(cbor_val.GetMap().find(key_aa)->second.type(),
-            CBORValue::Type::STRING);
+  ASSERT_EQ(cbor_val.GetMap().find(key_aa)->second.type(), Value::Type::STRING);
   EXPECT_EQ(cbor_val.GetMap().find(key_aa)->second.GetString(), "AA");
 
   auto cbor_data_with_extra_byte = WithExtraneousData(kMapTestCaseCbor);
-  CBORReader::DecoderError error_code;
-  cbor = CBORReader::Read(cbor_data_with_extra_byte, &error_code);
+  Reader::DecoderError error_code;
+  cbor = Reader::Read(cbor_data_with_extra_byte, &error_code);
   EXPECT_FALSE(cbor.has_value());
-  EXPECT_EQ(error_code, CBORReader::DecoderError::EXTRANEOUS_DATA);
+  EXPECT_EQ(error_code, Reader::DecoderError::EXTRANEOUS_DATA);
 
   size_t num_bytes_consumed;
-  cbor = CBORReader::Read(cbor_data_with_extra_byte, &num_bytes_consumed,
-                          &error_code);
+  cbor =
+      Reader::Read(cbor_data_with_extra_byte, &num_bytes_consumed, &error_code);
   ASSERT_TRUE(cbor.has_value());
-  ASSERT_EQ(cbor_val.type(), CBORValue::Type::MAP);
+  ASSERT_EQ(cbor_val.type(), Value::Type::MAP);
   ASSERT_EQ(cbor_val.GetMap().size(), 4u);
-  EXPECT_EQ(error_code, CBORReader::DecoderError::CBOR_NO_ERROR);
+  EXPECT_EQ(error_code, Reader::DecoderError::CBOR_NO_ERROR);
   EXPECT_EQ(num_bytes_consumed, kMapTestCaseCbor.size());
 }
 
@@ -430,49 +427,47 @@
       // clang-format on
   };
 
-  base::Optional<CBORValue> cbor = CBORReader::Read(kMapWithIntegerKeyCbor);
+  base::Optional<Value> cbor = Reader::Read(kMapWithIntegerKeyCbor);
   ASSERT_TRUE(cbor.has_value());
-  const CBORValue cbor_val = std::move(cbor.value());
-  ASSERT_EQ(cbor_val.type(), CBORValue::Type::MAP);
+  const Value cbor_val = std::move(cbor.value());
+  ASSERT_EQ(cbor_val.type(), Value::Type::MAP);
   ASSERT_EQ(cbor_val.GetMap().size(), 4u);
 
-  const CBORValue key_1(1);
+  const Value key_1(1);
   ASSERT_EQ(cbor_val.GetMap().count(key_1), 1u);
-  ASSERT_EQ(cbor_val.GetMap().find(key_1)->second.type(),
-            CBORValue::Type::STRING);
+  ASSERT_EQ(cbor_val.GetMap().find(key_1)->second.type(), Value::Type::STRING);
   EXPECT_EQ(cbor_val.GetMap().find(key_1)->second.GetString(), "a");
 
-  const CBORValue key_9(9);
+  const Value key_9(9);
   ASSERT_EQ(cbor_val.GetMap().count(key_9), 1u);
-  ASSERT_EQ(cbor_val.GetMap().find(key_9)->second.type(),
-            CBORValue::Type::STRING);
+  ASSERT_EQ(cbor_val.GetMap().find(key_9)->second.type(), Value::Type::STRING);
   EXPECT_EQ(cbor_val.GetMap().find(key_9)->second.GetString(), "b");
 
-  const CBORValue key_999(999);
+  const Value key_999(999);
   ASSERT_EQ(cbor_val.GetMap().count(key_999), 1u);
   ASSERT_EQ(cbor_val.GetMap().find(key_999)->second.type(),
-            CBORValue::Type::STRING);
+            Value::Type::STRING);
   EXPECT_EQ(cbor_val.GetMap().find(key_999)->second.GetString(), "c");
 
-  const CBORValue key_1111(1111);
+  const Value key_1111(1111);
   ASSERT_EQ(cbor_val.GetMap().count(key_1111), 1u);
   ASSERT_EQ(cbor_val.GetMap().find(key_1111)->second.type(),
-            CBORValue::Type::STRING);
+            Value::Type::STRING);
   EXPECT_EQ(cbor_val.GetMap().find(key_1111)->second.GetString(), "d");
 
   auto cbor_data_with_extra_byte = WithExtraneousData(kMapWithIntegerKeyCbor);
-  CBORReader::DecoderError error_code;
-  cbor = CBORReader::Read(cbor_data_with_extra_byte, &error_code);
+  Reader::DecoderError error_code;
+  cbor = Reader::Read(cbor_data_with_extra_byte, &error_code);
   EXPECT_FALSE(cbor.has_value());
-  EXPECT_EQ(error_code, CBORReader::DecoderError::EXTRANEOUS_DATA);
+  EXPECT_EQ(error_code, Reader::DecoderError::EXTRANEOUS_DATA);
 
   size_t num_bytes_consumed;
-  cbor = CBORReader::Read(cbor_data_with_extra_byte, &num_bytes_consumed,
-                          &error_code);
+  cbor =
+      Reader::Read(cbor_data_with_extra_byte, &num_bytes_consumed, &error_code);
   ASSERT_TRUE(cbor.has_value());
-  ASSERT_EQ(cbor_val.type(), CBORValue::Type::MAP);
+  ASSERT_EQ(cbor_val.type(), Value::Type::MAP);
   ASSERT_EQ(cbor_val.GetMap().size(), 4u);
-  EXPECT_EQ(error_code, CBORReader::DecoderError::CBOR_NO_ERROR);
+  EXPECT_EQ(error_code, Reader::DecoderError::CBOR_NO_ERROR);
   EXPECT_EQ(num_bytes_consumed, kMapWithIntegerKeyCbor.size());
 }
 
@@ -491,43 +486,43 @@
       // clang-format on
   };
 
-  base::Optional<CBORValue> cbor = CBORReader::Read(kMapWithIntegerKeyCbor);
+  base::Optional<Value> cbor = Reader::Read(kMapWithIntegerKeyCbor);
   ASSERT_TRUE(cbor.has_value());
-  const CBORValue cbor_val = std::move(cbor.value());
-  ASSERT_EQ(cbor_val.type(), CBORValue::Type::MAP);
+  const Value cbor_val = std::move(cbor.value());
+  ASSERT_EQ(cbor_val.type(), Value::Type::MAP);
   ASSERT_EQ(cbor_val.GetMap().size(), 3u);
 
-  const CBORValue key_1(-1);
+  const Value key_1(-1);
   ASSERT_EQ(cbor_val.GetMap().count(key_1), 1u);
   ASSERT_EQ(cbor_val.GetMap().find(key_1)->second.type(),
-            CBORValue::Type::UNSIGNED);
+            Value::Type::UNSIGNED);
   EXPECT_EQ(cbor_val.GetMap().find(key_1)->second.GetInteger(), 1);
 
-  const CBORValue key_2(-2);
+  const Value key_2(-2);
   ASSERT_EQ(cbor_val.GetMap().count(key_2), 1u);
   ASSERT_EQ(cbor_val.GetMap().find(key_2)->second.type(),
-            CBORValue::Type::UNSIGNED);
+            Value::Type::UNSIGNED);
   EXPECT_EQ(cbor_val.GetMap().find(key_2)->second.GetInteger(), 2);
 
-  const CBORValue key_100(-100);
+  const Value key_100(-100);
   ASSERT_EQ(cbor_val.GetMap().count(key_100), 1u);
   ASSERT_EQ(cbor_val.GetMap().find(key_100)->second.type(),
-            CBORValue::Type::UNSIGNED);
+            Value::Type::UNSIGNED);
   EXPECT_EQ(cbor_val.GetMap().find(key_100)->second.GetInteger(), 3);
 
   auto cbor_data_with_extra_byte = WithExtraneousData(kMapWithIntegerKeyCbor);
-  CBORReader::DecoderError error_code;
-  cbor = CBORReader::Read(cbor_data_with_extra_byte, &error_code);
+  Reader::DecoderError error_code;
+  cbor = Reader::Read(cbor_data_with_extra_byte, &error_code);
   EXPECT_FALSE(cbor.has_value());
-  EXPECT_EQ(error_code, CBORReader::DecoderError::EXTRANEOUS_DATA);
+  EXPECT_EQ(error_code, Reader::DecoderError::EXTRANEOUS_DATA);
 
   size_t num_bytes_consumed;
-  cbor = CBORReader::Read(cbor_data_with_extra_byte, &num_bytes_consumed,
-                          &error_code);
+  cbor =
+      Reader::Read(cbor_data_with_extra_byte, &num_bytes_consumed, &error_code);
   ASSERT_TRUE(cbor.has_value());
-  ASSERT_EQ(cbor_val.type(), CBORValue::Type::MAP);
+  ASSERT_EQ(cbor_val.type(), Value::Type::MAP);
   ASSERT_EQ(cbor_val.GetMap().size(), 3u);
-  EXPECT_EQ(error_code, CBORReader::DecoderError::CBOR_NO_ERROR);
+  EXPECT_EQ(error_code, Reader::DecoderError::CBOR_NO_ERROR);
   EXPECT_EQ(num_bytes_consumed, kMapWithIntegerKeyCbor.size());
 }
 
@@ -545,44 +540,43 @@
       // clang-format on
   };
 
-  base::Optional<CBORValue> cbor = CBORReader::Read(kMapArrayTestCaseCbor);
+  base::Optional<Value> cbor = Reader::Read(kMapArrayTestCaseCbor);
   ASSERT_TRUE(cbor.has_value());
-  const CBORValue cbor_val = std::move(cbor.value());
-  ASSERT_EQ(cbor_val.type(), CBORValue::Type::MAP);
+  const Value cbor_val = std::move(cbor.value());
+  ASSERT_EQ(cbor_val.type(), Value::Type::MAP);
   ASSERT_EQ(cbor_val.GetMap().size(), 2u);
 
-  const CBORValue key_a("a");
+  const Value key_a("a");
   ASSERT_EQ(cbor_val.GetMap().count(key_a), 1u);
   ASSERT_EQ(cbor_val.GetMap().find(key_a)->second.type(),
-            CBORValue::Type::UNSIGNED);
+            Value::Type::UNSIGNED);
   EXPECT_EQ(cbor_val.GetMap().find(key_a)->second.GetInteger(), 1u);
 
-  const CBORValue key_b("b");
+  const Value key_b("b");
   ASSERT_EQ(cbor_val.GetMap().count(key_b), 1u);
-  ASSERT_EQ(cbor_val.GetMap().find(key_b)->second.type(),
-            CBORValue::Type::ARRAY);
+  ASSERT_EQ(cbor_val.GetMap().find(key_b)->second.type(), Value::Type::ARRAY);
 
-  const CBORValue nested_array = cbor_val.GetMap().find(key_b)->second.Clone();
+  const Value nested_array = cbor_val.GetMap().find(key_b)->second.Clone();
   ASSERT_EQ(nested_array.GetArray().size(), 2u);
   for (int i = 0; i < 2; i++) {
-    ASSERT_THAT(nested_array.GetArray()[i].type(), CBORValue::Type::UNSIGNED);
+    ASSERT_THAT(nested_array.GetArray()[i].type(), Value::Type::UNSIGNED);
     EXPECT_EQ(nested_array.GetArray()[i].GetInteger(),
               static_cast<int64_t>(i + 2));
   }
 
   auto cbor_data_with_extra_byte = WithExtraneousData(kMapArrayTestCaseCbor);
-  CBORReader::DecoderError error_code;
-  cbor = CBORReader::Read(cbor_data_with_extra_byte, &error_code);
+  Reader::DecoderError error_code;
+  cbor = Reader::Read(cbor_data_with_extra_byte, &error_code);
   EXPECT_FALSE(cbor.has_value());
-  EXPECT_EQ(error_code, CBORReader::DecoderError::EXTRANEOUS_DATA);
+  EXPECT_EQ(error_code, Reader::DecoderError::EXTRANEOUS_DATA);
 
   size_t num_bytes_consumed;
-  cbor = CBORReader::Read(cbor_data_with_extra_byte, &num_bytes_consumed,
-                          &error_code);
+  cbor =
+      Reader::Read(cbor_data_with_extra_byte, &num_bytes_consumed, &error_code);
   ASSERT_TRUE(cbor.has_value());
-  ASSERT_EQ(cbor_val.type(), CBORValue::Type::MAP);
+  ASSERT_EQ(cbor_val.type(), Value::Type::MAP);
   ASSERT_EQ(cbor_val.GetMap().size(), 2u);
-  EXPECT_EQ(error_code, CBORReader::DecoderError::CBOR_NO_ERROR);
+  EXPECT_EQ(error_code, Reader::DecoderError::CBOR_NO_ERROR);
   EXPECT_EQ(num_bytes_consumed, kMapArrayTestCaseCbor.size());
 }
 
@@ -598,35 +592,34 @@
       // clang-format on
   };
 
-  CBORReader::DecoderError error_code;
-  base::Optional<CBORValue> cbor = CBORReader::Read(kMapTestCase, &error_code);
+  Reader::DecoderError error_code;
+  base::Optional<Value> cbor = Reader::Read(kMapTestCase, &error_code);
   ASSERT_TRUE(cbor.has_value());
-  ASSERT_EQ(cbor->type(), CBORValue::Type::MAP);
+  ASSERT_EQ(cbor->type(), Value::Type::MAP);
   ASSERT_EQ(cbor->GetMap().size(), 2u);
 
-  const CBORValue key_k("k");
+  const Value key_k("k");
   ASSERT_EQ(cbor->GetMap().count(key_k), 1u);
-  ASSERT_EQ(cbor->GetMap().find(key_k)->second.type(), CBORValue::Type::STRING);
+  ASSERT_EQ(cbor->GetMap().find(key_k)->second.type(), Value::Type::STRING);
   EXPECT_EQ(cbor->GetMap().find(key_k)->second.GetString(), "v");
 
-  const CBORValue key_foo("foo");
+  const Value key_foo("foo");
   ASSERT_EQ(cbor->GetMap().count(key_foo), 1u);
-  ASSERT_EQ(cbor->GetMap().find(key_foo)->second.type(),
-            CBORValue::Type::STRING);
+  ASSERT_EQ(cbor->GetMap().find(key_foo)->second.type(), Value::Type::STRING);
   EXPECT_EQ(cbor->GetMap().find(key_foo)->second.GetString(), "bar");
 
   auto cbor_data_with_extra_byte = WithExtraneousData(kMapTestCase);
-  cbor = CBORReader::Read(cbor_data_with_extra_byte, &error_code);
+  cbor = Reader::Read(cbor_data_with_extra_byte, &error_code);
   EXPECT_FALSE(cbor.has_value());
-  EXPECT_EQ(error_code, CBORReader::DecoderError::EXTRANEOUS_DATA);
+  EXPECT_EQ(error_code, Reader::DecoderError::EXTRANEOUS_DATA);
 
   size_t num_bytes_consumed;
-  cbor = CBORReader::Read(cbor_data_with_extra_byte, &num_bytes_consumed,
-                          &error_code);
+  cbor =
+      Reader::Read(cbor_data_with_extra_byte, &num_bytes_consumed, &error_code);
   ASSERT_TRUE(cbor.has_value());
-  ASSERT_EQ(cbor->type(), CBORValue::Type::MAP);
+  ASSERT_EQ(cbor->type(), Value::Type::MAP);
   ASSERT_EQ(cbor->GetMap().size(), 2u);
-  EXPECT_EQ(error_code, CBORReader::DecoderError::CBOR_NO_ERROR);
+  EXPECT_EQ(error_code, Reader::DecoderError::CBOR_NO_ERROR);
   EXPECT_EQ(num_bytes_consumed, kMapTestCase.size());
 }
 
@@ -642,38 +635,38 @@
       // clang-format on
   };
 
-  CBORReader::DecoderError error_code;
-  base::Optional<CBORValue> cbor = CBORReader::Read(kMapTestCase, &error_code);
+  Reader::DecoderError error_code;
+  base::Optional<Value> cbor = Reader::Read(kMapTestCase, &error_code);
   ASSERT_TRUE(cbor.has_value());
-  ASSERT_EQ(cbor->type(), CBORValue::Type::MAP);
+  ASSERT_EQ(cbor->type(), Value::Type::MAP);
   ASSERT_EQ(cbor->GetMap().size(), 2u);
 
-  const CBORValue key_k(std::vector<uint8_t>{'k'});
+  const Value key_k(std::vector<uint8_t>{'k'});
   ASSERT_EQ(cbor->GetMap().count(key_k), 1u);
   ASSERT_EQ(cbor->GetMap().find(key_k)->second.type(),
-            CBORValue::Type::BYTE_STRING);
+            Value::Type::BYTE_STRING);
   EXPECT_EQ(cbor->GetMap().find(key_k)->second.GetBytestring(),
             std::vector<uint8_t>{'v'});
 
-  const CBORValue key_foo(std::vector<uint8_t>{'f', 'o', 'o'});
+  const Value key_foo(std::vector<uint8_t>{'f', 'o', 'o'});
   ASSERT_EQ(cbor->GetMap().count(key_foo), 1u);
   ASSERT_EQ(cbor->GetMap().find(key_foo)->second.type(),
-            CBORValue::Type::BYTE_STRING);
+            Value::Type::BYTE_STRING);
   static const std::vector<uint8_t> kBarBytes{'b', 'a', 'r'};
   EXPECT_EQ(cbor->GetMap().find(key_foo)->second.GetBytestring(), kBarBytes);
 
   auto cbor_data_with_extra_byte = WithExtraneousData(kMapTestCase);
-  cbor = CBORReader::Read(cbor_data_with_extra_byte, &error_code);
+  cbor = Reader::Read(cbor_data_with_extra_byte, &error_code);
   EXPECT_FALSE(cbor.has_value());
-  EXPECT_EQ(error_code, CBORReader::DecoderError::EXTRANEOUS_DATA);
+  EXPECT_EQ(error_code, Reader::DecoderError::EXTRANEOUS_DATA);
 
   size_t num_bytes_consumed;
-  cbor = CBORReader::Read(cbor_data_with_extra_byte, &num_bytes_consumed,
-                          &error_code);
+  cbor =
+      Reader::Read(cbor_data_with_extra_byte, &num_bytes_consumed, &error_code);
   ASSERT_TRUE(cbor.has_value());
-  ASSERT_EQ(cbor->type(), CBORValue::Type::MAP);
+  ASSERT_EQ(cbor->type(), Value::Type::MAP);
   ASSERT_EQ(cbor->GetMap().size(), 2u);
-  EXPECT_EQ(error_code, CBORReader::DecoderError::CBOR_NO_ERROR);
+  EXPECT_EQ(error_code, Reader::DecoderError::CBOR_NO_ERROR);
   EXPECT_EQ(num_bytes_consumed, kMapTestCase.size());
 }
 
@@ -715,40 +708,40 @@
       // clang-format on
   };
 
-  CBORReader::DecoderError error_code;
-  base::Optional<CBORValue> cbor = CBORReader::Read(kMapTestCase, &error_code);
+  Reader::DecoderError error_code;
+  base::Optional<Value> cbor = Reader::Read(kMapTestCase, &error_code);
   ASSERT_TRUE(cbor.has_value());
-  ASSERT_EQ(cbor->type(), CBORValue::Type::MAP);
+  ASSERT_EQ(cbor->type(), Value::Type::MAP);
   ASSERT_EQ(cbor->GetMap().size(), 6u);
 
-  std::vector<CBORValue> keys;
+  std::vector<Value> keys;
   keys.emplace_back(10);
   keys.emplace_back(100);
   keys.emplace_back(-1);
-  keys.emplace_back(CBORValue::BinaryValue{'x', 'y'});
+  keys.emplace_back(Value::BinaryValue{'x', 'y'});
   keys.emplace_back("z");
   keys.emplace_back("aa");
   for (size_t i = 0; i < keys.size(); ++i) {
     SCOPED_TRACE(testing::Message() << "testing key at index: " << i);
     ASSERT_EQ(cbor->GetMap().count(keys[i]), 1u);
     ASSERT_EQ(cbor->GetMap().find(keys[i])->second.type(),
-              CBORValue::Type::UNSIGNED);
+              Value::Type::UNSIGNED);
     EXPECT_EQ(cbor->GetMap().find(keys[i])->second.GetInteger(),
               static_cast<int>(i));
   }
 
   auto cbor_data_with_extra_byte = WithExtraneousData(kMapTestCase);
-  cbor = CBORReader::Read(cbor_data_with_extra_byte, &error_code);
+  cbor = Reader::Read(cbor_data_with_extra_byte, &error_code);
   EXPECT_FALSE(cbor.has_value());
-  EXPECT_EQ(error_code, CBORReader::DecoderError::EXTRANEOUS_DATA);
+  EXPECT_EQ(error_code, Reader::DecoderError::EXTRANEOUS_DATA);
 
   size_t num_bytes_consumed;
-  cbor = CBORReader::Read(cbor_data_with_extra_byte, &num_bytes_consumed,
-                          &error_code);
+  cbor =
+      Reader::Read(cbor_data_with_extra_byte, &num_bytes_consumed, &error_code);
   ASSERT_TRUE(cbor.has_value());
-  ASSERT_EQ(cbor->type(), CBORValue::Type::MAP);
+  ASSERT_EQ(cbor->type(), Value::Type::MAP);
   ASSERT_EQ(cbor->GetMap().size(), 6u);
-  EXPECT_EQ(error_code, CBORReader::DecoderError::CBOR_NO_ERROR);
+  EXPECT_EQ(error_code, Reader::DecoderError::CBOR_NO_ERROR);
   EXPECT_EQ(num_bytes_consumed, arraysize(kMapTestCase));
 }
 
@@ -769,34 +762,34 @@
       // clang-format on
   };
 
-  base::Optional<CBORValue> cbor = CBORReader::Read(kNestedMapTestCase);
+  base::Optional<Value> cbor = Reader::Read(kNestedMapTestCase);
   ASSERT_TRUE(cbor.has_value());
-  const CBORValue cbor_val = std::move(cbor.value());
-  ASSERT_EQ(cbor_val.type(), CBORValue::Type::MAP);
+  const Value cbor_val = std::move(cbor.value());
+  ASSERT_EQ(cbor_val.type(), Value::Type::MAP);
   ASSERT_EQ(cbor_val.GetMap().size(), 2u);
 
-  const CBORValue key_a("a");
+  const Value key_a("a");
   ASSERT_EQ(cbor_val.GetMap().count(key_a), 1u);
   ASSERT_EQ(cbor_val.GetMap().find(key_a)->second.type(),
-            CBORValue::Type::UNSIGNED);
+            Value::Type::UNSIGNED);
   EXPECT_EQ(cbor_val.GetMap().find(key_a)->second.GetInteger(), 1u);
 
-  const CBORValue key_b("b");
+  const Value key_b("b");
   ASSERT_EQ(cbor_val.GetMap().count(key_b), 1u);
-  const CBORValue nested_map = cbor_val.GetMap().find(key_b)->second.Clone();
-  ASSERT_EQ(nested_map.type(), CBORValue::Type::MAP);
+  const Value nested_map = cbor_val.GetMap().find(key_b)->second.Clone();
+  ASSERT_EQ(nested_map.type(), Value::Type::MAP);
   ASSERT_EQ(nested_map.GetMap().size(), 2u);
 
-  const CBORValue key_c("c");
+  const Value key_c("c");
   ASSERT_EQ(nested_map.GetMap().count(key_c), 1u);
   ASSERT_EQ(nested_map.GetMap().find(key_c)->second.type(),
-            CBORValue::Type::UNSIGNED);
+            Value::Type::UNSIGNED);
   EXPECT_EQ(nested_map.GetMap().find(key_c)->second.GetInteger(), 2u);
 
-  const CBORValue key_d("d");
+  const Value key_d("d");
   ASSERT_EQ(nested_map.GetMap().count(key_d), 1u);
   ASSERT_EQ(nested_map.GetMap().find(key_d)->second.type(),
-            CBORValue::Type::UNSIGNED);
+            Value::Type::UNSIGNED);
   EXPECT_EQ(nested_map.GetMap().find(key_d)->second.GetInteger(), 3u);
 }
 
@@ -806,13 +799,11 @@
   static const std::vector<uint8_t> kMinNegativeInt = {
       0x3b, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
 
-  base::Optional<CBORValue> max_positive_int =
-      CBORReader::Read(kMaxPositiveInt);
+  base::Optional<Value> max_positive_int = Reader::Read(kMaxPositiveInt);
   ASSERT_TRUE(max_positive_int.has_value());
   EXPECT_EQ(max_positive_int.value().GetInteger(), INT64_MAX);
 
-  base::Optional<CBORValue> min_negative_int =
-      CBORReader::Read(kMinNegativeInt);
+  base::Optional<Value> min_negative_int = Reader::Read(kMinNegativeInt);
   ASSERT_TRUE(min_negative_int.has_value());
   EXPECT_EQ(min_negative_int.value().GetInteger(), INT64_MIN);
 }
@@ -824,27 +815,27 @@
   static const std::vector<uint8_t> kOutOfRangeNegativeInt = {
       0x3b, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
 
-  CBORReader::DecoderError error_code;
-  base::Optional<CBORValue> positive_int_out_of_range_cbor =
-      CBORReader::Read(kOutOfRangePositiveInt, &error_code);
+  Reader::DecoderError error_code;
+  base::Optional<Value> positive_int_out_of_range_cbor =
+      Reader::Read(kOutOfRangePositiveInt, &error_code);
   EXPECT_FALSE(positive_int_out_of_range_cbor.has_value());
-  EXPECT_EQ(error_code, CBORReader::DecoderError::OUT_OF_RANGE_INTEGER_VALUE);
+  EXPECT_EQ(error_code, Reader::DecoderError::OUT_OF_RANGE_INTEGER_VALUE);
 
-  base::Optional<CBORValue> negative_int_out_of_range_cbor =
-      CBORReader::Read(kOutOfRangeNegativeInt, &error_code);
+  base::Optional<Value> negative_int_out_of_range_cbor =
+      Reader::Read(kOutOfRangeNegativeInt, &error_code);
   EXPECT_FALSE(negative_int_out_of_range_cbor.has_value());
-  EXPECT_EQ(error_code, CBORReader::DecoderError::OUT_OF_RANGE_INTEGER_VALUE);
+  EXPECT_EQ(error_code, Reader::DecoderError::OUT_OF_RANGE_INTEGER_VALUE);
 }
 
 TEST(CBORReaderTest, TestReadSimpleValue) {
   static const struct {
-    const CBORValue::SimpleValue value;
+    const Value::SimpleValue value;
     const std::vector<uint8_t> cbor_data;
   } kSimpleValueTestCases[] = {
-      {CBORValue::SimpleValue::FALSE_VALUE, {0xf4}},
-      {CBORValue::SimpleValue::TRUE_VALUE, {0xf5}},
-      {CBORValue::SimpleValue::NULL_VALUE, {0xf6}},
-      {CBORValue::SimpleValue::UNDEFINED, {0xf7}},
+      {Value::SimpleValue::FALSE_VALUE, {0xf4}},
+      {Value::SimpleValue::TRUE_VALUE, {0xf5}},
+      {Value::SimpleValue::NULL_VALUE, {0xf6}},
+      {Value::SimpleValue::UNDEFINED, {0xf7}},
   };
 
   int test_element_index = 0;
@@ -852,24 +843,24 @@
     SCOPED_TRACE(testing::Message()
                  << "testing simple value at index : " << test_element_index++);
 
-    base::Optional<CBORValue> cbor = CBORReader::Read(test_case.cbor_data);
+    base::Optional<Value> cbor = Reader::Read(test_case.cbor_data);
     ASSERT_TRUE(cbor.has_value());
-    ASSERT_EQ(cbor.value().type(), CBORValue::Type::SIMPLE_VALUE);
+    ASSERT_EQ(cbor.value().type(), Value::Type::SIMPLE_VALUE);
     EXPECT_EQ(cbor.value().GetSimpleValue(), test_case.value);
 
     auto cbor_data_with_extra_byte = WithExtraneousData(test_case.cbor_data);
-    CBORReader::DecoderError error_code;
-    cbor = CBORReader::Read(cbor_data_with_extra_byte, &error_code);
+    Reader::DecoderError error_code;
+    cbor = Reader::Read(cbor_data_with_extra_byte, &error_code);
     EXPECT_FALSE(cbor.has_value());
-    EXPECT_EQ(error_code, CBORReader::DecoderError::EXTRANEOUS_DATA);
+    EXPECT_EQ(error_code, Reader::DecoderError::EXTRANEOUS_DATA);
 
     size_t num_bytes_consumed;
-    cbor = CBORReader::Read(cbor_data_with_extra_byte, &num_bytes_consumed,
-                            &error_code);
+    cbor = Reader::Read(cbor_data_with_extra_byte, &num_bytes_consumed,
+                        &error_code);
     ASSERT_TRUE(cbor.has_value());
-    ASSERT_EQ(cbor.value().type(), CBORValue::Type::SIMPLE_VALUE);
+    ASSERT_EQ(cbor.value().type(), Value::Type::SIMPLE_VALUE);
     EXPECT_EQ(cbor.value().GetSimpleValue(), test_case.value);
-    EXPECT_EQ(error_code, CBORReader::DecoderError::CBOR_NO_ERROR);
+    EXPECT_EQ(error_code, Reader::DecoderError::CBOR_NO_ERROR);
     EXPECT_EQ(num_bytes_consumed, test_case.cbor_data.size());
   }
 }
@@ -887,12 +878,12 @@
     SCOPED_TRACE(testing::Message()
                  << "testing unsupported floating point : "
                  << testing::PrintToString(unsupported_floating_point));
-    CBORReader::DecoderError error_code;
-    base::Optional<CBORValue> cbor =
-        CBORReader::Read(unsupported_floating_point, &error_code);
+    Reader::DecoderError error_code;
+    base::Optional<Value> cbor =
+        Reader::Read(unsupported_floating_point, &error_code);
     EXPECT_FALSE(cbor.has_value());
     EXPECT_EQ(error_code,
-              CBORReader::DecoderError::UNSUPPORTED_FLOATING_POINT_VALUE);
+              Reader::DecoderError::UNSUPPORTED_FLOATING_POINT_VALUE);
   }
 }
 
@@ -932,11 +923,10 @@
     SCOPED_TRACE(testing::Message() << "testing incomplete data at index : "
                                     << test_element_index++);
 
-    CBORReader::DecoderError error_code;
-    base::Optional<CBORValue> cbor =
-        CBORReader::Read(incomplete_data, &error_code);
+    Reader::DecoderError error_code;
+    base::Optional<Value> cbor = Reader::Read(incomplete_data, &error_code);
     EXPECT_FALSE(cbor.has_value());
-    EXPECT_EQ(error_code, CBORReader::DecoderError::INCOMPLETE_CBOR_DATA);
+    EXPECT_EQ(error_code, Reader::DecoderError::INCOMPLETE_CBOR_DATA);
   }
 }
 
@@ -955,11 +945,10 @@
       // clang-format on
   };
 
-  CBORReader::DecoderError error_code;
-  base::Optional<CBORValue> cbor =
-      CBORReader::Read(kMapWithUintKey, &error_code);
+  Reader::DecoderError error_code;
+  base::Optional<Value> cbor = Reader::Read(kMapWithUintKey, &error_code);
   EXPECT_FALSE(cbor.has_value());
-  EXPECT_EQ(error_code, CBORReader::DecoderError::INCORRECT_MAP_KEY_TYPE);
+  EXPECT_EQ(error_code, Reader::DecoderError::INCORRECT_MAP_KEY_TYPE);
 }
 
 TEST(CBORReaderTest, TestUnknownAdditionalInfoError) {
@@ -988,11 +977,10 @@
     SCOPED_TRACE(testing::Message()
                  << "testing data at index : " << test_element_index++);
 
-    CBORReader::DecoderError error_code;
-    base::Optional<CBORValue> cbor =
-        CBORReader::Read(incorrect_cbor, &error_code);
+    Reader::DecoderError error_code;
+    base::Optional<Value> cbor = Reader::Read(incorrect_cbor, &error_code);
     EXPECT_FALSE(cbor.has_value());
-    EXPECT_EQ(error_code, CBORReader::DecoderError::UNKNOWN_ADDITIONAL_INFO);
+    EXPECT_EQ(error_code, Reader::DecoderError::UNKNOWN_ADDITIONAL_INFO);
   }
 }
 
@@ -1014,11 +1002,10 @@
   for (const auto& zero_depth_data : kZeroDepthCBORList) {
     SCOPED_TRACE(testing::Message()
                  << "testing zero nested data : " << test_element_index++);
-    CBORReader::DecoderError error_code;
-    base::Optional<CBORValue> cbor =
-        CBORReader::Read(zero_depth_data, &error_code, 0);
+    Reader::DecoderError error_code;
+    base::Optional<Value> cbor = Reader::Read(zero_depth_data, &error_code, 0);
     EXPECT_TRUE(cbor.has_value());
-    EXPECT_EQ(error_code, CBORReader::DecoderError::CBOR_NO_ERROR);
+    EXPECT_EQ(error_code, Reader::DecoderError::CBOR_NO_ERROR);
   }
 
   // Corresponds to a CBOR structure with a nesting depth of 2:
@@ -1037,16 +1024,16 @@
       // clang-format on
   };
 
-  CBORReader::DecoderError error_code;
-  base::Optional<CBORValue> cbor_single_layer_max =
-      CBORReader::Read(kNestedCBORData, &error_code, 1);
+  Reader::DecoderError error_code;
+  base::Optional<Value> cbor_single_layer_max =
+      Reader::Read(kNestedCBORData, &error_code, 1);
   EXPECT_FALSE(cbor_single_layer_max.has_value());
-  EXPECT_EQ(error_code, CBORReader::DecoderError::TOO_MUCH_NESTING);
+  EXPECT_EQ(error_code, Reader::DecoderError::TOO_MUCH_NESTING);
 
-  base::Optional<CBORValue> cbor_double_layer_max =
-      CBORReader::Read(kNestedCBORData, &error_code, 2);
+  base::Optional<Value> cbor_double_layer_max =
+      Reader::Read(kNestedCBORData, &error_code, 2);
   EXPECT_TRUE(cbor_double_layer_max.has_value());
-  EXPECT_EQ(error_code, CBORReader::DecoderError::CBOR_NO_ERROR);
+  EXPECT_EQ(error_code, Reader::DecoderError::CBOR_NO_ERROR);
 }
 
 TEST(CBORReaderTest, TestOutOfOrderKeyError) {
@@ -1093,16 +1080,16 @@
   };
 
   int test_element_index = 0;
-  CBORReader::DecoderError error_code;
+  Reader::DecoderError error_code;
   for (const auto& unsorted_map : kMapsWithUnsortedKeys) {
     testing::Message scope_message;
     scope_message << "testing unsorted map : " << test_element_index++;
     SCOPED_TRACE(scope_message);
 
-    base::Optional<CBORValue> cbor =
-        CBORReader::Read(unsorted_map, &error_code);
+    base::Optional<Value> cbor =
+        Reader::Read(unsorted_map, &error_code);
     EXPECT_FALSE(cbor.has_value());
-    EXPECT_EQ(error_code, CBORReader::DecoderError::OUT_OF_ORDER_KEY);
+    EXPECT_EQ(error_code, Reader::DecoderError::OUT_OF_ORDER_KEY);
   }
 }
 
@@ -1130,12 +1117,11 @@
       // clang-format on
   };
 
-  CBORReader::DecoderError error_code;
+  Reader::DecoderError error_code;
 
-  base::Optional<CBORValue> cbor =
-      CBORReader::Read(kMapWithDuplicateKey, &error_code);
+  base::Optional<Value> cbor = Reader::Read(kMapWithDuplicateKey, &error_code);
   EXPECT_FALSE(cbor.has_value());
-  EXPECT_EQ(error_code, CBORReader::DecoderError::OUT_OF_ORDER_KEY);
+  EXPECT_EQ(error_code, Reader::DecoderError::OUT_OF_ORDER_KEY);
 }
 
 // Leveraging Markus Kuhn’s UTF-8 decoder stress test. See
@@ -1151,23 +1137,23 @@
   };
 
   int test_element_index = 0;
-  CBORReader::DecoderError error_code;
+  Reader::DecoderError error_code;
   for (const auto& cbor_byte : utf8_character_encodings) {
     SCOPED_TRACE(testing::Message() << "testing cbor data utf8 encoding : "
                                     << test_element_index++);
 
-    base::Optional<CBORValue> correctly_encoded_cbor =
-        CBORReader::Read(cbor_byte, &error_code);
+    base::Optional<Value> correctly_encoded_cbor =
+        Reader::Read(cbor_byte, &error_code);
     EXPECT_TRUE(correctly_encoded_cbor.has_value());
-    EXPECT_EQ(error_code, CBORReader::DecoderError::CBOR_NO_ERROR);
+    EXPECT_EQ(error_code, Reader::DecoderError::CBOR_NO_ERROR);
   }
 
   // Incorrect UTF8 encoding referenced by section 3.5.3 of the stress test.
   std::vector<uint8_t> impossible_utf_byte{0x64, 0xfe, 0xfe, 0xff, 0xff};
-  base::Optional<CBORValue> incorrectly_encoded_cbor =
-      CBORReader::Read(impossible_utf_byte, &error_code);
+  base::Optional<Value> incorrectly_encoded_cbor =
+      Reader::Read(impossible_utf_byte, &error_code);
   EXPECT_FALSE(incorrectly_encoded_cbor.has_value());
-  EXPECT_EQ(error_code, CBORReader::DecoderError::INVALID_UTF8);
+  EXPECT_EQ(error_code, Reader::DecoderError::INVALID_UTF8);
 }
 
 TEST(CBORReaderTest, TestExtraneousCBORDataError) {
@@ -1189,11 +1175,11 @@
     SCOPED_TRACE(testing::Message()
                  << "testing cbor extraneous data : " << test_element_index++);
 
-    CBORReader::DecoderError error_code;
-    base::Optional<CBORValue> cbor =
-        CBORReader::Read(extraneous_cbor_data, &error_code);
+    Reader::DecoderError error_code;
+    base::Optional<Value> cbor =
+        Reader::Read(extraneous_cbor_data, &error_code);
     EXPECT_FALSE(cbor.has_value());
-    EXPECT_EQ(error_code, CBORReader::DecoderError::EXTRANEOUS_DATA);
+    EXPECT_EQ(error_code, Reader::DecoderError::EXTRANEOUS_DATA);
   }
 }
 
@@ -1224,11 +1210,11 @@
                  << "testing unsupported cbor simple value  : "
                  << ::testing::PrintToString(unsupported_simple_val));
 
-    CBORReader::DecoderError error_code;
-    base::Optional<CBORValue> cbor =
-        CBORReader::Read(unsupported_simple_val, &error_code);
+    Reader::DecoderError error_code;
+    base::Optional<Value> cbor =
+        Reader::Read(unsupported_simple_val, &error_code);
     EXPECT_FALSE(cbor.has_value());
-    EXPECT_EQ(error_code, CBORReader::DecoderError::UNSUPPORTED_SIMPLE_VALUE);
+    EXPECT_EQ(error_code, Reader::DecoderError::UNSUPPORTED_SIMPLE_VALUE);
   }
 }
 
@@ -1240,10 +1226,10 @@
       {0xbb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
   };
   for (const auto& test_case : kTestCases) {
-    CBORReader::DecoderError error_code;
-    base::Optional<CBORValue> cbor = CBORReader::Read(test_case, &error_code);
+    Reader::DecoderError error_code;
+    base::Optional<Value> cbor = Reader::Read(test_case, &error_code);
     EXPECT_FALSE(cbor.has_value());
-    EXPECT_EQ(error_code, CBORReader::DecoderError::INCOMPLETE_CBOR_DATA);
+    EXPECT_EQ(error_code, Reader::DecoderError::INCOMPLETE_CBOR_DATA);
   }
 }
 
diff --git a/components/cbor/cbor_values.cc b/components/cbor/cbor_values.cc
index 397ce9a..7f37a422 100644
--- a/components/cbor/cbor_values.cc
+++ b/components/cbor/cbor_values.cc
@@ -13,13 +13,13 @@
 
 namespace cbor {
 
-CBORValue::CBORValue() noexcept : type_(Type::NONE) {}
+Value::Value() noexcept : type_(Type::NONE) {}
 
-CBORValue::CBORValue(CBORValue&& that) noexcept {
+Value::Value(Value&& that) noexcept {
   InternalMoveConstructFrom(std::move(that));
 }
 
-CBORValue::CBORValue(Type type) : type_(type) {
+Value::Value(Type type) : type_(type) {
   // Initialize with the default value.
   switch (type_) {
     case Type::UNSIGNED:
@@ -42,7 +42,7 @@
       NOTREACHED() << constants::kUnsupportedMajorType;
       return;
     case Type::SIMPLE_VALUE:
-      simple_value_ = CBORValue::SimpleValue::UNDEFINED;
+      simple_value_ = Value::SimpleValue::UNDEFINED;
       return;
     case Type::NONE:
       return;
@@ -50,35 +50,34 @@
   NOTREACHED();
 }
 
-CBORValue::CBORValue(SimpleValue in_simple)
+Value::Value(SimpleValue in_simple)
     : type_(Type::SIMPLE_VALUE), simple_value_(in_simple) {
   CHECK(static_cast<int>(in_simple) >= 20 && static_cast<int>(in_simple) <= 23);
 }
 
-CBORValue::CBORValue(bool boolean_value) : type_(Type::SIMPLE_VALUE) {
-  simple_value_ = boolean_value ? CBORValue::SimpleValue::TRUE_VALUE
-                                : CBORValue::SimpleValue::FALSE_VALUE;
+Value::Value(bool boolean_value) : type_(Type::SIMPLE_VALUE) {
+  simple_value_ = boolean_value ? Value::SimpleValue::TRUE_VALUE
+                                : Value::SimpleValue::FALSE_VALUE;
 }
 
-CBORValue::CBORValue(int integer_value)
-    : CBORValue(base::checked_cast<int64_t>(integer_value)) {}
+Value::Value(int integer_value)
+    : Value(base::checked_cast<int64_t>(integer_value)) {}
 
-CBORValue::CBORValue(int64_t integer_value) : integer_value_(integer_value) {
+Value::Value(int64_t integer_value) : integer_value_(integer_value) {
   type_ = integer_value >= 0 ? Type::UNSIGNED : Type::NEGATIVE;
 }
 
-CBORValue::CBORValue(base::span<const uint8_t> in_bytes)
+Value::Value(base::span<const uint8_t> in_bytes)
     : type_(Type::BYTE_STRING),
       bytestring_value_(in_bytes.begin(), in_bytes.end()) {}
 
-CBORValue::CBORValue(BinaryValue&& in_bytes) noexcept
+Value::Value(BinaryValue&& in_bytes) noexcept
     : type_(Type::BYTE_STRING), bytestring_value_(std::move(in_bytes)) {}
 
-CBORValue::CBORValue(const char* in_string, Type type)
-    : CBORValue(base::StringPiece(in_string), type) {}
+Value::Value(const char* in_string, Type type)
+    : Value(base::StringPiece(in_string), type) {}
 
-CBORValue::CBORValue(std::string&& in_string, Type type) noexcept
-    : type_(type) {
+Value::Value(std::string&& in_string, Type type) noexcept : type_(type) {
   switch (type_) {
     case Type::STRING:
       new (&string_value_) std::string();
@@ -94,7 +93,7 @@
   }
 }
 
-CBORValue::CBORValue(base::StringPiece in_string, Type type) : type_(type) {
+Value::Value(base::StringPiece in_string, Type type) : type_(type) {
   switch (type_) {
     case Type::STRING:
       new (&string_value_) std::string();
@@ -110,101 +109,100 @@
   }
 }
 
-CBORValue::CBORValue(const ArrayValue& in_array)
-    : type_(Type::ARRAY), array_value_() {
+Value::Value(const ArrayValue& in_array) : type_(Type::ARRAY), array_value_() {
   array_value_.reserve(in_array.size());
   for (const auto& val : in_array)
     array_value_.emplace_back(val.Clone());
 }
 
-CBORValue::CBORValue(ArrayValue&& in_array) noexcept
+Value::Value(ArrayValue&& in_array) noexcept
     : type_(Type::ARRAY), array_value_(std::move(in_array)) {}
 
-CBORValue::CBORValue(const MapValue& in_map) : type_(Type::MAP), map_value_() {
+Value::Value(const MapValue& in_map) : type_(Type::MAP), map_value_() {
   map_value_.reserve(in_map.size());
   for (const auto& it : in_map)
     map_value_.emplace_hint(map_value_.end(), it.first.Clone(),
                             it.second.Clone());
 }
 
-CBORValue::CBORValue(MapValue&& in_map) noexcept
+Value::Value(MapValue&& in_map) noexcept
     : type_(Type::MAP), map_value_(std::move(in_map)) {}
 
-CBORValue& CBORValue::operator=(CBORValue&& that) noexcept {
+Value& Value::operator=(Value&& that) noexcept {
   InternalCleanup();
   InternalMoveConstructFrom(std::move(that));
 
   return *this;
 }
 
-CBORValue::~CBORValue() {
+Value::~Value() {
   InternalCleanup();
 }
 
-CBORValue CBORValue::Clone() const {
+Value Value::Clone() const {
   switch (type_) {
     case Type::NONE:
-      return CBORValue();
+      return Value();
     case Type::UNSIGNED:
     case Type::NEGATIVE:
-      return CBORValue(integer_value_);
+      return Value(integer_value_);
     case Type::BYTE_STRING:
-      return CBORValue(bytestring_value_);
+      return Value(bytestring_value_);
     case Type::STRING:
-      return CBORValue(string_value_);
+      return Value(string_value_);
     case Type::ARRAY:
-      return CBORValue(array_value_);
+      return Value(array_value_);
     case Type::MAP:
-      return CBORValue(map_value_);
+      return Value(map_value_);
     case Type::TAG:
       NOTREACHED() << constants::kUnsupportedMajorType;
-      return CBORValue();
+      return Value();
     case Type::SIMPLE_VALUE:
-      return CBORValue(simple_value_);
+      return Value(simple_value_);
   }
 
   NOTREACHED();
-  return CBORValue();
+  return Value();
 }
 
-CBORValue::SimpleValue CBORValue::GetSimpleValue() const {
+Value::SimpleValue Value::GetSimpleValue() const {
   CHECK(is_simple());
   return simple_value_;
 }
 
-bool CBORValue::GetBool() const {
+bool Value::GetBool() const {
   CHECK(is_bool());
   return simple_value_ == SimpleValue::TRUE_VALUE;
 }
 
-const int64_t& CBORValue::GetInteger() const {
+const int64_t& Value::GetInteger() const {
   CHECK(is_integer());
   return integer_value_;
 }
 
-const int64_t& CBORValue::GetUnsigned() const {
+const int64_t& Value::GetUnsigned() const {
   CHECK(is_unsigned());
   CHECK_GE(integer_value_, 0);
   return integer_value_;
 }
 
-const int64_t& CBORValue::GetNegative() const {
+const int64_t& Value::GetNegative() const {
   CHECK(is_negative());
   CHECK_LT(integer_value_, 0);
   return integer_value_;
 }
 
-const std::string& CBORValue::GetString() const {
+const std::string& Value::GetString() const {
   CHECK(is_string());
   return string_value_;
 }
 
-const CBORValue::BinaryValue& CBORValue::GetBytestring() const {
+const Value::BinaryValue& Value::GetBytestring() const {
   CHECK(is_bytestring());
   return bytestring_value_;
 }
 
-base::StringPiece CBORValue::GetBytestringAsString() const {
+base::StringPiece Value::GetBytestringAsString() const {
   CHECK(is_bytestring());
   const auto& bytestring_value = GetBytestring();
   return base::StringPiece(
@@ -212,17 +210,17 @@
       bytestring_value.size());
 }
 
-const CBORValue::ArrayValue& CBORValue::GetArray() const {
+const Value::ArrayValue& Value::GetArray() const {
   CHECK(is_array());
   return array_value_;
 }
 
-const CBORValue::MapValue& CBORValue::GetMap() const {
+const Value::MapValue& Value::GetMap() const {
   CHECK(is_map());
   return map_value_;
 }
 
-void CBORValue::InternalMoveConstructFrom(CBORValue&& that) {
+void Value::InternalMoveConstructFrom(Value&& that) {
   type_ = that.type_;
 
   switch (type_) {
@@ -254,7 +252,7 @@
   NOTREACHED();
 }
 
-void CBORValue::InternalCleanup() {
+void Value::InternalCleanup() {
   switch (type_) {
     case Type::BYTE_STRING:
       bytestring_value_.~BinaryValue();
diff --git a/components/cbor/cbor_values.h b/components/cbor/cbor_values.h
index 39f2cca..abed1520 100644
--- a/components/cbor/cbor_values.h
+++ b/components/cbor/cbor_values.h
@@ -23,14 +23,14 @@
 // This does not support:
 //  * Floating-point numbers.
 //  * Indefinite-length encodings.
-class CBOR_EXPORT CBORValue {
+class CBOR_EXPORT Value {
  public:
   struct Less {
     // Comparison predicate to order keys in a dictionary as required by the
     // canonical CBOR order defined in
     // https://tools.ietf.org/html/rfc7049#section-3.9
     // TODO(808022): Clarify where this stands.
-    bool operator()(const CBORValue& a, const CBORValue& b) const {
+    bool operator()(const Value& a, const Value& b) const {
       // The current implementation only supports integer, text string,
       // and byte string keys.
       DCHECK((a.is_integer() || a.is_string() || a.is_bytestring()) &&
@@ -81,8 +81,8 @@
   };
 
   using BinaryValue = std::vector<uint8_t>;
-  using ArrayValue = std::vector<CBORValue>;
-  using MapValue = base::flat_map<CBORValue, CBORValue, Less>;
+  using ArrayValue = std::vector<Value>;
+  using MapValue = base::flat_map<Value, Value, Less>;
 
   enum class Type {
     UNSIGNED = 0,
@@ -103,39 +103,38 @@
     UNDEFINED = 23,
   };
 
-  CBORValue(CBORValue&& that) noexcept;
-  CBORValue() noexcept;  // A NONE value.
+  Value(Value&& that) noexcept;
+  Value() noexcept;  // A NONE value.
 
-  explicit CBORValue(Type type);
+  explicit Value(Type type);
 
-  explicit CBORValue(SimpleValue in_simple);
-  explicit CBORValue(bool boolean_value);
+  explicit Value(SimpleValue in_simple);
+  explicit Value(bool boolean_value);
 
-  explicit CBORValue(int integer_value);
-  explicit CBORValue(int64_t integer_value);
-  explicit CBORValue(uint64_t integer_value) = delete;
+  explicit Value(int integer_value);
+  explicit Value(int64_t integer_value);
+  explicit Value(uint64_t integer_value) = delete;
 
-  explicit CBORValue(base::span<const uint8_t> in_bytes);
-  explicit CBORValue(BinaryValue&& in_bytes) noexcept;
+  explicit Value(base::span<const uint8_t> in_bytes);
+  explicit Value(BinaryValue&& in_bytes) noexcept;
 
-  explicit CBORValue(const char* in_string, Type type = Type::STRING);
-  explicit CBORValue(std::string&& in_string,
-                     Type type = Type::STRING) noexcept;
-  explicit CBORValue(base::StringPiece in_string, Type type = Type::STRING);
+  explicit Value(const char* in_string, Type type = Type::STRING);
+  explicit Value(std::string&& in_string, Type type = Type::STRING) noexcept;
+  explicit Value(base::StringPiece in_string, Type type = Type::STRING);
 
-  explicit CBORValue(const ArrayValue& in_array);
-  explicit CBORValue(ArrayValue&& in_array) noexcept;
+  explicit Value(const ArrayValue& in_array);
+  explicit Value(ArrayValue&& in_array) noexcept;
 
-  explicit CBORValue(const MapValue& in_map);
-  explicit CBORValue(MapValue&& in_map) noexcept;
+  explicit Value(const MapValue& in_map);
+  explicit Value(MapValue&& in_map) noexcept;
 
-  CBORValue& operator=(CBORValue&& that) noexcept;
+  Value& operator=(Value&& that) noexcept;
 
-  ~CBORValue();
+  ~Value();
 
-  // CBORValue's copy constructor and copy assignment operator are deleted.
+  // Value's copy constructor and copy assignment operator are deleted.
   // Use this to obtain a deep copy explicitly.
-  CBORValue Clone() const;
+  Value Clone() const;
 
   // Returns the type of the value stored by the current Value object.
   Type type() const { return type_; }
@@ -181,10 +180,10 @@
     MapValue map_value_;
   };
 
-  void InternalMoveConstructFrom(CBORValue&& that);
+  void InternalMoveConstructFrom(Value&& that);
   void InternalCleanup();
 
-  DISALLOW_COPY_AND_ASSIGN(CBORValue);
+  DISALLOW_COPY_AND_ASSIGN(Value);
 };
 }  // namespace cbor
 
diff --git a/components/cbor/cbor_values_unittest.cc b/components/cbor/cbor_values_unittest.cc
index 23a959e..d303fe1 100644
--- a/components/cbor/cbor_values_unittest.cc
+++ b/components/cbor/cbor_values_unittest.cc
@@ -12,153 +12,150 @@
 namespace cbor {
 
 TEST(CBORValuesTest, TestNothrow) {
-  static_assert(std::is_nothrow_move_constructible<CBORValue>::value,
+  static_assert(std::is_nothrow_move_constructible<Value>::value,
                 "IsNothrowMoveConstructible");
-  static_assert(std::is_nothrow_default_constructible<CBORValue>::value,
+  static_assert(std::is_nothrow_default_constructible<Value>::value,
                 "IsNothrowDefaultConstructible");
-  static_assert(std::is_nothrow_constructible<CBORValue, std::string&&>::value,
+  static_assert(std::is_nothrow_constructible<Value, std::string&&>::value,
                 "IsNothrowMoveConstructibleFromString");
   static_assert(
-      std::is_nothrow_constructible<CBORValue, CBORValue::BinaryValue&&>::value,
+      std::is_nothrow_constructible<Value, Value::BinaryValue&&>::value,
       "IsNothrowMoveConstructibleFromBytestring");
   static_assert(
-      std::is_nothrow_constructible<CBORValue, CBORValue::ArrayValue&&>::value,
+      std::is_nothrow_constructible<Value, Value::ArrayValue&&>::value,
       "IsNothrowMoveConstructibleFromArray");
-  static_assert(std::is_nothrow_move_assignable<CBORValue>::value,
+  static_assert(std::is_nothrow_move_assignable<Value>::value,
                 "IsNothrowMoveAssignable");
 }
 
 // Test constructors
 TEST(CBORValuesTest, ConstructUnsigned) {
-  CBORValue value(37);
-  ASSERT_EQ(CBORValue::Type::UNSIGNED, value.type());
+  Value value(37);
+  ASSERT_EQ(Value::Type::UNSIGNED, value.type());
   EXPECT_EQ(37u, value.GetInteger());
 }
 
 TEST(CBORValuesTest, ConstructNegative) {
-  CBORValue value(-1);
-  ASSERT_EQ(CBORValue::Type::NEGATIVE, value.type());
+  Value value(-1);
+  ASSERT_EQ(Value::Type::NEGATIVE, value.type());
   EXPECT_EQ(-1, value.GetInteger());
 }
 
 TEST(CBORValuesTest, ConstructStringFromConstCharPtr) {
   const char* str = "foobar";
-  CBORValue value(str);
-  ASSERT_EQ(CBORValue::Type::STRING, value.type());
+  Value value(str);
+  ASSERT_EQ(Value::Type::STRING, value.type());
   EXPECT_EQ("foobar", value.GetString());
 }
 
 TEST(CBORValuesTest, ConstructStringFromStdStringConstRef) {
   std::string str = "foobar";
-  CBORValue value(str);
-  ASSERT_EQ(CBORValue::Type::STRING, value.type());
+  Value value(str);
+  ASSERT_EQ(Value::Type::STRING, value.type());
   EXPECT_EQ("foobar", value.GetString());
 }
 
 TEST(CBORValuesTest, ConstructStringFromStdStringRefRef) {
   std::string str = "foobar";
-  CBORValue value(std::move(str));
-  ASSERT_EQ(CBORValue::Type::STRING, value.type());
+  Value value(std::move(str));
+  ASSERT_EQ(Value::Type::STRING, value.type());
   EXPECT_EQ("foobar", value.GetString());
 }
 
 TEST(CBORValuesTest, ConstructBytestring) {
-  CBORValue value(CBORValue::BinaryValue({0xF, 0x0, 0x0, 0xB, 0xA, 0x2}));
-  ASSERT_EQ(CBORValue::Type::BYTE_STRING, value.type());
-  EXPECT_EQ(CBORValue::BinaryValue({0xF, 0x0, 0x0, 0xB, 0xA, 0x2}),
+  Value value(Value::BinaryValue({0xF, 0x0, 0x0, 0xB, 0xA, 0x2}));
+  ASSERT_EQ(Value::Type::BYTE_STRING, value.type());
+  EXPECT_EQ(Value::BinaryValue({0xF, 0x0, 0x0, 0xB, 0xA, 0x2}),
             value.GetBytestring());
 }
 
 TEST(CBORValuesTest, ConstructBytestringFromString) {
-  CBORValue value(CBORValue("hello", CBORValue::Type::BYTE_STRING));
-  ASSERT_EQ(CBORValue::Type::BYTE_STRING, value.type());
-  EXPECT_EQ(CBORValue::BinaryValue({'h', 'e', 'l', 'l', 'o'}),
+  Value value(Value("hello", Value::Type::BYTE_STRING));
+  ASSERT_EQ(Value::Type::BYTE_STRING, value.type());
+  EXPECT_EQ(Value::BinaryValue({'h', 'e', 'l', 'l', 'o'}),
             value.GetBytestring());
   EXPECT_EQ("hello", value.GetBytestringAsString());
 }
 
 TEST(CBORValuesTest, ConstructArray) {
-  CBORValue::ArrayValue array;
-  array.emplace_back(CBORValue("foo"));
+  Value::ArrayValue array;
+  array.emplace_back(Value("foo"));
   {
-    CBORValue value(array);
-    ASSERT_EQ(CBORValue::Type::ARRAY, value.type());
+    Value value(array);
+    ASSERT_EQ(Value::Type::ARRAY, value.type());
     ASSERT_EQ(1u, value.GetArray().size());
-    ASSERT_EQ(CBORValue::Type::STRING, value.GetArray()[0].type());
+    ASSERT_EQ(Value::Type::STRING, value.GetArray()[0].type());
     EXPECT_EQ("foo", value.GetArray()[0].GetString());
   }
 
-  array.back() = CBORValue("bar");
+  array.back() = Value("bar");
   {
-    CBORValue value(std::move(array));
-    ASSERT_EQ(CBORValue::Type::ARRAY, value.type());
+    Value value(std::move(array));
+    ASSERT_EQ(Value::Type::ARRAY, value.type());
     ASSERT_EQ(1u, value.GetArray().size());
-    ASSERT_EQ(CBORValue::Type::STRING, value.GetArray()[0].type());
+    ASSERT_EQ(Value::Type::STRING, value.GetArray()[0].type());
     EXPECT_EQ("bar", value.GetArray()[0].GetString());
   }
 }
 
 TEST(CBORValuesTest, ConstructMap) {
-  CBORValue::MapValue map;
-  const CBORValue key_foo("foo");
-  map[CBORValue("foo")] = CBORValue("bar");
+  Value::MapValue map;
+  const Value key_foo("foo");
+  map[Value("foo")] = Value("bar");
   {
-    CBORValue value(map);
-    ASSERT_EQ(CBORValue::Type::MAP, value.type());
+    Value value(map);
+    ASSERT_EQ(Value::Type::MAP, value.type());
     ASSERT_EQ(value.GetMap().count(key_foo), 1u);
-    ASSERT_EQ(CBORValue::Type::STRING,
-              value.GetMap().find(key_foo)->second.type());
+    ASSERT_EQ(Value::Type::STRING, value.GetMap().find(key_foo)->second.type());
     EXPECT_EQ("bar", value.GetMap().find(key_foo)->second.GetString());
   }
 
-  map[CBORValue("foo")] = CBORValue("baz");
+  map[Value("foo")] = Value("baz");
   {
-    CBORValue value(std::move(map));
-    ASSERT_EQ(CBORValue::Type::MAP, value.type());
+    Value value(std::move(map));
+    ASSERT_EQ(Value::Type::MAP, value.type());
     ASSERT_EQ(value.GetMap().count(key_foo), 1u);
-    ASSERT_EQ(CBORValue::Type::STRING,
-              value.GetMap().find(key_foo)->second.type());
+    ASSERT_EQ(Value::Type::STRING, value.GetMap().find(key_foo)->second.type());
     EXPECT_EQ("baz", value.GetMap().find(key_foo)->second.GetString());
   }
 }
 
 TEST(CBORValuesTest, ConstructSimpleValue) {
-  CBORValue false_value(CBORValue::SimpleValue::FALSE_VALUE);
-  ASSERT_EQ(CBORValue::Type::SIMPLE_VALUE, false_value.type());
-  EXPECT_EQ(CBORValue::SimpleValue::FALSE_VALUE, false_value.GetSimpleValue());
+  Value false_value(Value::SimpleValue::FALSE_VALUE);
+  ASSERT_EQ(Value::Type::SIMPLE_VALUE, false_value.type());
+  EXPECT_EQ(Value::SimpleValue::FALSE_VALUE, false_value.GetSimpleValue());
 
-  CBORValue true_value(CBORValue::SimpleValue::TRUE_VALUE);
-  ASSERT_EQ(CBORValue::Type::SIMPLE_VALUE, true_value.type());
-  EXPECT_EQ(CBORValue::SimpleValue::TRUE_VALUE, true_value.GetSimpleValue());
+  Value true_value(Value::SimpleValue::TRUE_VALUE);
+  ASSERT_EQ(Value::Type::SIMPLE_VALUE, true_value.type());
+  EXPECT_EQ(Value::SimpleValue::TRUE_VALUE, true_value.GetSimpleValue());
 
-  CBORValue null_value(CBORValue::SimpleValue::NULL_VALUE);
-  ASSERT_EQ(CBORValue::Type::SIMPLE_VALUE, null_value.type());
-  EXPECT_EQ(CBORValue::SimpleValue::NULL_VALUE, null_value.GetSimpleValue());
+  Value null_value(Value::SimpleValue::NULL_VALUE);
+  ASSERT_EQ(Value::Type::SIMPLE_VALUE, null_value.type());
+  EXPECT_EQ(Value::SimpleValue::NULL_VALUE, null_value.GetSimpleValue());
 
-  CBORValue undefined_value(CBORValue::SimpleValue::UNDEFINED);
-  ASSERT_EQ(CBORValue::Type::SIMPLE_VALUE, undefined_value.type());
-  EXPECT_EQ(CBORValue::SimpleValue::UNDEFINED,
-            undefined_value.GetSimpleValue());
+  Value undefined_value(Value::SimpleValue::UNDEFINED);
+  ASSERT_EQ(Value::Type::SIMPLE_VALUE, undefined_value.type());
+  EXPECT_EQ(Value::SimpleValue::UNDEFINED, undefined_value.GetSimpleValue());
 }
 
 TEST(CBORValuesTest, ConstructSimpleBooleanValue) {
-  CBORValue true_value(true);
-  ASSERT_EQ(CBORValue::Type::SIMPLE_VALUE, true_value.type());
+  Value true_value(true);
+  ASSERT_EQ(Value::Type::SIMPLE_VALUE, true_value.type());
   EXPECT_TRUE(true_value.GetBool());
 
-  CBORValue false_value(false);
-  ASSERT_EQ(CBORValue::Type::SIMPLE_VALUE, false_value.type());
+  Value false_value(false);
+  ASSERT_EQ(Value::Type::SIMPLE_VALUE, false_value.type());
   EXPECT_FALSE(false_value.GetBool());
 }
 
 // Test copy constructors
 TEST(CBORValuesTest, CopyUnsigned) {
-  CBORValue value(74);
-  CBORValue copied_value(value.Clone());
+  Value value(74);
+  Value copied_value(value.Clone());
   ASSERT_EQ(value.type(), copied_value.type());
   EXPECT_EQ(value.GetInteger(), copied_value.GetInteger());
 
-  CBORValue blank;
+  Value blank;
 
   blank = value.Clone();
   ASSERT_EQ(value.type(), blank.type());
@@ -166,12 +163,12 @@
 }
 
 TEST(CBORValuesTest, CopyNegativeInt) {
-  CBORValue value(-74);
-  CBORValue copied_value(value.Clone());
+  Value value(-74);
+  Value copied_value(value.Clone());
   ASSERT_EQ(value.type(), copied_value.type());
   EXPECT_EQ(value.GetInteger(), copied_value.GetInteger());
 
-  CBORValue blank;
+  Value blank;
 
   blank = value.Clone();
   ASSERT_EQ(value.type(), blank.type());
@@ -179,12 +176,12 @@
 }
 
 TEST(CBORValuesTest, CopyString) {
-  CBORValue value("foobar");
-  CBORValue copied_value(value.Clone());
+  Value value("foobar");
+  Value copied_value(value.Clone());
   ASSERT_EQ(value.type(), copied_value.type());
   EXPECT_EQ(value.GetString(), copied_value.GetString());
 
-  CBORValue blank;
+  Value blank;
 
   blank = value.Clone();
   ASSERT_EQ(value.type(), blank.type());
@@ -192,12 +189,12 @@
 }
 
 TEST(CBORValuesTest, CopyBytestring) {
-  CBORValue value(CBORValue::BinaryValue({0xF, 0x0, 0x0, 0xB, 0xA, 0x2}));
-  CBORValue copied_value(value.Clone());
+  Value value(Value::BinaryValue({0xF, 0x0, 0x0, 0xB, 0xA, 0x2}));
+  Value copied_value(value.Clone());
   ASSERT_EQ(value.type(), copied_value.type());
   EXPECT_EQ(value.GetBytestring(), copied_value.GetBytestring());
 
-  CBORValue blank;
+  Value blank;
 
   blank = value.Clone();
   ASSERT_EQ(value.type(), blank.type());
@@ -205,28 +202,28 @@
 }
 
 TEST(CBORValuesTest, CopyArray) {
-  CBORValue::ArrayValue array;
+  Value::ArrayValue array;
   array.emplace_back(123);
-  CBORValue value(std::move(array));
+  Value value(std::move(array));
 
-  CBORValue copied_value(value.Clone());
+  Value copied_value(value.Clone());
   ASSERT_EQ(1u, copied_value.GetArray().size());
   ASSERT_TRUE(copied_value.GetArray()[0].is_unsigned());
   EXPECT_EQ(value.GetArray()[0].GetInteger(),
             copied_value.GetArray()[0].GetInteger());
 
-  CBORValue blank;
+  Value blank;
   blank = value.Clone();
   EXPECT_EQ(1u, blank.GetArray().size());
 }
 
 TEST(CBORValuesTest, CopyMap) {
-  CBORValue::MapValue map;
-  CBORValue key_a("a");
-  map[CBORValue("a")] = CBORValue(123);
-  CBORValue value(std::move(map));
+  Value::MapValue map;
+  Value key_a("a");
+  map[Value("a")] = Value(123);
+  Value value(std::move(map));
 
-  CBORValue copied_value(value.Clone());
+  Value copied_value(value.Clone());
   EXPECT_EQ(1u, copied_value.GetMap().size());
   ASSERT_EQ(value.GetMap().count(key_a), 1u);
   ASSERT_EQ(copied_value.GetMap().count(key_a), 1u);
@@ -234,7 +231,7 @@
   EXPECT_EQ(value.GetMap().find(key_a)->second.GetInteger(),
             copied_value.GetMap().find(key_a)->second.GetInteger());
 
-  CBORValue blank;
+  Value blank;
   blank = value.Clone();
   EXPECT_EQ(1u, blank.GetMap().size());
   ASSERT_EQ(blank.GetMap().count(key_a), 1u);
@@ -244,12 +241,12 @@
 }
 
 TEST(CBORValuesTest, CopySimpleValue) {
-  CBORValue value(CBORValue::SimpleValue::TRUE_VALUE);
-  CBORValue copied_value(value.Clone());
+  Value value(Value::SimpleValue::TRUE_VALUE);
+  Value copied_value(value.Clone());
   EXPECT_EQ(value.type(), copied_value.type());
   EXPECT_EQ(value.GetSimpleValue(), copied_value.GetSimpleValue());
 
-  CBORValue blank;
+  Value blank;
 
   blank = value.Clone();
   EXPECT_EQ(value.type(), blank.type());
@@ -258,78 +255,78 @@
 
 // Test move constructors and move-assignment
 TEST(CBORValuesTest, MoveUnsigned) {
-  CBORValue value(74);
-  CBORValue moved_value(std::move(value));
-  EXPECT_EQ(CBORValue::Type::UNSIGNED, moved_value.type());
+  Value value(74);
+  Value moved_value(std::move(value));
+  EXPECT_EQ(Value::Type::UNSIGNED, moved_value.type());
   EXPECT_EQ(74u, moved_value.GetInteger());
 
-  CBORValue blank;
+  Value blank;
 
-  blank = CBORValue(654);
-  EXPECT_EQ(CBORValue::Type::UNSIGNED, blank.type());
+  blank = Value(654);
+  EXPECT_EQ(Value::Type::UNSIGNED, blank.type());
   EXPECT_EQ(654u, blank.GetInteger());
 }
 
 TEST(CBORValuesTest, MoveNegativeInteger) {
-  CBORValue value(-74);
-  CBORValue moved_value(std::move(value));
-  EXPECT_EQ(CBORValue::Type::NEGATIVE, moved_value.type());
+  Value value(-74);
+  Value moved_value(std::move(value));
+  EXPECT_EQ(Value::Type::NEGATIVE, moved_value.type());
   EXPECT_EQ(-74, moved_value.GetInteger());
 
-  CBORValue blank;
+  Value blank;
 
-  blank = CBORValue(-654);
-  EXPECT_EQ(CBORValue::Type::NEGATIVE, blank.type());
+  blank = Value(-654);
+  EXPECT_EQ(Value::Type::NEGATIVE, blank.type());
   EXPECT_EQ(-654, blank.GetInteger());
 }
 
 TEST(CBORValuesTest, MoveString) {
-  CBORValue value("foobar");
-  CBORValue moved_value(std::move(value));
-  EXPECT_EQ(CBORValue::Type::STRING, moved_value.type());
+  Value value("foobar");
+  Value moved_value(std::move(value));
+  EXPECT_EQ(Value::Type::STRING, moved_value.type());
   EXPECT_EQ("foobar", moved_value.GetString());
 
-  CBORValue blank;
+  Value blank;
 
-  blank = CBORValue("foobar");
-  EXPECT_EQ(CBORValue::Type::STRING, blank.type());
+  blank = Value("foobar");
+  EXPECT_EQ(Value::Type::STRING, blank.type());
   EXPECT_EQ("foobar", blank.GetString());
 }
 
 TEST(CBORValuesTest, MoveBytestring) {
-  const CBORValue::BinaryValue bytes({0xF, 0x0, 0x0, 0xB, 0xA, 0x2});
-  CBORValue value(bytes);
-  CBORValue moved_value(std::move(value));
-  EXPECT_EQ(CBORValue::Type::BYTE_STRING, moved_value.type());
+  const Value::BinaryValue bytes({0xF, 0x0, 0x0, 0xB, 0xA, 0x2});
+  Value value(bytes);
+  Value moved_value(std::move(value));
+  EXPECT_EQ(Value::Type::BYTE_STRING, moved_value.type());
   EXPECT_EQ(bytes, moved_value.GetBytestring());
 
-  CBORValue blank;
+  Value blank;
 
-  blank = CBORValue(bytes);
-  EXPECT_EQ(CBORValue::Type::BYTE_STRING, blank.type());
+  blank = Value(bytes);
+  EXPECT_EQ(Value::Type::BYTE_STRING, blank.type());
   EXPECT_EQ(bytes, blank.GetBytestring());
 }
 
 TEST(CBORValuesTest, MoveConstructMap) {
-  CBORValue::MapValue map;
-  const CBORValue key_a("a");
-  map[CBORValue("a")] = CBORValue(123);
+  Value::MapValue map;
+  const Value key_a("a");
+  map[Value("a")] = Value(123);
 
-  CBORValue value(std::move(map));
-  CBORValue moved_value(std::move(value));
-  ASSERT_EQ(CBORValue::Type::MAP, moved_value.type());
+  Value value(std::move(map));
+  Value moved_value(std::move(value));
+  ASSERT_EQ(Value::Type::MAP, moved_value.type());
   ASSERT_EQ(moved_value.GetMap().count(key_a), 1u);
   ASSERT_TRUE(moved_value.GetMap().find(key_a)->second.is_unsigned());
   EXPECT_EQ(123u, moved_value.GetMap().find(key_a)->second.GetInteger());
 }
 
 TEST(CBORValuesTest, MoveAssignMap) {
-  CBORValue::MapValue map;
-  const CBORValue key_a("a");
-  map[CBORValue("a")] = CBORValue(123);
+  Value::MapValue map;
+  const Value key_a("a");
+  map[Value("a")] = Value(123);
 
-  CBORValue blank;
-  blank = CBORValue(std::move(map));
+  Value blank;
+  blank = Value(std::move(map));
   ASSERT_TRUE(blank.is_map());
   ASSERT_EQ(blank.GetMap().count(key_a), 1u);
   ASSERT_TRUE(blank.GetMap().find(key_a)->second.is_unsigned());
@@ -337,34 +334,34 @@
 }
 
 TEST(CBORValuesTest, MoveArray) {
-  CBORValue::ArrayValue array;
+  Value::ArrayValue array;
   array.emplace_back(123);
-  CBORValue value(array);
-  CBORValue moved_value(std::move(value));
-  EXPECT_EQ(CBORValue::Type::ARRAY, moved_value.type());
+  Value value(array);
+  Value moved_value(std::move(value));
+  EXPECT_EQ(Value::Type::ARRAY, moved_value.type());
   EXPECT_EQ(123u, moved_value.GetArray().back().GetInteger());
 
-  CBORValue blank;
-  blank = CBORValue(std::move(array));
-  EXPECT_EQ(CBORValue::Type::ARRAY, blank.type());
+  Value blank;
+  blank = Value(std::move(array));
+  EXPECT_EQ(Value::Type::ARRAY, blank.type());
   EXPECT_EQ(123u, blank.GetArray().back().GetInteger());
 }
 
 TEST(CBORValuesTest, MoveSimpleValue) {
-  CBORValue value(CBORValue::SimpleValue::UNDEFINED);
-  CBORValue moved_value(std::move(value));
-  EXPECT_EQ(CBORValue::Type::SIMPLE_VALUE, moved_value.type());
-  EXPECT_EQ(CBORValue::SimpleValue::UNDEFINED, moved_value.GetSimpleValue());
+  Value value(Value::SimpleValue::UNDEFINED);
+  Value moved_value(std::move(value));
+  EXPECT_EQ(Value::Type::SIMPLE_VALUE, moved_value.type());
+  EXPECT_EQ(Value::SimpleValue::UNDEFINED, moved_value.GetSimpleValue());
 
-  CBORValue blank;
+  Value blank;
 
-  blank = CBORValue(CBORValue::SimpleValue::UNDEFINED);
-  EXPECT_EQ(CBORValue::Type::SIMPLE_VALUE, blank.type());
-  EXPECT_EQ(CBORValue::SimpleValue::UNDEFINED, blank.GetSimpleValue());
+  blank = Value(Value::SimpleValue::UNDEFINED);
+  EXPECT_EQ(Value::Type::SIMPLE_VALUE, blank.type());
+  EXPECT_EQ(Value::SimpleValue::UNDEFINED, blank.GetSimpleValue());
 }
 
 TEST(CBORValuesTest, SelfSwap) {
-  CBORValue test(1);
+  Value test(1);
   std::swap(test, test);
   EXPECT_EQ(test.GetInteger(), 1u);
 }
diff --git a/components/cbor/cbor_writer.cc b/components/cbor/cbor_writer.cc
index 5312ab9..d5fddd5 100644
--- a/components/cbor/cbor_writer.cc
+++ b/components/cbor/cbor_writer.cc
@@ -12,58 +12,57 @@
 
 namespace cbor {
 
-CBORWriter::~CBORWriter() {}
+Writer::~Writer() {}
 
 // static
-base::Optional<std::vector<uint8_t>> CBORWriter::Write(
-    const CBORValue& node,
-    size_t max_nesting_level) {
+base::Optional<std::vector<uint8_t>> Writer::Write(const Value& node,
+                                                   size_t max_nesting_level) {
   std::vector<uint8_t> cbor;
-  CBORWriter writer(&cbor);
+  Writer writer(&cbor);
   if (writer.EncodeCBOR(node, base::checked_cast<int>(max_nesting_level)))
     return cbor;
   return base::nullopt;
 }
 
-CBORWriter::CBORWriter(std::vector<uint8_t>* cbor) : encoded_cbor_(cbor) {}
+Writer::Writer(std::vector<uint8_t>* cbor) : encoded_cbor_(cbor) {}
 
-bool CBORWriter::EncodeCBOR(const CBORValue& node, int max_nesting_level) {
+bool Writer::EncodeCBOR(const Value& node, int max_nesting_level) {
   if (max_nesting_level < 0)
     return false;
 
   switch (node.type()) {
-    case CBORValue::Type::NONE: {
-      StartItem(CBORValue::Type::BYTE_STRING, 0);
+    case Value::Type::NONE: {
+      StartItem(Value::Type::BYTE_STRING, 0);
       return true;
     }
 
     // Represents unsigned integers.
-    case CBORValue::Type::UNSIGNED: {
+    case Value::Type::UNSIGNED: {
       int64_t value = node.GetUnsigned();
-      StartItem(CBORValue::Type::UNSIGNED, static_cast<uint64_t>(value));
+      StartItem(Value::Type::UNSIGNED, static_cast<uint64_t>(value));
       return true;
     }
 
     // Represents negative integers.
-    case CBORValue::Type::NEGATIVE: {
+    case Value::Type::NEGATIVE: {
       int64_t value = node.GetNegative();
-      StartItem(CBORValue::Type::NEGATIVE, static_cast<uint64_t>(-(value + 1)));
+      StartItem(Value::Type::NEGATIVE, static_cast<uint64_t>(-(value + 1)));
       return true;
     }
 
     // Represents a byte string.
-    case CBORValue::Type::BYTE_STRING: {
-      const CBORValue::BinaryValue& bytes = node.GetBytestring();
-      StartItem(CBORValue::Type::BYTE_STRING,
+    case Value::Type::BYTE_STRING: {
+      const Value::BinaryValue& bytes = node.GetBytestring();
+      StartItem(Value::Type::BYTE_STRING,
                 base::strict_cast<uint64_t>(bytes.size()));
       // Add the bytes.
       encoded_cbor_->insert(encoded_cbor_->end(), bytes.begin(), bytes.end());
       return true;
     }
 
-    case CBORValue::Type::STRING: {
+    case Value::Type::STRING: {
       base::StringPiece string = node.GetString();
-      StartItem(CBORValue::Type::STRING,
+      StartItem(Value::Type::STRING,
                 base::strict_cast<uint64_t>(string.size()));
 
       // Add the characters.
@@ -72,9 +71,9 @@
     }
 
     // Represents an array.
-    case CBORValue::Type::ARRAY: {
-      const CBORValue::ArrayValue& array = node.GetArray();
-      StartItem(CBORValue::Type::ARRAY, array.size());
+    case Value::Type::ARRAY: {
+      const Value::ArrayValue& array = node.GetArray();
+      StartItem(Value::Type::ARRAY, array.size());
       for (const auto& value : array) {
         if (!EncodeCBOR(value, max_nesting_level - 1))
           return false;
@@ -83,9 +82,9 @@
     }
 
     // Represents a map.
-    case CBORValue::Type::MAP: {
-      const CBORValue::MapValue& map = node.GetMap();
-      StartItem(CBORValue::Type::MAP, map.size());
+    case Value::Type::MAP: {
+      const Value::MapValue& map = node.GetMap();
+      StartItem(Value::Type::MAP, map.size());
 
       for (const auto& value : map) {
         if (!EncodeCBOR(value.first, max_nesting_level - 1))
@@ -96,14 +95,14 @@
       return true;
     }
 
-    case CBORValue::Type::TAG:
+    case Value::Type::TAG:
       NOTREACHED() << constants::kUnsupportedMajorType;
       return false;
 
     // Represents a simple value.
-    case CBORValue::Type::SIMPLE_VALUE: {
-      const CBORValue::SimpleValue simple_value = node.GetSimpleValue();
-      StartItem(CBORValue::Type::SIMPLE_VALUE,
+    case Value::Type::SIMPLE_VALUE: {
+      const Value::SimpleValue simple_value = node.GetSimpleValue();
+      StartItem(Value::Type::SIMPLE_VALUE,
                 base::checked_cast<uint64_t>(simple_value));
       return true;
     }
@@ -115,13 +114,13 @@
   return false;
 }
 
-void CBORWriter::StartItem(CBORValue::Type type, uint64_t size) {
+void Writer::StartItem(Value::Type type, uint64_t size) {
   encoded_cbor_->push_back(base::checked_cast<uint8_t>(
       static_cast<unsigned>(type) << constants::kMajorTypeBitShift));
   SetUint(size);
 }
 
-void CBORWriter::SetAdditionalInformation(uint8_t additional_information) {
+void Writer::SetAdditionalInformation(uint8_t additional_information) {
   DCHECK(!encoded_cbor_->empty());
   DCHECK_EQ(additional_information & constants::kAdditionalInformationMask,
             additional_information);
@@ -129,7 +128,7 @@
       (additional_information & constants::kAdditionalInformationMask);
 }
 
-void CBORWriter::SetUint(uint64_t value) {
+void Writer::SetUint(uint64_t value) {
   size_t count = GetNumUintBytes(value);
   int shift = -1;
   // Values under 24 are encoded directly in the initial byte.
@@ -164,7 +163,7 @@
   }
 }
 
-size_t CBORWriter::GetNumUintBytes(uint64_t value) {
+size_t Writer::GetNumUintBytes(uint64_t value) {
   if (value < 24) {
     return 0;
   } else if (value <= 0xFF) {
diff --git a/components/cbor/cbor_writer.h b/components/cbor/cbor_writer.h
index 89e24da..0515adbd 100644
--- a/components/cbor/cbor_writer.h
+++ b/components/cbor/cbor_writer.h
@@ -47,37 +47,37 @@
 //  3) Indefinite length items must be converted to definite length items.
 //  4) All maps must not have duplicate keys.
 //
-// Current implementation of CBORWriter encoder meets all the requirements of
+// Current implementation of Writer encoder meets all the requirements of
 // canonical CBOR.
 
 namespace cbor {
 
-class CBOR_EXPORT CBORWriter {
+class CBOR_EXPORT Writer {
  public:
   // Default that should be sufficiently large for most use cases.
   static constexpr size_t kDefaultMaxNestingDepth = 16;
 
-  ~CBORWriter();
+  ~Writer();
 
   // Returns the CBOR byte string representation of |node|, unless its nesting
   // depth is greater than |max_nesting_depth|, in which case an empty optional
   // value is returned. The nesting depth of |node| is defined as the number of
-  // arrays/maps that has to be traversed to reach the most nested CBORValue
+  // arrays/maps that has to be traversed to reach the most nested Value
   // contained in |node|. Primitive values and empty containers have nesting
   // depths of 0.
   static base::Optional<std::vector<uint8_t>> Write(
-      const CBORValue& node,
+      const Value& node,
       size_t max_nesting_level = kDefaultMaxNestingDepth);
 
  private:
-  explicit CBORWriter(std::vector<uint8_t>* cbor);
+  explicit Writer(std::vector<uint8_t>* cbor);
 
   // Called recursively to build the CBOR bytestring. When completed,
   // |encoded_cbor_| will contain the CBOR.
-  bool EncodeCBOR(const CBORValue& node, int max_nesting_level);
+  bool EncodeCBOR(const Value& node, int max_nesting_level);
 
   // Encodes the type and size of the data being added.
-  void StartItem(CBORValue::Type type, uint64_t size);
+  void StartItem(Value::Type type, uint64_t size);
 
   // Encodes the additional information for the data.
   void SetAdditionalInformation(uint8_t additional_information);
@@ -92,7 +92,7 @@
   // Holds the encoded CBOR data.
   std::vector<uint8_t>* encoded_cbor_;
 
-  DISALLOW_COPY_AND_ASSIGN(CBORWriter);
+  DISALLOW_COPY_AND_ASSIGN(Writer);
 };
 
 }  // namespace cbor
diff --git a/components/cbor/cbor_writer_unittest.cc b/components/cbor/cbor_writer_unittest.cc
index 955a19b..3067aad 100644
--- a/components/cbor/cbor_writer_unittest.cc
+++ b/components/cbor/cbor_writer_unittest.cc
@@ -39,7 +39,7 @@
        base::StringPiece("\x1b\x7f\xff\xff\xff\xff\xff\xff\xff")}};
 
   for (const UintTestCase& test_case : kUintTestCases) {
-    auto cbor = CBORWriter::Write(CBORValue(test_case.value));
+    auto cbor = Writer::Write(Value(test_case.value));
     ASSERT_TRUE(cbor.has_value());
     EXPECT_THAT(cbor.value(), testing::ElementsAreArray(test_case.cbor));
   }
@@ -68,7 +68,7 @@
     SCOPED_TRACE(testing::Message() << "testing  negative int at index: "
                                     << test_case.negative_int);
 
-    auto cbor = CBORWriter::Write(CBORValue(test_case.negative_int));
+    auto cbor = Writer::Write(Value(test_case.negative_int));
     ASSERT_TRUE(cbor.has_value());
     EXPECT_THAT(cbor.value(), testing::ElementsAreArray(test_case.cbor));
   }
@@ -86,7 +86,7 @@
   };
 
   for (const BytesTestCase& test_case : kBytesTestCases) {
-    auto cbor = CBORWriter::Write(CBORValue(test_case.bytes));
+    auto cbor = Writer::Write(Value(test_case.bytes));
     ASSERT_TRUE(cbor.has_value());
     EXPECT_THAT(cbor.value(), testing::ElementsAreArray(test_case.cbor));
   }
@@ -111,7 +111,7 @@
     SCOPED_TRACE(testing::Message()
                  << "testing encoding string : " << test_case.string);
 
-    auto cbor = CBORWriter::Write(CBORValue(test_case.string));
+    auto cbor = Writer::Write(Value(test_case.string));
     ASSERT_TRUE(cbor.has_value());
     EXPECT_THAT(cbor.value(), testing::ElementsAreArray(test_case.cbor));
   }
@@ -126,11 +126,11 @@
         0x18, 0x18, 0x19,
       // clang-format on
   };
-  std::vector<CBORValue> array;
+  std::vector<Value> array;
   for (int64_t i = 1; i <= 25; i++) {
-    array.push_back(CBORValue(i));
+    array.push_back(Value(i));
   }
-  auto cbor = CBORWriter::Write(CBORValue(array));
+  auto cbor = Writer::Write(Value(array));
   ASSERT_TRUE(cbor.has_value());
   EXPECT_THAT(cbor.value(),
               testing::ElementsAreArray(kArrayTestCaseCbor,
@@ -221,42 +221,41 @@
         0x62, 0x41, 0x41,  // value "AA"
       // clang-format on
   };
-  CBORValue::MapValue map;
+  Value::MapValue map;
   // Shorter strings sort first in CTAP, thus the “aa” value should be
   // serialised last in the map.
-  map[CBORValue("aa")] = CBORValue("AA");
-  map[CBORValue("e")] = CBORValue("E");
+  map[Value("aa")] = Value("AA");
+  map[Value("e")] = Value("E");
   // The empty string is shorter than all others, so should appear first among
   // the strings.
-  map[CBORValue("")] = CBORValue(".");
+  map[Value("")] = Value(".");
   // Map keys are sorted by major type, by byte length, and then by
   // byte-wise lexical order. So all integer type keys should appear before
   // key "" and all positive integer keys should appear before negative integer
   // keys.
-  map[CBORValue(-1)] = CBORValue("k");
-  map[CBORValue(-24)] = CBORValue("l");
-  map[CBORValue(-25)] = CBORValue("m");
-  map[CBORValue(-256)] = CBORValue("n");
-  map[CBORValue(-257)] = CBORValue("o");
-  map[CBORValue(-65537)] = CBORValue("p");
-  map[CBORValue(int64_t(-4294967296))] = CBORValue("q");
-  map[CBORValue(int64_t(-4294967297))] = CBORValue("r");
-  map[CBORValue(std::numeric_limits<int64_t>::min())] = CBORValue("s");
-  map[CBORValue(CBORValue::BinaryValue{'a'})] = CBORValue(2);
-  map[CBORValue(CBORValue::BinaryValue{'b', 'a', 'r'})] = CBORValue(3);
-  map[CBORValue(CBORValue::BinaryValue{'f', 'o', 'o'})] = CBORValue(4);
-  map[CBORValue(0)] = CBORValue("a");
-  map[CBORValue(23)] = CBORValue("b");
-  map[CBORValue(24)] = CBORValue("c");
-  map[CBORValue(std::numeric_limits<uint8_t>::max())] = CBORValue("d");
-  map[CBORValue(256)] = CBORValue("e");
-  map[CBORValue(std::numeric_limits<uint16_t>::max())] = CBORValue("f");
-  map[CBORValue(65536)] = CBORValue("g");
-  map[CBORValue(int64_t(std::numeric_limits<uint32_t>::max()))] =
-      CBORValue("h");
-  map[CBORValue(int64_t(4294967296))] = CBORValue("i");
-  map[CBORValue(std::numeric_limits<int64_t>::max())] = CBORValue("j");
-  auto cbor = CBORWriter::Write(CBORValue(map));
+  map[Value(-1)] = Value("k");
+  map[Value(-24)] = Value("l");
+  map[Value(-25)] = Value("m");
+  map[Value(-256)] = Value("n");
+  map[Value(-257)] = Value("o");
+  map[Value(-65537)] = Value("p");
+  map[Value(int64_t(-4294967296))] = Value("q");
+  map[Value(int64_t(-4294967297))] = Value("r");
+  map[Value(std::numeric_limits<int64_t>::min())] = Value("s");
+  map[Value(Value::BinaryValue{'a'})] = Value(2);
+  map[Value(Value::BinaryValue{'b', 'a', 'r'})] = Value(3);
+  map[Value(Value::BinaryValue{'f', 'o', 'o'})] = Value(4);
+  map[Value(0)] = Value("a");
+  map[Value(23)] = Value("b");
+  map[Value(24)] = Value("c");
+  map[Value(std::numeric_limits<uint8_t>::max())] = Value("d");
+  map[Value(256)] = Value("e");
+  map[Value(std::numeric_limits<uint16_t>::max())] = Value("f");
+  map[Value(65536)] = Value("g");
+  map[Value(int64_t(std::numeric_limits<uint32_t>::max()))] = Value("h");
+  map[Value(int64_t(4294967296))] = Value("i");
+  map[Value(std::numeric_limits<int64_t>::max())] = Value("j");
+  auto cbor = Writer::Write(Value(map));
   ASSERT_TRUE(cbor.has_value());
   EXPECT_THAT(cbor.value(), testing::ElementsAreArray(
                                 kMapTestCaseCbor, arraysize(kMapTestCaseCbor)));
@@ -275,13 +274,13 @@
           0x03,
       // clang-format on
   };
-  CBORValue::MapValue map;
-  map[CBORValue("a")] = CBORValue(1);
-  CBORValue::ArrayValue array;
-  array.push_back(CBORValue(2));
-  array.push_back(CBORValue(3));
-  map[CBORValue("b")] = CBORValue(array);
-  auto cbor = CBORWriter::Write(CBORValue(map));
+  Value::MapValue map;
+  map[Value("a")] = Value(1);
+  Value::ArrayValue array;
+  array.push_back(Value(2));
+  array.push_back(Value(3));
+  map[Value("b")] = Value(array);
+  auto cbor = Writer::Write(Value(map));
   ASSERT_TRUE(cbor.has_value());
   EXPECT_THAT(cbor.value(),
               testing::ElementsAreArray(kMapArrayTestCaseCbor,
@@ -304,13 +303,13 @@
           0x03,
       // clang-format on
   };
-  CBORValue::MapValue map;
-  map[CBORValue("a")] = CBORValue(1);
-  CBORValue::MapValue nested_map;
-  nested_map[CBORValue("c")] = CBORValue(2);
-  nested_map[CBORValue("d")] = CBORValue(3);
-  map[CBORValue("b")] = CBORValue(nested_map);
-  auto cbor = CBORWriter::Write(CBORValue(map));
+  Value::MapValue map;
+  map[Value("a")] = Value(1);
+  Value::MapValue nested_map;
+  nested_map[Value("c")] = Value(2);
+  nested_map[Value("d")] = Value(3);
+  map[Value("b")] = Value(nested_map);
+  auto cbor = Writer::Write(Value(map));
   ASSERT_TRUE(cbor.has_value());
   EXPECT_THAT(cbor.value(),
               testing::ElementsAreArray(kNestedMapTestCase,
@@ -350,14 +349,14 @@
       */
       // clang-format on
   };
-  CBORValue::MapValue map;
-  map[CBORValue(10)] = CBORValue(1);
-  map[CBORValue(100)] = CBORValue(2);
-  map[CBORValue(-1)] = CBORValue(3);
-  map[CBORValue("z")] = CBORValue(4);
-  map[CBORValue("aa")] = CBORValue(5);
+  Value::MapValue map;
+  map[Value(10)] = Value(1);
+  map[Value(100)] = Value(2);
+  map[Value(-1)] = Value(3);
+  map[Value("z")] = Value(4);
+  map[Value("aa")] = Value(5);
 
-  auto cbor = CBORWriter::Write(CBORValue(map));
+  auto cbor = Writer::Write(Value(map));
   ASSERT_TRUE(cbor.has_value());
   EXPECT_THAT(cbor.value(),
               testing::ElementsAreArray(kSignedExchangeExample,
@@ -366,16 +365,16 @@
 
 TEST(CBORWriterTest, TestWriteSimpleValue) {
   static const struct {
-    CBORValue::SimpleValue simple_value;
+    Value::SimpleValue simple_value;
     const base::StringPiece cbor;
   } kSimpleTestCase[] = {
-      {CBORValue::SimpleValue::FALSE_VALUE, base::StringPiece("\xf4")},
-      {CBORValue::SimpleValue::TRUE_VALUE, base::StringPiece("\xf5")},
-      {CBORValue::SimpleValue::NULL_VALUE, base::StringPiece("\xf6")},
-      {CBORValue::SimpleValue::UNDEFINED, base::StringPiece("\xf7")}};
+      {Value::SimpleValue::FALSE_VALUE, base::StringPiece("\xf4")},
+      {Value::SimpleValue::TRUE_VALUE, base::StringPiece("\xf5")},
+      {Value::SimpleValue::NULL_VALUE, base::StringPiece("\xf6")},
+      {Value::SimpleValue::UNDEFINED, base::StringPiece("\xf7")}};
 
   for (const auto& test_case : kSimpleTestCase) {
-    auto cbor = CBORWriter::Write(CBORValue(test_case.simple_value));
+    auto cbor = Writer::Write(Value(test_case.simple_value));
     ASSERT_TRUE(cbor.has_value());
     EXPECT_THAT(cbor.value(), testing::ElementsAreArray(test_case.cbor));
   }
@@ -385,33 +384,33 @@
 // depth is expected to be 0 since the CBOR decoder does not need to parse
 // any nested CBOR value elements.
 TEST(CBORWriterTest, TestWriteSingleLayer) {
-  const CBORValue simple_uint = CBORValue(1);
-  const CBORValue simple_string = CBORValue("a");
+  const Value simple_uint = Value(1);
+  const Value simple_string = Value("a");
   const std::vector<uint8_t> byte_data = {0x01, 0x02, 0x03, 0x04};
-  const CBORValue simple_bytestring = CBORValue(byte_data);
-  CBORValue::ArrayValue empty_cbor_array;
-  CBORValue::MapValue empty_cbor_map;
-  const CBORValue empty_array_value = CBORValue(empty_cbor_array);
-  const CBORValue empty_map_value = CBORValue(empty_cbor_map);
-  CBORValue::ArrayValue simple_array;
-  simple_array.push_back(CBORValue(2));
-  CBORValue::MapValue simple_map;
-  simple_map[CBORValue("b")] = CBORValue(3);
-  const CBORValue single_layer_cbor_map = CBORValue(simple_map);
-  const CBORValue single_layer_cbor_array = CBORValue(simple_array);
+  const Value simple_bytestring = Value(byte_data);
+  Value::ArrayValue empty_cbor_array;
+  Value::MapValue empty_cbor_map;
+  const Value empty_array_value = Value(empty_cbor_array);
+  const Value empty_map_value = Value(empty_cbor_map);
+  Value::ArrayValue simple_array;
+  simple_array.push_back(Value(2));
+  Value::MapValue simple_map;
+  simple_map[Value("b")] = Value(3);
+  const Value single_layer_cbor_map = Value(simple_map);
+  const Value single_layer_cbor_array = Value(simple_array);
 
-  EXPECT_TRUE(CBORWriter::Write(simple_uint, 0).has_value());
-  EXPECT_TRUE(CBORWriter::Write(simple_string, 0).has_value());
-  EXPECT_TRUE(CBORWriter::Write(simple_bytestring, 0).has_value());
+  EXPECT_TRUE(Writer::Write(simple_uint, 0).has_value());
+  EXPECT_TRUE(Writer::Write(simple_string, 0).has_value());
+  EXPECT_TRUE(Writer::Write(simple_bytestring, 0).has_value());
 
-  EXPECT_TRUE(CBORWriter::Write(empty_array_value, 0).has_value());
-  EXPECT_TRUE(CBORWriter::Write(empty_map_value, 0).has_value());
+  EXPECT_TRUE(Writer::Write(empty_array_value, 0).has_value());
+  EXPECT_TRUE(Writer::Write(empty_map_value, 0).has_value());
 
-  EXPECT_FALSE(CBORWriter::Write(single_layer_cbor_array, 0).has_value());
-  EXPECT_TRUE(CBORWriter::Write(single_layer_cbor_array, 1).has_value());
+  EXPECT_FALSE(Writer::Write(single_layer_cbor_array, 0).has_value());
+  EXPECT_TRUE(Writer::Write(single_layer_cbor_array, 1).has_value());
 
-  EXPECT_FALSE(CBORWriter::Write(single_layer_cbor_map, 0).has_value());
-  EXPECT_TRUE(CBORWriter::Write(single_layer_cbor_map, 1).has_value());
+  EXPECT_FALSE(Writer::Write(single_layer_cbor_map, 0).has_value());
+  EXPECT_TRUE(Writer::Write(single_layer_cbor_map, 1).has_value());
 }
 
 // Major type 5 nested CBOR map value with following structure.
@@ -419,14 +418,14 @@
 //      "b": {"c": 2,
 //            "d": 3}}
 TEST(CBORWriterTest, NestedMaps) {
-  CBORValue::MapValue cbor_map;
-  cbor_map[CBORValue("a")] = CBORValue(1);
-  CBORValue::MapValue nested_map;
-  nested_map[CBORValue("c")] = CBORValue(2);
-  nested_map[CBORValue("d")] = CBORValue(3);
-  cbor_map[CBORValue("b")] = CBORValue(nested_map);
-  EXPECT_TRUE(CBORWriter::Write(CBORValue(cbor_map), 2).has_value());
-  EXPECT_FALSE(CBORWriter::Write(CBORValue(cbor_map), 1).has_value());
+  Value::MapValue cbor_map;
+  cbor_map[Value("a")] = Value(1);
+  Value::MapValue nested_map;
+  nested_map[Value("c")] = Value(2);
+  nested_map[Value("d")] = Value(3);
+  cbor_map[Value("b")] = Value(nested_map);
+  EXPECT_TRUE(Writer::Write(Value(cbor_map), 2).has_value());
+  EXPECT_FALSE(Writer::Write(Value(cbor_map), 1).has_value());
 }
 
 // Testing Write() function for following CBOR structure with depth of 3.
@@ -437,21 +436,21 @@
 //       "b": {"c": 2,
 //             "d": 3}}]
 TEST(CBORWriterTest, UnbalancedNestedContainers) {
-  CBORValue::ArrayValue cbor_array;
-  CBORValue::MapValue cbor_map;
-  CBORValue::MapValue nested_map;
+  Value::ArrayValue cbor_array;
+  Value::MapValue cbor_map;
+  Value::MapValue nested_map;
 
-  cbor_map[CBORValue("a")] = CBORValue(1);
-  nested_map[CBORValue("c")] = CBORValue(2);
-  nested_map[CBORValue("d")] = CBORValue(3);
-  cbor_map[CBORValue("b")] = CBORValue(nested_map);
-  cbor_array.push_back(CBORValue(1));
-  cbor_array.push_back(CBORValue(2));
-  cbor_array.push_back(CBORValue(3));
-  cbor_array.push_back(CBORValue(cbor_map));
+  cbor_map[Value("a")] = Value(1);
+  nested_map[Value("c")] = Value(2);
+  nested_map[Value("d")] = Value(3);
+  cbor_map[Value("b")] = Value(nested_map);
+  cbor_array.push_back(Value(1));
+  cbor_array.push_back(Value(2));
+  cbor_array.push_back(Value(3));
+  cbor_array.push_back(Value(cbor_map));
 
-  EXPECT_TRUE(CBORWriter::Write(CBORValue(cbor_array), 3).has_value());
-  EXPECT_FALSE(CBORWriter::Write(CBORValue(cbor_array), 2).has_value());
+  EXPECT_TRUE(Writer::Write(Value(cbor_array), 3).has_value());
+  EXPECT_FALSE(Writer::Write(Value(cbor_array), 2).has_value());
 }
 
 // Testing Write() function for following CBOR structure.
@@ -464,27 +463,27 @@
 // Since above CBOR contains 5 nesting levels. Thus, Write() is expected to
 // return empty optional object when maximum nesting layer size is set to 4.
 TEST(CBORWriterTest, OverlyNestedCBOR) {
-  CBORValue::MapValue map;
-  CBORValue::MapValue nested_map;
-  CBORValue::MapValue inner_nested_map;
-  CBORValue::ArrayValue inner_array;
-  CBORValue::ArrayValue array;
+  Value::MapValue map;
+  Value::MapValue nested_map;
+  Value::MapValue inner_nested_map;
+  Value::ArrayValue inner_array;
+  Value::ArrayValue array;
 
-  map[CBORValue("a")] = CBORValue(1);
-  nested_map[CBORValue("c")] = CBORValue(2);
-  nested_map[CBORValue("d")] = CBORValue(3);
-  inner_nested_map[CBORValue("e")] = CBORValue(4);
-  inner_nested_map[CBORValue("f")] = CBORValue(5);
-  inner_array.push_back(CBORValue(6));
-  array.push_back(CBORValue(6));
-  array.push_back(CBORValue(7));
-  array.push_back(CBORValue(inner_array));
-  inner_nested_map[CBORValue("g")] = CBORValue(array);
-  nested_map[CBORValue("h")] = CBORValue(inner_nested_map);
-  map[CBORValue("b")] = CBORValue(nested_map);
+  map[Value("a")] = Value(1);
+  nested_map[Value("c")] = Value(2);
+  nested_map[Value("d")] = Value(3);
+  inner_nested_map[Value("e")] = Value(4);
+  inner_nested_map[Value("f")] = Value(5);
+  inner_array.push_back(Value(6));
+  array.push_back(Value(6));
+  array.push_back(Value(7));
+  array.push_back(Value(inner_array));
+  inner_nested_map[Value("g")] = Value(array);
+  nested_map[Value("h")] = Value(inner_nested_map);
+  map[Value("b")] = Value(nested_map);
 
-  EXPECT_TRUE(CBORWriter::Write(CBORValue(map), 5).has_value());
-  EXPECT_FALSE(CBORWriter::Write(CBORValue(map), 4).has_value());
+  EXPECT_TRUE(Writer::Write(Value(map), 5).has_value());
+  EXPECT_FALSE(Writer::Write(Value(map), 4).has_value());
 }
 
 }  // namespace cbor
diff --git a/components/cronet/BUILD.gn b/components/cronet/BUILD.gn
index 1ab35fc..1c2feff 100644
--- a/components/cronet/BUILD.gn
+++ b/components/cronet/BUILD.gn
@@ -137,7 +137,7 @@
     if (is_mac && !is_component_build) {
       ldflags = [
         "-install_name",
-        "@rpath/$_cronet_shared_lib_file_name",
+        "@executable_path/$_cronet_shared_lib_file_name",
       ]
       public_configs = [ ":shared_library_public_config" ]
     }
diff --git a/components/exo/buffer.cc b/components/exo/buffer.cc
index 146019d..ef4bd74b 100644
--- a/components/exo/buffer.cc
+++ b/components/exo/buffer.cc
@@ -19,7 +19,7 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "base/trace_event/trace_event.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "components/exo/layer_tree_frame_sink_holder.h"
 #include "components/exo/wm_helper.h"
 #include "components/viz/common/gpu/context_provider.h"
diff --git a/components/exo/client_controlled_shell_surface.cc b/components/exo/client_controlled_shell_surface.cc
index 17a5d0f..f1a0b442 100644
--- a/components/exo/client_controlled_shell_surface.cc
+++ b/components/exo/client_controlled_shell_surface.cc
@@ -30,7 +30,7 @@
 #include "base/no_destructor.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/trace_event/trace_event.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "components/exo/surface.h"
 #include "components/exo/wm_helper.h"
 #include "services/ws/public/mojom/window_tree_constants.mojom.h"
@@ -761,7 +761,14 @@
     preserve_widget_bounds_ = false;
   }
 
-  if (bounds == widget_->GetWindowBoundsInScreen() &&
+  // Calculate a minimum window visibility required bounds.
+  gfx::Rect adjusted_bounds = bounds;
+  if (!is_display_move_pending) {
+    ash::wm::ClientControlledState::AdjustBoundsForMinimumWindowVisibility(
+        target_display.bounds(), &adjusted_bounds);
+  }
+
+  if (adjusted_bounds == widget_->GetWindowBoundsInScreen() &&
       target_display.id() == current_display.id()) {
     return;
   }
@@ -778,19 +785,12 @@
     // Move the window relative to the current display.
     {
       ScopedSetBoundsLocally scoped_set_bounds(this);
-      window->SetBounds(gfx::Rect(origin, bounds.size()));
+      window->SetBounds(gfx::Rect(origin, adjusted_bounds.size()));
     }
     UpdateSurfaceBounds();
     return;
   }
 
-  // Calculate a minimum window visibility required bounds.
-  gfx::Rect adjusted_bounds = bounds;
-  if (!is_display_move_pending) {
-    ash::wm::ClientControlledState::AdjustBoundsForMinimumWindowVisibility(
-        target_display.bounds(), &adjusted_bounds);
-  }
-
   {
     ScopedSetBoundsLocally scoped_set_bounds(this);
     window->SetBoundsInScreen(adjusted_bounds, target_display);
diff --git a/components/exo/client_controlled_shell_surface_unittest.cc b/components/exo/client_controlled_shell_surface_unittest.cc
index 7c7371b..f9d6b78 100644
--- a/components/exo/client_controlled_shell_surface_unittest.cc
+++ b/components/exo/client_controlled_shell_surface_unittest.cc
@@ -1768,6 +1768,13 @@
   views::Widget* widget = shell_surface->GetWidget();
   EXPECT_EQ(gfx::Rect(774, 0, 200, 300), widget->GetWindowBoundsInScreen());
   EXPECT_EQ(gfx::Rect(774, 0, 200, 300), requested_bounds);
+
+  // Receiving the same bounds shouldn't try to update the bounds again.
+  requested_bounds.SetRect(0, 0, 0, 0);
+  shell_surface->SetGeometry(client_bounds);
+  surface->Commit();
+
+  EXPECT_TRUE(requested_bounds.IsEmpty());
 }
 
 TEST_F(ClientControlledShellSurfaceTest, SnappedInTabletMode) {
diff --git a/components/exo/display.cc b/components/exo/display.cc
index e4ad484a6..9910b46 100644
--- a/components/exo/display.cc
+++ b/components/exo/display.cc
@@ -11,7 +11,7 @@
 #include "base/command_line.h"
 #include "base/memory/ptr_util.h"
 #include "base/trace_event/trace_event.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "components/exo/client_controlled_shell_surface.h"
 #include "components/exo/data_device.h"
 #include "components/exo/file_helper.h"
diff --git a/components/exo/shell_surface_base.cc b/components/exo/shell_surface_base.cc
index 1c4ccb726..813dc3d 100644
--- a/components/exo/shell_surface_base.cc
+++ b/components/exo/shell_surface_base.cc
@@ -23,7 +23,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/trace_event/trace_event.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "cc/trees/layer_tree_frame_sink.h"
 #include "components/exo/surface.h"
 #include "components/exo/wm_helper.h"
diff --git a/components/exo/sub_surface.cc b/components/exo/sub_surface.cc
index 27592e5..b18beb31 100644
--- a/components/exo/sub_surface.cc
+++ b/components/exo/sub_surface.cc
@@ -6,7 +6,7 @@
 
 #include "base/logging.h"
 #include "base/trace_event/trace_event.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "components/exo/surface.h"
 
 namespace exo {
diff --git a/components/exo/surface.cc b/components/exo/surface.cc
index bb37435..504698a 100644
--- a/components/exo/surface.cc
+++ b/components/exo/surface.cc
@@ -12,7 +12,7 @@
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "base/trace_event/trace_event.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "cc/trees/layer_tree_frame_sink.h"
 #include "components/exo/buffer.h"
 #include "components/exo/pointer.h"
diff --git a/components/feed/core/feed_networking_host.cc b/components/feed/core/feed_networking_host.cc
index b4cf841..9e92198 100644
--- a/components/feed/core/feed_networking_host.cc
+++ b/components/feed/core/feed_networking_host.cc
@@ -107,7 +107,7 @@
 }
 
 void NetworkFetch::StartAccessTokenFetch() {
-  OAuth2TokenService::ScopeSet scopes{kAuthenticationScope};
+  identity::ScopeSet scopes{kAuthenticationScope};
   // It's safe to pass base::Unretained(this) since deleting the token fetcher
   // will prevent the callback from being completed.
   token_fetcher_ = std::make_unique<identity::PrimaryAccountAccessTokenFetcher>(
@@ -231,7 +231,7 @@
     status_code = simple_loader_->ResponseInfo()->headers->response_code();
 
     if (status_code == net::HTTP_UNAUTHORIZED) {
-      OAuth2TokenService::ScopeSet scopes{kAuthenticationScope};
+      identity::ScopeSet scopes{kAuthenticationScope};
       std::string account_id = identity_manager_->GetPrimaryAccountId();
       identity_manager_->RemoveAccessTokenFromCache(account_id, scopes,
                                                     access_token_);
diff --git a/components/gcm_driver/account_tracker.cc b/components/gcm_driver/account_tracker.cc
index 61d3ddd..a03b387 100644
--- a/components/gcm_driver/account_tracker.cc
+++ b/components/gcm_driver/account_tracker.cc
@@ -219,7 +219,7 @@
 }
 
 void AccountIdFetcher::Start() {
-  OAuth2TokenService::ScopeSet scopes;
+  identity::ScopeSet scopes;
   scopes.insert("https://www.googleapis.com/auth/userinfo.profile");
   access_token_fetcher_ = identity_manager_->CreateAccessTokenFetcherForAccount(
       account_key_, "gaia_account_tracker", scopes,
diff --git a/components/gcm_driver/android/BUILD.gn b/components/gcm_driver/android/BUILD.gn
index b9d9560..ee733919 100644
--- a/components/gcm_driver/android/BUILD.gn
+++ b/components/gcm_driver/android/BUILD.gn
@@ -14,7 +14,6 @@
 android_library("gcm_driver_java") {
   deps = [
     "//base:base_java",
-    "//components/gcm_driver/instance_id/android:instance_id_driver_java",
     "//content/public/android:content_java",
     "//third_party/android_tools:android_gcm_java",
     "//third_party/jsr-305:jsr_305_javalib",
@@ -25,13 +24,14 @@
     "java/src/org/chromium/components/gcm_driver/GCMMessage.java",
     "java/src/org/chromium/components/gcm_driver/GoogleCloudMessagingSubscriber.java",
     "java/src/org/chromium/components/gcm_driver/GoogleCloudMessagingV2.java",
+    "java/src/org/chromium/components/gcm_driver/LazySubscriptionsManager.java",
   ]
 }
 
 junit_binary("components_gcm_driver_junit_tests") {
   java_files = [
     "junit/src/org/chromium/components/gcm_driver/GCMMessageTest.java",
-    "junit/src/org/chromium/components/gcm_driver/GCMDriverTest.java",
+    "junit/src/org/chromium/components/gcm_driver/LazySubscriptionsManagerTest.java",
   ]
   deps = [
     ":gcm_driver_java",
diff --git a/components/gcm_driver/android/java/src/org/chromium/components/gcm_driver/GCMDriver.java b/components/gcm_driver/android/java/src/org/chromium/components/gcm_driver/GCMDriver.java
index 6513ec6..00219cd 100644
--- a/components/gcm_driver/android/java/src/org/chromium/components/gcm_driver/GCMDriver.java
+++ b/components/gcm_driver/android/java/src/org/chromium/components/gcm_driver/GCMDriver.java
@@ -4,25 +4,14 @@
 
 package org.chromium.components.gcm_driver;
 
-import android.content.Context;
-import android.content.SharedPreferences;
-
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import org.chromium.base.ContextUtils;
 import org.chromium.base.Log;
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.VisibleForTesting;
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.base.task.AsyncTask;
-import org.chromium.components.gcm_driver.instance_id.InstanceIDBridge;
 
 import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
 
 /**
  * This class is the Java counterpart to the C++ GCMDriverAndroid class.
@@ -34,10 +23,6 @@
 @JNINamespace("gcm")
 public class GCMDriver {
     private static final String TAG = "GCMDriver";
-    // The max number of most recent messages queued per lazy subscription until
-    // Chrome is foregrounded.
-    @VisibleForTesting
-    public static final int MESSAGES_QUEUE_SIZE = 3;
 
     // The instance of GCMDriver currently owned by a C++ GCMDriverAndroid, if any.
     private static GCMDriver sInstance;
@@ -135,118 +120,6 @@
                 message.getDataKeysAndValuesArray());
     }
 
-    /**
-     * Stores |message| on disk. Stored Messages for a subscription id will be
-     * returned by readMessages(). Only the most recent |MESSAGES_QUEUE_SIZE|
-     * messages with distinct collapse keys are kept.
-     * @param subscriptionId id of the subscription.
-     * @param message The message to be persisted.
-     */
-    public static void persistMessage(String subscriptionId, GCMMessage message) {
-        // Messages are stored as a JSONArray in SharedPreferences. The key is
-        // |subscriptionId|. The value is a string representing a JSONArray that
-        // contains messages serialized as a JSONObject.
-
-        // Load the persisted messages for this subscription.
-        Context context = ContextUtils.getApplicationContext();
-        SharedPreferences sharedPrefs =
-                context.getSharedPreferences(InstanceIDBridge.PREF_PACKAGE, Context.MODE_PRIVATE);
-        // Default is an empty queue if no messages are queued for this subscription.
-        String queueString = sharedPrefs.getString(subscriptionId, "[]");
-        try {
-            JSONArray queueJSON = new JSONArray(queueString);
-            if (message.getCollapseKey() != null) {
-                queueJSON = filterMessageBasedOnCollapseKey(queueJSON, message.getCollapseKey());
-            }
-            // TODO(https://crbug.com/882887):Add UMA to record how many
-            // messages are currently in the queue, to identify how often we hit
-            // the limit.
-
-            // If the queue is full remove the oldest message.
-            if (queueJSON.length() == MESSAGES_QUEUE_SIZE) {
-                Log.w(TAG,
-                        "Dropping GCM Message due queue size limit. Sender id:"
-                                + GCMMessage.peekSenderId(queueJSON.getJSONObject(0)));
-                JSONArray newQueue = new JSONArray();
-                // Copy all messages except the first one.
-                for (int i = 1; i < MESSAGES_QUEUE_SIZE; i++) {
-                    newQueue.put(queueJSON.get(i));
-                }
-                queueJSON = newQueue;
-            }
-            // Add the new message to the end.
-            queueJSON.put(message.toJSON());
-            sharedPrefs.edit().putString(subscriptionId, queueJSON.toString()).apply();
-        } catch (JSONException e) {
-            Log.e(TAG,
-                    "Error when parsing the persisted message queue for subscriber:"
-                            + subscriptionId + ":" + e.getMessage());
-        }
-    }
-
-    /**
-     * Filters our any messages in |messagesJSON| with the given collpase key. It returns the
-     * filtered list.
-     */
-    private static JSONArray filterMessageBasedOnCollapseKey(JSONArray messages, String collapseKey)
-            throws JSONException {
-        JSONArray filteredMessages = new JSONArray();
-        for (int i = 0; i < messages.length(); i++) {
-            JSONObject message = messages.getJSONObject(i);
-            if (GCMMessage.peekCollapseKey(message).equals(collapseKey)) {
-                Log.i(TAG,
-                        "Dropping GCM Message due to collapse key collision. Sender id:"
-                                + GCMMessage.peekSenderId(message));
-                continue;
-            }
-            filteredMessages.put(message);
-        }
-        return filteredMessages;
-    }
-
-    /**
-     *  Reads messages stored using persistMessage() for |subscriptionId|. No
-     *  more than |MESSAGES_QUEUE_SIZE| are returned.
-     *  @param subscriptionId The subscription id of the stored messages.
-     *  @return The messages stored. Returns an empty list in case of failure.
-     */
-    public static GCMMessage[] readMessages(String subscriptionId) {
-        // TODO(https://crbug.com/882887): Make sure to delete subscription
-        // information when the token goes.
-        Context context = ContextUtils.getApplicationContext();
-        SharedPreferences sharedPrefs =
-                context.getSharedPreferences(InstanceIDBridge.PREF_PACKAGE, Context.MODE_PRIVATE);
-
-        // Default is an empty queue if no messages are queued for this subscription.
-        String queueString = sharedPrefs.getString(subscriptionId, "[]");
-        try {
-            JSONArray queueJSON = new JSONArray(queueString);
-            List<GCMMessage> messages = new ArrayList<>();
-            for (int i = 0; i < queueJSON.length(); i++) {
-                try {
-                    GCMMessage persistedMessage =
-                            GCMMessage.createFromJSON(queueJSON.getJSONObject(i));
-                    if (persistedMessage == null) {
-                        Log.e(TAG,
-                                "Persisted GCM Message is invalid. Sender id:"
-                                        + GCMMessage.peekSenderId(queueJSON.getJSONObject(i)));
-                        continue;
-                    }
-                    messages.add(persistedMessage);
-                } catch (JSONException e) {
-                    Log.e(TAG,
-                            "Error when creating a GCMMessage from a JSONObject:" + e.getMessage());
-                }
-            }
-            return messages.toArray(new GCMMessage[messages.size()]);
-        } catch (JSONException e) {
-            Log.e(TAG,
-                    "Error when parsing the persisted message queue for subscriber:"
-                            + subscriptionId);
-        }
-        return new GCMMessage[0];
-    }
-
     @VisibleForTesting
     public static void overrideSubscriberForTesting(GoogleCloudMessagingSubscriber subscriber) {
         assert sInstance != null;
diff --git a/components/gcm_driver/android/java/src/org/chromium/components/gcm_driver/LazySubscriptionsManager.java b/components/gcm_driver/android/java/src/org/chromium/components/gcm_driver/LazySubscriptionsManager.java
new file mode 100644
index 0000000..2603fda
--- /dev/null
+++ b/components/gcm_driver/android/java/src/org/chromium/components/gcm_driver/LazySubscriptionsManager.java
@@ -0,0 +1,195 @@
+// 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.
+
+package org.chromium.components.gcm_driver;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import org.chromium.base.ContextUtils;
+import org.chromium.base.Log;
+import org.chromium.base.VisibleForTesting;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * This class is responsible for managing lazy subscriptions. It provides API to change and query
+ * whether a subscription is lazy, and toto persist and retrieve persisted messages.
+ */
+public class LazySubscriptionsManager {
+    private static final String TAG = "LazySubscriptions";
+    private static final String FCM_LAZY_SUBSCRIPTIONS = "fcm_lazy_subscriptions";
+    private static final String PREF_PACKAGE =
+            "org.chromium.components.gcm_driver.lazy_subscriptions";
+
+    // The max number of most recent messages queued per lazy subscription until
+    // Chrome is foregrounded.
+    @VisibleForTesting
+    public static final int MESSAGES_QUEUE_SIZE = 3;
+
+    // Private constructor because all methods in this class are static, and it
+    // shouldn't be instantiated.
+    private LazySubscriptionsManager() {}
+
+    /**
+     * Given an appId and a senderId, this methods builds a unique identifier for a subscription.
+     * Currently implementation concatenates both senderId and appId.
+     * @param appId
+     * @param senderId
+     * @return The unique identifier for the subscription.
+     */
+    public static String buildSubscriptionUniqueId(final String appId, final String senderId) {
+        return appId + senderId;
+    }
+
+    /**
+     * Stores the information about lazy subscriptions in SharedPreferences.
+     */
+    public static void storeLazinessInformation(final String subscriptionId, boolean isLazy) {
+        if (isLazy) {
+            Context context = ContextUtils.getApplicationContext();
+            SharedPreferences sharedPrefs =
+                    context.getSharedPreferences(PREF_PACKAGE, Context.MODE_PRIVATE);
+            Set<String> lazyIds = new HashSet<>(
+                    sharedPrefs.getStringSet(FCM_LAZY_SUBSCRIPTIONS, Collections.emptySet()));
+            lazyIds.add(subscriptionId);
+            sharedPrefs.edit().putStringSet(FCM_LAZY_SUBSCRIPTIONS, lazyIds).apply();
+        }
+        // TODO(https://crbug.com/882887): Check if that
+        // subscription was marked lazy before and handle the change
+        // accordingly.
+    }
+
+    /**
+     * Returns whether the subscription with the |appId| and |senderId| is lazy.
+     */
+    public static boolean isSubscriptionLazy(final String subscriptionId) {
+        Context context = ContextUtils.getApplicationContext();
+        SharedPreferences sharedPrefs =
+                context.getSharedPreferences(PREF_PACKAGE, Context.MODE_PRIVATE);
+        Set<String> lazyIds = new HashSet<>(
+                sharedPrefs.getStringSet(FCM_LAZY_SUBSCRIPTIONS, Collections.emptySet()));
+        return lazyIds.contains(subscriptionId);
+    }
+
+    /**
+     * Stores |message| on disk. Stored Messages for a subscription id will be
+     * returned by readMessages(). Only the most recent |MESSAGES_QUEUE_SIZE|
+     * messages with distinct collapse keys are kept.
+     * @param subscriptionId id of the subscription.
+     * @param message The message to be persisted.
+     */
+    public static void persistMessage(String subscriptionId, GCMMessage message) {
+        // Messages are stored as a JSONArray in SharedPreferences. The key is
+        // |subscriptionId|. The value is a string representing a JSONArray that
+        // contains messages serialized as a JSONObject.
+
+        // Load the persisted messages for this subscription.
+        Context context = ContextUtils.getApplicationContext();
+        SharedPreferences sharedPrefs =
+                context.getSharedPreferences(PREF_PACKAGE, Context.MODE_PRIVATE);
+        // Default is an empty queue if no messages are queued for this subscription.
+        String queueString = sharedPrefs.getString(subscriptionId, "[]");
+        try {
+            JSONArray queueJSON = new JSONArray(queueString);
+            if (message.getCollapseKey() != null) {
+                queueJSON = filterMessageBasedOnCollapseKey(queueJSON, message.getCollapseKey());
+            }
+            // TODO(https://crbug.com/882887):Add UMA to record how many
+            // messages are currently in the queue, to identify how often we hit
+            // the limit.
+
+            // If the queue is full remove the oldest message.
+            if (queueJSON.length() == MESSAGES_QUEUE_SIZE) {
+                Log.w(TAG,
+                        "Dropping GCM Message due queue size limit. Sender id:"
+                                + GCMMessage.peekSenderId(queueJSON.getJSONObject(0)));
+                JSONArray newQueue = new JSONArray();
+                // Copy all messages except the first one.
+                for (int i = 1; i < MESSAGES_QUEUE_SIZE; i++) {
+                    newQueue.put(queueJSON.get(i));
+                }
+                queueJSON = newQueue;
+            }
+            // Add the new message to the end.
+            queueJSON.put(message.toJSON());
+            sharedPrefs.edit().putString(subscriptionId, queueJSON.toString()).apply();
+        } catch (JSONException e) {
+            Log.e(TAG,
+                    "Error when parsing the persisted message queue for subscriber:"
+                            + subscriptionId + ":" + e.getMessage());
+        }
+    }
+
+    /**
+     *  Reads messages stored using persistMessage() for |subscriptionId|. No
+     *  more than |MESSAGES_QUEUE_SIZE| are returned.
+     *  @param subscriptionId The subscription id of the stored messages.
+     *  @return The messages stored. Returns an empty list in case of failure.
+     */
+    public static GCMMessage[] readMessages(String subscriptionId) {
+        // TODO(https://crbug.com/882887): Make sure to delete subscription
+        // information when the token goes.
+        Context context = ContextUtils.getApplicationContext();
+        SharedPreferences sharedPrefs =
+                context.getSharedPreferences(PREF_PACKAGE, Context.MODE_PRIVATE);
+
+        // Default is an empty queue if no messages are queued for this subscription.
+        String queueString = sharedPrefs.getString(subscriptionId, "[]");
+        try {
+            JSONArray queueJSON = new JSONArray(queueString);
+            List<GCMMessage> messages = new ArrayList<>();
+            for (int i = 0; i < queueJSON.length(); i++) {
+                try {
+                    GCMMessage persistedMessage =
+                            GCMMessage.createFromJSON(queueJSON.getJSONObject(i));
+                    if (persistedMessage == null) {
+                        Log.e(TAG,
+                                "Persisted GCM Message is invalid. Sender id:"
+                                        + GCMMessage.peekSenderId(queueJSON.getJSONObject(i)));
+                        continue;
+                    }
+                    messages.add(persistedMessage);
+                } catch (JSONException e) {
+                    Log.e(TAG,
+                            "Error when creating a GCMMessage from a JSONObject:" + e.getMessage());
+                }
+            }
+            return messages.toArray(new GCMMessage[messages.size()]);
+        } catch (JSONException e) {
+            Log.e(TAG,
+                    "Error when parsing the persisted message queue for subscriber:"
+                            + subscriptionId);
+        }
+        return new GCMMessage[0];
+    }
+
+    /**
+     * Filters our any messages in |messagesJSON| with the given collpase key. It returns the
+     * filtered list.
+     */
+    private static JSONArray filterMessageBasedOnCollapseKey(JSONArray messages, String collapseKey)
+            throws JSONException {
+        JSONArray filteredMessages = new JSONArray();
+        for (int i = 0; i < messages.length(); i++) {
+            JSONObject message = messages.getJSONObject(i);
+            if (GCMMessage.peekCollapseKey(message).equals(collapseKey)) {
+                Log.i(TAG,
+                        "Dropping GCM Message due to collapse key collision. Sender id:"
+                                + GCMMessage.peekSenderId(message));
+                continue;
+            }
+            filteredMessages.put(message);
+        }
+        return filteredMessages;
+    }
+}
diff --git a/components/gcm_driver/android/junit/src/org/chromium/components/gcm_driver/GCMDriverTest.java b/components/gcm_driver/android/junit/src/org/chromium/components/gcm_driver/LazySubscriptionsManagerTest.java
similarity index 61%
rename from components/gcm_driver/android/junit/src/org/chromium/components/gcm_driver/GCMDriverTest.java
rename to components/gcm_driver/android/junit/src/org/chromium/components/gcm_driver/LazySubscriptionsManagerTest.java
index 03a15e8..c84efadf 100644
--- a/components/gcm_driver/android/junit/src/org/chromium/components/gcm_driver/GCMDriverTest.java
+++ b/components/gcm_driver/android/junit/src/org/chromium/components/gcm_driver/LazySubscriptionsManagerTest.java
@@ -6,6 +6,8 @@
 
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
 import android.os.Bundle;
 
@@ -16,11 +18,40 @@
 import org.chromium.base.test.BaseRobolectricTestRunner;
 
 /**
- * Unit tests for GCMDriver.
+ * Unit tests for LazySubscriptionsManager.
  */
 @RunWith(BaseRobolectricTestRunner.class)
 @Config(manifest = Config.NONE)
-public class GCMDriverTest {
+public class LazySubscriptionsManagerTest {
+    /**
+     * Tests that lazy subscriptions are stored.
+     */
+    @Test
+    public void testMarkSubscriptionAsLazy() {
+        final String subscriptionId = "subscription_id";
+        LazySubscriptionsManager.storeLazinessInformation(subscriptionId, true);
+        assertTrue(LazySubscriptionsManager.isSubscriptionLazy(subscriptionId));
+    }
+
+    /**
+     * Tests that unlazy subscriptions are stored.
+     */
+    @Test
+    public void testMarkSubscriptionAsNotLazy() {
+        final String subscriptionId = "subscription_id";
+        LazySubscriptionsManager.storeLazinessInformation(subscriptionId, false);
+        assertFalse(LazySubscriptionsManager.isSubscriptionLazy(subscriptionId));
+    }
+
+    /**
+     * Tests subscriptions are not lazy be default.
+     */
+    @Test
+    public void testDefaultSubscriptionNotLazy() {
+        final String subscriptionId = "subscription_id";
+        assertFalse(LazySubscriptionsManager.isSubscriptionLazy(subscriptionId));
+    }
+
     /**
      * Tests that GCM messages are persisted and read.
      */
@@ -33,13 +64,13 @@
         extras.putString("subtype", "MyAppId");
         extras.putString("collapse_key", "CollapseKey");
         GCMMessage message = new GCMMessage("MySenderId", extras);
-        GCMDriver.persistMessage(subscriptionId, message);
+        LazySubscriptionsManager.persistMessage(subscriptionId, message);
 
-        GCMMessage messages[] = GCMDriver.readMessages(subscriptionId);
+        GCMMessage messages[] = LazySubscriptionsManager.readMessages(subscriptionId);
         assertEquals(1, messages.length);
         assertEquals(message.getSenderId(), messages[0].getSenderId());
 
-        messages = GCMDriver.readMessages(anotherSubscriptionId);
+        messages = LazySubscriptionsManager.readMessages(anotherSubscriptionId);
         assertEquals(0, messages.length);
     }
 
@@ -57,17 +88,18 @@
         final int extraMessagesCount = 5;
 
         // Persist |MESSAGES_QUEUE_SIZE| + |extraMessagesCount| messages.
-        for (int i = 0; i < GCMDriver.MESSAGES_QUEUE_SIZE + extraMessagesCount; i++) {
+        for (int i = 0; i < LazySubscriptionsManager.MESSAGES_QUEUE_SIZE + extraMessagesCount;
+                i++) {
             Bundle extras = new Bundle();
             extras.putString("subtype", "MyAppId");
             extras.putString("collapse_key", collapseKeyPrefix + i);
             GCMMessage message = new GCMMessage("MySenderId", extras);
-            GCMDriver.persistMessage(subscriptionId, message);
+            LazySubscriptionsManager.persistMessage(subscriptionId, message);
         }
         // Check that only the most recent |MESSAGES_QUEUE_SIZE| are persisted.
-        GCMMessage messages[] = GCMDriver.readMessages(subscriptionId);
-        assertEquals(GCMDriver.MESSAGES_QUEUE_SIZE, messages.length);
-        for (int i = 0; i < GCMDriver.MESSAGES_QUEUE_SIZE; i++) {
+        GCMMessage messages[] = LazySubscriptionsManager.readMessages(subscriptionId);
+        assertEquals(LazySubscriptionsManager.MESSAGES_QUEUE_SIZE, messages.length);
+        for (int i = 0; i < LazySubscriptionsManager.MESSAGES_QUEUE_SIZE; i++) {
             assertEquals(
                     collapseKeyPrefix + (i + extraMessagesCount), messages[i].getCollapseKey());
         }
@@ -90,18 +122,18 @@
 
         // Persist a message and make sure it's persisted.
         GCMMessage message1 = new GCMMessage("MySenderId", extras);
-        GCMDriver.persistMessage(subscriptionId, message1);
+        LazySubscriptionsManager.persistMessage(subscriptionId, message1);
 
-        GCMMessage messages[] = GCMDriver.readMessages(subscriptionId);
+        GCMMessage messages[] = LazySubscriptionsManager.readMessages(subscriptionId);
         assertEquals(1, messages.length);
         assertArrayEquals(rawData1, messages[0].getRawData());
 
         // Persist another message with the same collapse key and another raw data.
         extras.putByteArray("rawData", rawData2);
         GCMMessage message2 = new GCMMessage("MySenderId", extras);
-        GCMDriver.persistMessage(subscriptionId, message2);
+        LazySubscriptionsManager.persistMessage(subscriptionId, message2);
 
-        messages = GCMDriver.readMessages(subscriptionId);
+        messages = LazySubscriptionsManager.readMessages(subscriptionId);
         assertEquals(1, messages.length);
         assertArrayEquals(rawData2, messages[0].getRawData());
     }
diff --git a/components/gcm_driver/gcm_account_tracker.cc b/components/gcm_driver/gcm_account_tracker.cc
index b85bfc6..b1bc996 100644
--- a/components/gcm_driver/gcm_account_tracker.cc
+++ b/components/gcm_driver/gcm_account_tracker.cc
@@ -290,7 +290,7 @@
 void GCMAccountTracker::GetToken(AccountInfos::iterator& account_iter) {
   DCHECK_EQ(account_iter->second.state, TOKEN_NEEDED);
 
-  OAuth2TokenService::ScopeSet scopes;
+  identity::ScopeSet scopes;
   scopes.insert(kGCMGroupServerScope);
   scopes.insert(kGCMCheckinServerScope);
 
diff --git a/components/gcm_driver/instance_id/android/BUILD.gn b/components/gcm_driver/instance_id/android/BUILD.gn
index f955ef4..ca773e2f 100644
--- a/components/gcm_driver/instance_id/android/BUILD.gn
+++ b/components/gcm_driver/instance_id/android/BUILD.gn
@@ -22,6 +22,7 @@
   deps = [
     "$google_play_services_package:google_play_services_iid_java",
     "//base:base_java",
+    "//components/gcm_driver/android:gcm_driver_java",
   ]
 
   java_files = [
@@ -39,12 +40,3 @@
 
   java_files = [ "javatests/src/org/chromium/components/gcm_driver/instance_id/FakeInstanceIDWithSubtype.java" ]
 }
-
-junit_binary("components_instance_id_junit_tests") {
-  java_files = [ "junit/src/org/chromium/components/gcm_driver/instance_id/InstanceIDBridgeTest.java" ]
-  deps = [
-    ":instance_id_driver_java",
-    "//base:base_java",
-    "//base:base_junit_test_support",
-  ]
-}
diff --git a/components/gcm_driver/instance_id/android/java/src/org/chromium/components/gcm_driver/instance_id/InstanceIDBridge.java b/components/gcm_driver/instance_id/android/java/src/org/chromium/components/gcm_driver/instance_id/InstanceIDBridge.java
index 3167195..9c3162ca 100644
--- a/components/gcm_driver/instance_id/android/java/src/org/chromium/components/gcm_driver/instance_id/InstanceIDBridge.java
+++ b/components/gcm_driver/instance_id/android/java/src/org/chromium/components/gcm_driver/instance_id/InstanceIDBridge.java
@@ -4,20 +4,14 @@
 
 package org.chromium.components.gcm_driver.instance_id;
 
-import android.content.Context;
-import android.content.SharedPreferences;
 import android.os.Bundle;
 
-import org.chromium.base.ContextUtils;
-import org.chromium.base.VisibleForTesting;
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.base.task.AsyncTask;
+import org.chromium.components.gcm_driver.LazySubscriptionsManager;
 
 import java.io.IOException;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
 import java.util.concurrent.ExecutionException;
 
 /**
@@ -26,8 +20,6 @@
  */
 @JNINamespace("instance_id")
 public class InstanceIDBridge {
-    private static final String FCM_LAZY_SUBSCRIPTIONS = "fcm_lazy_subscriptions";
-    public static final String PREF_PACKAGE = "org.chromium.components.gcm_driver.instance_id";
     private final String mSubtype;
     private long mNativeInstanceIDAndroid;
     /**
@@ -44,41 +36,6 @@
     }
 
     /**
-     * Stores the information about lazy subscriptions in SharedPreferences.
-     */
-    @VisibleForTesting
-    public void storeLazinessInformation(final String authorizedEntity, boolean isLazy) {
-        if (isLazy) {
-            Context context = ContextUtils.getApplicationContext();
-            SharedPreferences sharedPrefs =
-                    context.getSharedPreferences(PREF_PACKAGE, Context.MODE_PRIVATE);
-            Set<String> lazyIds = new HashSet<>(
-                    sharedPrefs.getStringSet(FCM_LAZY_SUBSCRIPTIONS, Collections.emptySet()));
-            lazyIds.add(buildSubscriptionUniqueId(mSubtype, authorizedEntity));
-            sharedPrefs.edit().putStringSet(FCM_LAZY_SUBSCRIPTIONS, lazyIds).apply();
-        }
-        // TODO(https://crbug.com/882887): Check if that
-        // subscription was marked lazy before and handle the change
-        // accordingly.
-    }
-
-    /**
-     * Returns whether the subscription with the |appId| and |senderId| is lazy.
-     */
-    public static boolean isSubscriptionLazy(final String appId, final String senderId) {
-        Context context = ContextUtils.getApplicationContext();
-        SharedPreferences sharedPrefs =
-                context.getSharedPreferences(PREF_PACKAGE, Context.MODE_PRIVATE);
-        Set<String> lazyIds = new HashSet<>(
-                sharedPrefs.getStringSet(FCM_LAZY_SUBSCRIPTIONS, Collections.emptySet()));
-        return lazyIds.contains(buildSubscriptionUniqueId(appId, senderId));
-    }
-
-    private static String buildSubscriptionUniqueId(final String appId, final String senderId) {
-        return appId + senderId;
-    }
-
-    /**
      * Returns a wrapped {@link InstanceIDWithSubtype}. Multiple InstanceIDBridge instances may
      * share an underlying InstanceIDWithSubtype.
      */
@@ -155,7 +112,10 @@
             @Override
             protected String doBackgroundWork() {
                 try {
-                    storeLazinessInformation(authorizedEntity, isLazy);
+                    LazySubscriptionsManager.storeLazinessInformation(
+                            LazySubscriptionsManager.buildSubscriptionUniqueId(
+                                    mSubtype, authorizedEntity),
+                            isLazy);
                     return mInstanceID.getToken(authorizedEntity, scope, extras);
                 } catch (IOException ex) {
                     return "";
diff --git a/components/gcm_driver/instance_id/android/junit/src/org/chromium/components/gcm_driver/instance_id/InstanceIDBridgeTest.java b/components/gcm_driver/instance_id/android/junit/src/org/chromium/components/gcm_driver/instance_id/InstanceIDBridgeTest.java
deleted file mode 100644
index ffd1107..0000000
--- a/components/gcm_driver/instance_id/android/junit/src/org/chromium/components/gcm_driver/instance_id/InstanceIDBridgeTest.java
+++ /dev/null
@@ -1,60 +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.
-
-package org.chromium.components.gcm_driver.instance_id;
-
-import static org.junit.Assert.assertEquals;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.annotation.Config;
-
-import org.chromium.base.test.BaseRobolectricTestRunner;
-
-/**
- * Unit tests for InstanceIDBridge.
- */
-@RunWith(BaseRobolectricTestRunner.class)
-@Config(manifest = Config.NONE)
-public class InstanceIDBridgeTest {
-    /**
-     * Tests that lazy subscriptions are stored.
-     */
-    @Test
-    public void testMarkSubscriptionAsLazy() {
-        final String appId = "app_id";
-        final String senderId = "sender_id";
-
-        InstanceIDBridge instanceIDBridge =
-                InstanceIDBridge.create(/*nativeInstanceIDAndroid=*/0L, appId);
-
-        instanceIDBridge.storeLazinessInformation(senderId, true);
-        assertEquals(true, InstanceIDBridge.isSubscriptionLazy(appId, senderId));
-    }
-
-    /**
-     * Tests that unlazy subscriptions are stored.
-     */
-    @Test
-    public void testMarkSubscriptionAsNotLazy() {
-        final String appId = "app_id";
-        final String senderId = "sender_id";
-
-        InstanceIDBridge instanceIDBridge =
-                InstanceIDBridge.create(/*nativeInstanceIDAndroid=*/0L, senderId);
-
-        instanceIDBridge.storeLazinessInformation(senderId, false);
-        assertEquals(false, InstanceIDBridge.isSubscriptionLazy(appId, senderId));
-    }
-
-    /**
-     * Tests subscriptions are not lazy be default.
-     */
-    @Test
-    public void testDefaultSubscriptionNotLazy() {
-        final String appId = "app_id";
-        final String senderId = "sender_id";
-        assertEquals(false, InstanceIDBridge.isSubscriptionLazy(appId, senderId));
-    }
-}
diff --git a/components/guest_view/browser/guest_view_base.cc b/components/guest_view/browser/guest_view_base.cc
index da6dd81..37319be 100644
--- a/components/guest_view/browser/guest_view_base.cc
+++ b/components/guest_view/browser/guest_view_base.cc
@@ -137,7 +137,16 @@
     if (destroyed_)
       return;
     destroyed_ = true;
-    guest_->Destroy(true);
+
+    bool also_delete = true;
+    WebContents* guest_web_contents = guest_->web_contents();
+    if (content::GuestMode::IsCrossProcessFrameGuest(guest_web_contents)) {
+      // The outer WebContents have ownership of attached OOPIF-based guests, so
+      // we are not responsible for their deletion.
+      if (guest_web_contents->GetOuterWebContents())
+        also_delete = false;
+    }
+    guest_->Destroy(also_delete);
   }
 
   DISALLOW_COPY_AND_ASSIGN(OwnerContentsObserver);
diff --git a/components/guest_view/browser/guest_view_message_filter.cc b/components/guest_view/browser/guest_view_message_filter.cc
index 7f80a47..2b6ca26 100644
--- a/components/guest_view/browser/guest_view_message_filter.cc
+++ b/components/guest_view/browser/guest_view_message_filter.cc
@@ -168,8 +168,8 @@
         // frame |embedder_frame| hosts the inner WebContents.
         // NOTE: this must be called after WillAttach, because it could unblock
         // pending requests which depend on the WebViewGuest being initialized.
-        guest_web_contents->AttachToOuterWebContentsFrame(embedder_web_contents,
-                                                          embedder_frame);
+        guest_web_contents->AttachToOuterWebContentsFrame(
+            base::WrapUnique<WebContents>(guest_web_contents), embedder_frame);
 
         // We don't ACK until after AttachToOuterWebContentsFrame, so that
         // |embedder_frame| gets swapped before the AttachIframeGuest callback
diff --git a/components/history/core/browser/web_history_service.cc b/components/history/core/browser/web_history_service.cc
index ecd48e6..21e8fa0 100644
--- a/components/history/core/browser/web_history_service.cc
+++ b/components/history/core/browser/web_history_service.cc
@@ -169,7 +169,7 @@
 
   // Tells the request to do its thang.
   void Start() override {
-    OAuth2TokenService::ScopeSet oauth_scopes;
+    identity::ScopeSet oauth_scopes;
     oauth_scopes.insert(kHistoryOAuthScope);
 
     access_token_fetcher_ =
@@ -197,7 +197,7 @@
     // If the response code indicates that the token might not be valid,
     // invalidate the token and try again.
     if (response_code_ == net::HTTP_UNAUTHORIZED && ++auth_retry_count_ <= 1) {
-      OAuth2TokenService::ScopeSet oauth_scopes;
+      identity::ScopeSet oauth_scopes;
       oauth_scopes.insert(kHistoryOAuthScope);
       identity_manager_->RemoveAccessTokenFromCache(
           identity_manager_->GetPrimaryAccountId(), oauth_scopes,
diff --git a/components/invalidation/impl/profile_identity_provider.cc b/components/invalidation/impl/profile_identity_provider.cc
index 34247778..f392053 100644
--- a/components/invalidation/impl/profile_identity_provider.cc
+++ b/components/invalidation/impl/profile_identity_provider.cc
@@ -17,7 +17,7 @@
   AccessTokenFetcherAdaptor(const std::string& active_account_id,
                             const std::string& oauth_consumer_name,
                             identity::IdentityManager* identity_manager,
-                            const OAuth2TokenService::ScopeSet& scopes,
+                            const identity::ScopeSet& scopes,
                             ActiveAccountAccessTokenCallback callback);
   ~AccessTokenFetcherAdaptor() override = default;
 
@@ -37,7 +37,7 @@
     const std::string& active_account_id,
     const std::string& oauth_consumer_name,
     identity::IdentityManager* identity_manager,
-    const OAuth2TokenService::ScopeSet& scopes,
+    const identity::ScopeSet& scopes,
     ActiveAccountAccessTokenCallback callback)
     : callback_(std::move(callback)) {
   access_token_fetcher_ = identity_manager->CreateAccessTokenFetcherForAccount(
@@ -95,7 +95,7 @@
 std::unique_ptr<ActiveAccountAccessTokenFetcher>
 ProfileIdentityProvider::FetchAccessToken(
     const std::string& oauth_consumer_name,
-    const OAuth2TokenService::ScopeSet& scopes,
+    const identity::ScopeSet& scopes,
     ActiveAccountAccessTokenCallback callback) {
   return std::make_unique<AccessTokenFetcherAdaptor>(
       GetActiveAccountId(), oauth_consumer_name, identity_manager_, scopes,
@@ -103,7 +103,7 @@
 }
 
 void ProfileIdentityProvider::InvalidateAccessToken(
-    const OAuth2TokenService::ScopeSet& scopes,
+    const identity::ScopeSet& scopes,
     const std::string& access_token) {
   identity_manager_->RemoveAccessTokenFromCache(GetActiveAccountId(), scopes,
                                                 access_token);
diff --git a/components/invalidation/impl/profile_identity_provider.h b/components/invalidation/impl/profile_identity_provider.h
index 39095f5..98f6e8c 100644
--- a/components/invalidation/impl/profile_identity_provider.h
+++ b/components/invalidation/impl/profile_identity_provider.h
@@ -25,9 +25,9 @@
   bool IsActiveAccountAvailable() override;
   std::unique_ptr<ActiveAccountAccessTokenFetcher> FetchAccessToken(
       const std::string& oauth_consumer_name,
-      const OAuth2TokenService::ScopeSet& scopes,
+      const identity::ScopeSet& scopes,
       ActiveAccountAccessTokenCallback callback) override;
-  void InvalidateAccessToken(const OAuth2TokenService::ScopeSet& scopes,
+  void InvalidateAccessToken(const identity::ScopeSet& scopes,
                              const std::string& access_token) override;
   void SetActiveAccountId(const std::string& account_id) override;
 
diff --git a/components/metrics/call_stack_profile_metrics_provider.cc b/components/metrics/call_stack_profile_metrics_provider.cc
index 3334a8c..b4f3a74 100644
--- a/components/metrics/call_stack_profile_metrics_provider.cc
+++ b/components/metrics/call_stack_profile_metrics_provider.cc
@@ -11,10 +11,12 @@
 
 #include "base/bind.h"
 #include "base/macros.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/no_destructor.h"
 #include "base/synchronization/lock.h"
 #include "base/thread_annotations.h"
 #include "base/time/time.h"
+#include "base/timer/elapsed_timer.h"
 #include "third_party/metrics_proto/chrome_user_metrics_extension.pb.h"
 
 namespace metrics {
@@ -53,9 +55,12 @@
   std::vector<SampledProfile> deserialized_profiles;
   deserialized_profiles.reserve(serialized_profiles.size());
   for (const auto& serialized_profile : serialized_profiles) {
+    base::ElapsedTimer timer;
     SampledProfile profile;
     if (profile.ParseFromArray(serialized_profile.data(),
                                serialized_profile.size())) {
+      UMA_HISTOGRAM_TIMES("StackSamplingProfiler.ProfileDeserializationTime",
+                          timer.Elapsed());
       deserialized_profiles.push_back(std::move(profile));
     }
   }
@@ -241,8 +246,12 @@
   // There was no room to store the unserialized profile directly, but there was
   // room to store it in serialized form. Serialize the profile without holding
   // the lock, then try again to store it.
+  base::ElapsedTimer timer;
   std::string serialized_profile;
   profile.SerializeToString(&serialized_profile);
+  UMA_HISTOGRAM_TIMES("StackSamplingProfiler.ProfileSerializationTime",
+                      timer.Elapsed());
+
   MaybeCollectSerializedProfile(profile_start_time,
                                 std::move(serialized_profile));
 }
diff --git a/components/metrics/metrics_service.cc b/components/metrics/metrics_service.cc
index 13b3be3..fb8f5419 100644
--- a/components/metrics/metrics_service.cc
+++ b/components/metrics/metrics_service.cc
@@ -901,6 +901,11 @@
       // but those will be overwritten when an embedded profile is extracted.
       std::unique_ptr<MetricsLog> log = CreateLog(MetricsLog::INDEPENDENT_LOG);
 
+      // Note that something is happening. This must be set before the
+      // operation is requested in case the loader decides to do everything
+      // immediately rather than as a background task.
+      independent_loader_active_ = true;
+
       // Give the new log to a loader for management and then run it on the
       // provider that has something to give. A copy of the pointer is needed
       // because the unique_ptr may get moved before the value can be used
@@ -913,7 +918,6 @@
           base::BindOnce(&MetricsService::PrepareProviderMetricsLogDone,
                          self_ptr_factory_.GetWeakPtr(), std::move(loader)),
           provider.get());
-      independent_loader_active_ = true;
 
       // Something was found so there may still be more work to do.
       return true;
diff --git a/components/ntp_snippets/breaking_news/subscription_manager_impl.cc b/components/ntp_snippets/breaking_news/subscription_manager_impl.cc
index 1be2fbd..87bd9c27 100644
--- a/components/ntp_snippets/breaking_news/subscription_manager_impl.cc
+++ b/components/ntp_snippets/breaking_news/subscription_manager_impl.cc
@@ -100,7 +100,7 @@
     access_token_fetcher_ = nullptr;
   }
 
-  OAuth2TokenService::ScopeSet scopes = {kContentSuggestionsApiScope};
+  identity::ScopeSet scopes = {kContentSuggestionsApiScope};
   access_token_fetcher_ = std::make_unique<
       identity::PrimaryAccountAccessTokenFetcher>(
       "ntp_snippets", identity_manager_, scopes,
diff --git a/components/ntp_snippets/remote/remote_suggestions_fetcher_impl.cc b/components/ntp_snippets/remote/remote_suggestions_fetcher_impl.cc
index a445f193..334a5eee 100644
--- a/components/ntp_snippets/remote/remote_suggestions_fetcher_impl.cc
+++ b/components/ntp_snippets/remote/remote_suggestions_fetcher_impl.cc
@@ -275,7 +275,7 @@
     return;
   }
 
-  OAuth2TokenService::ScopeSet scopes{kContentSuggestionsApiScope};
+  identity::ScopeSet scopes{kContentSuggestionsApiScope};
   token_fetcher_ = std::make_unique<identity::PrimaryAccountAccessTokenFetcher>(
       "ntp_snippets", identity_manager_, scopes,
       base::BindOnce(&RemoteSuggestionsFetcherImpl::AccessTokenFetchFinished,
@@ -377,7 +377,7 @@
   DCHECK(fetch_result == FetchResult::SUCCESS || !categories.has_value());
 
   if (fetch_result == FetchResult::HTTP_ERROR_UNAUTHORIZED) {
-    OAuth2TokenService::ScopeSet scopes{kContentSuggestionsApiScope};
+    identity::ScopeSet scopes{kContentSuggestionsApiScope};
     std::string account_id = identity_manager_->GetPrimaryAccountId();
     identity_manager_->RemoveAccessTokenFromCache(account_id, scopes,
                                                   access_token);
diff --git a/components/omnibox/browser/contextual_suggestions_service.cc b/components/omnibox/browser/contextual_suggestions_service.cc
index 5fc02b6..8d3312a 100644
--- a/components/omnibox/browser/contextual_suggestions_service.cc
+++ b/components/omnibox/browser/contextual_suggestions_service.cc
@@ -312,7 +312,7 @@
   }
 
   // Create the oauth2 token fetcher.
-  const OAuth2TokenService::ScopeSet scopes{
+  const identity::ScopeSet scopes{
       "https://www.googleapis.com/auth/cusco-chrome-extension"};
   token_fetcher_ = std::make_unique<identity::PrimaryAccountAccessTokenFetcher>(
       "contextual_suggestions_service", identity_manager_, scopes,
diff --git a/components/omnibox/browser/document_suggestions_service.cc b/components/omnibox/browser/document_suggestions_service.cc
index 0ac9c7e42..74808b2 100644
--- a/components/omnibox/browser/document_suggestions_service.cc
+++ b/components/omnibox/browser/document_suggestions_service.cc
@@ -117,7 +117,7 @@
 
   // Create and fetch an OAuth2 token.
   std::string scope = "https://www.googleapis.com/auth/cloud_search.query";
-  OAuth2TokenService::ScopeSet scopes;
+  identity::ScopeSet scopes;
   scopes.insert(scope);
   token_fetcher_ = std::make_unique<identity::PrimaryAccountAccessTokenFetcher>(
       "document_suggestions_service", identity_manager_, scopes,
diff --git a/components/payments/core/currency_formatter_unittest.cc b/components/payments/core/currency_formatter_unittest.cc
index 4a19e1b..fa76a7e 100644
--- a/components/payments/core/currency_formatter_unittest.cc
+++ b/components/payments/core/currency_formatter_unittest.cc
@@ -36,16 +36,19 @@
 
 TEST_P(PaymentsCurrencyFormatterTest, IsValidCurrencyFormat) {
   CurrencyFormatter formatter(GetParam().currency_code, GetParam().locale_name);
-  base::string16 output_amount = formatter.Format(GetParam().amount);
+  base::string16 actual_output = formatter.Format(GetParam().amount);
 
   // Convenience so the test cases can use regular spaces.
   const base::string16 kSpace(base::ASCIIToUTF16(" "));
   const base::string16 kNonBreakingSpace(base::UTF8ToUTF16(u8"\u00a0"));
-  base::string16 converted;
-  base::ReplaceChars(base::UTF8ToUTF16(GetParam().expected_amount), kSpace,
-                     kNonBreakingSpace, &converted);
+  const base::string16 kNarrowNonBreakingSpace(base::UTF8ToUTF16(u8"\u202f"));
+  base::ReplaceChars(actual_output, kNonBreakingSpace, kSpace, &actual_output);
+  base::ReplaceChars(actual_output, kNarrowNonBreakingSpace, kSpace,
+                     &actual_output);
+  base::string16 expected_output =
+      base::UTF8ToUTF16(GetParam().expected_amount);
 
-  EXPECT_EQ(converted, output_amount)
+  EXPECT_EQ(expected_output, actual_output)
       << "Failed to convert " << GetParam().amount << " ("
       << GetParam().currency_code << ") in " << GetParam().locale_name;
   EXPECT_EQ(GetParam().expected_currency_code,
@@ -135,7 +138,7 @@
             "123456789012345678901234567890.123456789012345678901234567890",
             "USD",
             "fr_FR",
-            "123 456 789 012 345 678 901 234 567 890,123456789 $",
+            "123 456 789 012 345 678 901 234 567 890,123456789 $",
             "USD")));
 
 }  // namespace
diff --git a/components/policy/tools/generate_policy_source.py b/components/policy/tools/generate_policy_source.py
index dcbabf3..2f8d3ad 100755
--- a/components/policy/tools/generate_policy_source.py
+++ b/components/policy/tools/generate_policy_source.py
@@ -865,7 +865,7 @@
           'void SetEnterpriseUsersDefaults(PolicyMap* policy_map) {\n')
 
   for policy in policies:
-    if policy.has_enterprise_default:
+    if policy.has_enterprise_default and policy.is_supported:
       declare_default_stmts, fetch_default =\
           _GenerateDefaultValue(policy.enterprise_default)
       if not fetch_default:
diff --git a/components/safe_browsing/common/safe_browsing_prefs.cc b/components/safe_browsing/common/safe_browsing_prefs.cc
index 97ffdb9..e224e09 100644
--- a/components/safe_browsing/common/safe_browsing_prefs.cc
+++ b/components/safe_browsing/common/safe_browsing_prefs.cc
@@ -18,38 +18,6 @@
 
 namespace {
 
-// Name of the Scout Transition UMA metric.
-const char kScoutTransitionMetricName[] = "SafeBrowsing.Pref.Scout.Transition";
-
-// Reasons that a state transition for Scout was performed.
-// These values are written to logs.  New enum values can be added, but
-// existing enums must never be renumbered or deleted and reused.
-enum ScoutTransitionReason {
-  // Flag forced Scout Group to true
-  FORCE_SCOUT_FLAG_TRUE = 0,
-  // Flag forced Scout Group to false
-  FORCE_SCOUT_FLAG_FALSE = 1,
-  // User in OnlyShowScout group, enters Scout Group
-  ONLY_SHOW_SCOUT_OPT_IN = 2,
-  // User in CanShowScout group, enters Scout Group immediately
-  CAN_SHOW_SCOUT_OPT_IN_SCOUT_GROUP_ON = 3,
-  // User in CanShowScout group, waiting for interstitial to enter Scout Group
-  CAN_SHOW_SCOUT_OPT_IN_WAIT_FOR_INTERSTITIAL = 4,
-  // User in CanShowScout group saw the first interstitial and entered the Scout
-  // Group
-  CAN_SHOW_SCOUT_OPT_IN_SAW_FIRST_INTERSTITIAL = 5,
-  // User in Control group
-  CONTROL = 6,
-  // Rollback: SBER2 on on implies SBER1 can turn on
-  ROLLBACK_SBER2_IMPLIES_SBER1 = 7,
-  // Rollback: SBER2 off so SBER1 must be turned off
-  ROLLBACK_NO_SBER2_SET_SBER1_FALSE = 8,
-  // Rollback: SBER2 absent so SBER1 must be cleared
-  ROLLBACK_NO_SBER2_CLEAR_SBER1 = 9,
-  // New reasons must be added BEFORE MAX_REASONS
-  MAX_REASONS
-};
-
 // The Extended Reporting pref that is currently active, used for UMA metrics.
 // These values are written to logs.  New enum values can be added, but
 // existing enums must never be renumbered or deleted and reused.
@@ -60,25 +28,6 @@
   MAX_SBER_PREF
 };
 
-// A histogram for tracking a nullable boolean, which can be false, true or
-// null. These values are written to logs. New enum values can be added, but
-// existing enums must never be renumbered or deleted and reused.
-enum NullableBoolean {
-  NULLABLE_BOOLEAN_FALSE = 0,
-  NULLABLE_BOOLEAN_TRUE = 1,
-  NULLABLE_BOOLEAN_NULL = 2,
-  MAX_NULLABLE_BOOLEAN
-};
-
-NullableBoolean GetPrefValueOrNull(const PrefService& prefs,
-                                   const std::string& pref_name) {
-  if (!prefs.HasPrefPath(pref_name)) {
-    return NULLABLE_BOOLEAN_NULL;
-  }
-  return prefs.GetBoolean(pref_name) ? NULLABLE_BOOLEAN_TRUE
-                                     : NULLABLE_BOOLEAN_FALSE;
-}
-
 // Update the correct UMA metric based on which pref was changed and which UI
 // the change was made on.
 void RecordExtendedReportingPrefChanged(
@@ -137,12 +86,8 @@
 const char kSafeBrowsingIncidentsSent[] = "safebrowsing.incidents_sent";
 const char kSafeBrowsingProceedAnywayDisabled[] =
     "safebrowsing.proceed_anyway_disabled";
-const char kSafeBrowsingSawInterstitialExtendedReporting[] =
-    "safebrowsing.saw_interstitial_sber1";
 const char kSafeBrowsingSawInterstitialScoutReporting[] =
     "safebrowsing.saw_interstitial_sber2";
-const char kSafeBrowsingScoutGroupSelected[] =
-    "safebrowsing.scout_group_selected";
 const char kSafeBrowsingScoutReportingEnabled[] =
     "safebrowsing.scout_reporting_enabled";
 const char kSafeBrowsingTriggerEventTimestamps[] =
@@ -165,9 +110,6 @@
 
 namespace safe_browsing {
 
-const base::Feature kCanShowScoutOptIn{"CanShowScoutOptIn",
-                                       base::FEATURE_ENABLED_BY_DEFAULT};
-
 bool ExtendedReportingPrefExists(const PrefService& prefs) {
   return prefs.HasPrefPath(prefs::kSafeBrowsingScoutReportingEnabled);
 }
@@ -197,35 +139,13 @@
 
   // Track whether this user has ever seen a security interstitial.
   UMA_HISTOGRAM_BOOLEAN(
-      "SafeBrowsing.Pref.SawInterstitial.SBER1Pref",
-      prefs.GetBoolean(prefs::kSafeBrowsingSawInterstitialExtendedReporting));
-  UMA_HISTOGRAM_BOOLEAN(
       "SafeBrowsing.Pref.SawInterstitial.SBER2Pref",
       prefs.GetBoolean(prefs::kSafeBrowsingSawInterstitialScoutReporting));
-
-  // These metrics track the Scout transition.
-  if (prefs.GetBoolean(prefs::kSafeBrowsingScoutGroupSelected)) {
-    UMA_HISTOGRAM_ENUMERATION(
-        "SafeBrowsing.Pref.Scout.ScoutGroup.SBER2Pref",
-        GetPrefValueOrNull(prefs, prefs::kSafeBrowsingScoutReportingEnabled),
-        MAX_NULLABLE_BOOLEAN);
-  } else {
-    // The following metric is a corner case. User was previously in the
-    // Scout group and was able to opt-in to the Scout pref, but was since
-    // removed from the Scout group (eg: by rolling back a Scout experiment).
-    UMA_HISTOGRAM_ENUMERATION(
-        "SafeBrowsing.Pref.Scout.NoScoutGroup.SBER2Pref",
-        GetPrefValueOrNull(prefs, prefs::kSafeBrowsingScoutReportingEnabled),
-        MAX_NULLABLE_BOOLEAN);
-  }
 }
 
 void RegisterProfilePrefs(PrefRegistrySimple* registry) {
   registry->RegisterBooleanPref(prefs::kSafeBrowsingScoutReportingEnabled,
                                 false);
-  registry->RegisterBooleanPref(prefs::kSafeBrowsingScoutGroupSelected, false);
-  registry->RegisterBooleanPref(
-      prefs::kSafeBrowsingSawInterstitialExtendedReporting, false);
   registry->RegisterBooleanPref(
       prefs::kSafeBrowsingSawInterstitialScoutReporting, false);
   registry->RegisterBooleanPref(
@@ -327,17 +247,7 @@
 }
 
 void UpdatePrefsBeforeSecurityInterstitial(PrefService* prefs) {
-  // Move the user into the Scout Group if the CanShowScoutOptIn experiment is
-  // enabled and they're not in the group already.
-  if (base::FeatureList::IsEnabled(kCanShowScoutOptIn) &&
-      !prefs->GetBoolean(prefs::kSafeBrowsingScoutGroupSelected)) {
-    prefs->SetBoolean(prefs::kSafeBrowsingScoutGroupSelected, true);
-    UMA_HISTOGRAM_ENUMERATION(kScoutTransitionMetricName,
-                              CAN_SHOW_SCOUT_OPT_IN_SAW_FIRST_INTERSTITIAL,
-                              MAX_REASONS);
-  }
-
-  // Remember that this user saw an interstitial with the current opt-in text.
+  // Remember that this user saw an interstitial.
   prefs->SetBoolean(prefs::kSafeBrowsingSawInterstitialScoutReporting, true);
 }
 
diff --git a/components/safe_browsing/common/safe_browsing_prefs.h b/components/safe_browsing/common/safe_browsing_prefs.h
index 6d68d3f..160d5da 100644
--- a/components/safe_browsing/common/safe_browsing_prefs.h
+++ b/components/safe_browsing/common/safe_browsing_prefs.h
@@ -34,19 +34,9 @@
 // users to proceed anyway.
 extern const char kSafeBrowsingProceedAnywayDisabled[];
 
-// Boolean indicating whether the user has ever seen a security interstitial
-// containing the legacy Extended Reporting opt-in.
-extern const char kSafeBrowsingSawInterstitialExtendedReporting[];
-
-// Boolean indicating whether the user has ever seen a security interstitial
-// containing the new Scout opt-in.
+// Boolean indicating whether the user has ever seen a security interstitial.
 extern const char kSafeBrowsingSawInterstitialScoutReporting[];
 
-// Boolean indicating whether the Scout reporting workflow is enabled. This
-// affects which of SafeBrowsingExtendedReporting or SafeBrowsingScoutReporting
-// is used.
-extern const char kSafeBrowsingScoutGroupSelected[];
-
 // Boolean indicating whether Safe Browsing Scout reporting is enabled, which
 // collects data for malware detection.
 extern const char kSafeBrowsingScoutReportingEnabled[];
@@ -94,11 +84,6 @@
 
 namespace safe_browsing {
 
-// When this feature is enabled, the Scout opt-in text will be displayed as of
-// the next security incident. Until then, the legacy SBER text will appear.
-// TODO: this is temporary (crbug.com/662944)
-extern const base::Feature kCanShowScoutOptIn;
-
 // Enumerates the level of Safe Browsing Extended Reporting that is currently
 // available.
 enum ExtendedReportingLevel {
diff --git a/components/safe_browsing/common/safe_browsing_prefs_unittest.cc b/components/safe_browsing/common/safe_browsing_prefs_unittest.cc
index d4a2629..0e00ab1 100644
--- a/components/safe_browsing/common/safe_browsing_prefs_unittest.cc
+++ b/components/safe_browsing/common/safe_browsing_prefs_unittest.cc
@@ -26,10 +26,6 @@
     prefs_.registry()->RegisterBooleanPref(
         prefs::kSafeBrowsingScoutReportingEnabled, false);
     prefs_.registry()->RegisterBooleanPref(
-        prefs::kSafeBrowsingScoutGroupSelected, false);
-    prefs_.registry()->RegisterBooleanPref(
-        prefs::kSafeBrowsingSawInterstitialExtendedReporting, false);
-    prefs_.registry()->RegisterBooleanPref(
         prefs::kSafeBrowsingSawInterstitialScoutReporting, false);
     prefs_.registry()->RegisterStringPref(
         prefs::kPasswordProtectionChangePasswordURL, "");
@@ -37,55 +33,27 @@
     prefs_.registry()->RegisterBooleanPref(
         prefs::kSafeBrowsingExtendedReportingOptInAllowed, true);
     prefs_.registry()->RegisterListPref(prefs::kSafeBrowsingWhitelistDomains);
-
-    ResetExperiments(/*can_show_scout=*/false);
   }
 
-  void ResetPrefs(bool scout_reporting, bool scout_group) {
+  void ResetPrefs(bool scout_reporting) {
     prefs_.SetBoolean(prefs::kSafeBrowsingScoutReportingEnabled,
                       scout_reporting);
-    prefs_.SetBoolean(prefs::kSafeBrowsingScoutGroupSelected, scout_group);
   }
 
-  void ResetExperiments(bool can_show_scout) {
-    std::vector<base::StringPiece> enabled_features;
-    std::vector<base::StringPiece> disabled_features;
-
-    auto* target_vector =
-        can_show_scout ? &enabled_features : &disabled_features;
-    target_vector->push_back(kCanShowScoutOptIn.name);
-
-    feature_list_.reset(new base::test::ScopedFeatureList);
-    feature_list_->InitFromCommandLine(
-        base::JoinString(enabled_features, ","),
-        base::JoinString(disabled_features, ","));
-  }
-
-  bool IsScoutGroupSelected() {
-    return prefs_.GetBoolean(prefs::kSafeBrowsingScoutGroupSelected);
-  }
-
-  void ExpectPrefs(bool scout_reporting, bool scout_group) {
-    LOG(INFO) << "Pref values: scout=" << scout_reporting
-              << " scout_group=" << scout_group;
+  void ExpectPrefs(bool scout_reporting) {
+    LOG(INFO) << "Pref values: scout=" << scout_reporting;
     EXPECT_EQ(scout_reporting,
               prefs_.GetBoolean(prefs::kSafeBrowsingScoutReportingEnabled));
-    EXPECT_EQ(scout_group,
-              prefs_.GetBoolean(prefs::kSafeBrowsingScoutGroupSelected));
   }
 
-  void ExpectPrefsExist(bool scout_reporting, bool scout_group) {
-    LOG(INFO) << "Prefs exist: scout=" << scout_reporting
-              << " scout_group=" << scout_group;
+  void ExpectPrefsExist(bool scout_reporting) {
+    LOG(INFO) << "Prefs exist: scout=" << scout_reporting;
     EXPECT_EQ(scout_reporting,
               prefs_.HasPrefPath(prefs::kSafeBrowsingScoutReportingEnabled));
-    EXPECT_EQ(scout_group,
-              prefs_.HasPrefPath(prefs::kSafeBrowsingScoutGroupSelected));
   }
   TestingPrefServiceSimple prefs_;
 
  private:
-  std::unique_ptr<base::test::ScopedFeatureList> feature_list_;
   content::TestBrowserThreadBundle thread_bundle_;
 };
 
@@ -98,28 +66,15 @@
   GetSafeBrowsingExtendedReportingLevel
 #endif
 TEST_F(SafeBrowsingPrefsTest, MAYBE_GetSafeBrowsingExtendedReportingLevel) {
-  // By Default, extneded reporting is off.
+  // By Default, extended reporting is off.
   EXPECT_EQ(SBER_LEVEL_OFF, GetExtendedReportingLevel(prefs_));
 
-  // The value of the Scout pref affects the reporting level directly,
-  // regardless of the experiment configuration since Scout is the only level
-  // we are using.
-  // No scout group.
-  ResetPrefs(/*scout_reporting=*/true, /*scout_group=*/false);
+  // The value of the Scout pref affects the reporting level directly.
+  ResetPrefs(/*scout_reporting=*/true);
   EXPECT_EQ(SBER_LEVEL_SCOUT, GetExtendedReportingLevel(prefs_));
-  // Scout group but no experiment.
-  ResetPrefs(/*scout_reporting=*/true, /*scout_group=*/true);
-  EXPECT_EQ(SBER_LEVEL_SCOUT, GetExtendedReportingLevel(prefs_));
-  ResetExperiments(/*can_show_scout=*/true);
   // Scout pref off, so reporting is off.
-  ResetPrefs(/*scout_reporting=*/false, /*scout_group=*/true);
+  ResetPrefs(/*scout_reporting=*/false);
   EXPECT_EQ(SBER_LEVEL_OFF, GetExtendedReportingLevel(prefs_));
-  // Scout pref off with the experiment group off, so reporting remains off.
-  ResetPrefs(/*scout_reporting=*/false, /*scout_group=*/true);
-  EXPECT_EQ(SBER_LEVEL_OFF, GetExtendedReportingLevel(prefs_));
-  // Turning on Scout gives us Scout level reporting
-  ResetPrefs(/*scout_reporting=*/true, /*scout_group=*/true);
-  EXPECT_EQ(SBER_LEVEL_SCOUT, GetExtendedReportingLevel(prefs_));
 }
 
 // TODO(crbug.com/881476) disabled for flaky crashes.
diff --git a/components/safe_browsing/db/util.h b/components/safe_browsing/db/util.h
index 70fbcd7..cbe16e7 100644
--- a/components/safe_browsing/db/util.h
+++ b/components/safe_browsing/db/util.h
@@ -18,7 +18,7 @@
 #include "base/containers/flat_map.h"
 #include "base/strings/string_piece.h"
 #include "base/time/time.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "components/safe_browsing/common/safe_browsing_prefs.h"
 #include "components/safe_browsing/db/v4_protocol_manager_util.h"
 
diff --git a/components/safe_browsing/db/v4_get_hash_protocol_manager.cc b/components/safe_browsing/db/v4_get_hash_protocol_manager.cc
index 2484294..9b5fc51 100644
--- a/components/safe_browsing/db/v4_get_hash_protocol_manager.cc
+++ b/components/safe_browsing/db/v4_get_hash_protocol_manager.cc
@@ -14,7 +14,7 @@
 #include "base/strings/string_split.h"
 #include "base/timer/timer.h"
 #include "base/trace_event/trace_event.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "components/data_use_measurement/core/data_use_user_data.h"
 #include "content/public/browser/browser_thread.h"
 #include "net/base/load_flags.h"
diff --git a/components/safe_browsing/triggers/ad_sampler_trigger_unittest.cc b/components/safe_browsing/triggers/ad_sampler_trigger_unittest.cc
index 0c6aa5c4..ee718330 100644
--- a/components/safe_browsing/triggers/ad_sampler_trigger_unittest.cc
+++ b/components/safe_browsing/triggers/ad_sampler_trigger_unittest.cc
@@ -48,7 +48,6 @@
     safe_browsing::RegisterProfilePrefs(prefs_.registry());
     prefs_.SetBoolean(prefs::kSafeBrowsingExtendedReportingOptInAllowed, true);
     prefs_.SetBoolean(prefs::kSafeBrowsingScoutReportingEnabled, true);
-    prefs_.SetBoolean(prefs::kSafeBrowsingScoutGroupSelected, true);
   }
 
   void CreateTriggerWithFrequency(const size_t denominator) {
diff --git a/components/safe_browsing/triggers/suspicious_site_trigger_unittest.cc b/components/safe_browsing/triggers/suspicious_site_trigger_unittest.cc
index 51fd9a3..48490da 100644
--- a/components/safe_browsing/triggers/suspicious_site_trigger_unittest.cc
+++ b/components/safe_browsing/triggers/suspicious_site_trigger_unittest.cc
@@ -42,7 +42,6 @@
     safe_browsing::RegisterProfilePrefs(prefs_.registry());
     prefs_.SetBoolean(prefs::kSafeBrowsingExtendedReportingOptInAllowed, true);
     prefs_.SetBoolean(prefs::kSafeBrowsingScoutReportingEnabled, true);
-    prefs_.SetBoolean(prefs::kSafeBrowsingScoutGroupSelected, true);
   }
 
   void CreateTrigger(bool monitor_mode) {
diff --git a/components/safe_browsing/triggers/trigger_manager_unittest.cc b/components/safe_browsing/triggers/trigger_manager_unittest.cc
index 37dfd06..3b03d92 100644
--- a/components/safe_browsing/triggers/trigger_manager_unittest.cc
+++ b/components/safe_browsing/triggers/trigger_manager_unittest.cc
@@ -72,7 +72,6 @@
     safe_browsing::RegisterProfilePrefs(pref_service_.registry());
     SetPref(prefs::kSafeBrowsingExtendedReportingOptInAllowed, true);
     SetPref(prefs::kSafeBrowsingScoutReportingEnabled, true);
-    SetPref(prefs::kSafeBrowsingScoutGroupSelected, true);
 
     MockTriggerThrottler* mock_throttler = new MockTriggerThrottler();
     ON_CALL(*mock_throttler, TriggerCanFire(_)).WillByDefault(Return(true));
diff --git a/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.cc b/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.cc
index 4eba01d..57462a4d 100644
--- a/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.cc
+++ b/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.cc
@@ -12,7 +12,7 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/stl_util.h"
 #include "base/trace_event/trace_event.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "components/subresource_filter/content/browser/activation_state_computing_navigation_throttle.h"
 #include "components/subresource_filter/content/browser/async_document_subresource_filter.h"
 #include "components/subresource_filter/content/browser/navigation_console_logger.h"
diff --git a/components/subresource_filter/content/browser/ruleset_service.cc b/components/subresource_filter/content/browser/ruleset_service.cc
index b8a71bf8..07c373ab 100644
--- a/components/subresource_filter/content/browser/ruleset_service.cc
+++ b/components/subresource_filter/content/browser/ruleset_service.cc
@@ -23,7 +23,7 @@
 #include "base/task_runner_util.h"
 #include "base/threading/scoped_blocking_call.h"
 #include "base/trace_event/trace_event.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
 #include "components/subresource_filter/content/common/subresource_filter_messages.h"
diff --git a/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.cc b/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.cc
index f54f7e7..2be64c5 100644
--- a/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.cc
+++ b/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.cc
@@ -11,7 +11,7 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/timer/timer.h"
 #include "base/trace_event/trace_event.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "components/subresource_filter/content/browser/content_activation_list_utils.h"
 #include "components/subresource_filter/content/browser/navigation_console_logger.h"
 #include "components/subresource_filter/content/browser/subresource_filter_client.h"
diff --git a/components/subresource_filter/content/browser/subresource_filter_safe_browsing_client.cc b/components/subresource_filter/content/browser/subresource_filter_safe_browsing_client.cc
index 2ad490a..268042f 100644
--- a/components/subresource_filter/content/browser/subresource_filter_safe_browsing_client.cc
+++ b/components/subresource_filter/content/browser/subresource_filter_safe_browsing_client.cc
@@ -11,7 +11,7 @@
 #include "base/logging.h"
 #include "base/single_thread_task_runner.h"
 #include "base/trace_event/trace_event.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.h"
 #include "components/subresource_filter/content/browser/subresource_filter_safe_browsing_client_request.h"
 #include "content/public/browser/browser_thread.h"
diff --git a/components/subresource_filter/core/browser/subresource_filter_features.cc b/components/subresource_filter/core/browser/subresource_filter_features.cc
index 4792eae..bedf9d1 100644
--- a/components/subresource_filter/core/browser/subresource_filter_features.cc
+++ b/components/subresource_filter/core/browser/subresource_filter_features.cc
@@ -19,7 +19,7 @@
 #include "base/strings/string_util.h"
 #include "base/synchronization/lock.h"
 #include "base/time/time.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "components/subresource_filter/core/common/common_features.h"
 
 namespace subresource_filter {
diff --git a/components/subresource_filter/core/browser/subresource_filter_features_test_support.cc b/components/subresource_filter/core/browser/subresource_filter_features_test_support.cc
index ec3f292..22d4752 100644
--- a/components/subresource_filter/core/browser/subresource_filter_features_test_support.cc
+++ b/components/subresource_filter/core/browser/subresource_filter_features_test_support.cc
@@ -12,7 +12,7 @@
 #include "base/json/json_writer.h"
 #include "base/memory/ref_counted.h"
 #include "base/strings/string_util.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "base/values.h"
 
 namespace subresource_filter {
diff --git a/components/suggestions/suggestions_service_impl.cc b/components/suggestions/suggestions_service_impl.cc
index 1c3678c..60e82bf 100644
--- a/components/suggestions/suggestions_service_impl.cc
+++ b/components/suggestions/suggestions_service_impl.cc
@@ -377,7 +377,7 @@
   if (token_fetcher_)
     return;
 
-  OAuth2TokenService::ScopeSet scopes{GaiaConstants::kChromeSyncOAuth2Scope};
+  identity::ScopeSet scopes{GaiaConstants::kChromeSyncOAuth2Scope};
   token_fetcher_ = std::make_unique<identity::PrimaryAccountAccessTokenFetcher>(
       "suggestions_service", identity_manager_, scopes,
       base::BindOnce(&SuggestionsServiceImpl::AccessTokenAvailable,
diff --git a/components/test/data/web_database/version_79.sql b/components/test/data/web_database/version_79.sql
index b4074a8..e187ce7 100644
--- a/components/test/data/web_database/version_79.sql
+++ b/components/test/data/web_database/version_79.sql
@@ -2,8 +2,8 @@
 BEGIN TRANSACTION;
 CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, value LONGVARCHAR);
 INSERT INTO "meta" VALUES('mmap_status','-1');
-INSERT INTO "meta" VALUES('version','78');
-INSERT INTO "meta" VALUES('last_compatible_version','78');
+INSERT INTO "meta" VALUES('version','79');
+INSERT INTO "meta" VALUES('last_compatible_version','79');
 CREATE TABLE token_service (service VARCHAR PRIMARY KEY NOT NULL,encrypted_token BLOB);
 CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url VARCHAR NOT NULL,safe_for_autoreplace INTEGER,originating_url VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT 0,input_encodings VARCHAR,suggest_url VARCHAR,prepopulate_id INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT 0,last_modified INTEGER DEFAULT 0,sync_guid VARCHAR,alternate_urls VARCHAR,image_url VARCHAR,search_url_post_params VARCHAR,suggest_url_post_params VARCHAR,image_url_post_params VARCHAR,new_tab_url VARCHAR,last_visited INTEGER DEFAULT 0);
 CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower VARCHAR, date_created INTEGER DEFAULT 0, date_last_used INTEGER DEFAULT 0, count INTEGER DEFAULT 1, PRIMARY KEY (name, value));
@@ -25,7 +25,4 @@
 INSERT INTO autofill_model_type_state VALUES (1, 'state');
 CREATE INDEX autofill_name ON autofill (name);
 CREATE INDEX autofill_name_value_lower ON autofill (name, value_lower);
-CREATE TABLE ie7_logins (url_hash VARCHAR NOT NULL, UNIQUE(url_hash));
-CREATE INDEX ie7_logins_hash ON ie7_logins (url_hash);
-CREATE TABLE logins (url_hash VARCHAR NOT NULL, UNIQUE(url_hash));
 COMMIT;
diff --git a/components/timers/BUILD.gn b/components/timers/BUILD.gn
index c6f4a12f..0c9e8ce3 100644
--- a/components/timers/BUILD.gn
+++ b/components/timers/BUILD.gn
@@ -23,6 +23,7 @@
   deps = [
     ":timers",
     "//base",
+    "//base/test:test_support",
     "//testing/gtest",
   ]
 }
diff --git a/components/timers/alarm_timer_unittest.cc b/components/timers/alarm_timer_unittest.cc
index 868eb787..7863d77 100644
--- a/components/timers/alarm_timer_unittest.cc
+++ b/components/timers/alarm_timer_unittest.cc
@@ -8,12 +8,11 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
-#include "base/files/file_descriptor_watcher_posix.h"
 #include "base/location.h"
 #include "base/macros.h"
-#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
+#include "base/test/scoped_task_environment.h"
 #include "base/threading/platform_thread.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
@@ -96,8 +95,8 @@
 // that timers work properly in all configurations.
 
 TEST(AlarmTimerTest, SimpleAlarmTimer) {
-  base::MessageLoopForIO loop;
-  base::FileDescriptorWatcher file_descriptor_watcher(&loop);
+  base::test::ScopedTaskEnvironment task_environment(
+      base::test::ScopedTaskEnvironment::MainThreadType::IO);
 
   base::RunLoop run_loop;
   bool did_run = false;
@@ -111,8 +110,8 @@
 }
 
 TEST(AlarmTimerTest, SimpleAlarmTimer_Cancel) {
-  base::MessageLoopForIO loop;
-  base::FileDescriptorWatcher file_descriptor_watcher(&loop);
+  base::test::ScopedTaskEnvironment task_environment(
+      base::test::ScopedTaskEnvironment::MainThreadType::IO);
 
   bool did_run_a = false;
   AlarmTimerTester* a =
@@ -139,8 +138,8 @@
 // If underlying timer does not handle this properly, we will crash or fail
 // in full page heap environment.
 TEST(AlarmTimerTest, SelfDeletingAlarmTimer) {
-  base::MessageLoopForIO loop;
-  base::FileDescriptorWatcher file_descriptor_watcher(&loop);
+  base::test::ScopedTaskEnvironment task_environment(
+      base::test::ScopedTaskEnvironment::MainThreadType::IO);
 
   base::RunLoop run_loop;
   bool did_run = false;
@@ -154,8 +153,8 @@
 }
 
 TEST(AlarmTimerTest, AlarmTimerZeroDelay) {
-  base::MessageLoopForIO loop;
-  base::FileDescriptorWatcher file_descriptor_watcher(&loop);
+  base::test::ScopedTaskEnvironment task_environment(
+      base::test::ScopedTaskEnvironment::MainThreadType::IO);
 
   base::RunLoop run_loop;
   bool did_run = false;
@@ -169,8 +168,8 @@
 }
 
 TEST(AlarmTimerTest, AlarmTimerZeroDelay_Cancel) {
-  base::MessageLoopForIO loop;
-  base::FileDescriptorWatcher file_descriptor_watcher(&loop);
+  base::test::ScopedTaskEnvironment task_environment(
+      base::test::ScopedTaskEnvironment::MainThreadType::IO);
 
   bool did_run_a = false;
   AlarmTimerTester* a =
@@ -201,9 +200,9 @@
   // if debug heap checking is enabled.
   bool did_run = false;
   {
-    auto loop = std::make_unique<base::MessageLoopForIO>();
-    auto file_descriptor_watcher =
-        std::make_unique<base::FileDescriptorWatcher>(loop.get());
+    base::test::ScopedTaskEnvironment task_environment(
+        base::test::ScopedTaskEnvironment::MainThreadType::IO);
+
     AlarmTimerTester a(&did_run, kTenMilliseconds, base::OnceClosure());
     AlarmTimerTester b(&did_run, kTenMilliseconds, base::OnceClosure());
     AlarmTimerTester c(&did_run, kTenMilliseconds, base::OnceClosure());
@@ -216,9 +215,6 @@
     // tasks posted by FileDescriptorWatcher::WatchReadable() are leaked.
     base::RunLoop().RunUntilIdle();
 
-    // MessageLoop and FileDescriptorWatcher destruct.
-    file_descriptor_watcher.reset();
-    loop.reset();
   }  // SimpleAlarmTimers destruct. SHOULD NOT CRASH, of course.
 
   EXPECT_FALSE(did_run);
@@ -226,8 +222,9 @@
 
 TEST(AlarmTimerTest, NonRepeatIsRunning) {
   {
-    base::MessageLoopForIO loop;
-    base::FileDescriptorWatcher file_descriptor_watcher(&loop);
+    base::test::ScopedTaskEnvironment task_environment(
+        base::test::ScopedTaskEnvironment::MainThreadType::IO);
+
     timers::SimpleAlarmTimer timer;
     EXPECT_FALSE(timer.IsRunning());
     timer.Start(FROM_HERE, base::TimeDelta::FromDays(1), base::DoNothing());
@@ -247,8 +244,9 @@
 }
 
 TEST(AlarmTimerTest, RetainNonRepeatIsRunning) {
-  base::MessageLoopForIO loop;
-  base::FileDescriptorWatcher file_descriptor_watcher(&loop);
+  base::test::ScopedTaskEnvironment task_environment(
+      base::test::ScopedTaskEnvironment::MainThreadType::IO);
+
   timers::SimpleAlarmTimer timer;
   EXPECT_FALSE(timer.IsRunning());
   timer.Start(FROM_HERE, base::TimeDelta::FromDays(1), base::DoNothing());
@@ -292,8 +290,9 @@
 
 TEST(AlarmTimerTest, ContinuationStopStart) {
   ClearAllCallbackHappened();
-  base::MessageLoopForIO loop;
-  base::FileDescriptorWatcher file_descriptor_watcher(&loop);
+  base::test::ScopedTaskEnvironment task_environment(
+      base::test::ScopedTaskEnvironment::MainThreadType::IO);
+
   timers::SimpleAlarmTimer timer;
   timer.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(10),
               base::BindRepeating(&SetCallbackHappened1,
@@ -312,8 +311,8 @@
 
 TEST(AlarmTimerTest, ContinuationReset) {
   ClearAllCallbackHappened();
-  base::MessageLoopForIO loop;
-  base::FileDescriptorWatcher file_descriptor_watcher(&loop);
+  base::test::ScopedTaskEnvironment task_environment(
+      base::test::ScopedTaskEnvironment::MainThreadType::IO);
 
   base::RunLoop run_loop;
   timers::SimpleAlarmTimer timer;
@@ -329,8 +328,9 @@
 // Verify that no crash occurs if a timer is deleted while its callback is
 // running.
 TEST(AlarmTimerTest, DeleteTimerWhileCallbackIsRunning) {
-  base::MessageLoopForIO loop;
-  base::FileDescriptorWatcher file_descriptor_watcher(&loop);
+  base::test::ScopedTaskEnvironment task_environment(
+      base::test::ScopedTaskEnvironment::MainThreadType::IO);
+
   base::RunLoop run_loop;
 
   // Will be deleted by the callback.
@@ -350,8 +350,8 @@
 // Verify that no crash occurs if a zero-delay timer is deleted while its
 // callback is running.
 TEST(AlarmTimerTest, DeleteTimerWhileCallbackIsRunningZeroDelay) {
-  base::MessageLoopForIO loop;
-  base::FileDescriptorWatcher file_descriptor_watcher(&loop);
+  base::test::ScopedTaskEnvironment task_environment(
+      base::test::ScopedTaskEnvironment::MainThreadType::IO);
   base::RunLoop run_loop;
 
   // Will be deleted by the callback.
diff --git a/components/toolbar/toolbar_field_trial.cc b/components/toolbar/toolbar_field_trial.cc
index ef8948d8..a76e283d7 100644
--- a/components/toolbar/toolbar_field_trial.cc
+++ b/components/toolbar/toolbar_field_trial.cc
@@ -29,6 +29,9 @@
 #endif
 };
 
+const base::Feature kHideFileUrlScheme{"OmniboxUIExperimentHideFileUrlScheme",
+                                       base::FEATURE_ENABLED_BY_DEFAULT};
+
 const base::Feature kHideSteadyStateUrlPathQueryAndRef {
   "OmniboxUIExperimentHideSteadyStateUrlPathQueryAndRef",
 #if defined(OS_IOS)
diff --git a/components/toolbar/toolbar_field_trial.h b/components/toolbar/toolbar_field_trial.h
index 04603e67..9ab9e345 100644
--- a/components/toolbar/toolbar_field_trial.h
+++ b/components/toolbar/toolbar_field_trial.h
@@ -18,6 +18,10 @@
 // the toolbar. It is restored during editing.
 extern const base::Feature kHideSteadyStateUrlTrivialSubdomains;
 
+// Feature used to hide the file scheme from URLs displayed in the toolbar.
+// It is restored during editing.
+extern const base::Feature kHideFileUrlScheme;
+
 // Feature used to hide the path, query and ref from steady state URLs
 // displayed in the toolbar. It is restored during editing.
 extern const base::Feature kHideSteadyStateUrlPathQueryAndRef;
diff --git a/components/toolbar/toolbar_model_impl.cc b/components/toolbar/toolbar_model_impl.cc
index 1ba1b413..b3bc7b6db 100644
--- a/components/toolbar/toolbar_model_impl.cc
+++ b/components/toolbar/toolbar_model_impl.cc
@@ -61,6 +61,9 @@
   if (toolbar::features::IsHideSteadyStateUrlTrivialSubdomainsEnabled())
     format_types |= url_formatter::kFormatUrlOmitTrivialSubdomains;
 
+  if (base::FeatureList::IsEnabled(toolbar::features::kHideFileUrlScheme))
+    format_types |= url_formatter::kFormatUrlOmitFileScheme;
+
   return GetFormattedURL(format_types);
 }
 
diff --git a/components/tracing/BUILD.gn b/components/tracing/BUILD.gn
index 2dfc25bf..42d878a 100644
--- a/components/tracing/BUILD.gn
+++ b/components/tracing/BUILD.gn
@@ -5,6 +5,10 @@
 import("//testing/test.gni")
 import("//build/config/compiler/compiler.gni")
 
+if (is_android) {
+  import("//build/config/android/rules.gni")
+}
+
 config("wrap_find_exidx") {
   ldflags = [ "-Wl,-wrap,dl_unwind_find_exidx" ]
 }
@@ -89,6 +93,10 @@
 
   if (is_android && can_unwind_with_cfi_table && is_official_build) {
     sources += [ "common/stack_unwinder_android_unittest.cc" ]
+    deps += [
+      ":jni_headers",
+      ":tracing_test_helper_java",
+    ]
   }
 }
 
@@ -115,3 +123,20 @@
     deps += [ "//testing/android/native_test:native_test_native_code" ]
   }
 }
+
+if (is_android) {
+  generate_jni("jni_headers") {
+    sources = [
+      "android/test/src/org/chromium/tracing/UnwindTestHelper.java",
+    ]
+    jni_package = "tracing"
+  }
+
+  android_library("tracing_test_helper_java") {
+    deps = [
+      "//base:base_java",
+    ]
+    java_files =
+        [ "android/test/src/org/chromium/tracing/UnwindTestHelper.java" ]
+  }
+}
diff --git a/components/tracing/DEPS b/components/tracing/DEPS
index 08980e5e..bde9c00 100644
--- a/components/tracing/DEPS
+++ b/components/tracing/DEPS
@@ -6,4 +6,7 @@
   '.*browsertest\.cc': [
     "+content/public/test",
   ],
+  'stack_unwinder_android_unittest.cc': [
+    "+jni",
+  ],
 }
diff --git a/components/tracing/android/test/src/org/chromium/tracing/UnwindTestHelper.java b/components/tracing/android/test/src/org/chromium/tracing/UnwindTestHelper.java
new file mode 100644
index 0000000..c5b1b4d
--- /dev/null
+++ b/components/tracing/android/test/src/org/chromium/tracing/UnwindTestHelper.java
@@ -0,0 +1,29 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.tracing;
+
+import android.os.ConditionVariable;
+
+import org.chromium.base.annotations.CalledByNative;
+import org.chromium.base.annotations.JNINamespace;
+
+/**
+ * Helper to run code through JNI layer to test JNI unwinding.
+ */
+@JNINamespace("tracing")
+public final class UnwindTestHelper {
+    private static final ConditionVariable sBlock = new ConditionVariable();
+
+    @CalledByNative
+    public static void blockCurrentThread() {
+        sBlock.block();
+        sBlock.close();
+    }
+
+    @CalledByNative
+    public static void unblockAllThreads() {
+        sBlock.open();
+    }
+}
diff --git a/components/tracing/common/graphics_memory_dump_provider_android_unittest.cc b/components/tracing/common/graphics_memory_dump_provider_android_unittest.cc
index cd856bb..01f5ad1 100644
--- a/components/tracing/common/graphics_memory_dump_provider_android_unittest.cc
+++ b/components/tracing/common/graphics_memory_dump_provider_android_unittest.cc
@@ -5,7 +5,7 @@
 #include "components/tracing/common/graphics_memory_dump_provider_android.h"
 #include "base/trace_event/memory_allocator_dump.h"
 #include "base/trace_event/process_memory_dump.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/components/tracing/common/stack_unwinder_android.cc b/components/tracing/common/stack_unwinder_android.cc
index 8080ba3..637911e 100644
--- a/components/tracing/common/stack_unwinder_android.cc
+++ b/components/tracing/common/stack_unwinder_android.cc
@@ -14,6 +14,7 @@
 #include <algorithm>
 #include <memory>
 
+#include "base/android/jni_generator/jni_generator_helper.h"
 #include "base/debug/proc_maps_linux.h"
 #include "base/logging.h"
 #include "base/metrics/histogram_macros.h"
@@ -82,6 +83,9 @@
   AsyncSafeWaitableEvent* event_;
 };
 
+using JniMarker = jni_generator::JniJavaCallContextUnchecked;
+using JniMarkers = std::vector<const JniMarker*>;
+
 // Unwinds from given |cursor| readable by libunwind, and returns
 // the number of frames added to the output. This function can unwind through
 // android framework and then chrome functions. It cannot handle the cases when
@@ -92,13 +96,15 @@
 size_t TraceStackWithContext(unw_cursor_t* cursor,
                              CFIBacktraceAndroid* cfi_unwinder,
                              const tracing::StackUnwinderAndroid* unwinder,
-                             uintptr_t stack_segment_base,
+                             const uintptr_t stack_segment_base,
+                             const JniMarkers& jni_markers,
                              const void** out_trace,
-                             size_t max_depth) {
+                             const size_t max_depth) {
   size_t depth = 0;
   unw_word_t ip = 0, sp = 0;
   unw_get_reg(cursor, UNW_REG_SP, &sp);
-  uintptr_t initial_sp = sp;
+  const uintptr_t initial_sp = sp;
+  uintptr_t previous_sp = 0;
   do {
     unw_get_reg(cursor, UNW_REG_IP, &ip);
     unw_get_reg(cursor, UNW_REG_SP, &sp);
@@ -106,6 +112,13 @@
     if (stack_segment_base > 0)
       DCHECK_LT(sp, stack_segment_base);
 
+    // If SP and IP did not change from previous frame, then unwinding failed.
+    if (previous_sp == sp &&
+        ip == reinterpret_cast<uintptr_t>(out_trace[depth - 1])) {
+      break;
+    }
+    previous_sp = sp;
+
     // If address is in chrome library, then use CFI unwinder since chrome might
     // not have EHABI unwind tables.
     if (CFIBacktraceAndroid::is_chrome_address(ip))
@@ -125,11 +138,27 @@
     // library.
     uintptr_t lr = 0;
     unw_get_reg(cursor, UNW_ARM_LR, &lr);
-    return depth + cfi_unwinder->Unwind(ip, sp, lr, out_trace + depth,
-                                        max_depth - depth);
-  } else if (depth == 0) {
-    RecordUnwindResult(SamplingProfilerUnwindResult::kFirstFrameUnmapped);
+    depth +=
+        cfi_unwinder->Unwind(ip, sp, lr, out_trace + depth, max_depth - depth);
   }
+  if (depth >= max_depth)
+    return depth;
+
+  // Try unwinding the rest of frames from Jni markers on stack if present. This
+  // is to skip trying to unwind art frames which do not have unwind
+  // information.
+  for (const auto* marker : jni_markers) {
+    // Skip if we already walked past this marker.
+    if (sp > marker->sp)
+      continue;
+    depth += cfi_unwinder->Unwind(marker->pc, marker->sp, /*lr=*/0,
+                                  out_trace + depth, max_depth - depth);
+    if (depth >= max_depth)
+      break;
+  }
+
+  if (depth == 0)
+    RecordUnwindResult(SamplingProfilerUnwindResult::kFirstFrameUnmapped);
   return depth;
 }
 
@@ -271,7 +300,7 @@
     return 0;
   return TraceStackWithContext(
       &cursor, CFIBacktraceAndroid::GetInitializedInstance(), this,
-      /* stack_segment_base=*/0, out_trace, max_depth);
+      /* stack_segment_base=*/0, JniMarkers(), out_trace, max_depth);
 }
 
 size_t StackUnwinderAndroid::TraceStack(base::PlatformThreadId tid,
@@ -335,10 +364,28 @@
   }
   DCHECK(replaced_sp);
 
-  // Unwind can use address on the stack. So, replace them as well. See EHABI
-  // #7.5.4 table 3.
   uintptr_t* new_stack = reinterpret_cast<uintptr_t*>(stack_copy_buffer.get());
+  constexpr uintptr_t marker_l =
+                          jni_generator::kJniStackMarkerValue & 0xFFFFFFFF,
+                      marker_r = jni_generator::kJniStackMarkerValue >> 32;
+  JniMarkers jni_markers;
   for (size_t i = 0; i < stack_size / sizeof(uintptr_t); ++i) {
+    if (new_stack[i] == marker_r && i > 0 && new_stack[i - 1] == marker_l) {
+      // Note: JniJavaCallContext::sp will be replaced with offset below.
+      const JniMarker* marker =
+          reinterpret_cast<const JniMarker*>(new_stack + i - 1);
+      DCHECK_EQ(jni_generator::kJniStackMarkerValue,
+                jni_markers.back()->marker);
+      if (marker->sp >= sp && marker->sp < sp + stack_size &&
+          CFIBacktraceAndroid::is_chrome_address(marker->pc)) {
+        jni_markers.push_back(marker);
+      } else {
+        NOTREACHED();
+      }
+    }
+
+    // Unwind can use address on the stack. So, replace them as well. See EHABI
+    // #7.5.4 table 3.
     if (new_stack[i] >= sp && new_stack[i] < sp + stack_size)
       new_stack[i] += relocation_offset;
   }
@@ -381,7 +428,7 @@
   return TraceStackWithContext(
       &cursor, cfi_unwinder, this,
       reinterpret_cast<uintptr_t>(stack_copy_buffer.get()) + stack_size,
-      out_trace, max_depth);
+      jni_markers, out_trace, max_depth);
 }
 
 uintptr_t StackUnwinderAndroid::GetEndAddressOfRegion(uintptr_t addr) const {
diff --git a/components/tracing/common/stack_unwinder_android_unittest.cc b/components/tracing/common/stack_unwinder_android_unittest.cc
index d0833545..96a107c4 100644
--- a/components/tracing/common/stack_unwinder_android_unittest.cc
+++ b/components/tracing/common/stack_unwinder_android_unittest.cc
@@ -4,10 +4,12 @@
 
 #include "components/tracing/common/stack_unwinder_android.h"
 
+#include "base/android/jni_generator/jni_generator_helper.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/task/post_task.h"
 #include "base/test/scoped_task_environment.h"
 #include "base/trace_event/cfi_backtrace_android.h"
+#include "jni/UnwindTestHelper_jni.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace tracing {
@@ -95,4 +97,56 @@
   }
 }
 
+TEST_F(StackUnwinderTest, UnwindOtherThreadOnJNICall) {
+  auto task_runner = base::CreateSingleThreadTaskRunnerWithTraits(
+      {base::MayBlock(), base::TaskPriority::BEST_EFFORT});
+
+  auto callback = [](StackUnwinderAndroid* unwinder, base::PlatformThreadId tid,
+                     uintptr_t test_pc) {
+    const void* frames[kMaxStackFrames];
+    size_t result = unwinder->TraceStack(tid, frames, kMaxStackFrames);
+    bool found_jni = false;
+    uintptr_t jni_address =
+        reinterpret_cast<uintptr_t>(&Java_UnwindTestHelper_blockCurrentThread);
+    EXPECT_GT(result, 2u);
+    for (size_t i = 0; i < result; ++i) {
+      uintptr_t addr = reinterpret_cast<uintptr_t>(frames[i]);
+      EXPECT_TRUE(unwinder->IsAddressMapped(addr));
+      // Check if address is near |jni_address|.
+      if (addr > jni_address && addr < jni_address + 50)
+        found_jni = true;
+    }
+    EXPECT_TRUE(found_jni);
+
+    JNIEnv* env = base::android::AttachCurrentThread();
+    Java_UnwindTestHelper_unblockAllThreads(env);
+  };
+
+  // Post task on background thread to unwind the current thread.
+  task_runner->PostDelayedTask(
+      FROM_HERE,
+      base::BindOnce(callback, base::Unretained(unwinder()),
+                     base::PlatformThread::CurrentId(), GetCurrentPC()),
+      base::TimeDelta::FromMilliseconds(10));
+  JNIEnv* env = base::android::AttachCurrentThread();
+  Java_UnwindTestHelper_blockCurrentThread(env);
+}
+
+TEST_F(StackUnwinderTest, JNIMarkerConsistent) {
+  jni_generator::JniJavaCallContextUnchecked marker;
+  JNIEnv* env = base::android::AttachCurrentThread();
+  std::atomic<jmethodID> method(nullptr);
+
+  uintptr_t sp, pc;
+  asm volatile("mov %0, sp" : "=r"(sp));
+  asm volatile("mov %0, pc" : "=r"(pc));
+  marker.Init<base::android::MethodID::TYPE_STATIC>(
+      env, org_chromium_tracing_UnwindTestHelper_clazz(env),
+      "blockCurrentThread", "()V", &method);
+
+  EXPECT_EQ(marker.sp, sp);
+  // The |marker.pc| recorded should be close from where we recorded |pc|.
+  EXPECT_NEAR(marker.pc, pc, 50);
+}
+
 }  // namespace tracing
diff --git a/components/tracing/common/tracing_sampler_profiler.cc b/components/tracing/common/tracing_sampler_profiler.cc
index 2aedfdb..60535dc 100644
--- a/components/tracing/common/tracing_sampler_profiler.cc
+++ b/components/tracing/common/tracing_sampler_profiler.cc
@@ -38,8 +38,13 @@
  public:
   void OnSampleCompleted(
       std::vector<base::StackSamplingProfiler::Frame> frames) override {
-    if (frames.empty())
+    if (frames.empty()) {
+      TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("cpu_profiler"),
+                           "StackCpuSampling", TRACE_EVENT_SCOPE_THREAD,
+                           "frames", "empty");
+
       return;
+    }
     // Insert an event with the frames rendered as a string with the following
     // formats:
     //   offset - module [debugid]
diff --git a/components/tracing/test/trace_event_perftest.cc b/components/tracing/test/trace_event_perftest.cc
index 9090b63..2cd7a03 100644
--- a/components/tracing/test/trace_event_perftest.cc
+++ b/components/tracing/test/trace_event_perftest.cc
@@ -12,7 +12,7 @@
 #include "base/run_loop.h"
 #include "base/threading/thread.h"
 #include "base/trace_event/trace_event.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "perf_test_helpers.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/components/url_formatter/elide_url_unittest.cc b/components/url_formatter/elide_url_unittest.cc
index e2fc441..095a274 100644
--- a/components/url_formatter/elide_url_unittest.cc
+++ b/components/url_formatter/elide_url_unittest.cc
@@ -318,6 +318,7 @@
      {
          /* clang-format off */
          "file:///C:/path1/path2/path3/filename",
+         "/C:/path1/path2/path3/filename",
          "C:/path1/path2/path3/filename",
          "C:/path1/path2/" + kEllipsisStr + "/filename",
          /* clang-format on */
@@ -327,7 +328,6 @@
     {"file:///C:path1/path2/path3/filename",
      {
          /* clang-format off */
-         "file:///C:/path1/path2/path3/filename",
          "C:/path1/path2/path3/filename",
          "C:/path1/path2/" + kEllipsisStr + "/filename",
          "C:/path1/" + kEllipsisStr + "/filename",
diff --git a/components/url_formatter/url_formatter.cc b/components/url_formatter/url_formatter.cc
index 2f0bbb6..4ef6820d 100644
--- a/components/url_formatter/url_formatter.cc
+++ b/components/url_formatter/url_formatter.cc
@@ -417,6 +417,7 @@
 const FormatUrlType kFormatUrlExperimentalElideAfterHost = 1 << 4;
 const FormatUrlType kFormatUrlOmitTrivialSubdomains = 1 << 5;
 const FormatUrlType kFormatUrlTrimAfterHost = 1 << 6;
+const FormatUrlType kFormatUrlOmitFileScheme = 1 << 7;
 
 const FormatUrlType kFormatUrlOmitDefaults =
     kFormatUrlOmitUsernamePassword | kFormatUrlOmitHTTP |
@@ -486,7 +487,7 @@
   const url::Parsed& parsed = url.parsed_for_possibly_invalid_spec();
 
   // Scheme & separators.  These are ASCII.
-  const size_t scheme_size = static_cast<size_t>(parsed.CountCharactersBefore(
+  size_t scheme_size = static_cast<size_t>(parsed.CountCharactersBefore(
       url::Parsed::USERNAME, true /* include_delimiter */));
   base::string16 url_string;
   url_string.insert(url_string.end(), spec.begin(), spec.begin() + scheme_size);
@@ -622,10 +623,28 @@
       (((format_types & kFormatUrlOmitHTTP) &&
         url.SchemeIs(url::kHttpScheme)) ||
        ((format_types & kFormatUrlOmitHTTPS) &&
-        url.SchemeIs(url::kHttpsScheme)));
+        url.SchemeIs(url::kHttpsScheme)) ||
+       ((format_types & kFormatUrlOmitFileScheme) &&
+        url.SchemeIs(url::kFileScheme)));
 
   // If we need to strip out schemes do it after the fact.
   if (strip_scheme) {
+    DCHECK(new_parsed->scheme.is_valid());
+    size_t scheme_and_separator_len =
+        new_parsed->scheme.len + 3;  // +3 for ://.
+#if defined(OS_WIN)
+    // Because there's an additional leading slash after the scheme for local
+    // files on Windows, we should remove it for URL display when eliding
+    // the scheme by offsetting by an additional character.
+    if (url.SchemeIs(url::kFileScheme) &&
+        base::StartsWith(url_string, base::ASCIIToUTF16("file:///"),
+                         base::CompareCase::INSENSITIVE_ASCII)) {
+      ++new_parsed->path.begin;
+      ++scheme_size;
+      ++scheme_and_separator_len;
+    }
+#endif
+
     url_string.erase(0, scheme_size);
     // Because offsets in the |adjustments| are already calculated with respect
     // to the string with the http:// prefix in it, those offsets remain correct
@@ -638,10 +657,8 @@
       *prefix_end -= scheme_size;
 
     // Adjust new_parsed.
-    DCHECK(new_parsed->scheme.is_valid());
-    int delta = -(new_parsed->scheme.len + 3);  // +3 for ://.
     new_parsed->scheme.reset();
-    AdjustAllComponentsButScheme(delta, new_parsed);
+    AdjustAllComponentsButScheme(-scheme_and_separator_len, new_parsed);
   }
 
   return url_string;
diff --git a/components/url_formatter/url_formatter.h b/components/url_formatter/url_formatter.h
index 988d325a..95fb222 100644
--- a/components/url_formatter/url_formatter.h
+++ b/components/url_formatter/url_formatter.h
@@ -85,6 +85,9 @@
 // are all omitted.
 extern const FormatUrlType kFormatUrlTrimAfterHost;
 
+// If the scheme is 'file://', it's removed. Not in kFormatUrlOmitDefaults.
+extern const FormatUrlType kFormatUrlOmitFileScheme;
+
 // Convenience for omitting all unecessary types. Does not include HTTPS scheme
 // removal, or experimental flags.
 extern const FormatUrlType kFormatUrlOmitDefaults;
diff --git a/components/url_formatter/url_formatter_unittest.cc b/components/url_formatter/url_formatter_unittest.cc
index 535d780..c327b293 100644
--- a/components/url_formatter/url_formatter_unittest.cc
+++ b/components/url_formatter/url_formatter_unittest.cc
@@ -1196,6 +1196,17 @@
        kFormatUrlOmitHTTP, net::UnescapeRule::NORMAL, L"http://ftp.google.com/",
        7},
 
+      // -------- omit file: --------
+#if defined(OS_WIN)
+      {"omit file on Windows", "file:///C:/Users/homedirname/folder/file.pdf/",
+       kFormatUrlOmitFileScheme, net::UnescapeRule::NORMAL,
+       L"C:/Users/homedirname/folder/file.pdf/", -1},
+#else
+      {"omit file", "file:///Users/homedirname/folder/file.pdf/",
+       kFormatUrlOmitFileScheme, net::UnescapeRule::NORMAL,
+       L"/Users/homedirname/folder/file.pdf/", 0},
+#endif
+
       // -------- omit trailing slash on bare hostname --------
       {"omit slash when it's the entire path", "http://www.google.com/",
        kFormatUrlOmitTrailingSlashOnBareHostname, net::UnescapeRule::NORMAL,
diff --git a/components/viz/client/frame_evictor.cc b/components/viz/client/frame_evictor.cc
index e4529fc..1ee0aea 100644
--- a/components/viz/client/frame_evictor.cc
+++ b/components/viz/client/frame_evictor.cc
@@ -8,47 +8,34 @@
 
 namespace viz {
 
-FrameEvictor::FrameEvictor(FrameEvictorClient* client)
-    : client_(client), has_frame_(false), visible_(false) {}
+FrameEvictor::FrameEvictor(FrameEvictorClient* client) : client_(client) {}
 
 FrameEvictor::~FrameEvictor() {
-  DiscardedFrame();
+  OnSurfaceDiscarded();
 }
 
-void FrameEvictor::SwappedFrame(bool visible) {
-  visible_ = visible;
-  has_frame_ = true;
-  FrameEvictionManager::GetInstance()->AddFrame(this, visible);
+void FrameEvictor::OnNewSurfaceEmbedded() {
+  has_surface_ = true;
+  FrameEvictionManager::GetInstance()->AddFrame(this, visible_);
 }
 
-void FrameEvictor::DiscardedFrame() {
+void FrameEvictor::OnSurfaceDiscarded() {
   FrameEvictionManager::GetInstance()->RemoveFrame(this);
-  has_frame_ = false;
+  has_surface_ = false;
 }
 
 void FrameEvictor::SetVisible(bool visible) {
   if (visible_ == visible)
     return;
   visible_ = visible;
-  if (has_frame_) {
-    if (visible) {
-      LockFrame();
-    } else {
-      UnlockFrame();
-    }
+  if (has_surface_) {
+    if (visible)
+      FrameEvictionManager::GetInstance()->LockFrame(this);
+    else
+      FrameEvictionManager::GetInstance()->UnlockFrame(this);
   }
 }
 
-void FrameEvictor::LockFrame() {
-  DCHECK(has_frame_);
-  FrameEvictionManager::GetInstance()->LockFrame(this);
-}
-
-void FrameEvictor::UnlockFrame() {
-  DCHECK(has_frame_);
-  FrameEvictionManager::GetInstance()->UnlockFrame(this);
-}
-
 void FrameEvictor::EvictCurrentFrame() {
   client_->EvictDelegatedFrame();
 }
diff --git a/components/viz/client/frame_evictor.h b/components/viz/client/frame_evictor.h
index c6fd3c1..ad901f6 100644
--- a/components/viz/client/frame_evictor.h
+++ b/components/viz/client/frame_evictor.h
@@ -16,28 +16,35 @@
   virtual void EvictDelegatedFrame() = 0;
 };
 
+// Keeps track of the visibility state of a child and notifies when the parent
+// needs to drop its surface.
 class VIZ_CLIENT_EXPORT FrameEvictor : public FrameEvictionManagerClient {
  public:
-  // |client| must outlive |this|.
   explicit FrameEvictor(FrameEvictorClient* client);
   ~FrameEvictor() override;
 
-  void SwappedFrame(bool visible);
-  void DiscardedFrame();
+  // Called when the parent allocates a new LocalSurfaceId for this child and
+  // embeds it.
+  void OnNewSurfaceEmbedded();
+
+  // Called when the parent stops embedding the child's surface and evicts it.
+  void OnSurfaceDiscarded();
+
+  // Returns whether the parent is currently embedding a surface of this child.
+  bool has_surface() const { return has_surface_; }
+
+  // Notifies that the visibility state of the child has changed.
   void SetVisible(bool visible);
-  bool HasFrame() { return has_frame_; }
+
   bool visible() const { return visible_; }
 
  private:
-  void LockFrame();
-  void UnlockFrame();
-
   // FrameEvictionManagerClient implementation.
   void EvictCurrentFrame() override;
 
   FrameEvictorClient* client_;
-  bool has_frame_;
-  bool visible_;
+  bool has_surface_ = false;
+  bool visible_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(FrameEvictor);
 };
diff --git a/components/viz/common/display/renderer_settings.h b/components/viz/common/display/renderer_settings.h
index 9d16d67c..9539d2b 100644
--- a/components/viz/common/display/renderer_settings.h
+++ b/components/viz/common/display/renderer_settings.h
@@ -36,6 +36,7 @@
   int highp_threshold_min = 0;
   bool auto_resize_output_surface = true;
   bool requires_alpha_channel = false;
+  bool record_sk_picture = false;
 
   int slow_down_compositing_scale_factor = 1;
 
diff --git a/components/viz/common/features.cc b/components/viz/common/features.cc
index c6cc4e0..16430030 100644
--- a/components/viz/common/features.cc
+++ b/components/viz/common/features.cc
@@ -41,14 +41,18 @@
 const base::Feature kEnableVizHitTestSurfaceLayer{
     "VizHitTestSurfaceLayer", base::FEATURE_DISABLED_BY_DEFAULT};
 
-// Use the SkiaRenderer.
+// Use the Skia deferred display list.
 const base::Feature kUseSkiaDeferredDisplayList{
     "UseSkiaDeferredDisplayList", base::FEATURE_DISABLED_BY_DEFAULT};
 
-// Use the Skia deferred display list.
+// Use the SkiaRenderer.
 const base::Feature kUseSkiaRenderer{"UseSkiaRenderer",
                                      base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Use the SkiaRenderer to record SkPicture.
+const base::Feature kRecordSkPicture{"RecordSkPicture",
+                                     base::FEATURE_DISABLED_BY_DEFAULT};
+
 bool IsSurfaceSynchronizationEnabled() {
   auto* command_line = base::CommandLine::ForCurrentProcess();
   return base::FeatureList::IsEnabled(kEnableSurfaceSynchronization) ||
@@ -83,6 +87,11 @@
   return base::FeatureList::IsEnabled(kUseSkiaRenderer);
 }
 
+bool IsRecordingSkPicture() {
+  return IsUsingSkiaRenderer() &&
+         base::FeatureList::IsEnabled(kRecordSkPicture);
+}
+
 bool IsUsingSkiaDeferredDisplayList() {
   return IsUsingSkiaRenderer() &&
          base::FeatureList::IsEnabled(kUseSkiaDeferredDisplayList) &&
diff --git a/components/viz/common/features.h b/components/viz/common/features.h
index 1a257ec..02a92f7 100644
--- a/components/viz/common/features.h
+++ b/components/viz/common/features.h
@@ -17,6 +17,7 @@
 VIZ_COMMON_EXPORT extern const base::Feature kEnableVizHitTestSurfaceLayer;
 VIZ_COMMON_EXPORT extern const base::Feature kUseSkiaDeferredDisplayList;
 VIZ_COMMON_EXPORT extern const base::Feature kUseSkiaRenderer;
+VIZ_COMMON_EXPORT extern const base::Feature kRecordSkPicture;
 VIZ_COMMON_EXPORT extern const base::Feature kVizDisplayCompositor;
 
 VIZ_COMMON_EXPORT bool IsDrawOcclusionEnabled();
@@ -26,6 +27,7 @@
 VIZ_COMMON_EXPORT bool IsVizHitTestingSurfaceLayerEnabled();
 VIZ_COMMON_EXPORT bool IsUsingSkiaDeferredDisplayList();
 VIZ_COMMON_EXPORT bool IsUsingSkiaRenderer();
+VIZ_COMMON_EXPORT bool IsRecordingSkPicture();
 
 }  // namespace features
 
diff --git a/components/viz/common/frame_sinks/begin_frame_args.cc b/components/viz/common/frame_sinks/begin_frame_args.cc
index 9c7cca3e..29d1a3d 100644
--- a/components/viz/common/frame_sinks/begin_frame_args.cc
+++ b/components/viz/common/frame_sinks/begin_frame_args.cc
@@ -4,7 +4,7 @@
 
 #include "components/viz/common/frame_sinks/begin_frame_args.h"
 
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 
 namespace viz {
 
diff --git a/components/viz/common/frame_sinks/begin_frame_source.cc b/components/viz/common/frame_sinks/begin_frame_source.cc
index fe2e720f..65b081cb 100644
--- a/components/viz/common/frame_sinks/begin_frame_source.cc
+++ b/components/viz/common/frame_sinks/begin_frame_source.cc
@@ -13,7 +13,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "base/trace_event/trace_event.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "components/viz/common/frame_sinks/delay_based_time_source.h"
 
 namespace viz {
diff --git a/components/viz/common/frame_sinks/delay_based_time_source.cc b/components/viz/common/frame_sinks/delay_based_time_source.cc
index 4dfcee3..eb34c49 100644
--- a/components/viz/common/frame_sinks/delay_based_time_source.cc
+++ b/components/viz/common/frame_sinks/delay_based_time_source.cc
@@ -13,7 +13,7 @@
 #include "base/logging.h"
 #include "base/single_thread_task_runner.h"
 #include "base/trace_event/trace_event.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "components/viz/common/frame_sinks/begin_frame_args.h"
 
 namespace viz {
diff --git a/components/viz/common/gl_scaler.cc b/components/viz/common/gl_scaler.cc
index b91e049..df66d86 100644
--- a/components/viz/common/gl_scaler.cc
+++ b/components/viz/common/gl_scaler.cc
@@ -6,13 +6,11 @@
 
 #include <sstream>
 #include <string>
-#include <utility>
 
 #include "base/logging.h"
 #include "components/viz/common/gpu/context_provider.h"
 #include "gpu/GLES2/gl2chromium.h"
 #include "gpu/GLES2/gl2extchromium.h"
-#include "gpu/command_buffer/common/capabilities.h"
 #include "ui/gfx/color_transform.h"
 #include "ui/gfx/geometry/rect_conversions.h"
 
@@ -34,8 +32,12 @@
   if (!context_provider_) {
     return false;
   }
-  const gpu::Capabilities& caps = context_provider_->ContextCapabilities();
-  return caps.texture_half_float_linear && caps.color_buffer_half_float_rgba;
+  if (!supports_half_floats_.has_value()) {
+    supports_half_floats_ = AreAllGLExtensionsPresent(
+        context_provider_->ContextGL(),
+        {"GL_EXT_color_buffer_half_float", "GL_OES_texture_half_float_linear"});
+  }
+  return supports_half_floats_.value();
 }
 
 int GLScaler::GetMaxDrawBuffersSupported() const {
@@ -48,13 +50,8 @@
     // present, the actual platform-supported maximum.
     GLES2Interface* const gl = context_provider_->ContextGL();
     DCHECK(gl);
-    if (const auto* extensions = gl->GetString(GL_EXTENSIONS)) {
-      const std::string extensions_string =
-          " " + std::string(reinterpret_cast<const char*>(extensions)) + " ";
-      if (extensions_string.find(" GL_EXT_draw_buffers ") !=
-          std::string::npos) {
-        gl->GetIntegerv(GL_MAX_DRAW_BUFFERS_EXT, &max_draw_buffers_);
-      }
+    if (AreAllGLExtensionsPresent(gl, {"GL_EXT_draw_buffers"})) {
+      gl->GetIntegerv(GL_MAX_DRAW_BUFFERS_EXT, &max_draw_buffers_);
     }
 
     if (max_draw_buffers_ < 1) {
@@ -223,12 +220,12 @@
 
 GLScaler::ShaderProgram* GLScaler::GetShaderProgram(
     Shader shader,
-    GLint texture_format,
+    GLenum texture_type,
     const gfx::ColorTransform* color_transform,
     const GLenum swizzle[2]) {
   const ShaderCacheKey key{
       shader,
-      texture_format,
+      texture_type,
       color_transform ? color_transform->GetSrcColorSpace() : gfx::ColorSpace(),
       color_transform ? color_transform->GetDstColorSpace() : gfx::ColorSpace(),
       swizzle[0],
@@ -239,13 +236,31 @@
     DCHECK(gl);
     it = shader_programs_
              .emplace(std::piecewise_construct, std::forward_as_tuple(key),
-                      std::forward_as_tuple(gl, shader, texture_format,
+                      std::forward_as_tuple(gl, shader, texture_type,
                                             color_transform, swizzle))
              .first;
   }
   return &it->second;
 }
 
+// static
+bool GLScaler::AreAllGLExtensionsPresent(
+    gpu::gles2::GLES2Interface* gl,
+    const std::vector<std::string>& names) {
+  DCHECK(gl);
+  if (const auto* extensions = gl->GetString(GL_EXTENSIONS)) {
+    const std::string extensions_string =
+        " " + std::string(reinterpret_cast<const char*>(extensions)) + " ";
+    for (const std::string& name : names) {
+      if (extensions_string.find(" " + name + " ") == std::string::npos) {
+        return false;
+      }
+    }
+    return true;
+  }
+  return false;
+}
+
 GLScaler::Parameters::Parameters() = default;
 GLScaler::Parameters::~Parameters() = default;
 
@@ -260,12 +275,12 @@
 GLScaler::ShaderProgram::ShaderProgram(
     gpu::gles2::GLES2Interface* gl,
     GLScaler::Shader shader,
-    GLint texture_format,
+    GLenum texture_type,
     const gfx::ColorTransform* color_transform,
     const GLenum swizzle[2])
     : gl_(gl),
       shader_(shader),
-      texture_format_(texture_format),
+      texture_type_(texture_type),
       program_(gl_->CreateProgram()) {
   DCHECK(program_);
 
@@ -283,12 +298,16 @@
           "uniform vec4 src_rect;\n");
 
   fragment_header << "precision mediump float;\n";
-  if (texture_format_ == GL_RGBA16F_EXT) {
-    fragment_header << "precision mediump sampler2D;\n";
-  } else if (texture_format_ == GL_RGBA) {
-    fragment_header << "precision lowp sampler2D;\n";
-  } else {
-    NOTIMPLEMENTED();
+  switch (texture_type_) {
+    case GL_FLOAT:
+      fragment_header << "precision highp sampler2D;\n";
+      break;
+    case GL_HALF_FLOAT_OES:
+      fragment_header << "precision mediump sampler2D;\n";
+      break;
+    default:
+      fragment_header << "precision lowp sampler2D;\n";
+      break;
   }
   fragment_header << "uniform sampler2D s_texture;\n";
 
@@ -1088,8 +1107,8 @@
     gl_->BindTexture(GL_TEXTURE_2D, intermediate_texture_);
     // Note: Not setting the filter or wrap parameters on the texture here
     // because that will be done in ScaleToMultipleOutputs() anyway.
-    gl_->TexImage2D(GL_TEXTURE_2D, 0, program_->texture_format(), size.width(),
-                    size.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+    gl_->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.width(), size.height(), 0,
+                    GL_RGBA, program_->texture_type(), nullptr);
     intermediate_texture_size_ = size;
   }
 }
diff --git a/components/viz/common/gl_scaler.h b/components/viz/common/gl_scaler.h
index 9ef13ec5..592435c 100644
--- a/components/viz/common/gl_scaler.h
+++ b/components/viz/common/gl_scaler.h
@@ -9,12 +9,15 @@
 
 #include <map>
 #include <memory>
+#include <string>
 #include <tuple>
 #include <utility>
+#include <vector>
 
 #include "base/compiler_specific.h"
 #include "base/macros.h"
 #include "base/memory/scoped_refptr.h"
+#include "base/optional.h"
 #include "components/viz/common/gpu/context_lost_observer.h"
 #include "components/viz/common/viz_common_export.h"
 #include "gpu/command_buffer/client/gles2_interface.h"
@@ -285,13 +288,13 @@
    public:
     ShaderProgram(GLES2Interface* gl,
                   Shader shader,
-                  GLint texture_format,
+                  GLenum texture_type,
                   const gfx::ColorTransform* color_transform,
                   const GLenum swizzle[2]);
     ~ShaderProgram();
 
     Shader shader() const { return shader_; }
-    GLint texture_format() const { return texture_format_; }
+    GLenum texture_type() const { return texture_type_; }
 
     // UseProgram must be called with GL_ARRAY_BUFFER bound to a vertex
     // attribute buffer. |src_texture_size| is the size of the entire source
@@ -320,7 +323,7 @@
    private:
     GLES2Interface* const gl_;
     const Shader shader_;
-    const GLint texture_format_;
+    const GLenum texture_type_;
 
     // A program for copying a source texture into a destination texture.
     const GLuint program_;
@@ -421,10 +424,15 @@
 
   // Returns a cached ShaderProgram, creating one on-demand if necessary.
   ShaderProgram* GetShaderProgram(Shader shader,
-                                  GLint texture_format,
+                                  GLenum texture_type,
                                   const gfx::ColorTransform* color_transform,
                                   const GLenum swizzle[2]);
 
+  // Returns true if the given |gl| context mentions all of |names| in its
+  // extensions string.
+  static bool AreAllGLExtensionsPresent(gpu::gles2::GLES2Interface* gl,
+                                        const std::vector<std::string>& names);
+
   // The provider of the GL context. This is non-null while the GL context is
   // valid and GLScaler is observing for context loss.
   scoped_refptr<ContextProvider> context_provider_;
@@ -432,7 +440,11 @@
   // Set by Configure() to the resolved set of Parameters.
   Parameters params_;
 
-  // The maximum number of simultaneous draw buffers, lazy initialized by
+  // If set to true, half-float textures are supported. This is lazy-initialized
+  // by SupportsPreciseColorManagement().
+  mutable base::Optional<bool> supports_half_floats_;
+
+  // The maximum number of simultaneous draw buffers, lazy-initialized by
   // GetMaxDrawBuffersSupported(). -1 means "not yet known."
   mutable int max_draw_buffers_ = -1;
 
@@ -440,7 +452,7 @@
   // to the arguments of GetShaderProgram(): the shader, the texture format, the
   // source and output color spaces (color transform), and the two swizzles.
   using ShaderCacheKey = std::
-      tuple<Shader, GLint, gfx::ColorSpace, gfx::ColorSpace, GLenum, GLenum>;
+      tuple<Shader, GLenum, gfx::ColorSpace, gfx::ColorSpace, GLenum, GLenum>;
   std::map<ShaderCacheKey, ShaderProgram> shader_programs_;
 
   // The GL_ARRAY_BUFFER that holds the vertices and the texture coordinates
diff --git a/components/viz/common/gl_scaler_overscan_pixeltest.cc b/components/viz/common/gl_scaler_overscan_pixeltest.cc
index 2383c6a..21cf4d40 100644
--- a/components/viz/common/gl_scaler_overscan_pixeltest.cc
+++ b/components/viz/common/gl_scaler_overscan_pixeltest.cc
@@ -39,7 +39,7 @@
     scaler_->chain_ = std::make_unique<ScalerStage>(gl_, shader, primary_axis,
                                                     scale_from, scale_to);
     scaler_->chain_->set_shader_program(scaler_->GetShaderProgram(
-        shader, GL_RGBA, nullptr, GLScaler::Parameters().swizzle));
+        shader, GL_UNSIGNED_BYTE, nullptr, GLScaler::Parameters().swizzle));
   }
 
   // Converts the given |source_rect| into a possibly-larger one that includes
diff --git a/components/viz/common/gl_scaler_shader_pixeltest.cc b/components/viz/common/gl_scaler_shader_pixeltest.cc
index cb84b1c8..347ee7b 100644
--- a/components/viz/common/gl_scaler_shader_pixeltest.cc
+++ b/components/viz/common/gl_scaler_shader_pixeltest.cc
@@ -74,7 +74,8 @@
         is_swizzling_output() ? GL_BGRA_EXT : GL_RGBA,
         is_swizzling_output() ? GL_BGRA_EXT : GL_RGBA,
     };
-    return scaler_->GetShaderProgram(shader, GL_RGBA, transform.get(), swizzle);
+    return scaler_->GetShaderProgram(shader, GL_UNSIGNED_BYTE, transform.get(),
+                                     swizzle);
   }
 
   GLuint CreateTexture(const gfx::Size& size) {
@@ -135,7 +136,9 @@
     GLuint result = texture;
     if (is_swizzling_output()) {
       const GLenum swizzle[2] = {GL_BGRA_EXT, GL_BGRA_EXT};
-      scaler_->GetShaderProgram(Shader::BILINEAR, GL_RGBA, nullptr, swizzle)
+      scaler_
+          ->GetShaderProgram(Shader::BILINEAR, GL_UNSIGNED_BYTE, nullptr,
+                             swizzle)
           ->UseProgram(size, gfx::RectF(gfx::Rect(size)), size,
                        Axis::HORIZONTAL, false);
       result = RenderToNewTexture(result, size);
@@ -146,8 +149,8 @@
           gfx::ColorTransform::Intent::INTENT_ABSOLUTE);
       const GLenum swizzle[2] = {GL_RGBA, GL_RGBA};
       scaler_
-          ->GetShaderProgram(Shader::BILINEAR, GL_RGBA, transform.get(),
-                             swizzle)
+          ->GetShaderProgram(Shader::BILINEAR, GL_UNSIGNED_BYTE,
+                             transform.get(), swizzle)
           ->UseProgram(size, gfx::RectF(gfx::Rect(size)), size,
                        Axis::HORIZONTAL, false);
       result = RenderToNewTexture(result, size);
diff --git a/components/viz/common/quads/content_draw_quad_base.cc b/components/viz/common/quads/content_draw_quad_base.cc
index fc84e35..465dfa7 100644
--- a/components/viz/common/quads/content_draw_quad_base.cc
+++ b/components/viz/common/quads/content_draw_quad_base.cc
@@ -5,7 +5,7 @@
 #include "components/viz/common/quads/content_draw_quad_base.h"
 
 #include "base/logging.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "base/values.h"
 #include "cc/base/math_util.h"
 
diff --git a/components/viz/common/quads/debug_border_draw_quad.cc b/components/viz/common/quads/debug_border_draw_quad.cc
index f413800..fed85f8 100644
--- a/components/viz/common/quads/debug_border_draw_quad.cc
+++ b/components/viz/common/quads/debug_border_draw_quad.cc
@@ -5,7 +5,7 @@
 #include "components/viz/common/quads/debug_border_draw_quad.h"
 
 #include "base/logging.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "base/values.h"
 
 namespace viz {
diff --git a/components/viz/common/quads/draw_quad.cc b/components/viz/common/quads/draw_quad.cc
index 2257fbc8..d3158e67 100644
--- a/components/viz/common/quads/draw_quad.cc
+++ b/components/viz/common/quads/draw_quad.cc
@@ -7,7 +7,7 @@
 #include <stddef.h>
 
 #include "base/logging.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "base/values.h"
 #include "cc/base/math_util.h"
 #include "components/viz/common/traced_value.h"
diff --git a/components/viz/common/quads/picture_draw_quad.cc b/components/viz/common/quads/picture_draw_quad.cc
index 2036308..588f354 100644
--- a/components/viz/common/quads/picture_draw_quad.cc
+++ b/components/viz/common/quads/picture_draw_quad.cc
@@ -4,7 +4,7 @@
 
 #include "components/viz/common/quads/picture_draw_quad.h"
 
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "base/values.h"
 #include "cc/base/math_util.h"
 #include "components/viz/common/resources/platform_color.h"
diff --git a/components/viz/common/quads/render_pass.cc b/components/viz/common/quads/render_pass.cc
index 54cd2b5..985ada9 100644
--- a/components/viz/common/quads/render_pass.cc
+++ b/components/viz/common/quads/render_pass.cc
@@ -11,7 +11,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/trace_event/trace_event.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "base/values.h"
 #include "cc/base/math_util.h"
 #include "components/viz/common/frame_sinks/copy_output_request.h"
diff --git a/components/viz/common/quads/render_pass_draw_quad.cc b/components/viz/common/quads/render_pass_draw_quad.cc
index 1f4a71b..4bd6826 100644
--- a/components/viz/common/quads/render_pass_draw_quad.cc
+++ b/components/viz/common/quads/render_pass_draw_quad.cc
@@ -4,7 +4,7 @@
 
 #include "components/viz/common/quads/render_pass_draw_quad.h"
 
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "base/values.h"
 #include "cc/base/math_util.h"
 #include "components/viz/common/traced_value.h"
diff --git a/components/viz/common/quads/shared_quad_state.cc b/components/viz/common/quads/shared_quad_state.cc
index f724b8e..67e84ef 100644
--- a/components/viz/common/quads/shared_quad_state.cc
+++ b/components/viz/common/quads/shared_quad_state.cc
@@ -5,7 +5,7 @@
 #include "components/viz/common/quads/shared_quad_state.h"
 
 #include "base/trace_event/trace_event.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "base/values.h"
 #include "cc/base/math_util.h"
 #include "components/viz/common/traced_value.h"
diff --git a/components/viz/common/quads/solid_color_draw_quad.cc b/components/viz/common/quads/solid_color_draw_quad.cc
index c9f8c36..6708e20 100644
--- a/components/viz/common/quads/solid_color_draw_quad.cc
+++ b/components/viz/common/quads/solid_color_draw_quad.cc
@@ -5,7 +5,7 @@
 #include "components/viz/common/quads/solid_color_draw_quad.h"
 
 #include "base/logging.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "base/values.h"
 
 namespace viz {
diff --git a/components/viz/common/quads/stream_video_draw_quad.cc b/components/viz/common/quads/stream_video_draw_quad.cc
index 8f0feb8..03eaf79 100644
--- a/components/viz/common/quads/stream_video_draw_quad.cc
+++ b/components/viz/common/quads/stream_video_draw_quad.cc
@@ -5,7 +5,7 @@
 #include "components/viz/common/quads/stream_video_draw_quad.h"
 
 #include "base/logging.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "base/values.h"
 #include "cc/base/math_util.h"
 
diff --git a/components/viz/common/quads/surface_draw_quad.cc b/components/viz/common/quads/surface_draw_quad.cc
index 3edad1aa..f59cae0 100644
--- a/components/viz/common/quads/surface_draw_quad.cc
+++ b/components/viz/common/quads/surface_draw_quad.cc
@@ -6,7 +6,7 @@
 
 #include "base/logging.h"
 #include "base/optional.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "base/values.h"
 
 namespace viz {
diff --git a/components/viz/common/quads/texture_draw_quad.cc b/components/viz/common/quads/texture_draw_quad.cc
index 31c6e75..a29fa9224 100644
--- a/components/viz/common/quads/texture_draw_quad.cc
+++ b/components/viz/common/quads/texture_draw_quad.cc
@@ -7,7 +7,7 @@
 #include <stddef.h>
 
 #include "base/logging.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "base/values.h"
 #include "cc/base/math_util.h"
 #include "ui/gfx/geometry/vector2d_f.h"
diff --git a/components/viz/common/quads/tile_draw_quad.cc b/components/viz/common/quads/tile_draw_quad.cc
index 72e8dee2..cc17510 100644
--- a/components/viz/common/quads/tile_draw_quad.cc
+++ b/components/viz/common/quads/tile_draw_quad.cc
@@ -5,7 +5,7 @@
 #include "components/viz/common/quads/tile_draw_quad.h"
 
 #include "base/logging.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "base/values.h"
 
 namespace viz {
diff --git a/components/viz/common/quads/yuv_video_draw_quad.cc b/components/viz/common/quads/yuv_video_draw_quad.cc
index 91254b3..bf46a5d 100644
--- a/components/viz/common/quads/yuv_video_draw_quad.cc
+++ b/components/viz/common/quads/yuv_video_draw_quad.cc
@@ -5,7 +5,7 @@
 #include "components/viz/common/quads/yuv_video_draw_quad.h"
 
 #include "base/logging.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "base/values.h"
 #include "cc/base/math_util.h"
 
diff --git a/components/viz/common/traced_value.cc b/components/viz/common/traced_value.cc
index b3a23c2f..25a4860 100644
--- a/components/viz/common/traced_value.cc
+++ b/components/viz/common/traced_value.cc
@@ -5,7 +5,7 @@
 #include "components/viz/common/traced_value.h"
 
 #include "base/strings/stringprintf.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 
 namespace viz {
 
diff --git a/components/viz/host/renderer_settings_creation.cc b/components/viz/host/renderer_settings_creation.cc
index eca60205..3f5fddf7 100644
--- a/components/viz/host/renderer_settings_creation.cc
+++ b/components/viz/host/renderer_settings_creation.cc
@@ -67,6 +67,8 @@
       !base::CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kDisableMacOverlays);
 #endif
+  renderer_settings.record_sk_picture = features::IsRecordingSkPicture();
+
   if (command_line->HasSwitch(switches::kSlowDownCompositingScaleFactor)) {
     const int kMinSlowDownScaleFactor = 1;
     const int kMaxSlowDownScaleFactor = 1000;
diff --git a/components/viz/service/display/display.cc b/components/viz/service/display/display.cc
index 29c3e793..775d568 100644
--- a/components/viz/service/display/display.cc
+++ b/components/viz/service/display/display.cc
@@ -241,9 +241,12 @@
       // GPU compositing with GL.
       DCHECK(output_surface_);
       DCHECK(output_surface_->context_provider());
+      SkiaRenderer::DrawMode mode = settings_.record_sk_picture
+                                        ? SkiaRenderer::DrawMode::SKPRECORD
+                                        : SkiaRenderer::DrawMode::GL;
       renderer_ = std::make_unique<SkiaRenderer>(
           &settings_, output_surface_.get(), resource_provider_.get(),
-          nullptr /* skia_output_surface */, SkiaRenderer::DrawMode::GL);
+          nullptr /* skia_output_surface */, mode);
     }
   } else if (output_surface_->context_provider()) {
     renderer_ = std::make_unique<GLRenderer>(&settings_, output_surface_.get(),
diff --git a/components/viz/service/display/skia_renderer.cc b/components/viz/service/display/skia_renderer.cc
index 6d7bbe4..b86ae9e 100644
--- a/components/viz/service/display/skia_renderer.cc
+++ b/components/viz/service/display/skia_renderer.cc
@@ -212,13 +212,23 @@
       DCHECK(skia_output_surface_);
       break;
     }
+    case DrawMode::SKPRECORD: {
+      DCHECK(output_surface_);
+      context_provider_ = output_surface_->context_provider();
+      const auto& context_caps = context_provider_->ContextCapabilities();
+      use_swap_with_bounds_ = context_caps.swap_buffers_with_bounds;
+      if (context_caps.sync_query) {
+        sync_queries_ =
+            base::Optional<SyncQueryCollection>(context_provider_->ContextGL());
+      }
+    }
   }
 }
 
 SkiaRenderer::~SkiaRenderer() = default;
 
 bool SkiaRenderer::CanPartialSwap() {
-  if (draw_mode_ != DrawMode::GL)
+  if (draw_mode_ != DrawMode::GL && draw_mode_ != DrawMode::SKPRECORD)
     return false;
 
   DCHECK(context_provider_);
@@ -230,7 +240,7 @@
 
 void SkiaRenderer::BeginDrawingFrame() {
   TRACE_EVENT0("viz", "SkiaRenderer::BeginDrawingFrame");
-  if (draw_mode_ != DrawMode::GL)
+  if (draw_mode_ != DrawMode::GL && draw_mode_ != DrawMode::SKPRECORD)
     return;
 
   // Copied from GLRenderer.
@@ -311,6 +321,18 @@
       output_surface_->SwapBuffers(std::move(output_frame));
       break;
     }
+    case DrawMode::SKPRECORD: {
+      // write to skp files
+      std::string file_name = "composited-frame.skp";
+      SkFILEWStream file(file_name.c_str());
+      DCHECK(file.isValid());
+
+      auto data = root_picture_->serialize();
+      file.write(data->data(), data->size());
+      file.fsync();
+      root_picture_ = nullptr;
+      root_recorder_.reset();
+    }
   }
 
   swap_buffer_rect_ = gfx::Rect();
@@ -395,6 +417,16 @@
       }
       break;
     }
+    case DrawMode::SKPRECORD: {
+      root_recorder_ = std::make_unique<SkPictureRecorder>();
+
+      current_recorder_ = root_recorder_.get();
+      current_picture_ = &root_picture_;
+      root_canvas_ = root_recorder_->beginRecording(
+          SkRect::MakeWH(current_frame()->device_viewport_size.width(),
+                         current_frame()->device_viewport_size.height()));
+      break;
+    }
   }
 
   current_canvas_ = root_canvas_;
@@ -431,6 +463,13 @@
       non_root_surface_ = backing.render_pass_surface;
       current_surface_ = non_root_surface_.get();
       current_canvas_ = non_root_surface_->getCanvas();
+      break;
+    }
+    case DrawMode::SKPRECORD: {
+      current_recorder_ = backing.recorder.get();
+      current_picture_ = &backing.picture;
+      current_canvas_ = current_recorder_->beginRecording(
+          SkRect::MakeWH(backing.size.width(), backing.size.height()));
     }
   }
 }
@@ -904,6 +943,15 @@
       case DrawMode::GL:  // Fallthrough
       case DrawMode::VULKAN: {
         content_image = backing.render_pass_surface->makeImageSnapshot();
+        break;
+      }
+      case DrawMode::SKPRECORD: {
+        content_image = SkImage::MakeFromPicture(
+            backing.picture,
+            SkISize::Make(backing.size.width(), backing.size.height()), nullptr,
+            nullptr, SkImage::BitDepth::kU8,
+            backing.color_space.ToSkColorSpace());
+        return;
       }
     }
 
@@ -1076,6 +1124,11 @@
       copy_image->asLegacyBitmap(&bitmap);
       request->SendResult(
           std::make_unique<CopyOutputSkBitmapResult>(copy_rect, bitmap));
+      break;
+    }
+    case DrawMode::SKPRECORD: {
+      NOTIMPLEMENTED();
+      break;
     }
   }
 }
@@ -1126,6 +1179,11 @@
       current_canvas_->flush();
       break;
     }
+    case DrawMode::SKPRECORD: {
+      current_canvas_->flush();
+      sk_sp<SkPicture> picture = current_recorder_->finishRecordingAsPicture();
+      *current_picture_ = picture;
+    }
   }
 }
 
@@ -1160,6 +1218,8 @@
 #endif
     case DrawMode::GL:
       return context_provider_->GrContext();
+    case DrawMode::SKPRECORD:
+      return nullptr;
   }
 }
 
@@ -1218,14 +1278,22 @@
     case DrawMode::GL: {
       caps.texture_format_bgra8888 =
           context_provider_->ContextCapabilities().texture_format_bgra8888;
+      break;
+    }
+    case DrawMode::SKPRECORD: {
+      render_pass_backings_.emplace(
+          std::move(render_pass_id),
+          RenderPassBacking(requirements.size, requirements.mipmap,
+                            current_frame()->current_render_pass->color_space));
+      return;
     }
   }
 
-  render_pass_backings_.insert(std::pair<RenderPassId, RenderPassBacking>(
-      render_pass_id,
+  render_pass_backings_.emplace(
+      std::move(render_pass_id),
       RenderPassBacking(gr_context, caps, requirements.size,
                         requirements.mipmap,
-                        current_frame()->current_render_pass->color_space)));
+                        current_frame()->current_render_pass->color_space));
 }
 
 SkiaRenderer::RenderPassBacking::RenderPassBacking(
@@ -1263,6 +1331,14 @@
       kTopLeft_GrSurfaceOrigin, &surface_props, mipmap);
 }
 
+SkiaRenderer::RenderPassBacking::RenderPassBacking(
+    const gfx::Size& size,
+    bool mipmap,
+    const gfx::ColorSpace& color_space)
+    : size(size), mipmap(mipmap), color_space(color_space) {
+  recorder = std::make_unique<SkPictureRecorder>();
+}
+
 SkiaRenderer::RenderPassBacking::~RenderPassBacking() {}
 
 SkiaRenderer::RenderPassBacking::RenderPassBacking(
@@ -1273,6 +1349,7 @@
       format(other.format) {
   render_pass_surface = other.render_pass_surface;
   other.render_pass_surface = nullptr;
+  recorder = std::move(other.recorder);
 }
 
 SkiaRenderer::RenderPassBacking& SkiaRenderer::RenderPassBacking::operator=(
@@ -1283,6 +1360,7 @@
   format = other.format;
   render_pass_surface = other.render_pass_surface;
   other.render_pass_surface = nullptr;
+  recorder = std::move(other.recorder);
   return *this;
 }
 
diff --git a/components/viz/service/display/skia_renderer.h b/components/viz/service/display/skia_renderer.h
index e77fc09..cd54755 100644
--- a/components/viz/service/display/skia_renderer.h
+++ b/components/viz/service/display/skia_renderer.h
@@ -13,9 +13,11 @@
 #include "components/viz/service/display/sync_query_collection.h"
 #include "components/viz/service/viz_service_export.h"
 #include "gpu/vulkan/buildflags.h"
+#include "third_party/skia/include/core/SkPictureRecorder.h"
 #include "ui/latency/latency_info.h"
 
 class SkNWayCanvas;
+class SkPictureRecorder;
 
 namespace gpu {
 struct Capabilities;
@@ -34,7 +36,7 @@
 class VIZ_SERVICE_EXPORT SkiaRenderer : public DirectRenderer {
  public:
   // Different draw modes that are supported by SkiaRenderer right now.
-  enum DrawMode { GL, DDL, VULKAN };
+  enum DrawMode { GL, DDL, VULKAN, SKPRECORD };
 
   // TODO(penghuang): Remove skia_output_surface when DDL is used everywhere.
   SkiaRenderer(const RendererSettings* settings,
@@ -125,11 +127,19 @@
     bool mipmap;
     gfx::ColorSpace color_space;
     ResourceFormat format;
+
+    // Specific for SkPictureRecorder.
+    std::unique_ptr<SkPictureRecorder> recorder;
+    sk_sp<SkPicture> picture;
+
     RenderPassBacking(GrContext* gr_context,
                       const gpu::Capabilities& caps,
                       const gfx::Size& size,
                       bool mipmap,
                       const gfx::ColorSpace& color_space);
+    RenderPassBacking(const gfx::Size& size,
+                      bool mipmap,
+                      const gfx::ColorSpace& color_space);
     ~RenderPassBacking();
     RenderPassBacking(RenderPassBacking&&);
     RenderPassBacking& operator=(RenderPassBacking&&);
@@ -203,6 +213,12 @@
   using YUVIds = std::tuple<ResourceId, ResourceId, ResourceId, ResourceId>;
   base::flat_map<YUVIds, sk_sp<SkImage>> yuv_promise_images_;
 
+  // Specific for SkPRecord.
+  std::unique_ptr<SkPictureRecorder> root_recorder_;
+  sk_sp<SkPicture> root_picture_;
+  sk_sp<SkPicture>* current_picture_;
+  SkPictureRecorder* current_recorder_;
+
   DISALLOW_COPY_AND_ASSIGN(SkiaRenderer);
 };
 
diff --git a/components/viz/service/hit_test/hit_test_aggregator.cc b/components/viz/service/hit_test/hit_test_aggregator.cc
index 2f0d1f0..52a6d471 100644
--- a/components/viz/service/hit_test/hit_test_aggregator.cc
+++ b/components/viz/service/hit_test/hit_test_aggregator.cc
@@ -58,16 +58,15 @@
 }
 
 base::Optional<int64_t> HitTestAggregator::GetTraceIdIfUpdated(
-    const SurfaceId& surface_id) {
+    const SurfaceId& surface_id,
+    uint64_t active_frame_index) {
   bool enabled;
   TRACE_EVENT_CATEGORY_GROUP_ENABLED(
       TRACE_DISABLED_BY_DEFAULT("viz.hit_testing_flow"), &enabled);
   if (!enabled)
     return base::nullopt;
 
-  int32_t active_frame_index =
-      hit_test_manager_->GetActiveFrameIndex(surface_id);
-  int32_t& frame_index = last_active_frame_index_[surface_id];
+  uint64_t& frame_index = last_active_frame_index_[surface_id.frame_sink_id()];
   if (frame_index == active_frame_index)
     return base::nullopt;
   frame_index = active_frame_index;
@@ -75,13 +74,17 @@
 }
 
 void HitTestAggregator::AppendRoot(const SurfaceId& surface_id) {
+  uint64_t active_frame_index;
   const HitTestRegionList* hit_test_region_list =
       hit_test_manager_->GetActiveHitTestRegionList(
-          local_surface_id_lookup_delegate_, surface_id.frame_sink_id());
+          local_surface_id_lookup_delegate_, surface_id.frame_sink_id(),
+          &active_frame_index);
+
   if (!hit_test_region_list)
     return;
 
-  base::Optional<int64_t> trace_id = GetTraceIdIfUpdated(surface_id);
+  base::Optional<int64_t> trace_id =
+      GetTraceIdIfUpdated(surface_id, active_frame_index);
   TRACE_EVENT_WITH_FLOW1(
       TRACE_DISABLED_BY_DEFAULT("viz.hit_testing_flow"), "Event.Pipeline",
       TRACE_ID_GLOBAL(trace_id.value_or(-1)),
@@ -126,9 +129,11 @@
 
     referenced_child_regions_.insert(region.frame_sink_id);
 
+    uint64_t active_frame_index;
     const HitTestRegionList* hit_test_region_list =
         hit_test_manager_->GetActiveHitTestRegionList(
-            local_surface_id_lookup_delegate_, region.frame_sink_id);
+            local_surface_id_lookup_delegate_, region.frame_sink_id,
+            &active_frame_index);
     if (!hit_test_region_list) {
       // Hit-test data not found with this FrameSinkId. This means that it
       // failed to find a surface corresponding to this FrameSinkId at surface
@@ -156,7 +161,8 @@
                 region.frame_sink_id);
         SurfaceId surface_id(region.frame_sink_id, local_surface_id);
 
-        base::Optional<int64_t> trace_id = GetTraceIdIfUpdated(surface_id);
+        base::Optional<int64_t> trace_id =
+            GetTraceIdIfUpdated(surface_id, active_frame_index);
         TRACE_EVENT_WITH_FLOW1(
             TRACE_DISABLED_BY_DEFAULT("viz.hit_testing_flow"), "Event.Pipeline",
             TRACE_ID_GLOBAL(trace_id.value_or(-1)),
diff --git a/components/viz/service/hit_test/hit_test_aggregator.h b/components/viz/service/hit_test/hit_test_aggregator.h
index 28f70b4..e4d6a92 100644
--- a/components/viz/service/hit_test/hit_test_aggregator.h
+++ b/components/viz/service/hit_test/hit_test_aggregator.h
@@ -60,10 +60,11 @@
                    int32_t child_count);
 
   // Returns the |trace_id| of the |begin_frame_ack| in the active frame for
-  // the given surface_id if it is different than when it was last queried.
+  // the given |surface_id| if it is different than when it was last queried.
   // This is used in order to ensure that the flow between receiving hit-test
   // data and aggregating is included only once per submission.
-  base::Optional<int64_t> GetTraceIdIfUpdated(const SurfaceId& surface_id);
+  base::Optional<int64_t> GetTraceIdIfUpdated(const SurfaceId& surface_id,
+                                              uint64_t active_frame_index);
 
   const HitTestManager* const hit_test_manager_;
 
@@ -89,7 +90,7 @@
   // to detect cycles.
   base::flat_set<FrameSinkId> referenced_child_regions_;
 
-  base::flat_map<SurfaceId, int32_t> last_active_frame_index_;
+  base::flat_map<FrameSinkId, uint64_t> last_active_frame_index_;
 
   // Handles the case when this object is deleted after
   // the PostTaskAggregation call is scheduled but before invocation.
diff --git a/components/viz/service/hit_test/hit_test_manager.cc b/components/viz/service/hit_test/hit_test_manager.cc
index 17afc70..de6ba7c 100644
--- a/components/viz/service/hit_test/hit_test_manager.cc
+++ b/components/viz/service/hit_test/hit_test_manager.cc
@@ -68,7 +68,8 @@
 
 const HitTestRegionList* HitTestManager::GetActiveHitTestRegionList(
     LatestLocalSurfaceIdLookupDelegate* delegate,
-    const FrameSinkId& frame_sink_id) const {
+    const FrameSinkId& frame_sink_id,
+    uint64_t* store_active_frame_index) const {
   if (!delegate)
     return nullptr;
 
@@ -85,6 +86,8 @@
   Surface* surface = surface_manager_->GetSurfaceForId(surface_id);
   DCHECK(surface);
   uint64_t frame_index = surface->GetActiveFrameIndex();
+  if (store_active_frame_index)
+    *store_active_frame_index = frame_index;
 
   auto& frame_index_map = search->second;
   auto search2 = frame_index_map.find(frame_index);
@@ -94,11 +97,6 @@
   return &search2->second;
 }
 
-int32_t HitTestManager::GetActiveFrameIndex(const SurfaceId& id) const {
-  Surface* surface = surface_manager_->GetSurfaceForId(id);
-  return surface->GetActiveFrameIndex();
-}
-
 int64_t HitTestManager::GetTraceId(const SurfaceId& id) const {
   Surface* surface = surface_manager_->GetSurfaceForId(id);
   return surface->GetActiveFrame().metadata.begin_frame_ack.trace_id;
diff --git a/components/viz/service/hit_test/hit_test_manager.h b/components/viz/service/hit_test/hit_test_manager.h
index 15beb3f..1780895 100644
--- a/components/viz/service/hit_test/hit_test_manager.h
+++ b/components/viz/service/hit_test/hit_test_manager.h
@@ -45,12 +45,13 @@
   // Returns the HitTestRegionList corresponding to the given
   // |frame_sink_id| and the active CompositorFrame matched by frame_index.
   // The returned pointer is not stable and should not be stored or used after
-  // calling any non-const methods on this class.
+  // calling any non-const methods on this class. ActiveFrameIndex is stored
+  // if |store_active_frame_index| is given, which is used to detect updates.
   const HitTestRegionList* GetActiveHitTestRegionList(
       LatestLocalSurfaceIdLookupDelegate* delegate,
-      const FrameSinkId& frame_sink_id) const;
+      const FrameSinkId& frame_sink_id,
+      uint64_t* store_active_frame_index = nullptr) const;
 
-  int32_t GetActiveFrameIndex(const SurfaceId& id) const;
   int64_t GetTraceId(const SurfaceId& id) const;
 
  private:
diff --git a/components/viz/test/begin_frame_source_test.h b/components/viz/test/begin_frame_source_test.h
index ce77a7a..086f1c53 100644
--- a/components/viz/test/begin_frame_source_test.h
+++ b/components/viz/test/begin_frame_source_test.h
@@ -5,7 +5,7 @@
 #ifndef COMPONENTS_VIZ_TEST_BEGIN_FRAME_SOURCE_TEST_H_
 #define COMPONENTS_VIZ_TEST_BEGIN_FRAME_SOURCE_TEST_H_
 
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "components/viz/common/frame_sinks/begin_frame_source.h"
 #include "components/viz/test/begin_frame_args_test.h"
 #include "testing/gmock/include/gmock/gmock.h"
diff --git a/content/app/DEPS b/content/app/DEPS
index cd56a2a..4a94233 100644
--- a/content/app/DEPS
+++ b/content/app/DEPS
@@ -1,5 +1,4 @@
 include_rules = [
-  "+components/download",
   "+components/tracing",
   "+content",
   "+device/bluetooth",
diff --git a/content/app/content_main_runner_impl.cc b/content/app/content_main_runner_impl.cc
index a37944b5..d442aae 100644
--- a/content/app/content_main_runner_impl.cc
+++ b/content/app/content_main_runner_impl.cc
@@ -39,7 +39,6 @@
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/trace_event/trace_event.h"
-#include "components/download/public/common/download_task_runner.h"
 #include "components/tracing/common/trace_startup.h"
 #include "content/app/mojo/mojo_init.h"
 #include "content/browser/browser_process_sub_thread.h"
@@ -154,10 +153,6 @@
 #include "services/service_manager/zygote/host/zygote_host_impl_linux.h"
 #endif
 
-#if defined(OS_ANDROID)
-#include "content/browser/android/browser_startup_controller.h"
-#endif
-
 namespace content {
 extern int GpuMain(const content::MainFunctionParams&);
 #if BUILDFLAG(ENABLE_PLUGINS)
@@ -172,11 +167,6 @@
 
 namespace {
 
-#if !defined(CHROME_MULTIPLE_DLL_CHILD)
-const char kAllowStartingServiceManagerOnly[] =
-    "allow-start-service-manager-only";
-#endif
-
 #if defined(V8_USE_EXTERNAL_STARTUP_DATA) && defined(OS_ANDROID)
 #if defined __LP64__
 #define kV8SnapshotDataDescriptor kV8Snapshot64DataDescriptor
@@ -864,20 +854,13 @@
   RegisterMainThreadFactories();
 
 #if !defined(CHROME_MULTIPLE_DLL_CHILD)
-  if (process_type.empty())
-    return RunServiceManager(main_params, start_service_manager_only);
-#endif  // !defined(CHROME_MULTIPLE_DLL_CHILD)
+  // The thread used to start the ServiceManager is handed-off to
+  // BrowserMain() which may elect to promote it (e.g. to BrowserThread::IO).
+  if (process_type.empty()) {
+    startup_data_ = std::make_unique<StartupDataImpl>();
+    startup_data_->thread = BrowserProcessSubThread::CreateIOThread();
+    main_params.startup_data = startup_data_.get();
 
-  return RunOtherNamedProcessTypeMain(process_type, main_params, delegate_);
-}
-
-#if !defined(CHROME_MULTIPLE_DLL_CHILD)
-int ContentMainRunnerImpl::RunServiceManager(MainFunctionParams& main_params,
-                                             bool start_service_manager_only) {
-  if (is_browser_main_loop_started_)
-    return -1;
-
-  if (!service_manager_context_) {
     if (GetContentClient()->browser()->ShouldCreateTaskScheduler()) {
       // Create and start the TaskScheduler early to allow upcoming code to use
       // the post_task.h API.
@@ -916,33 +899,13 @@
     // incorrect to post to a BrowserThread before this point.
     BrowserTaskExecutor::Create();
 
-    // The thread used to start the ServiceManager is handed-off to
-    // BrowserMain() which may elect to promote it (e.g. to BrowserThread::IO).
-    service_manager_thread_ = BrowserProcessSubThread::CreateIOThread();
-    service_manager_context_.reset(
-        new ServiceManagerContext(service_manager_thread_->task_runner()));
-    download::SetIOTaskRunner(service_manager_thread_->task_runner());
-#if defined(OS_ANDROID)
-    base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::BindOnce(&ServiceManagerStartupComplete));
-#endif
+    return RunBrowserProcessMain(main_params, delegate_);
   }
-
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          kAllowStartingServiceManagerOnly) &&
-      start_service_manager_only) {
-    return -1;
-  }
-
-  is_browser_main_loop_started_ = true;
-  startup_data_ = std::make_unique<StartupDataImpl>();
-  startup_data_->thread = std::move(service_manager_thread_);
-  startup_data_->service_manager_context = service_manager_context_.get();
-  main_params.startup_data = startup_data_.get();
-  return RunBrowserProcessMain(main_params, delegate_);
-}
 #endif  // !defined(CHROME_MULTIPLE_DLL_CHILD)
 
+  return RunOtherNamedProcessTypeMain(process_type, main_params, delegate_);
+}
+
 void ContentMainRunnerImpl::Shutdown() {
   DCHECK(is_initialized_);
   DCHECK(!is_shutdown_);
diff --git a/content/app/content_main_runner_impl.h b/content/app/content_main_runner_impl.h
index 29c9675f..c402da2 100644
--- a/content/app/content_main_runner_impl.h
+++ b/content/app/content_main_runner_impl.h
@@ -12,12 +12,10 @@
 #include "base/message_loop/message_loop.h"
 #include "base/metrics/field_trial.h"
 #include "build/build_config.h"
-#include "content/browser/service_manager/service_manager_context.h"
 #include "content/browser/startup_data_impl.h"
 #include "content/public/app/content_main.h"
 #include "content/public/app/content_main_runner.h"
 #include "content/public/common/content_client.h"
-#include "content/public/common/main_function_params.h"
 
 #if defined(OS_WIN)
 #include "sandbox/win/src/sandbox_types.h"
@@ -48,20 +46,6 @@
   void Shutdown() override;
 
  private:
-#if !defined(CHROME_MULTIPLE_DLL_CHILD)
-  int RunServiceManager(MainFunctionParams& main_function_params,
-                        bool start_service_manager_only);
-
-  bool is_browser_main_loop_started_ = false;
-
-  std::unique_ptr<base::MessageLoop> main_message_loop_;
-
-  std::unique_ptr<StartupDataImpl> startup_data_;
-  std::unique_ptr<base::FieldTrialList> field_trial_list_;
-  std::unique_ptr<BrowserProcessSubThread> service_manager_thread_;
-  std::unique_ptr<ServiceManagerContext> service_manager_context_;
-#endif  // !defined(CHROME_MULTIPLE_DLL_CHILD)
-
   // True if the runner has been initialized.
   bool is_initialized_ = false;
 
@@ -89,6 +73,14 @@
 
   CreatedMainPartsClosure* created_main_parts_closure_ = nullptr;
 
+#if !defined(CHROME_MULTIPLE_DLL_CHILD)
+  std::unique_ptr<base::MessageLoop> main_message_loop_;
+
+  std::unique_ptr<StartupDataImpl> startup_data_;
+
+  std::unique_ptr<base::FieldTrialList> field_trial_list_;
+#endif  // !defined(CHROME_MULTIPLE_DLL_CHILD)
+
   DISALLOW_COPY_AND_ASSIGN(ContentMainRunnerImpl);
 };
 
diff --git a/content/browser/android/synchronous_compositor_host.cc b/content/browser/android/synchronous_compositor_host.cc
index ff49053..c45f535 100644
--- a/content/browser/android/synchronous_compositor_host.cc
+++ b/content/browser/android/synchronous_compositor_host.cc
@@ -13,7 +13,7 @@
 #include "base/memory/shared_memory.h"
 #include "base/task/post_task.h"
 #include "base/threading/thread_restrictions.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "content/browser/android/synchronous_compositor_sync_call_bridge.h"
 #include "content/browser/bad_message.h"
 #include "content/browser/renderer_host/render_widget_host_view_android.h"
diff --git a/content/browser/android/tracing_controller_android.cc b/content/browser/android/tracing_controller_android.cc
index 9a03da86..406bc01 100644
--- a/content/browser/android/tracing_controller_android.cc
+++ b/content/browser/android/tracing_controller_android.cc
@@ -7,15 +7,18 @@
 #include <string>
 
 #include "base/android/jni_android.h"
+#include "base/android/jni_array.h"
 #include "base/android/jni_string.h"
 #include "base/json/json_writer.h"
 #include "base/logging.h"
 #include "base/trace_event/trace_event.h"
+#include "content/browser/tracing/tracing_controller_impl.h"
 #include "content/public/browser/tracing_controller.h"
 #include "jni/TracingControllerAndroid_jni.h"
 
 using base::android::JavaParamRef;
 using base::android::ScopedJavaLocalRef;
+using base::android::ScopedJavaGlobalRef;
 
 namespace content {
 
@@ -58,15 +61,23 @@
 void TracingControllerAndroid::StopTracing(
     JNIEnv* env,
     const JavaParamRef<jobject>& obj,
-    const JavaParamRef<jstring>& jfilepath) {
+    const JavaParamRef<jstring>& jfilepath,
+    bool compressfile,
+    const base::android::JavaParamRef<jobject>& callback) {
   base::FilePath file_path(
       base::android::ConvertJavaStringToUTF8(env, jfilepath));
-  if (!TracingController::GetInstance()->StopTracing(
-          TracingController::CreateFileEndpoint(
-              file_path, base::Bind(&TracingControllerAndroid::OnTracingStopped,
-                                    weak_factory_.GetWeakPtr())))) {
+  ScopedJavaGlobalRef<jobject> global_callback(env, callback);
+  auto endpoint = TracingController::CreateFileEndpoint(
+      file_path,
+      base::BindRepeating(&TracingControllerAndroid::OnTracingStopped,
+                          weak_factory_.GetWeakPtr(), global_callback));
+  if (compressfile) {
+    endpoint =
+        TracingControllerImpl::CreateCompressedStringEndpoint(endpoint, true);
+  }
+  if (!TracingController::GetInstance()->StopTracing(endpoint)) {
     LOG(ERROR) << "EndTracingAsync failed, forcing an immediate stop";
-    OnTracingStopped();
+    OnTracingStopped(global_callback);
   }
 }
 
@@ -79,37 +90,47 @@
       base::android::ConvertJavaStringToUTF8(env, jfilename.obj()));
 }
 
-void TracingControllerAndroid::OnTracingStopped() {
+void TracingControllerAndroid::OnTracingStopped(
+    const base::android::ScopedJavaGlobalRef<jobject>& callback) {
   JNIEnv* env = base::android::AttachCurrentThread();
   base::android::ScopedJavaLocalRef<jobject> obj = weak_java_object_.get(env);
   if (obj.obj())
-    Java_TracingControllerAndroid_onTracingStopped(env, obj);
+    Java_TracingControllerAndroid_onTracingStopped(env, obj, callback);
 }
 
-bool TracingControllerAndroid::GetKnownCategoryGroupsAsync(
+bool TracingControllerAndroid::GetKnownCategoriesAsync(
     JNIEnv* env,
-    const JavaParamRef<jobject>& obj) {
-  if (!TracingController::GetInstance()->GetCategories(
-          base::Bind(&TracingControllerAndroid::OnKnownCategoriesReceived,
-                     weak_factory_.GetWeakPtr()))) {
-    return false;
-  }
-  return true;
+    const JavaParamRef<jobject>& obj,
+    const JavaParamRef<jobject>& callback) {
+  ScopedJavaGlobalRef<jobject> global_callback(env, callback);
+  return TracingController::GetInstance()->GetCategories(
+      base::BindOnce(&TracingControllerAndroid::OnKnownCategoriesReceived,
+                     weak_factory_.GetWeakPtr(), global_callback));
 }
 
 void TracingControllerAndroid::OnKnownCategoriesReceived(
+    const ScopedJavaGlobalRef<jobject>& callback,
     const std::set<std::string>& categories_received) {
   base::ListValue category_list;
-  for (std::set<std::string>::const_iterator it = categories_received.begin();
-       it != categories_received.end();
-       ++it) {
-    category_list.AppendString(*it);
-  }
+  for (const std::string& category : categories_received)
+    category_list.AppendString(category);
   std::string received_category_list;
   base::JSONWriter::Write(category_list, &received_category_list);
 
   // This log is required by adb_profile_chrome.py.
+  // TODO(crbug.com/898816): Replace (users of) this with DevTools' Tracing API.
   LOG(WARNING) << "{\"traceCategoriesList\": " << received_category_list << "}";
+
+  JNIEnv* env = base::android::AttachCurrentThread();
+  base::android::ScopedJavaLocalRef<jobject> obj = weak_java_object_.get(env);
+  if (obj.obj()) {
+    std::vector<std::string> category_vector(categories_received.begin(),
+                                             categories_received.end());
+    base::android::ScopedJavaLocalRef<jobjectArray> jcategories =
+        base::android::ToJavaArrayOfStrings(env, category_vector);
+    Java_TracingControllerAndroid_onKnownCategoriesReceived(
+        env, obj, jcategories, callback);
+  }
 }
 
 static ScopedJavaLocalRef<jstring>
@@ -121,4 +142,26 @@
       env, trace_config.ToCategoryFilterString());
 }
 
+bool TracingControllerAndroid::GetTraceBufferUsageAsync(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& obj,
+    const JavaParamRef<jobject>& callback) {
+  ScopedJavaGlobalRef<jobject> global_callback(env, callback);
+  return TracingController::GetInstance()->GetTraceBufferUsage(
+      base::BindOnce(&TracingControllerAndroid::OnTraceBufferUsageReceived,
+                     weak_factory_.GetWeakPtr(), global_callback));
+}
+
+void TracingControllerAndroid::OnTraceBufferUsageReceived(
+    const ScopedJavaGlobalRef<jobject>& callback,
+    float percent_full,
+    size_t approximate_event_count) {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  base::android::ScopedJavaLocalRef<jobject> obj = weak_java_object_.get(env);
+  if (obj.obj()) {
+    Java_TracingControllerAndroid_onTraceBufferUsageReceived(
+        env, obj, percent_full, approximate_event_count, callback);
+  }
+}
+
 }  // namespace content
diff --git a/content/browser/android/tracing_controller_android.h b/content/browser/android/tracing_controller_android.h
index 98b7d39..2a5c984 100644
--- a/content/browser/android/tracing_controller_android.h
+++ b/content/browser/android/tracing_controller_android.h
@@ -26,17 +26,30 @@
                     const base::android::JavaParamRef<jstring>& trace_options);
   void StopTracing(JNIEnv* env,
                    const base::android::JavaParamRef<jobject>& obj,
-                   const base::android::JavaParamRef<jstring>& jfilepath);
-  bool GetKnownCategoryGroupsAsync(
+                   const base::android::JavaParamRef<jstring>& jfilepath,
+                   bool compressfile,
+                   const base::android::JavaParamRef<jobject>& callback);
+  bool GetKnownCategoriesAsync(
       JNIEnv* env,
-      const base::android::JavaParamRef<jobject>& obj);
+      const base::android::JavaParamRef<jobject>& obj,
+      const base::android::JavaParamRef<jobject>& callback);
+  bool GetTraceBufferUsageAsync(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& obj,
+      const base::android::JavaParamRef<jobject>& callback);
   static void GenerateTracingFilePath(base::FilePath* file_path);
 
  private:
   ~TracingControllerAndroid();
-  void OnTracingStopped();
+  void OnTracingStopped(
+      const base::android::ScopedJavaGlobalRef<jobject>& callback);
   void OnKnownCategoriesReceived(
+      const base::android::ScopedJavaGlobalRef<jobject>& callback,
       const std::set<std::string>& categories_received);
+  void OnTraceBufferUsageReceived(
+      const base::android::ScopedJavaGlobalRef<jobject>& callback,
+      float percent_full,
+      size_t approximate_event_count);
 
   JavaObjectWeakGlobalRef weak_java_object_;
   base::WeakPtrFactory<TracingControllerAndroid> weak_factory_;
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc
index 0acb2d2..a9d7b13 100644
--- a/content/browser/browser_main_loop.cc
+++ b/content/browser/browser_main_loop.cc
@@ -561,7 +561,6 @@
     // This is always invoked before |io_thread_| is initialized (i.e. never
     // resets it).
     io_thread_ = std::move(startup_data->thread);
-    service_manager_context_ = startup_data->service_manager_context;
   }
 
   parts_.reset(
@@ -1082,8 +1081,7 @@
     BrowserGpuChannelHostFactory::instance()->CloseChannel();
 
   // Shutdown the Service Manager and IPC.
-  service_manager_context_->ShutDown();
-  owned_service_manager_context_.reset();
+  service_manager_context_.reset();
   mojo_ipc_support_.reset();
 
   if (save_file_manager_)
@@ -1539,13 +1537,9 @@
       base::CreateSingleThreadTaskRunnerWithTraits({BrowserThread::IO}),
       mojo::core::ScopedIPCSupport::ShutdownPolicy::FAST));
 
-  if (!service_manager_context_) {
-    owned_service_manager_context_ =
-        std::make_unique<ServiceManagerContext>(io_thread_->task_runner());
-    service_manager_context_ = owned_service_manager_context_.get();
-  }
+  service_manager_context_.reset(
+      new ServiceManagerContext(io_thread_->task_runner()));
   ServiceManagerContext::StartBrowserConnection();
-
 #if defined(OS_MACOSX)
   mojo::core::SetMachPortProvider(MachBroker::GetInstance());
 #endif  // defined(OS_MACOSX)
diff --git a/content/browser/browser_main_loop.h b/content/browser/browser_main_loop.h
index b70af76..f9118502 100644
--- a/content/browser/browser_main_loop.h
+++ b/content/browser/browser_main_loop.h
@@ -351,10 +351,8 @@
       gpu_data_manager_visual_proxy_;
 #endif
 
-  ServiceManagerContext* service_manager_context_ = nullptr;
-  std::unique_ptr<ServiceManagerContext> owned_service_manager_context_;
-
   // Members initialized in |BrowserThreadsStarted()| --------------------------
+  std::unique_ptr<ServiceManagerContext> service_manager_context_;
   std::unique_ptr<mojo::core::ScopedIPCSupport> mojo_ipc_support_;
 
   // |user_input_monitor_| has to outlive |audio_manager_|, so declared first.
diff --git a/content/browser/browser_main_loop_unittest.cc b/content/browser/browser_main_loop_unittest.cc
index 7d73547..b5d345fc 100644
--- a/content/browser/browser_main_loop_unittest.cc
+++ b/content/browser/browser_main_loop_unittest.cc
@@ -37,7 +37,6 @@
     browser_main_loop.MainMessageLoopStart();
     browser_main_loop.Init();
     browser_main_loop.CreateThreads();
-    browser_main_loop.InitializeMojo();
     EXPECT_GE(base::TaskScheduler::GetInstance()
                   ->GetMaxConcurrentNonBlockedTasksWithTraitsDeprecated(
                       {base::TaskPriority::USER_VISIBLE}),
diff --git a/content/browser/child_process_launcher_helper_posix.cc b/content/browser/child_process_launcher_helper_posix.cc
index bdd38c9c..15a9977 100644
--- a/content/browser/child_process_launcher_helper_posix.cc
+++ b/content/browser/child_process_launcher_helper_posix.cc
@@ -9,6 +9,7 @@
 #include "base/posix/global_descriptors.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
+#include "build/build_config.h"
 #include "content/browser/posix_file_descriptor_info_impl.h"
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/common/content_client.h"
@@ -80,12 +81,15 @@
   std::unique_ptr<PosixFileDescriptorInfo> files_to_register(
       PosixFileDescriptorInfoImpl::Create());
 
+// Mac shared memory doesn't use file descriptors.
+#if !defined(OS_MACOSX)
   base::SharedMemoryHandle shm = base::FieldTrialList::GetFieldTrialHandle();
   if (shm.IsValid()) {
     files_to_register->Share(
         service_manager::kFieldTrialDescriptor,
         base::SharedMemory::GetFdFromSharedMemoryHandle(shm));
   }
+#endif
 
   DCHECK(mojo_channel_remote_endpoint.is_valid());
   files_to_register->Share(
diff --git a/content/browser/code_cache/generated_code_cache.cc b/content/browser/code_cache/generated_code_cache.cc
index 19fa697..5ff073f 100644
--- a/content/browser/code_cache/generated_code_cache.cc
+++ b/content/browser/code_cache/generated_code_cache.cc
@@ -8,7 +8,8 @@
 #include "content/public/common/url_constants.h"
 #include "net/base/completion_callback.h"
 #include "net/base/completion_once_callback.h"
-#include "net/http/http_util.h"
+#include "net/base/url_util.h"
+#include "url/gurl.h"
 
 namespace content {
 
@@ -51,14 +52,14 @@
   // Add a prefix _ so it can't be parsed as a valid URL.
   std::string key = "_key";
   // Remove reference, username and password sections of the URL.
-  key.append(net::HttpUtil::SpecForRequest(resource_url));
+  key.append(net::SimplifyUrlForRequest(resource_url).spec());
   // Add a separator between URL and origin to avoid any possibility of
   // attacks by crafting the URL. URLs do not contain any control ASCII
   // characters, and also space is encoded. So use ' \n' as a seperator.
   key.append(" \n");
 
   if (origin_lock.is_valid())
-    key.append(net::HttpUtil::SpecForRequest(origin_lock));
+    key.append(net::SimplifyUrlForRequest(origin_lock).spec());
   return key;
 }
 }  // namespace
diff --git a/content/browser/devtools/devtools_url_interceptor_request_job.cc b/content/browser/devtools/devtools_url_interceptor_request_job.cc
index dd860149..ae502a0 100644
--- a/content/browser/devtools/devtools_url_interceptor_request_job.cc
+++ b/content/browser/devtools/devtools_url_interceptor_request_job.cc
@@ -386,7 +386,7 @@
 class DevToolsURLInterceptorRequestJob::MockResponseDetails {
  public:
   MockResponseDetails(scoped_refptr<net::HttpResponseHeaders> response_headers,
-                      std::unique_ptr<std::string> response_bytes);
+                      std::string response_bytes);
 
   ~MockResponseDetails();
 
@@ -407,9 +407,9 @@
 
 DevToolsURLInterceptorRequestJob::MockResponseDetails::MockResponseDetails(
     scoped_refptr<net::HttpResponseHeaders> response_headers,
-    std::unique_ptr<std::string> response_bytes)
+    std::string response_bytes)
     : response_headers_(std::move(response_headers)),
-      response_bytes_(response_bytes ? std::move(*response_bytes) : ""),
+      response_bytes_(std::move(response_bytes)),
       read_offset_(0),
       response_time_(base::TimeTicks::Now()) {
   if (!response_headers) {
@@ -971,7 +971,7 @@
   raw_headers.append(new_url);
   raw_headers.append(2, '\0');
   mock_response_details_ = std::make_unique<MockResponseDetails>(
-      base::MakeRefCounted<net::HttpResponseHeaders>(raw_headers), nullptr);
+      base::MakeRefCounted<net::HttpResponseHeaders>(raw_headers), "");
 
   NotifyHeadersComplete();
 }
@@ -1047,7 +1047,8 @@
   if (modifications->response_headers || modifications->response_body) {
     mock_response_details_ = std::make_unique<MockResponseDetails>(
         std::move(modifications->response_headers),
-        std::move(modifications->response_body));
+        modifications->response_body ? std::move(*modifications->response_body)
+                                     : "");
 
     // Set cookies in the network stack.
     net::CookieOptions options;
diff --git a/content/browser/devtools/devtools_url_loader_interceptor.cc b/content/browser/devtools/devtools_url_loader_interceptor.cc
index f689423..7596c2f3 100644
--- a/content/browser/devtools/devtools_url_loader_interceptor.cc
+++ b/content/browser/devtools/devtools_url_loader_interceptor.cc
@@ -322,9 +322,6 @@
       pending_auth_callback_;
   TakeResponseBodyPipeCallback pending_response_body_pipe_callback_;
 
-  // TODO(https://crbug.com/882661): Remove this as soon as the bug is fixed.
-  bool on_receive_response_sent_ = false;
-
   DISALLOW_COPY_AND_ASSIGN(InterceptionJob);
 };
 
@@ -880,7 +877,6 @@
     DCHECK_EQ(State::kResponseReceived, state_);
     DCHECK(!body_reader_);
     client_->OnReceiveResponse(response_metadata_->head);
-    on_receive_response_sent_ = true;
     response_metadata_.reset();
     loader_->ResumeReadingBodyFromNet();
     client_binding_.ResumeIncomingMethodCallProcessing();
@@ -1071,7 +1067,6 @@
 
 void InterceptionJob::SendResponse(const base::StringPiece& body) {
   client_->OnReceiveResponse(response_metadata_->head);
-  on_receive_response_sent_ = true;
 
   // We shouldn't be able to transfer a string that big over the protocol,
   // but just in case...
@@ -1086,7 +1081,6 @@
 
   if (!response_metadata_->cached_metadata.empty())
     client_->OnReceiveCachedMetadata(response_metadata_->cached_metadata);
-  CHECK(on_receive_response_sent_);
   client_->OnStartLoadingResponseBody(std::move(pipe.consumer_handle));
   if (response_metadata_->transfer_size)
     client_->OnTransferSizeUpdated(response_metadata_->transfer_size);
@@ -1325,7 +1319,6 @@
   DCHECK(!response_metadata_);
   if (!(stage_ & InterceptionStage::RESPONSE)) {
     client_->OnReceiveResponse(head);
-    on_receive_response_sent_ = true;
     return;
   }
   loader_->PauseReadingBodyFromNet();
@@ -1398,13 +1391,10 @@
     return;
   }
   DCHECK_EQ(State::kResponseReceived, state_);
-  if (ShouldBypassForResponse()) {
-    // Remove this CHECK once https://crbug.com/882661 is fixed.
-    CHECK(on_receive_response_sent_);
+  if (ShouldBypassForResponse())
     client_->OnStartLoadingResponseBody(std::move(body));
-  } else {
+  else
     body_reader_->StartReading(std::move(body));
-  }
 }
 
 void InterceptionJob::OnComplete(
diff --git a/content/browser/devtools/protocol/network_handler.cc b/content/browser/devtools/protocol/network_handler.cc
index 22580674..8ec313b 100644
--- a/content/browser/devtools/protocol/network_handler.cc
+++ b/content/browser/devtools/protocol/network_handler.cc
@@ -1854,7 +1854,7 @@
 void NetworkHandler::ContinueInterceptedRequest(
     const std::string& interception_id,
     Maybe<std::string> error_reason,
-    Maybe<std::string> base64_raw_response,
+    Maybe<protocol::Binary> raw_response,
     Maybe<std::string> url,
     Maybe<std::string> method,
     Maybe<std::string> post_data,
@@ -1864,27 +1864,24 @@
   scoped_refptr<net::HttpResponseHeaders> response_headers;
   std::unique_ptr<std::string> response_body;
 
-  if (base64_raw_response.isJust()) {
-    std::string decoded;
-    if (!base::Base64Decode(base64_raw_response.fromJust(), &decoded)) {
-      callback->sendFailure(Response::InvalidParams("Invalid rawResponse."));
-      return;
-    }
+  if (raw_response.isJust()) {
+    const protocol::Binary& raw = raw_response.fromJust();
 
     std::string raw_headers;
-    int header_size =
-        net::HttpUtil::LocateEndOfHeaders(decoded.c_str(), decoded.size());
+    int header_size = net::HttpUtil::LocateEndOfHeaders(
+        reinterpret_cast<const char*>(raw.data()), raw.size());
     if (header_size == -1) {
       LOG(WARNING) << "Can't find headers in raw response";
       header_size = 0;
     } else {
-      raw_headers =
-          net::HttpUtil::AssembleRawHeaders(decoded.c_str(), header_size);
+      raw_headers = net::HttpUtil::AssembleRawHeaders(
+          reinterpret_cast<const char*>(raw.data()), header_size);
     }
-    CHECK_LE(static_cast<size_t>(header_size), decoded.size());
+    CHECK_LE(static_cast<size_t>(header_size), raw.size());
     response_headers =
         base::MakeRefCounted<net::HttpResponseHeaders>(std::move(raw_headers));
-    response_body = std::make_unique<std::string>(decoded.substr(header_size));
+    response_body = std::make_unique<std::string>(raw.data() + header_size,
+                                                  raw.data() + raw.size());
   }
 
   base::Optional<net::Error> error;
diff --git a/content/browser/devtools/protocol/network_handler.h b/content/browser/devtools/protocol/network_handler.h
index a132103..39937cf 100644
--- a/content/browser/devtools/protocol/network_handler.h
+++ b/content/browser/devtools/protocol/network_handler.h
@@ -119,7 +119,7 @@
   void ContinueInterceptedRequest(
       const std::string& request_id,
       Maybe<std::string> error_reason,
-      Maybe<std::string> base64_raw_response,
+      Maybe<protocol::Binary> raw_response,
       Maybe<std::string> url,
       Maybe<std::string> method,
       Maybe<std::string> post_data,
diff --git a/content/browser/devtools/protocol_string.cc b/content/browser/devtools/protocol_string.cc
index b96f778..0b92afa 100644
--- a/content/browser/devtools/protocol_string.cc
+++ b/content/browser/devtools/protocol_string.cc
@@ -196,25 +196,13 @@
 }
 
 // static
-Binary Binary::fromVector(std::vector<uint8_t>&& data) {
+Binary Binary::fromVector(std::vector<uint8_t> data) {
   return Binary(base::RefCountedBytes::TakeVector(&data));
 }
 
 // static
-Binary Binary::fromVector(const std::vector<uint8_t>& data) {
-  std::vector<uint8_t> copied_data(data);
-  return Binary(base::RefCountedBytes::TakeVector(&copied_data));
-}
-
-// static
-Binary Binary::fromString(std::string&& data) {
+Binary Binary::fromString(std::string data) {
   return Binary(base::RefCountedString::TakeString(&data));
 }
-
-// static
-Binary Binary::fromString(const std::string& data) {
-  std::string copied_data(data);
-  return Binary(base::RefCountedString::TakeString(&copied_data));
-}
 }  // namespace protocol
 }  // namespace content
diff --git a/content/browser/devtools/protocol_string.h b/content/browser/devtools/protocol_string.h
index fb43a8b..90cc73dd 100644
--- a/content/browser/devtools/protocol_string.h
+++ b/content/browser/devtools/protocol_string.h
@@ -101,10 +101,8 @@
 
   static Binary fromBase64(const String& base64, bool* success);
   static Binary fromRefCounted(scoped_refptr<base::RefCountedMemory> memory);
-  static Binary fromVector(std::vector<uint8_t>&& data);
-  static Binary fromVector(const std::vector<uint8_t>& data);
-  static Binary fromString(std::string&& data);
-  static Binary fromString(const std::string& data);
+  static Binary fromVector(std::vector<uint8_t> data);
+  static Binary fromString(std::string data);
 
  private:
   explicit Binary(scoped_refptr<base::RefCountedMemory> bytes);
diff --git a/content/browser/download/download_manager_impl.cc b/content/browser/download/download_manager_impl.cc
index 6826a995..13e7ee4 100644
--- a/content/browser/download/download_manager_impl.cc
+++ b/content/browser/download/download_manager_impl.cc
@@ -10,6 +10,7 @@
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/debug/alias.h"
+#include "base/debug/dump_without_crashing.h"
 #include "base/i18n/case_conversion.h"
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
@@ -546,7 +547,19 @@
   uint32_t max_id = download::DownloadItem::kInvalidId;
   for (auto& download : in_progress_downloads) {
     DCHECK(!base::ContainsKey(downloads_by_guid_, download->GetGuid()));
-    DCHECK(!base::ContainsKey(downloads_, download->GetId()));
+    // It is problematic to have 2 downloads with the same ID. Log cases that
+    // this happens (without crashing) to track https://crbug.com/898859. Remove
+    // this once the issue is fixed.
+    if (base::ContainsKey(downloads_, download->GetId())) {
+      static auto* download_id_error = base::debug::AllocateCrashKeyString(
+          "download_id_error", base::debug::CrashKeySize::Size32);
+      base::debug::SetCrashKeyString(
+          download_id_error,
+          base::StringPrintf(
+              "id = %d, same_guid = %d", download->GetId(),
+              download->GetGuid() == downloads_[download->GetId()]->GetGuid()));
+      base::debug::DumpWithoutCrashing();
+    }
     uint32_t id = download->GetId();
     if (id > max_id)
       max_id = id;
diff --git a/content/browser/font_unique_name_lookup/font_unique_name_lookup.cc b/content/browser/font_unique_name_lookup/font_unique_name_lookup.cc
index 5199a96..15a2aae0 100644
--- a/content/browser/font_unique_name_lookup/font_unique_name_lookup.cc
+++ b/content/browser/font_unique_name_lookup/font_unique_name_lookup.cc
@@ -23,8 +23,6 @@
 
 namespace {
 
-using namespace ::icu_62;
-
 const char kProtobufFilename[] = "font_unique_name_table.pb";
 static const char* const kAndroidFontPaths[] = {"/system/fonts",
                                                 "/vendor/fonts"};
@@ -285,9 +283,9 @@
                sfnt_name.encoding_id == TT_MAC_ID_ROMAN) {
       codepage_name = "macintosh";
     }
-    UnicodeString sfnt_name_unicode(reinterpret_cast<char*>(sfnt_name.string),
-                                    sfnt_name.string_len,
-                                    codepage_name.c_str());
+    icu::UnicodeString sfnt_name_unicode(
+        reinterpret_cast<char*>(sfnt_name.string), sfnt_name.string_len,
+        codepage_name.c_str());
     if (sfnt_name_unicode.isBogus())
       return false;
     // Firefox performs case insensitive matching for src: local().
diff --git a/content/browser/frame_host/frame_tree_node_blame_context.cc b/content/browser/frame_host/frame_tree_node_blame_context.cc
index 6ef7d23..f856b11 100644
--- a/content/browser/frame_host/frame_tree_node_blame_context.cc
+++ b/content/browser/frame_host/frame_tree_node_blame_context.cc
@@ -6,7 +6,7 @@
 
 #include "base/process/process_handle.h"
 #include "base/strings/stringprintf.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "content/browser/frame_host/frame_tree.h"
 #include "url/gurl.h"
 
diff --git a/content/browser/frame_host/frame_tree_node_blame_context_unittest.cc b/content/browser/frame_host/frame_tree_node_blame_context_unittest.cc
index ff79b54..262ce97 100644
--- a/content/browser/frame_host/frame_tree_node_blame_context_unittest.cc
+++ b/content/browser/frame_host/frame_tree_node_blame_context_unittest.cc
@@ -10,7 +10,7 @@
 #include <string>
 
 #include "base/test/trace_event_analyzer.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "content/browser/frame_host/frame_tree.h"
 #include "content/browser/frame_host/frame_tree_node.h"
 #include "content/common/frame_owner_properties.h"
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index 5acc969fc..0b9f55d 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -26,7 +26,7 @@
 #include "base/task/post_task.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "build/build_config.h"
 #include "cc/base/switches.h"
 #include "content/browser/accessibility/browser_accessibility_manager.h"
@@ -135,6 +135,7 @@
 #include "content/public/common/content_features.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/isolated_world_ids.h"
+#include "content/public/common/network_service_util.h"
 #include "content/public/common/service_manager_connection.h"
 #include "content/public/common/service_names.mojom.h"
 #include "content/public/common/url_constants.h"
@@ -406,13 +407,6 @@
                      render_process_id, params.render_view_routing_id));
 }
 
-bool IsOutOfProcessNetworkService() {
-  return base::FeatureList::IsEnabled(network::features::kNetworkService) &&
-         !base::FeatureList::IsEnabled(features::kNetworkServiceInProcess) &&
-         !base::CommandLine::ForCurrentProcess()->HasSwitch(
-             switches::kSingleProcess);
-}
-
 // Takes the lower 31 bits of the metric-name-hash of a Mojo interface |name|.
 base::Histogram::Sample HashInterfaceNameToHistogramSample(
     base::StringPiece name) {
diff --git a/content/browser/media/key_system_support_impl.cc b/content/browser/media/key_system_support_impl.cc
index 624cca5..d136b8e 100644
--- a/content/browser/media/key_system_support_impl.cc
+++ b/content/browser/media/key_system_support_impl.cc
@@ -178,6 +178,8 @@
   // Supported codecs and encryption schemes.
   auto capability = media::mojom::KeySystemCapability::New();
   capability->video_codecs = cdm_info->capability.video_codecs;
+  capability->supports_vp9_profile2 =
+      cdm_info->capability.supports_vp9_profile2;
   capability->encryption_schemes =
       SetToVector(cdm_info->capability.encryption_schemes);
 
diff --git a/content/browser/network_service_client.cc b/content/browser/network_service_client.cc
index 5df9fbb3..f8c5f414 100644
--- a/content/browser/network_service_client.cc
+++ b/content/browser/network_service_client.cc
@@ -22,6 +22,7 @@
 #include "content/public/browser/login_delegate.h"
 #include "content/public/browser/network_service_instance.h"
 #include "content/public/browser/resource_request_info.h"
+#include "content/public/common/network_service_util.h"
 #include "content/public/common/resource_type.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
 #include "net/ssl/client_cert_store.h"
@@ -319,9 +320,14 @@
                               base::Unretained(this))))
 #endif
 {
+  if (IsOutOfProcessNetworkService())
+    net::CertDatabase::GetInstance()->AddObserver(this);
 }
 
-NetworkServiceClient::~NetworkServiceClient() = default;
+NetworkServiceClient::~NetworkServiceClient() {
+  if (IsOutOfProcessNetworkService())
+    net::CertDatabase::GetInstance()->RemoveObserver(this);
+}
 
 void NetworkServiceClient::OnAuthRequired(
     uint32_t process_id,
@@ -402,6 +408,12 @@
       std::move(web_contents_getter), ssl_info, fatal);
 }
 
+#if defined(OS_CHROMEOS)
+void NetworkServiceClient::OnUsedTrustAnchor(const std::string& username_hash) {
+  GetContentClient()->browser()->OnUsedTrustAnchor(username_hash);
+}
+#endif
+
 void NetworkServiceClient::OnFileUploadRequested(
     uint32_t process_id,
     bool async,
@@ -482,6 +494,10 @@
                                      std::move(callback));
 }
 
+void NetworkServiceClient::OnCertDBChanged() {
+  GetNetworkService()->OnCertDBChanged();
+}
+
 #if defined(OS_ANDROID)
 void NetworkServiceClient::OnApplicationStateChange(
     base::android::ApplicationState state) {
diff --git a/content/browser/network_service_client.h b/content/browser/network_service_client.h
index 92cb62219..70cc35e 100644
--- a/content/browser/network_service_client.h
+++ b/content/browser/network_service_client.h
@@ -9,6 +9,7 @@
 #include "build/build_config.h"
 #include "content/common/content_export.h"
 #include "mojo/public/cpp/bindings/binding.h"
+#include "net/cert/cert_database.h"
 #include "services/network/public/mojom/network_service.mojom.h"
 #include "url/gurl.h"
 
@@ -19,7 +20,8 @@
 namespace content {
 
 class CONTENT_EXPORT NetworkServiceClient
-    : public network::mojom::NetworkServiceClient {
+    : public network::mojom::NetworkServiceClient,
+      public net::CertDatabase::Observer {
  public:
   explicit NetworkServiceClient(network::mojom::NetworkServiceClientRequest
                                     network_service_client_request);
@@ -52,6 +54,9 @@
                              const net::SSLInfo& ssl_info,
                              bool fatal,
                              OnSSLCertificateErrorCallback response) override;
+#if defined(OS_CHROMEOS)
+  void OnUsedTrustAnchor(const std::string& username_hash) override;
+#endif
   void OnFileUploadRequested(uint32_t process_id,
                              bool async,
                              const std::vector<base::FilePath>& file_paths,
@@ -80,6 +85,9 @@
                        int64_t recv_bytes,
                        int64_t sent_bytes) override;
 
+  // net::CertDatabase::Observer implementation:
+  void OnCertDBChanged() override;
+
 #if defined(OS_ANDROID)
   void OnApplicationStateChange(base::android::ApplicationState state);
 #endif
diff --git a/content/browser/renderer_host/delegated_frame_host.cc b/content/browser/renderer_host/delegated_frame_host.cc
index 024410c3..8bb353b 100644
--- a/content/browser/renderer_host/delegated_frame_host.cc
+++ b/content/browser/renderer_host/delegated_frame_host.cc
@@ -57,6 +57,7 @@
   host_frame_sink_manager_->SetFrameSinkDebugLabel(frame_sink_id_,
                                                    "DelegatedFrameHost");
   CreateCompositorFrameSinkSupport();
+  frame_evictor_->SetVisible(client_->DelegatedFrameHostIsVisible());
 }
 
 DelegatedFrameHost::~DelegatedFrameHost() {
@@ -79,6 +80,8 @@
         CreateTabSwitchingTimeRecorder(base::TimeTicks::Now()));
   }
 
+  frame_evictor_->SetVisible(true);
+
   // Use the default deadline to synchronize web content with browser UI.
   // TODO(fsamuel): Investigate if there is a better deadline to use here.
   EmbedSurface(new_local_surface_id, new_dip_size,
@@ -86,7 +89,7 @@
 }
 
 bool DelegatedFrameHost::HasSavedFrame() const {
-  return frame_evictor_->HasFrame();
+  return frame_evictor_->has_surface();
 }
 
 void DelegatedFrameHost::WasHidden() {
@@ -219,9 +222,7 @@
     return;
   }
 
-  // Notify |frame_evictor_| that a new surface was embedded.
-  // TODO(samans): Rename this and remove visibility as parameter.
-  frame_evictor_->SwappedFrame(true /* visibility */);
+  frame_evictor_->OnNewSurfaceEmbedded();
 
   if (!primary_surface_id ||
       primary_surface_id->local_surface_id() != local_surface_id_) {
@@ -243,10 +244,8 @@
     client_->DelegatedFrameHostGetLayer()->SetShowSurface(
         new_primary_surface_id, current_frame_size_in_dip_, GetGutterColor(),
         deadline_policy, false /* stretch_content_to_fill_bounds */);
-    if (compositor_ && !base::CommandLine::ForCurrentProcess()->HasSwitch(
-                           switches::kDisableResizeLock)) {
+    if (compositor_)
       compositor_->OnChildResizing();
-    }
   }
 }
 
@@ -349,7 +348,7 @@
       viz::SurfaceId(frame_sink_id_, local_surface_id_)};
   DCHECK(host_frame_sink_manager_);
   host_frame_sink_manager_->EvictSurfaces(surface_ids);
-  frame_evictor_->DiscardedFrame();
+  frame_evictor_->OnSurfaceDiscarded();
   client_->WasEvicted();
 }
 
@@ -380,7 +379,7 @@
 
 void DelegatedFrameHost::OnLostVizProcess() {
   if (HasSavedFrame())
-    frame_evictor_->DiscardedFrame();
+    frame_evictor_->OnSurfaceDiscarded();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index ee574ee..23ad5f8cc 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -1228,12 +1228,6 @@
     dest->AppendSwitchASCII(switch_name, base::JoinString(features, ","));
 }
 
-void GetNetworkChangeManager(
-    network::mojom::NetworkChangeManagerRequest request) {
-  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-  GetNetworkService()->GetNetworkChangeManager(std::move(request));
-}
-
 std::set<int>& GetCurrentCorbPluginExceptions() {
   static base::NoDestructor<std::set<int>> s_data;
   return *s_data;
@@ -2290,9 +2284,6 @@
   registry->AddInterface(base::BindRepeating(&KeySystemSupportImpl::Create));
 #endif  // BUILDFLAG(ENABLE_LIBRARY_CDMS)
 
-  AddUIThreadInterface(registry.get(),
-                       base::BindRepeating(&GetNetworkChangeManager));
-
   AddUIThreadInterface(
       registry.get(),
       base::BindRepeating(&RenderProcessHostImpl::BindVideoDecoderService,
diff --git a/content/browser/scheduler/browser_task_executor.cc b/content/browser/scheduler/browser_task_executor.cc
index e966424..a5dcf92 100644
--- a/content/browser/scheduler/browser_task_executor.cc
+++ b/content/browser/scheduler/browser_task_executor.cc
@@ -4,6 +4,9 @@
 
 #include "content/browser/scheduler/browser_task_executor.h"
 
+#include <atomic>
+
+#include "base/deferred_sequenced_task_runner.h"
 #include "base/no_destructor.h"
 #include "content/browser/browser_thread_impl.h"
 
@@ -52,6 +55,92 @@
   DISALLOW_COPY_AND_ASSIGN(BrowserThreadTaskRunner);
 };
 
+// TODO(eseckler): This should be replaced by the BrowserUIThreadScheduler.
+class AfterStartupTaskRunner : public base::SingleThreadTaskRunner {
+ public:
+  explicit AfterStartupTaskRunner(
+      scoped_refptr<base::SingleThreadTaskRunner> proxied_task_runner)
+      : proxied_task_runner_(proxied_task_runner) {
+    Reset();
+  }
+
+  void Reset() {
+    listening_for_startup_ = false;
+    deferred_task_runner_ =
+        base::MakeRefCounted<base::DeferredSequencedTaskRunner>(
+            proxied_task_runner_);
+  }
+
+  // SingleThreadTaskRunner implementation.
+  bool PostDelayedTask(const base::Location& from_here,
+                       base::OnceClosure task,
+                       base::TimeDelta delay) override {
+    EnsureListeningForStartup();
+    return deferred_task_runner_->PostDelayedTask(from_here, std::move(task),
+                                                  delay);
+  }
+
+  bool PostNonNestableDelayedTask(const base::Location& from_here,
+                                  base::OnceClosure task,
+                                  base::TimeDelta delay) override {
+    EnsureListeningForStartup();
+    return deferred_task_runner_->PostNonNestableDelayedTask(
+        from_here, std::move(task), delay);
+  }
+
+  bool RunsTasksInCurrentSequence() const override {
+    return deferred_task_runner_->RunsTasksInCurrentSequence();
+  }
+
+  void EnsureListeningForStartup() {
+    if (!listening_for_startup_.exchange(true)) {
+      BrowserThread::PostAfterStartupTask(
+          FROM_HERE, proxied_task_runner_,
+          base::BindOnce(&AfterStartupTaskRunner::Start,
+                         base::Unretained(this)));
+    }
+  }
+
+ private:
+  ~AfterStartupTaskRunner() override {}
+
+  void Start() { deferred_task_runner_->Start(); }
+
+  std::atomic_bool listening_for_startup_;
+  scoped_refptr<SingleThreadTaskRunner> proxied_task_runner_;
+  scoped_refptr<base::DeferredSequencedTaskRunner> deferred_task_runner_;
+
+  DISALLOW_COPY_AND_ASSIGN(AfterStartupTaskRunner);
+};
+
+scoped_refptr<BrowserThreadTaskRunner> GetProxyTaskRunnerForThreadImpl(
+    BrowserThread::ID id) {
+  using TaskRunnerMap = std::array<scoped_refptr<BrowserThreadTaskRunner>,
+                                   BrowserThread::ID_COUNT>;
+  static const base::NoDestructor<TaskRunnerMap> task_runners([] {
+    TaskRunnerMap task_runners;
+    for (int i = 0; i < BrowserThread::ID_COUNT; ++i)
+      task_runners[i] = base::MakeRefCounted<BrowserThreadTaskRunner>(
+          static_cast<BrowserThread::ID>(i));
+    return task_runners;
+  }());
+  return (*task_runners)[id];
+}
+
+scoped_refptr<AfterStartupTaskRunner> GetAfterStartupTaskRunnerForThreadImpl(
+    BrowserThread::ID id) {
+  using TaskRunnerMap = std::array<scoped_refptr<AfterStartupTaskRunner>,
+                                   BrowserThread::ID_COUNT>;
+  static const base::NoDestructor<TaskRunnerMap> task_runners([] {
+    TaskRunnerMap task_runners;
+    for (int i = 0; i < BrowserThread::ID_COUNT; ++i)
+      task_runners[i] = base::MakeRefCounted<AfterStartupTaskRunner>(
+          GetProxyTaskRunnerForThreadImpl(static_cast<BrowserThread::ID>(i)));
+    return task_runners;
+  }());
+  return (*task_runners)[id];
+}
+
 }  // namespace
 
 BrowserTaskExecutor::BrowserTaskExecutor() = default;
@@ -67,6 +156,10 @@
 
 // static
 void BrowserTaskExecutor::ResetForTesting() {
+  for (int i = 0; i < BrowserThread::ID_COUNT; ++i) {
+    GetAfterStartupTaskRunnerForThreadImpl(static_cast<BrowserThread::ID>(i))
+        ->Reset();
+  }
   if (g_browser_task_executor) {
     base::UnregisterTaskExecutorForTesting(
         BrowserTaskTraitsExtension::kExtensionId);
@@ -84,11 +177,11 @@
   const BrowserTaskTraitsExtension& extension =
       traits.GetExtension<BrowserTaskTraitsExtension>();
   if (extension.nestable()) {
-    return GetTaskRunner(extension)->PostDelayedTask(from_here, std::move(task),
-                                                     delay);
+    return GetTaskRunner(traits, extension)
+        ->PostDelayedTask(from_here, std::move(task), delay);
   } else {
-    return GetTaskRunner(extension)->PostNonNestableDelayedTask(
-        from_here, std::move(task), delay);
+    return GetTaskRunner(traits, extension)
+        ->PostNonNestableDelayedTask(from_here, std::move(task), delay);
   }
 }
 
@@ -124,30 +217,33 @@
   DCHECK_EQ(BrowserTaskTraitsExtension::kExtensionId, traits.extension_id());
   const BrowserTaskTraitsExtension& extension =
       traits.GetExtension<BrowserTaskTraitsExtension>();
-  return GetTaskRunner(extension);
+  return GetTaskRunner(traits, extension);
 }
 
 scoped_refptr<base::SingleThreadTaskRunner> BrowserTaskExecutor::GetTaskRunner(
+    const base::TaskTraits& traits,
     const BrowserTaskTraitsExtension& extension) {
   BrowserThread::ID thread_id = extension.browser_thread();
   DCHECK_GE(thread_id, 0);
   DCHECK_LT(thread_id, BrowserThread::ID::ID_COUNT);
+  // TODO(eseckler): For now, make BEST_EFFORT tasks run after startup. Once the
+  // BrowserUIThreadScheduler is in place, this should be handled by its
+  // policies instead.
+  if (traits.priority() == base::TaskPriority::BEST_EFFORT)
+    return GetAfterStartupTaskRunnerForThread(thread_id);
   return GetProxyTaskRunnerForThread(thread_id);
 }
 
 // static
 scoped_refptr<base::SingleThreadTaskRunner>
 BrowserTaskExecutor::GetProxyTaskRunnerForThread(BrowserThread::ID id) {
-  using TaskRunnerMap = std::array<scoped_refptr<base::SingleThreadTaskRunner>,
-                                   BrowserThread::ID_COUNT>;
-  static const base::NoDestructor<TaskRunnerMap> task_runners([] {
-    TaskRunnerMap task_runners;
-    for (int i = 0; i < BrowserThread::ID_COUNT; ++i)
-      task_runners[i] = base::MakeRefCounted<BrowserThreadTaskRunner>(
-          static_cast<BrowserThread::ID>(i));
-    return task_runners;
-  }());
-  return (*task_runners)[id];
+  return GetProxyTaskRunnerForThreadImpl(id);
+}
+
+// static
+scoped_refptr<base::SingleThreadTaskRunner>
+BrowserTaskExecutor::GetAfterStartupTaskRunnerForThread(BrowserThread::ID id) {
+  return GetAfterStartupTaskRunnerForThreadImpl(id);
 }
 
 }  // namespace content
diff --git a/content/browser/scheduler/browser_task_executor.h b/content/browser/scheduler/browser_task_executor.h
index 418d6176f..29e99387 100644
--- a/content/browser/scheduler/browser_task_executor.h
+++ b/content/browser/scheduler/browser_task_executor.h
@@ -6,6 +6,7 @@
 #define CONTENT_BROWSER_SCHEDULER_BROWSER_TASK_EXECUTOR_H_
 
 #include "base/gtest_prod_util.h"
+#include "base/memory/scoped_refptr.h"
 #include "base/task/task_executor.h"
 #include "build/build_config.h"
 #include "content/common/content_export.h"
@@ -53,6 +54,8 @@
                            EnsureUIThreadTraitPointsToExpectedQueue);
   FRIEND_TEST_ALL_PREFIXES(BrowserTaskExecutorTest,
                            EnsureIOThreadTraitPointsToExpectedQueue);
+  FRIEND_TEST_ALL_PREFIXES(BrowserTaskExecutorTest,
+                           BestEffortTasksRunAfterStartup);
 
   BrowserTaskExecutor();
   ~BrowserTaskExecutor() override;
@@ -61,11 +64,15 @@
       const base::TaskTraits& traits);
 
   scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner(
+      const base::TaskTraits& traits,
       const BrowserTaskTraitsExtension& extension);
 
   static scoped_refptr<base::SingleThreadTaskRunner>
   GetProxyTaskRunnerForThread(BrowserThread::ID id);
 
+  static scoped_refptr<base::SingleThreadTaskRunner>
+  GetAfterStartupTaskRunnerForThread(BrowserThread::ID id);
+
   DISALLOW_COPY_AND_ASSIGN(BrowserTaskExecutor);
 };
 
diff --git a/content/browser/scheduler/browser_task_executor_unittest.cc b/content/browser/scheduler/browser_task_executor_unittest.cc
index 7f283afe..433a701 100644
--- a/content/browser/scheduler/browser_task_executor_unittest.cc
+++ b/content/browser/scheduler/browser_task_executor_unittest.cc
@@ -4,12 +4,13 @@
 
 #include "content/browser/scheduler/browser_task_executor.h"
 
-#include "base/message_loop/message_loop.h"
-#include "base/run_loop.h"
+#include <vector>
+
 #include "base/task/post_task.h"
-#include "base/task/task_scheduler/task_scheduler.h"
-#include "content/browser/browser_thread_impl.h"
+#include "base/test/scoped_task_environment.h"
 #include "content/public/browser/browser_task_traits.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "content/test/test_content_browser_client.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace content {
@@ -17,23 +18,45 @@
 class BrowserTaskExecutorTest : public testing::Test {
  public:
   void SetUp() override {
-    base::TaskScheduler::CreateAndStartWithDefaultParams("Test");
-    BrowserTaskExecutor::Create();
-    message_loop_ = std::make_unique<base::MessageLoop>();
+    old_browser_client_ = SetBrowserClientForTesting(&browser_client_);
   }
 
-  void TearDown() override {
-    BrowserTaskExecutor::ResetForTesting();
-    base::TaskScheduler::GetInstance()->Shutdown();
-    base::TaskScheduler::GetInstance()->JoinForTesting();
-    base::TaskScheduler::SetInstance(nullptr);
-    message_loop_.reset();
-  }
-
-  static void RunUntilIdle() { base::RunLoop().RunUntilIdle(); }
+  void TearDown() override { SetBrowserClientForTesting(old_browser_client_); }
 
  protected:
-  std::unique_ptr<base::MessageLoop> message_loop_;
+  class AfterStartupBrowserClient : public TestContentBrowserClient {
+   public:
+    void PostAfterStartupTask(
+        const base::Location& from_here,
+        const scoped_refptr<base::TaskRunner>& task_runner,
+        base::OnceClosure task) override {
+      // The tests only post from UI thread.
+      DCHECK_CURRENTLY_ON(BrowserThread::UI);
+      tasks_.emplace_back(TaskEntry{from_here, task_runner, std::move(task)});
+    }
+
+    void RunTasks() {
+      DCHECK_CURRENTLY_ON(BrowserThread::UI);
+      for (TaskEntry& task : tasks_) {
+        task.task_runner->PostTask(task.from_here, std::move(task.task));
+      }
+      tasks_.clear();
+    }
+
+    struct TaskEntry {
+      base::Location from_here;
+      scoped_refptr<base::TaskRunner> task_runner;
+      base::OnceClosure task;
+    };
+    std::vector<TaskEntry> tasks_;
+  };
+
+  base::test::ScopedTaskEnvironment environment_{
+      base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME};
+  TestBrowserThreadBundle thread_bundle_{
+      TestBrowserThreadBundle::PLAIN_MAINLOOP};
+  AfterStartupBrowserClient browser_client_;
+  ContentBrowserClient* old_browser_client_;
 };
 
 TEST_F(BrowserTaskExecutorTest, EnsureUIThreadTraitPointsToExpectedQueue) {
@@ -48,4 +71,89 @@
       BrowserTaskExecutor::GetProxyTaskRunnerForThread(BrowserThread::IO));
 }
 
+namespace {
+void SetBoolFlag(bool* flag) {
+  *flag = true;
+}
+}  // namespace
+
+TEST_F(BrowserTaskExecutorTest, UserVisibleOrBlockingTasksRunDuringStartup) {
+  bool ran_best_effort = false;
+  bool ran_user_visible = false;
+  bool ran_user_blocking = false;
+
+  base::PostTaskWithTraits(
+      FROM_HERE, {BrowserThread::UI, base::TaskPriority::BEST_EFFORT},
+      base::BindOnce(&SetBoolFlag, base::Unretained(&ran_best_effort)));
+  base::PostTaskWithTraits(
+      FROM_HERE, {BrowserThread::UI, base::TaskPriority::USER_VISIBLE},
+      base::BindOnce(&SetBoolFlag, base::Unretained(&ran_user_visible)));
+  base::PostTaskWithTraits(
+      FROM_HERE, {BrowserThread::UI, base::TaskPriority::USER_BLOCKING},
+      base::BindOnce(&SetBoolFlag, base::Unretained(&ran_user_blocking)));
+
+  environment_.RunUntilIdle();
+
+  EXPECT_FALSE(ran_best_effort);
+  EXPECT_TRUE(ran_user_visible);
+  EXPECT_TRUE(ran_user_blocking);
+}
+
+TEST_F(BrowserTaskExecutorTest, BestEffortTasksRunAfterStartup) {
+  auto ui_best_effort_runner = base::CreateSingleThreadTaskRunnerWithTraits(
+      {BrowserThread::UI, base::TaskPriority::BEST_EFFORT});
+
+  // The TaskRunner shouldn't post directly to the proxy task runner.
+  EXPECT_NE(
+      ui_best_effort_runner,
+      BrowserTaskExecutor::GetProxyTaskRunnerForThread(BrowserThread::UI));
+
+  // Posting BEST_EFFORT tasks before startup should go to the browser_client_.
+  bool ran_first_task = false;
+  ui_best_effort_runner->PostTask(
+      FROM_HERE,
+      base::BindOnce(&SetBoolFlag, base::Unretained(&ran_first_task)));
+
+  ui_best_effort_runner->PostDelayedTask(
+      FROM_HERE, base::DoNothing(), base::TimeDelta::FromMilliseconds(100));
+  base::PostDelayedTaskWithTraits(
+      FROM_HERE, {BrowserThread::UI, base::TaskPriority::BEST_EFFORT},
+      base::DoNothing(), base::TimeDelta::FromMilliseconds(200));
+  PostDelayedTaskWithTraits(
+      FROM_HERE, {BrowserThread::IO, base::TaskPriority::BEST_EFFORT},
+      base::DoNothing(), base::TimeDelta::FromMilliseconds(300));
+
+  // There should be a pending tasks, one from each thread's
+  // AfterStartupTaskRunner.
+  EXPECT_EQ(browser_client_.tasks_.size(), 2u);
+
+  EXPECT_EQ(environment_.GetPendingMainThreadTaskCount(), 0u);
+
+  // Emulate startup complete after 1 sec - this should post the two tasks to
+  // the UI thread.
+  environment_.FastForwardBy(base::TimeDelta::FromSeconds(1));
+  browser_client_.RunTasks();
+  EXPECT_EQ(environment_.GetPendingMainThreadTaskCount(), 2u);
+
+  // Run the two tasks including the first BEST_EFFORT task posted as immediate.
+  // The three other BEST_EFFORT tasks should remain since they are delayed
+  // tasks. They should have been posted with their original delays.
+  environment_.RunUntilIdle();
+  EXPECT_TRUE(ran_first_task);
+  EXPECT_EQ(environment_.GetPendingMainThreadTaskCount(), 3u);
+
+  // Run the delayed tasks one by one.
+  for (size_t pending_tasks = 3; pending_tasks > 0; pending_tasks--) {
+    EXPECT_EQ(environment_.NextMainThreadPendingTaskDelay(),
+              base::TimeDelta::FromMilliseconds(100));
+    environment_.FastForwardBy(base::TimeDelta::FromMilliseconds(100));
+    EXPECT_EQ(environment_.GetPendingMainThreadTaskCount(), pending_tasks - 1u);
+  }
+
+  // Posting another BEST_EFFORT task should bypass the browser_client_.
+  ui_best_effort_runner->PostTask(FROM_HERE, base::DoNothing());
+  EXPECT_EQ(browser_client_.tasks_.size(), 0u);
+  EXPECT_EQ(environment_.GetPendingMainThreadTaskCount(), 1u);
+}
+
 }  // namespace content
diff --git a/content/browser/service_manager/service_manager_context.cc b/content/browser/service_manager/service_manager_context.cc
index 2c577ee..37dafa0 100644
--- a/content/browser/service_manager/service_manager_context.cc
+++ b/content/browser/service_manager/service_manager_context.cc
@@ -763,10 +763,6 @@
 }
 
 ServiceManagerContext::~ServiceManagerContext() {
-  ShutDown();
-}
-
-void ServiceManagerContext::ShutDown() {
   // NOTE: The in-process ServiceManager MUST be destroyed before the browser
   // process-wide ServiceManagerConnection. Otherwise it's possible for the
   // ServiceManager to receive connection requests for service:content_browser
@@ -777,7 +773,6 @@
     ServiceManagerConnection::DestroyForProcess();
   service_manager_thread_task_runner_->PostTask(
       FROM_HERE, base::BindOnce(&DestroyConnectorOnIOThread));
-  packaged_services_connection_.reset();
 }
 
 // static
@@ -801,12 +796,22 @@
   RegisterCommonBrowserInterfaces(browser_connection);
   browser_connection->Start();
 
-  if (base::FeatureList::IsEnabled(network::features::kNetworkService))
-    return;
-
-  // Create the in-process NetworkService object so that its getter is
-  // available on the IO thread.
-  GetNetworkService();
+  bool network_service_enabled =
+      base::FeatureList::IsEnabled(network::features::kNetworkService);
+  bool network_service_in_process =
+      base::FeatureList::IsEnabled(features::kNetworkServiceInProcess) ||
+      base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kSingleProcess);
+  if (!network_service_enabled) {
+    // Create the in-process NetworkService object so that its getter is
+    // available on the IO thread.
+    GetNetworkService();
+  } else if (!network_service_in_process) {
+    // Start the network service process as soon as possible, since it is
+    // critical to start up performance.
+    browser_connection->GetConnector()->StartService(
+        mojom::kNetworkServiceName);
+  }
 }
 
 // static
diff --git a/content/browser/service_manager/service_manager_context.h b/content/browser/service_manager/service_manager_context.h
index 5845051..eebd74a 100644
--- a/content/browser/service_manager/service_manager_context.h
+++ b/content/browser/service_manager/service_manager_context.h
@@ -50,9 +50,6 @@
 
   static base::DeferredSequencedTaskRunner* GetAudioServiceRunner();
 
-  // Shutdowns the ServiceManager and the connections to the ServiceManager.
-  void ShutDown();
-
  private:
   class InProcessServiceManagerContext;
 
diff --git a/content/browser/startup_data_impl.h b/content/browser/startup_data_impl.h
index ddc91a0f..e3f06271 100644
--- a/content/browser/startup_data_impl.h
+++ b/content/browser/startup_data_impl.h
@@ -12,15 +12,13 @@
 
 namespace content {
 
-class ServiceManagerContext;
-
 // The browser implementation of StartupData.
 struct StartupDataImpl : public StartupData {
   StartupDataImpl();
   ~StartupDataImpl() override;
 
+  // TODO(hanxi): add ServiceManagerContext* here.
   std::unique_ptr<BrowserProcessSubThread> thread;
-  ServiceManagerContext* service_manager_context;
 };
 
 }  // namespace content
diff --git a/content/browser/utility_process_host.cc b/content/browser/utility_process_host.cc
index a17f803..20afe9e 100644
--- a/content/browser/utility_process_host.cc
+++ b/content/browser/utility_process_host.cc
@@ -348,6 +348,7 @@
 #if defined(OS_MACOSX)
       service_manager::switches::kEnableSandboxLogging,
 #endif
+      switches::kDisableTestCerts,
       switches::kEnableLogging,
       switches::kForceTextDirection,
       switches::kForceUIDirection,
diff --git a/content/browser/wake_lock/wake_lock_browsertest.cc b/content/browser/wake_lock/wake_lock_browsertest.cc
index d63a632..0dc015e 100644
--- a/content/browser/wake_lock/wake_lock_browsertest.cc
+++ b/content/browser/wake_lock/wake_lock_browsertest.cc
@@ -340,6 +340,10 @@
   WaitForPossibleUpdate();
   EXPECT_TRUE(HasWakeLock());
 
+  // Grab a watcher for the RenderFrameHost of the first site.
+  RenderFrameDeletedObserver frame_observer(
+      GetNestedFrameNode()->current_frame_host());
+
   // Navigate nested frame to a cross-site document.
   NavigateFrameToURL(GetNestedFrameNode(), embedded_test_server()->GetURL(
                                                "b.com", "/simple_page.html"));
@@ -348,6 +352,15 @@
   // Ensure that a new process has been created for the nested frame.
   EXPECT_TRUE(GetNestedFrame()->IsCrossProcessSubframe());
 
+  // While the navigation to the second URL has completed, the teardown of the
+  // host-side objects for the first URL may not have yet. The WakeLock will
+  // only be released once the first renderer is cleaned up since it is held
+  // by that renderer.
+  // TODO(crbug.com/899384): This races with the new renderer then, would it
+  // cause us to release a WakeLock that it requested before the old renderer
+  // was torn down?
+  frame_observer.WaitUntilDeleted();
+
   // Screen wake lock should be released.
   EXPECT_FALSE(HasWakeLock());
 
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 68b0df9..c5ae682b 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -479,38 +479,45 @@
           FrameTreeNode::kFrameTreeNodeInvalidId),
       focused_web_contents_(current_web_contents) {}
 
-WebContentsImpl::WebContentsTreeNode::~WebContentsTreeNode() {
-  if (OuterContentsFrameTreeNode())
-    OuterContentsFrameTreeNode()->RemoveObserver(this);
-
-  if (outer_web_contents_)
-    outer_web_contents_->node_.DetachInnerWebContents(current_web_contents_);
-}
+WebContentsImpl::WebContentsTreeNode::~WebContentsTreeNode() {}
 
 void WebContentsImpl::WebContentsTreeNode::ConnectToOuterWebContents(
-    WebContentsImpl* outer_web_contents,
+    std::unique_ptr<WebContents> current_web_contents,
     RenderFrameHostImpl* outer_contents_frame) {
+  DCHECK_EQ(current_web_contents.get(), current_web_contents_);
+  auto* outer_web_contents =
+      static_cast<WebContentsImpl*>(FromRenderFrameHost(outer_contents_frame));
+
   focused_web_contents_ = nullptr;
   outer_web_contents_ = outer_web_contents;
   outer_contents_frame_tree_node_id_ =
       outer_contents_frame->frame_tree_node()->frame_tree_node_id();
 
-  outer_web_contents_->node_.AttachInnerWebContents(current_web_contents_);
+  outer_web_contents_->node_.AttachInnerWebContents(
+      std::move(current_web_contents));
   outer_contents_frame->frame_tree_node()->AddObserver(this);
 }
 
 void WebContentsImpl::WebContentsTreeNode::AttachInnerWebContents(
-    WebContentsImpl* inner_web_contents) {
-  inner_web_contents_.push_back(inner_web_contents);
+    std::unique_ptr<WebContents> inner_web_contents) {
+  inner_web_contents_.push_back(std::move(inner_web_contents));
 }
 
-void WebContentsImpl::WebContentsTreeNode::DetachInnerWebContents(
+std::unique_ptr<WebContents>
+WebContentsImpl::WebContentsTreeNode::DetachInnerWebContents(
     WebContentsImpl* inner_web_contents) {
-  DCHECK(base::ContainsValue(inner_web_contents_, inner_web_contents));
-  inner_web_contents_.erase(
-      std::remove(inner_web_contents_.begin(), inner_web_contents_.end(),
-                  inner_web_contents),
-      inner_web_contents_.end());
+  std::unique_ptr<WebContents> detached_contents;
+  for (std::unique_ptr<WebContents>& web_contents : inner_web_contents_) {
+    if (web_contents.get() == inner_web_contents) {
+      detached_contents = std::move(web_contents);
+      std::swap(web_contents, inner_web_contents_.back());
+      inner_web_contents_.pop_back();
+      return detached_contents;
+    }
+  }
+
+  NOTREACHED();
+  return nullptr;
 }
 
 FrameTreeNode*
@@ -523,7 +530,9 @@
   DCHECK_EQ(outer_contents_frame_tree_node_id_, node->frame_tree_node_id())
       << "WebContentsTreeNode should only receive notifications for the "
          "FrameTreeNode in its outer WebContents that hosts it.";
-  delete current_web_contents_;  // deletes |this| too.
+
+  // Deletes |this| too.
+  outer_web_contents_->node_.DetachInnerWebContents(current_web_contents_);
 }
 
 void WebContentsImpl::WebContentsTreeNode::SetFocusedWebContents(
@@ -537,17 +546,22 @@
 WebContentsImpl::WebContentsTreeNode::GetInnerWebContentsInFrame(
     const FrameTreeNode* frame) {
   auto ftn_id = frame->frame_tree_node_id();
-  for (WebContentsImpl* contents : inner_web_contents_) {
-    if (contents->node_.outer_contents_frame_tree_node_id() == ftn_id) {
-      return contents;
+  for (auto& contents : inner_web_contents_) {
+    WebContentsImpl* impl = static_cast<WebContentsImpl*>(contents.get());
+    if (impl->node_.outer_contents_frame_tree_node_id() == ftn_id) {
+      return impl;
     }
   }
   return nullptr;
 }
 
-const std::vector<WebContentsImpl*>&
-WebContentsImpl::WebContentsTreeNode::inner_web_contents() const {
-  return inner_web_contents_;
+std::vector<WebContentsImpl*>
+WebContentsImpl::WebContentsTreeNode::GetInnerWebContents() const {
+  std::vector<WebContentsImpl*> inner_web_contents;
+  for (auto& contents : inner_web_contents_)
+    inner_web_contents.push_back(static_cast<WebContentsImpl*>(contents.get()));
+
+  return inner_web_contents;
 }
 
 // WebContentsImpl -------------------------------------------------------------
@@ -1248,7 +1262,7 @@
     return inner_contents;
   }
 
-  return node_.inner_web_contents();
+  return node_.GetInnerWebContents();
 }
 
 std::vector<WebContentsImpl*> WebContentsImpl::GetWebContentsAndAllInner() {
@@ -1779,9 +1793,10 @@
 }
 
 void WebContentsImpl::AttachToOuterWebContentsFrame(
-    WebContents* outer_web_contents,
+    std::unique_ptr<WebContents> current_web_contents,
     RenderFrameHost* outer_contents_frame) {
   DCHECK(!node_.outer_web_contents());
+  DCHECK_EQ(current_web_contents.get(), this);
 
   RenderFrameHostManager* render_manager = GetRenderManager();
 
@@ -1802,16 +1817,12 @@
   if (!render_manager->GetRenderWidgetHostView())
     CreateRenderWidgetHostViewForRenderManager(GetRenderViewHost());
 
-  auto* outer_web_contents_impl =
-      static_cast<WebContentsImpl*>(outer_web_contents);
   auto* outer_contents_frame_impl =
       static_cast<RenderFrameHostImpl*>(outer_contents_frame);
   // Create a link to our outer WebContents.
-  node_.ConnectToOuterWebContents(outer_web_contents_impl,
+  node_.ConnectToOuterWebContents(std::move(current_web_contents),
                                   outer_contents_frame_impl);
 
-  DCHECK(outer_contents_frame);
-
   // Create a proxy in top-level RenderFrameHostManager, pointing to the
   // SiteInstance of the outer WebContents. The proxy will be used to send
   // postMessage to the inner WebContents.
@@ -1820,7 +1831,7 @@
 
   ReattachToOuterWebContentsFrame();
 
-  if (outer_web_contents_impl->frame_tree_.GetFocusedFrame() ==
+  if (node_.outer_web_contents()->frame_tree_.GetFocusedFrame() ==
       outer_contents_frame_impl->frame_tree_node()) {
     SetFocusedFrame(frame_tree_.root(),
                     outer_contents_frame->GetSiteInstance());
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index e3eb4c5..ac4e414 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -358,7 +358,7 @@
   bool NeedToFireBeforeUnload() override;
   void DispatchBeforeUnload(bool auto_cancel) override;
   void AttachToOuterWebContentsFrame(
-      WebContents* outer_web_contents,
+      std::unique_ptr<WebContents> current_web_contents,
       RenderFrameHost* outer_contents_frame) override;
   WebContentsImpl* GetOuterWebContents() override;
   WebContentsImpl* GetOutermostWebContents() override;
@@ -1093,8 +1093,11 @@
     explicit WebContentsTreeNode(WebContentsImpl* current_web_contents);
     ~WebContentsTreeNode() final;
 
-    void ConnectToOuterWebContents(WebContentsImpl* outer_web_contents,
-                                   RenderFrameHostImpl* outer_contents_frame);
+    // Connects |current_web_contents| to the outer WebContents that owns
+    // |outer_contents_frame|.
+    void ConnectToOuterWebContents(
+        std::unique_ptr<WebContents> current_web_contents,
+        RenderFrameHostImpl* outer_contents_frame);
 
     WebContentsImpl* outer_web_contents() const { return outer_web_contents_; }
     int outer_contents_frame_tree_node_id() const {
@@ -1109,11 +1112,13 @@
     // otherwise.
     WebContentsImpl* GetInnerWebContentsInFrame(const FrameTreeNode* frame);
 
-    const std::vector<WebContentsImpl*>& inner_web_contents() const;
+    std::vector<WebContentsImpl*> GetInnerWebContents() const;
 
    private:
-    void AttachInnerWebContents(WebContentsImpl* inner_web_contents);
-    void DetachInnerWebContents(WebContentsImpl* inner_web_contents);
+    void AttachInnerWebContents(
+        std::unique_ptr<WebContents> inner_web_contents);
+    std::unique_ptr<WebContents> DetachInnerWebContents(
+        WebContentsImpl* inner_web_contents);
 
     // FrameTreeNode::Observer implementation.
     void OnFrameTreeNodeDestroyed(FrameTreeNode* node) final;
@@ -1129,8 +1134,9 @@
     // |current_web_contents_| as an inner WebContents.
     int outer_contents_frame_tree_node_id_;
 
-    // List of inner WebContents that we host.
-    std::vector<WebContentsImpl*> inner_web_contents_;
+    // List of inner WebContents that we host. The outer WebContents owns the
+    // inner WebContents.
+    std::vector<std::unique_ptr<WebContents>> inner_web_contents_;
 
     // Only the root node should have this set. This indicates the WebContents
     // whose frame tree has the focused frame. The WebContents tree could be
diff --git a/content/browser/web_package/signed_exchange_cert_fetcher_unittest.cc b/content/browser/web_package/signed_exchange_cert_fetcher_unittest.cc
index f25ee99..4540e58 100644
--- a/content/browser/web_package/signed_exchange_cert_fetcher_unittest.cc
+++ b/content/browser/web_package/signed_exchange_cert_fetcher_unittest.cc
@@ -163,20 +163,20 @@
   }
 
   static std::string CreateCertMessage(const base::StringPiece& cert_data) {
-    cbor::CBORValue::MapValue cbor_map;
-    cbor_map[cbor::CBORValue("sct")] =
-        cbor::CBORValue("SCT", cbor::CBORValue::Type::BYTE_STRING);
-    cbor_map[cbor::CBORValue("cert")] =
-        cbor::CBORValue(cert_data, cbor::CBORValue::Type::BYTE_STRING);
-    cbor_map[cbor::CBORValue("ocsp")] =
-        cbor::CBORValue("OCSP", cbor::CBORValue::Type::BYTE_STRING);
+    cbor::Value::MapValue cbor_map;
+    cbor_map[cbor::Value("sct")] =
+        cbor::Value("SCT", cbor::Value::Type::BYTE_STRING);
+    cbor_map[cbor::Value("cert")] =
+        cbor::Value(cert_data, cbor::Value::Type::BYTE_STRING);
+    cbor_map[cbor::Value("ocsp")] =
+        cbor::Value("OCSP", cbor::Value::Type::BYTE_STRING);
 
-    cbor::CBORValue::ArrayValue cbor_array;
-    cbor_array.push_back(cbor::CBORValue(u8"\U0001F4DC\u26D3"));
-    cbor_array.push_back(cbor::CBORValue(std::move(cbor_map)));
+    cbor::Value::ArrayValue cbor_array;
+    cbor_array.push_back(cbor::Value(u8"\U0001F4DC\u26D3"));
+    cbor_array.push_back(cbor::Value(std::move(cbor_map)));
 
     base::Optional<std::vector<uint8_t>> serialized =
-        cbor::CBORWriter::Write(cbor::CBORValue(std::move(cbor_array)));
+        cbor::Writer::Write(cbor::Value(std::move(cbor_array)));
     if (!serialized)
       return std::string();
     return std::string(reinterpret_cast<char*>(serialized->data()),
diff --git a/content/browser/web_package/signed_exchange_certificate_chain.cc b/content/browser/web_package/signed_exchange_certificate_chain.cc
index c8e35ff3..d2e3bc38 100644
--- a/content/browser/web_package/signed_exchange_certificate_chain.cc
+++ b/content/browser/web_package/signed_exchange_certificate_chain.cc
@@ -24,26 +24,25 @@
   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("loading"),
                "SignedExchangeCertificateChain::ParseB2");
 
-  cbor::CBORReader::DecoderError error;
-  base::Optional<cbor::CBORValue> value =
-      cbor::CBORReader::Read(message, &error);
+  cbor::Reader::DecoderError error;
+  base::Optional<cbor::Value> value = cbor::Reader::Read(message, &error);
   if (!value.has_value()) {
     signed_exchange_utils::ReportErrorAndTraceEvent(
         devtools_proxy,
-        base::StringPrintf("Failed to decode CBORValue. CBOR error: %s",
-                           cbor::CBORReader::ErrorCodeToString(error)));
+        base::StringPrintf("Failed to decode Value. CBOR error: %s",
+                           cbor::Reader::ErrorCodeToString(error)));
     return nullptr;
   }
   if (!value->is_array()) {
     signed_exchange_utils::ReportErrorAndTraceEvent(
         devtools_proxy,
         base::StringPrintf(
-            "Expected top-level CBORValue to be an array. Actual type: %d",
+            "Expected top-level Value to be an array. Actual type: %d",
             static_cast<int>(value->type())));
     return nullptr;
   }
 
-  const cbor::CBORValue::ArrayValue& top_level_array = value->GetArray();
+  const cbor::Value::ArrayValue& top_level_array = value->GetArray();
   // Expect at least 2 elements (magic string and main certificate).
   if (top_level_array.size() < 2) {
     signed_exchange_utils::ReportErrorAndTraceEvent(
@@ -77,12 +76,12 @@
               i, static_cast<int>(top_level_array[i].type())));
       return nullptr;
     }
-    const cbor::CBORValue::MapValue& cert_map = top_level_array[i].GetMap();
+    const cbor::Value::MapValue& cert_map = top_level_array[i].GetMap();
 
     // Step 1. Each cert value MUST be a DER-encoded X.509v3 certificate
     // ([RFC5280]). Other key/value pairs in the same array item define
     // properties of this certificate. [spec text]
-    auto cert_iter = cert_map.find(cbor::CBORValue(kCertKey));
+    auto cert_iter = cert_map.find(cbor::Value(kCertKey));
     if (cert_iter == cert_map.end() || !cert_iter->second.is_bytestring()) {
       signed_exchange_utils::ReportErrorAndTraceEvent(
           devtools_proxy,
@@ -92,7 +91,7 @@
     }
     der_certs.push_back(cert_iter->second.GetBytestringAsString());
 
-    auto ocsp_iter = cert_map.find(cbor::CBORValue(kOcspKey));
+    auto ocsp_iter = cert_map.find(cbor::Value(kOcspKey));
     if (i == 1) {
       // Step 2. The first certificate’s ocsp value MUST be a complete,
       // DER-encoded OCSP response for that certificate (using the ASN.1 type
@@ -125,7 +124,7 @@
     //
     // We use SCTs only of the main certificate.
     if (i == 1) {
-      auto sct_iter = cert_map.find(cbor::CBORValue(kSctKey));
+      auto sct_iter = cert_map.find(cbor::Value(kSctKey));
       if (sct_iter != cert_map.end()) {
         if (!sct_iter->second.is_bytestring()) {
           signed_exchange_utils::ReportErrorAndTraceEvent(
diff --git a/content/browser/web_package/signed_exchange_certificate_chain_unittest.cc b/content/browser/web_package/signed_exchange_certificate_chain_unittest.cc
index 9914948..94cf0ff7 100644
--- a/content/browser/web_package/signed_exchange_certificate_chain_unittest.cc
+++ b/content/browser/web_package/signed_exchange_certificate_chain_unittest.cc
@@ -21,8 +21,8 @@
 
 namespace {
 
-cbor::CBORValue CBORByteString(base::StringPiece str) {
-  return cbor::CBORValue(str, cbor::CBORValue::Type::BYTE_STRING);
+cbor::Value CBORByteString(base::StringPiece str) {
+  return cbor::Value(str, cbor::Value::Type::BYTE_STRING);
 }
 
 }  // namespace
@@ -34,11 +34,10 @@
 }
 
 TEST(SignedExchangeCertificateParseB2Test, EmptyChain) {
-  cbor::CBORValue::ArrayValue cbor_array;
-  cbor_array.push_back(cbor::CBORValue(u8"\U0001F4DC\u26D3"));
+  cbor::Value::ArrayValue cbor_array;
+  cbor_array.push_back(cbor::Value(u8"\U0001F4DC\u26D3"));
 
-  auto serialized =
-      cbor::CBORWriter::Write(cbor::CBORValue(std::move(cbor_array)));
+  auto serialized = cbor::Writer::Write(cbor::Value(std::move(cbor_array)));
   ASSERT_TRUE(serialized.has_value());
 
   auto parsed = SignedExchangeCertificateChain::Parse(
@@ -47,16 +46,15 @@
 }
 
 TEST(SignedExchangeCertificateParseB2Test, MissingCert) {
-  cbor::CBORValue::MapValue cbor_map;
-  cbor_map[cbor::CBORValue("sct")] = CBORByteString("SCT");
-  cbor_map[cbor::CBORValue("ocsp")] = CBORByteString("OCSP");
+  cbor::Value::MapValue cbor_map;
+  cbor_map[cbor::Value("sct")] = CBORByteString("SCT");
+  cbor_map[cbor::Value("ocsp")] = CBORByteString("OCSP");
 
-  cbor::CBORValue::ArrayValue cbor_array;
-  cbor_array.push_back(cbor::CBORValue(u8"\U0001F4DC\u26D3"));
-  cbor_array.push_back(cbor::CBORValue(std::move(cbor_map)));
+  cbor::Value::ArrayValue cbor_array;
+  cbor_array.push_back(cbor::Value(u8"\U0001F4DC\u26D3"));
+  cbor_array.push_back(cbor::Value(std::move(cbor_map)));
 
-  auto serialized =
-      cbor::CBORWriter::Write(cbor::CBORValue(std::move(cbor_array)));
+  auto serialized = cbor::Writer::Write(cbor::Value(std::move(cbor_array)));
   ASSERT_TRUE(serialized.has_value());
 
   auto parsed = SignedExchangeCertificateChain::Parse(
@@ -72,17 +70,16 @@
   base::StringPiece cert_der =
       net::x509_util::CryptoBufferAsStringPiece(certs[0]->cert_buffer());
 
-  cbor::CBORValue::MapValue cbor_map;
-  cbor_map[cbor::CBORValue("sct")] = CBORByteString("SCT");
-  cbor_map[cbor::CBORValue("cert")] = CBORByteString(cert_der);
-  cbor_map[cbor::CBORValue("ocsp")] = CBORByteString("OCSP");
+  cbor::Value::MapValue cbor_map;
+  cbor_map[cbor::Value("sct")] = CBORByteString("SCT");
+  cbor_map[cbor::Value("cert")] = CBORByteString(cert_der);
+  cbor_map[cbor::Value("ocsp")] = CBORByteString("OCSP");
 
-  cbor::CBORValue::ArrayValue cbor_array;
-  cbor_array.push_back(cbor::CBORValue(u8"\U0001F4DC\u26D3"));
-  cbor_array.push_back(cbor::CBORValue(std::move(cbor_map)));
+  cbor::Value::ArrayValue cbor_array;
+  cbor_array.push_back(cbor::Value(u8"\U0001F4DC\u26D3"));
+  cbor_array.push_back(cbor::Value(std::move(cbor_map)));
 
-  auto serialized =
-      cbor::CBORWriter::Write(cbor::CBORValue(std::move(cbor_array)));
+  auto serialized = cbor::Writer::Write(cbor::Value(std::move(cbor_array)));
   ASSERT_TRUE(serialized.has_value());
 
   auto parsed = SignedExchangeCertificateChain::Parse(
@@ -103,16 +100,15 @@
   base::StringPiece cert_der =
       net::x509_util::CryptoBufferAsStringPiece(certs[0]->cert_buffer());
 
-  cbor::CBORValue::MapValue cbor_map;
-  cbor_map[cbor::CBORValue("sct")] = CBORByteString("SCT");
-  cbor_map[cbor::CBORValue("cert")] = CBORByteString(cert_der);
+  cbor::Value::MapValue cbor_map;
+  cbor_map[cbor::Value("sct")] = CBORByteString("SCT");
+  cbor_map[cbor::Value("cert")] = CBORByteString(cert_der);
 
-  cbor::CBORValue::ArrayValue cbor_array;
-  cbor_array.push_back(cbor::CBORValue(u8"\U0001F4DC\u26D3"));
-  cbor_array.push_back(cbor::CBORValue(std::move(cbor_map)));
+  cbor::Value::ArrayValue cbor_array;
+  cbor_array.push_back(cbor::Value(u8"\U0001F4DC\u26D3"));
+  cbor_array.push_back(cbor::Value(std::move(cbor_map)));
 
-  auto serialized =
-      cbor::CBORWriter::Write(cbor::CBORValue(std::move(cbor_array)));
+  auto serialized = cbor::Writer::Write(cbor::Value(std::move(cbor_array)));
   ASSERT_TRUE(serialized.has_value());
 
   auto parsed = SignedExchangeCertificateChain::Parse(
@@ -130,21 +126,20 @@
   base::StringPiece cert2_der =
       net::x509_util::CryptoBufferAsStringPiece(certs[1]->cert_buffer());
 
-  cbor::CBORValue::MapValue cbor_map1;
-  cbor_map1[cbor::CBORValue("sct")] = CBORByteString("SCT");
-  cbor_map1[cbor::CBORValue("cert")] = CBORByteString(cert1_der);
-  cbor_map1[cbor::CBORValue("ocsp")] = CBORByteString("OCSP");
+  cbor::Value::MapValue cbor_map1;
+  cbor_map1[cbor::Value("sct")] = CBORByteString("SCT");
+  cbor_map1[cbor::Value("cert")] = CBORByteString(cert1_der);
+  cbor_map1[cbor::Value("ocsp")] = CBORByteString("OCSP");
 
-  cbor::CBORValue::MapValue cbor_map2;
-  cbor_map2[cbor::CBORValue("cert")] = CBORByteString(cert2_der);
+  cbor::Value::MapValue cbor_map2;
+  cbor_map2[cbor::Value("cert")] = CBORByteString(cert2_der);
 
-  cbor::CBORValue::ArrayValue cbor_array;
-  cbor_array.push_back(cbor::CBORValue(u8"\U0001F4DC\u26D3"));
-  cbor_array.push_back(cbor::CBORValue(std::move(cbor_map1)));
-  cbor_array.push_back(cbor::CBORValue(std::move(cbor_map2)));
+  cbor::Value::ArrayValue cbor_array;
+  cbor_array.push_back(cbor::Value(u8"\U0001F4DC\u26D3"));
+  cbor_array.push_back(cbor::Value(std::move(cbor_map1)));
+  cbor_array.push_back(cbor::Value(std::move(cbor_map2)));
 
-  auto serialized =
-      cbor::CBORWriter::Write(cbor::CBORValue(std::move(cbor_array)));
+  auto serialized = cbor::Writer::Write(cbor::Value(std::move(cbor_array)));
   ASSERT_TRUE(serialized.has_value());
 
   auto parsed = SignedExchangeCertificateChain::Parse(
@@ -169,22 +164,21 @@
   base::StringPiece cert2_der =
       net::x509_util::CryptoBufferAsStringPiece(certs[1]->cert_buffer());
 
-  cbor::CBORValue::MapValue cbor_map1;
-  cbor_map1[cbor::CBORValue("sct")] = CBORByteString("SCT");
-  cbor_map1[cbor::CBORValue("cert")] = CBORByteString(cert1_der);
-  cbor_map1[cbor::CBORValue("ocsp")] = CBORByteString("OCSP1");
+  cbor::Value::MapValue cbor_map1;
+  cbor_map1[cbor::Value("sct")] = CBORByteString("SCT");
+  cbor_map1[cbor::Value("cert")] = CBORByteString(cert1_der);
+  cbor_map1[cbor::Value("ocsp")] = CBORByteString("OCSP1");
 
-  cbor::CBORValue::MapValue cbor_map2;
-  cbor_map2[cbor::CBORValue("cert")] = CBORByteString(cert2_der);
-  cbor_map2[cbor::CBORValue("ocsp")] = CBORByteString("OCSP2");
+  cbor::Value::MapValue cbor_map2;
+  cbor_map2[cbor::Value("cert")] = CBORByteString(cert2_der);
+  cbor_map2[cbor::Value("ocsp")] = CBORByteString("OCSP2");
 
-  cbor::CBORValue::ArrayValue cbor_array;
-  cbor_array.push_back(cbor::CBORValue(u8"\U0001F4DC\u26D3"));
-  cbor_array.push_back(cbor::CBORValue(std::move(cbor_map1)));
-  cbor_array.push_back(cbor::CBORValue(std::move(cbor_map2)));
+  cbor::Value::ArrayValue cbor_array;
+  cbor_array.push_back(cbor::Value(u8"\U0001F4DC\u26D3"));
+  cbor_array.push_back(cbor::Value(std::move(cbor_map1)));
+  cbor_array.push_back(cbor::Value(std::move(cbor_map2)));
 
-  auto serialized =
-      cbor::CBORWriter::Write(cbor::CBORValue(std::move(cbor_array)));
+  auto serialized = cbor::Writer::Write(cbor::Value(std::move(cbor_array)));
   ASSERT_TRUE(serialized.has_value());
 
   auto parsed = SignedExchangeCertificateChain::Parse(
diff --git a/content/browser/web_package/signed_exchange_envelope.cc b/content/browser/web_package/signed_exchange_envelope.cc
index 1b2d42e..039a8d6 100644
--- a/content/browser/web_package/signed_exchange_envelope.cc
+++ b/content/browser/web_package/signed_exchange_envelope.cc
@@ -69,7 +69,7 @@
   return method == "GET" || method == "HEAD" || method == "POST";
 }
 
-bool ParseRequestMap(const cbor::CBORValue& value,
+bool ParseRequestMap(const cbor::Value& value,
                      SignedExchangeEnvelope* out,
                      SignedExchangeDevToolsProxy* devtools_proxy) {
   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("loading"), "ParseRequestMap");
@@ -82,10 +82,10 @@
     return false;
   }
 
-  const cbor::CBORValue::MapValue& request_map = value.GetMap();
+  const cbor::Value::MapValue& request_map = value.GetMap();
 
-  auto method_iter = request_map.find(
-      cbor::CBORValue(kMethodKey, cbor::CBORValue::Type::BYTE_STRING));
+  auto method_iter =
+      request_map.find(cbor::Value(kMethodKey, cbor::Value::Type::BYTE_STRING));
   if (method_iter == request_map.end() ||
       !method_iter->second.is_bytestring()) {
     signed_exchange_utils::ReportErrorAndTraceEvent(
@@ -150,7 +150,7 @@
   return true;
 }
 
-bool ParseResponseMap(const cbor::CBORValue& value,
+bool ParseResponseMap(const cbor::Value& value,
                       SignedExchangeEnvelope* out,
                       SignedExchangeDevToolsProxy* devtools_proxy) {
   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("loading"), "ParseResponseMap");
@@ -163,9 +163,9 @@
     return false;
   }
 
-  const cbor::CBORValue::MapValue& response_map = value.GetMap();
+  const cbor::Value::MapValue& response_map = value.GetMap();
   auto status_iter = response_map.find(
-      cbor::CBORValue(kStatusKey, cbor::CBORValue::Type::BYTE_STRING));
+      cbor::Value(kStatusKey, cbor::Value::Type::BYTE_STRING));
   if (status_iter == response_map.end() ||
       !status_iter->second.is_bytestring()) {
     signed_exchange_utils::ReportErrorAndTraceEvent(
@@ -282,26 +282,25 @@
 
   const GURL& request_url = fallback_url;
 
-  cbor::CBORReader::DecoderError error;
-  base::Optional<cbor::CBORValue> value =
-      cbor::CBORReader::Read(cbor_header, &error);
+  cbor::Reader::DecoderError error;
+  base::Optional<cbor::Value> value = cbor::Reader::Read(cbor_header, &error);
   if (!value.has_value()) {
     signed_exchange_utils::ReportErrorAndTraceEvent(
         devtools_proxy,
-        base::StringPrintf("Failed to decode CBORValue. CBOR error: %s",
-                           cbor::CBORReader::ErrorCodeToString(error)));
+        base::StringPrintf("Failed to decode Value. CBOR error: %s",
+                           cbor::Reader::ErrorCodeToString(error)));
     return base::nullopt;
   }
   if (!value->is_array()) {
     signed_exchange_utils::ReportErrorAndTraceEvent(
         devtools_proxy,
         base::StringPrintf(
-            "Expected top-level CBORValue to be an array. Actual type : %d",
+            "Expected top-level Value to be an array. Actual type : %d",
             static_cast<int>(value->type())));
     return base::nullopt;
   }
 
-  const cbor::CBORValue::ArrayValue& top_level_array = value->GetArray();
+  const cbor::Value::ArrayValue& top_level_array = value->GetArray();
   constexpr size_t kTopLevelArraySize = 2;
   if (top_level_array.size() != kTopLevelArraySize) {
     signed_exchange_utils::ReportErrorAndTraceEvent(
diff --git a/content/browser/web_package/signed_exchange_envelope_unittest.cc b/content/browser/web_package/signed_exchange_envelope_unittest.cc
index 99c7963..d9259ca 100644
--- a/content/browser/web_package/signed_exchange_envelope_unittest.cc
+++ b/content/browser/web_package/signed_exchange_envelope_unittest.cc
@@ -29,8 +29,8 @@
     " cert-sha256=*W7uB969dFW3Mb5ZefPS9Tq5ZbH5iSmOILpjv2qEArmI=*;"
     " date=1511128380; expires=1511733180";
 
-cbor::CBORValue CBORByteString(const char* str) {
-  return cbor::CBORValue(str, cbor::CBORValue::Type::BYTE_STRING);
+cbor::Value CBORByteString(const char* str) {
+  return cbor::Value(str, cbor::Value::Type::BYTE_STRING);
 }
 
 base::Optional<SignedExchangeEnvelope> GenerateHeaderAndParse(
@@ -38,18 +38,18 @@
     base::StringPiece signature,
     const std::map<const char*, const char*>& request_map,
     const std::map<const char*, const char*>& response_map) {
-  cbor::CBORValue::MapValue request_cbor_map;
-  cbor::CBORValue::MapValue response_cbor_map;
+  cbor::Value::MapValue request_cbor_map;
+  cbor::Value::MapValue response_cbor_map;
   for (auto& pair : request_map)
     request_cbor_map[CBORByteString(pair.first)] = CBORByteString(pair.second);
   for (auto& pair : response_map)
     response_cbor_map[CBORByteString(pair.first)] = CBORByteString(pair.second);
 
-  cbor::CBORValue::ArrayValue array;
-  array.push_back(cbor::CBORValue(std::move(request_cbor_map)));
-  array.push_back(cbor::CBORValue(std::move(response_cbor_map)));
+  cbor::Value::ArrayValue array;
+  array.push_back(cbor::Value(std::move(request_cbor_map)));
+  array.push_back(cbor::Value(std::move(response_cbor_map)));
 
-  auto serialized = cbor::CBORWriter::Write(cbor::CBORValue(std::move(array)));
+  auto serialized = cbor::Writer::Write(cbor::Value(std::move(array)));
   return SignedExchangeEnvelope::Parse(
       fallback_url, signature,
       base::make_span(serialized->data(), serialized->size()),
diff --git a/content/browser/webauth/authenticator_impl.cc b/content/browser/webauth/authenticator_impl.cc
index 4b1116ed..b6e957e0 100644
--- a/content/browser/webauth/authenticator_impl.cc
+++ b/content/browser/webauth/authenticator_impl.cc
@@ -377,13 +377,13 @@
         mojo::ConvertTo<blink::mojom::AuthenticatorTransport>(transport));
   }
 
-  const base::Optional<cbor::CBORValue>& maybe_extensions =
+  const base::Optional<cbor::Value>& maybe_extensions =
       response_data.attestation_object().authenticator_data().extensions();
   if (maybe_extensions) {
     DCHECK(maybe_extensions->is_map());
-    const cbor::CBORValue::MapValue& extensions = maybe_extensions->GetMap();
+    const cbor::Value::MapValue& extensions = maybe_extensions->GetMap();
     const auto hmac_secret_it =
-        extensions.find(cbor::CBORValue(device::kExtensionHmacSecret));
+        extensions.find(cbor::Value(device::kExtensionHmacSecret));
     if (hmac_secret_it != extensions.end() &&
         hmac_secret_it->second.is_bool()) {
       response->echo_hmac_create_secret = true;
diff --git a/content/browser/webauth/authenticator_impl_unittest.cc b/content/browser/webauth/authenticator_impl_unittest.cc
index 11bf5db1..4ebddda 100644
--- a/content/browser/webauth/authenticator_impl_unittest.cc
+++ b/content/browser/webauth/authenticator_impl_unittest.cc
@@ -71,8 +71,8 @@
 using blink::mojom::PublicKeyCredentialUserEntity;
 using blink::mojom::PublicKeyCredentialUserEntityPtr;
 using blink::mojom::AuthenticatorTransport;
-using cbor::CBORValue;
-using cbor::CBORReader;
+using cbor::Value;
+using cbor::Reader;
 
 namespace {
 
@@ -1257,8 +1257,8 @@
         continue;
       }
 
-      base::Optional<CBORValue> attestation_value =
-          CBORReader::Read(callback_receiver.value()->attestation_object);
+      base::Optional<Value> attestation_value =
+          Reader::Read(callback_receiver.value()->attestation_object);
       ASSERT_TRUE(attestation_value);
       ASSERT_TRUE(attestation_value->is_map());
       const auto& attestation = attestation_value->GetMap();
@@ -1287,19 +1287,19 @@
 
           // A self-attestation should not include an X.509 chain nor ECDAA key.
           const auto attestation_statement_it =
-              attestation.find(CBORValue("attStmt"));
+              attestation.find(Value("attStmt"));
           ASSERT_TRUE(attestation_statement_it != attestation.end());
           ASSERT_TRUE(attestation_statement_it->second.is_map());
           const auto& attestation_statement =
               attestation_statement_it->second.GetMap();
 
-          ASSERT_TRUE(attestation_statement.find(CBORValue("x5c")) ==
+          ASSERT_TRUE(attestation_statement.find(Value("x5c")) ==
                       attestation_statement.end());
-          ASSERT_TRUE(attestation_statement.find(CBORValue("ecdaaKeyId")) ==
+          ASSERT_TRUE(attestation_statement.find(Value("ecdaaKeyId")) ==
                       attestation_statement.end());
 
           // The AAGUID should be all zero.
-          const auto auth_data_it = attestation.find(CBORValue("authData"));
+          const auto auth_data_it = attestation.find(Value("authData"));
           ASSERT_TRUE(auth_data_it != attestation.end());
           ASSERT_TRUE(auth_data_it->second.is_bytestring());
           const std::vector<uint8_t>& auth_data =
@@ -1340,10 +1340,10 @@
 
   // Expects that |map| contains the given key with a string-value equal to
   // |expected|.
-  static void ExpectMapHasKeyWithStringValue(const CBORValue::MapValue& map,
+  static void ExpectMapHasKeyWithStringValue(const Value::MapValue& map,
                                              const char* key,
                                              const char* expected) {
-    const auto it = map.find(CBORValue(key));
+    const auto it = map.find(Value(key));
     ASSERT_TRUE(it != map.end()) << "No such key '" << key << "'";
     const auto& value = it->second;
     EXPECT_TRUE(value.is_string())
@@ -1357,15 +1357,14 @@
   // Asserts that the webauthn attestation CBOR map in
   // |attestation| contains a single X.509 certificate containing |substring|.
   static void ExpectCertificateContainingSubstring(
-      const CBORValue::MapValue& attestation,
+      const Value::MapValue& attestation,
       const std::string& substring) {
-    const auto& attestation_statement_it =
-        attestation.find(CBORValue("attStmt"));
+    const auto& attestation_statement_it = attestation.find(Value("attStmt"));
     ASSERT_TRUE(attestation_statement_it != attestation.end());
     ASSERT_TRUE(attestation_statement_it->second.is_map());
     const auto& attestation_statement =
         attestation_statement_it->second.GetMap();
-    const auto& x5c_it = attestation_statement.find(CBORValue("x5c"));
+    const auto& x5c_it = attestation_statement.find(Value("x5c"));
     ASSERT_TRUE(x5c_it != attestation_statement.end());
     ASSERT_TRUE(x5c_it->second.is_array());
     const auto& x5c = x5c_it->second.GetArray();
@@ -2065,13 +2064,13 @@
     callback_receiver.WaitForCallback();
     EXPECT_EQ(AuthenticatorStatus::SUCCESS, callback_receiver.status());
 
-    base::Optional<CBORValue> attestation_value =
-        CBORReader::Read(callback_receiver.value()->attestation_object);
+    base::Optional<Value> attestation_value =
+        Reader::Read(callback_receiver.value()->attestation_object);
     ASSERT_TRUE(attestation_value);
     ASSERT_TRUE(attestation_value->is_map());
     const auto& attestation = attestation_value->GetMap();
 
-    const auto auth_data_it = attestation.find(CBORValue(device::kAuthDataKey));
+    const auto auth_data_it = attestation.find(Value(device::kAuthDataKey));
     ASSERT_TRUE(auth_data_it != attestation.end());
     ASSERT_TRUE(auth_data_it->second.is_bytestring());
     const std::vector<uint8_t>& auth_data =
@@ -2087,9 +2086,9 @@
     const auto& extensions = parsed_auth_data->extensions();
     if (extensions) {
       CHECK(extensions->is_map());
-      const cbor::CBORValue::MapValue& extensions_map = extensions->GetMap();
+      const cbor::Value::MapValue& extensions_map = extensions->GetMap();
       const auto hmac_secret_it =
-          extensions_map.find(cbor::CBORValue(device::kExtensionHmacSecret));
+          extensions_map.find(cbor::Value(device::kExtensionHmacSecret));
       if (hmac_secret_it != extensions_map.end()) {
         ASSERT_TRUE(hmac_secret_it->second.is_bool());
         EXPECT_TRUE(hmac_secret_it->second.GetBool());
diff --git a/content/browser/webrtc/webrtc_image_capture_browsertest.cc b/content/browser/webrtc/webrtc_image_capture_browsertest.cc
index bec1c122..183a04f 100644
--- a/content/browser/webrtc/webrtc_image_capture_browsertest.cc
+++ b/content/browser/webrtc/webrtc_image_capture_browsertest.cc
@@ -33,6 +33,7 @@
 #define MAYBE_GetTrackCapabilities GetTrackCapabilities
 #define MAYBE_GetTrackSettings GetTrackSettings
 #define MAYBE_ManipulateZoom DISABLED_ManipulateZoom
+#define MAYBE_ManipulateExposureTime DISABLED_ManipulateExposureTime
 #else
 #define MAYBE_GetPhotoCapabilities GetPhotoCapabilities
 #define MAYBE_GetPhotoSettings GetPhotoSettings
@@ -41,6 +42,7 @@
 #define MAYBE_GetTrackCapabilities GetTrackCapabilities
 #define MAYBE_GetTrackSettings GetTrackSettings
 #define MAYBE_ManipulateZoom ManipulateZoom
+#define MAYBE_ManipulateExposureTime ManipulateExposureTime
 #endif
 
 namespace {
@@ -227,6 +229,12 @@
   ASSERT_TRUE(RunImageCaptureTestCase("testManipulateZoom()"));
 }
 
+IN_PROC_BROWSER_TEST_P(WebRtcImageCaptureSucceedsBrowserTest,
+                       MAYBE_ManipulateExposureTime) {
+  embedded_test_server()->StartAcceptingConnections();
+  ASSERT_TRUE(RunImageCaptureTestCase("testManipulateExposureTime()"));
+}
+
 INSTANTIATE_TEST_CASE_P(
     ,  // Use no prefix, so that these get picked up when using
        // --gtest_filter=WebRtc*
diff --git a/content/child/field_trial.cc b/content/child/field_trial.cc
index b33c04ff..26b6e3e1 100644
--- a/content/child/field_trial.cc
+++ b/content/child/field_trial.cc
@@ -33,7 +33,7 @@
 
 // Ensure any field trials in browser are reflected into the child
 // process.
-#if defined(OS_WIN)
+#if defined(OS_WIN) || defined(OS_MACOSX)
   base::FieldTrialList::CreateTrialsFromCommandLine(
       command_line, switches::kFieldTrialHandle, -1);
 #elif defined(OS_POSIX) || defined(OS_FUCHSIA)
diff --git a/content/public/android/java/src/org/chromium/content/browser/TracingControllerAndroid.java b/content/public/android/java/src/org/chromium/content/browser/TracingControllerAndroid.java
index 43183631..6bafaa5 100644
--- a/content/public/android/java/src/org/chromium/content/browser/TracingControllerAndroid.java
+++ b/content/public/android/java/src/org/chromium/content/browser/TracingControllerAndroid.java
@@ -11,7 +11,9 @@
 import android.content.IntentFilter;
 import android.os.Environment;
 import android.text.TextUtils;
+import android.util.Pair;
 
+import org.chromium.base.Callback;
 import org.chromium.base.Log;
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
@@ -42,7 +44,6 @@
  */
 @JNINamespace("content")
 public class TracingControllerAndroid {
-
     private static final String TAG = "cr.TracingController";
 
     private static final String ACTION_START = "GPU_PROFILER_START";
@@ -69,6 +70,7 @@
     private boolean mShowToasts = true;
 
     private String mFilename;
+    private boolean mCompressFile;
 
     public TracingControllerAndroid(Context context) {
         mContext = context;
@@ -144,17 +146,13 @@
     /**
      * Start profiling to a new file in the Downloads directory.
      *
-     * Calls #startTracing(String, boolean, String, String) with a new timestamped filename.
-     * @see #startTracing(String, boolean, String, String)
+     * Calls #startTracing(String, boolean, String, String, boolean) with a new timestamped
+     * filename. Doesn't compress the file.
+     *
+     * @see #startTracing(String, boolean, String, String, boolean)
      */
     public boolean startTracing(boolean showToasts, String categories, String traceOptions) {
-        mShowToasts = showToasts;
-
-        String filePath = generateTracingFilePath();
-        if (filePath == null) {
-            logAndToastError(mContext.getString(R.string.profiler_no_storage_toast));
-        }
-        return startTracing(filePath, showToasts, categories, traceOptions);
+        return startTracing(null, showToasts, categories, traceOptions, false);
     }
 
     private void initializeNativeControllerIfNeeded() {
@@ -164,13 +162,14 @@
     }
 
     /**
-     * Start profiling to the specified file. Returns true on success.
+     * Start profiling to the specified file (if not null) or to a new file in the Downloads
+     * directory.
      *
      * Only one TracingControllerAndroid can be running at the same time. If another profiler
      * is running when this method is called, it will be cancelled. If this
      * profiler is already running, this method does nothing and returns false.
      *
-     * @param filename The name of the file to output the profile data to.
+     * @param filename The name of the file to output the profile data to, or null.
      * @param showToasts Whether or not we want to show toasts during this profiling session.
      * When we are timing the profile run we might not want to incur extra draw overhead of showing
      * notifications about the profiling system.
@@ -179,19 +178,30 @@
      * @param traceOptions Which trace options to use. See
      * TraceOptions::TraceOptions(const std::string& options_string)
      * (in base/trace_event/trace_event_impl.h) for the format.
+     * @param compressFile Whether the trace file should be compressed (gzip).
+     * @return Whether tracing was started successfully.
      */
     public boolean startTracing(String filename, boolean showToasts, String categories,
-            String traceOptions) {
+            String traceOptions, boolean compressFile) {
         mShowToasts = showToasts;
+
+        if (filename == null) {
+            filename = generateTracingFilePath();
+            if (filename == null) {
+                logAndToastError(mContext.getString(R.string.profiler_no_storage_toast));
+                return false;
+            }
+        }
+
         if (isTracing()) {
             // Don't need a toast because this shouldn't happen via the UI.
             Log.e(TAG, "Received startTracing, but we're already tracing");
             return false;
         }
+
         // Lazy initialize the native side, to allow construction before the library is loaded.
         initializeNativeControllerIfNeeded();
-        if (!nativeStartTracing(mNativeTracingControllerAndroid, categories,
-                traceOptions.toString())) {
+        if (!nativeStartTracing(mNativeTracingControllerAndroid, categories, traceOptions)) {
             logAndToastError(mContext.getString(R.string.profiler_error_toast));
             return false;
         }
@@ -199,16 +209,20 @@
         logForProfiler(String.format(PROFILER_STARTED_FMT, categories));
         showToast(mContext.getString(R.string.profiler_started_toast) + ": " + categories);
         mFilename = filename;
+        mCompressFile = compressFile;
         mIsTracing = true;
         return true;
     }
 
     /**
-     * Stop profiling. This won't take effect until Chrome has flushed its file.
+     * Stop profiling and run |callback| when stopped. This won't take effect until Chrome has
+     * flushed its file.
+     *
+     * @param callback The Callback executed when tracing has stopped.
      */
-    public void stopTracing() {
+    public void stopTracing(Callback<Void> callback) {
         if (isTracing()) {
-            nativeStopTracing(mNativeTracingControllerAndroid, mFilename);
+            nativeStopTracing(mNativeTracingControllerAndroid, mFilename, mCompressFile, callback);
         }
     }
 
@@ -216,7 +230,8 @@
      * Called by native code when the profiler's output file is closed.
      */
     @CalledByNative
-    protected void onTracingStopped() {
+    @SuppressWarnings("unchecked")
+    protected void onTracingStopped(Object callback) {
         if (!isTracing()) {
             // Don't need a toast because this shouldn't happen via the UI.
             Log.e(TAG, "Received onTracingStopped, but we aren't tracing");
@@ -227,20 +242,69 @@
         showToast(mContext.getString(R.string.profiler_stopped_toast, mFilename));
         mIsTracing = false;
         mFilename = null;
+        mCompressFile = false;
+
+        if (callback != null) ((Callback<Void>) callback).onResult(null);
     }
 
     /**
-     * Get known category groups.
+     * Get known categories.
      */
-    public void getCategoryGroups() {
+    public void getKnownCategories() {
+        if (!getKnownCategories(null)) {
+            Log.e(TAG, "Unable to fetch tracing category list.");
+        }
+    }
+
+    /**
+     * Get known categories and run |callback| with the set of known categories.
+     *
+     * @param callback The callback that receives the result.
+     * @return Whether initiating the request was successful.
+     */
+    public boolean getKnownCategories(Callback<String[]> callback) {
         // Lazy initialize the native side, to allow construction before the library is loaded.
         initializeNativeControllerIfNeeded();
-        if (!nativeGetKnownCategoryGroupsAsync(mNativeTracingControllerAndroid)) {
-            Log.e(TAG, "Unable to fetch tracing record groups list.");
+        return nativeGetKnownCategoriesAsync(mNativeTracingControllerAndroid, callback);
+    }
+
+    /**
+     * Called by native when the categories requested by getKnownCategories were obtained.
+     *
+     * @param categories The set of category names.
+     * @param callback The callback that was provided to nativeGetKnownCategoriesAsync.
+     */
+    @CalledByNative
+    @SuppressWarnings("unchecked")
+    public void onKnownCategoriesReceived(String[] categories, Object callback) {
+        if (callback != null) {
+            ((Callback<String[]>) callback).onResult(categories);
         }
     }
 
     /**
+     * Get the current estimated trace buffer usage and approximate total event count in the buffer.
+     *
+     * @param callback The callback that receives the result as a Pair of (percentage_full,
+     * approximate_event_count).
+     * @return Whether initiating the request was successful.
+     */
+    public boolean getTraceBufferUsage(Callback<Pair<Float, Long>> callback) {
+        assert callback != null;
+        // Lazy initialize the native side, to allow construction before the library is loaded.
+        initializeNativeControllerIfNeeded();
+        return nativeGetTraceBufferUsageAsync(mNativeTracingControllerAndroid, callback);
+    }
+
+    @CalledByNative
+    @SuppressWarnings("unchecked")
+    public void onTraceBufferUsageReceived(
+            float percentFull, long approximateEventCount, Object callback) {
+        ((Callback<Pair<Float, Long>>) callback)
+                .onResult(new Pair<>(percentFull, approximateEventCount));
+    }
+
+    /**
      * Clean up the C++ side of this class.
      * After the call, this class instance shouldn't be used.
      */
@@ -257,6 +321,7 @@
     }
 
     // The |str| string needs to match the ones that adb_chrome_profiler looks for.
+    // TODO(crbug.com/898816): Replace (users of) this with DevTools' Tracing API.
     private void logForProfiler(String str) {
         Log.i(TAG, str);
     }
@@ -275,6 +340,7 @@
         }
     }
 
+    // TODO(crbug.com/898816): Replace (users of) this with DevTools' Tracing API.
     class TracingBroadcastReceiver extends BroadcastReceiver {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -290,14 +356,14 @@
                         ? "record-until-full" : "record-continuously";
                 String filename = intent.getStringExtra(FILE_EXTRA);
                 if (filename != null) {
-                    startTracing(filename, true, categories, traceOptions);
+                    startTracing(filename, true, categories, traceOptions, false);
                 } else {
                     startTracing(true, categories, traceOptions);
                 }
             } else if (intent.getAction().endsWith(ACTION_STOP)) {
-                stopTracing();
+                stopTracing(null);
             } else if (intent.getAction().endsWith(ACTION_LIST_CATEGORIES)) {
-                getCategoryGroups();
+                getKnownCategories();
             } else {
                 Log.e(TAG, "Unexpected intent: %s", intent);
             }
@@ -309,7 +375,11 @@
     private native void nativeDestroy(long nativeTracingControllerAndroid);
     private native boolean nativeStartTracing(
             long nativeTracingControllerAndroid, String categories, String traceOptions);
-    private native void nativeStopTracing(long nativeTracingControllerAndroid, String filename);
-    private native boolean nativeGetKnownCategoryGroupsAsync(long nativeTracingControllerAndroid);
+    private native void nativeStopTracing(long nativeTracingControllerAndroid, String filename,
+            boolean compressFile, Callback<Void> callback);
+    private native boolean nativeGetKnownCategoriesAsync(
+            long nativeTracingControllerAndroid, Callback<String[]> callback);
     private native String nativeGetDefaultCategories();
+    private native boolean nativeGetTraceBufferUsageAsync(
+            long nativeTracingControllerAndroid, Callback<Pair<Float, Long>> callback);
 }
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/TracingControllerAndroidTest.java b/content/public/android/javatests/src/org/chromium/content/browser/TracingControllerAndroidTest.java
index 586bc15..46b75ca8 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/TracingControllerAndroidTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/TracingControllerAndroidTest.java
@@ -6,22 +6,27 @@
 
 import static org.chromium.base.test.util.ScalableTimeout.scaleTimeout;
 
-import android.os.SystemClock;
+import android.os.ConditionVariable;
 import android.support.test.filters.MediumTest;
+import android.util.Pair;
 
+import org.hamcrest.CoreMatchers;
 import org.junit.Assert;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import org.chromium.base.Callback;
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.test.BaseJUnit4ClassRunner;
-import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
+import org.chromium.content_public.browser.test.util.CriteriaHelper;
 import org.chromium.content_shell_apk.ContentShellActivity;
 import org.chromium.content_shell_apk.ContentShellActivityTestRule;
 
 import java.io.File;
+import java.io.FileInputStream;
+import java.util.Arrays;
 
 /**
  * Test suite for TracingControllerAndroid.
@@ -36,7 +41,6 @@
     @Test
     @MediumTest
     @Feature({"GPU"})
-    @DisabledTest(message = "crbug.com/621956")
     public void testTraceFileCreation() throws Exception {
         ContentShellActivity activity = mActivityTestRule.launchContentShellWithUrl("about:blank");
         mActivityTestRule.waitForActiveShellToBeDoneLoading();
@@ -45,37 +49,111 @@
         Assert.assertFalse(tracingController.isTracing());
         Assert.assertNull(tracingController.getOutputPath());
 
-        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
-            @Override
-            public void run() {
-                Assert.assertTrue(tracingController.startTracing(true, "*", "record-until-full"));
-            }
+        ThreadUtils.runOnUiThreadBlocking(() -> {
+            Assert.assertTrue(tracingController.startTracing(true, "*", "record-until-full"));
         });
 
         Assert.assertTrue(tracingController.isTracing());
         File file = new File(tracingController.getOutputPath());
         Assert.assertTrue(file.getName().startsWith("chrome-profile-results"));
 
-        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
-            @Override
-            public void run() {
-                tracingController.stopTracing();
-            }
-        });
+        ThreadUtils.runOnUiThreadBlocking(() -> { tracingController.stopTracing(null); });
 
         // The tracer stops asynchronously, because it needs to wait for native code to flush and
         // close the output file. Give it a little time.
-        long startTime = SystemClock.uptimeMillis();
-        while (tracingController.isTracing()) {
-            if (SystemClock.uptimeMillis() > startTime + TIMEOUT_MILLIS) {
-                Assert.fail("Timed out waiting for tracing to stop.");
-            }
-            Thread.sleep(1000);
-        }
+        CriteriaHelper.pollInstrumentationThread(() -> !tracingController.isTracing(),
+                "Timed out waiting for tracing to stop.", TIMEOUT_MILLIS, 100);
 
         // It says it stopped, so it should have written the output file.
         Assert.assertTrue(file.exists());
         Assert.assertTrue(file.delete());
         tracingController.destroy();
     }
+
+    private class TestCallback<T> implements Callback<T> {
+        @Override
+        public void onResult(T result) {
+            mWasCalled.open();
+            mResult = result;
+        }
+
+        public ConditionVariable mWasCalled = new ConditionVariable();
+        public T mResult;
+    }
+
+    @Test
+    @MediumTest
+    @Feature({"GPU"})
+    public void testGetKnownCategories() throws Exception {
+        ContentShellActivity activity = mActivityTestRule.launchContentShellWithUrl("about:blank");
+        mActivityTestRule.waitForActiveShellToBeDoneLoading();
+
+        final TracingControllerAndroid tracingController = new TracingControllerAndroid(activity);
+        Assert.assertFalse(tracingController.isTracing());
+
+        TestCallback<String[]> callback = new TestCallback<>();
+        ThreadUtils.runOnUiThreadBlocking(
+                () -> { Assert.assertTrue(tracingController.getKnownCategories(callback)); });
+
+        Assert.assertTrue(callback.mWasCalled.block(TIMEOUT_MILLIS));
+        Assert.assertThat(Arrays.asList(callback.mResult), CoreMatchers.hasItem("toplevel"));
+        tracingController.destroy();
+    }
+
+    @Test
+    @MediumTest
+    @Feature({"GPU"})
+    public void testBufferUsage() throws Exception {
+        ContentShellActivity activity = mActivityTestRule.launchContentShellWithUrl("about:blank");
+        mActivityTestRule.waitForActiveShellToBeDoneLoading();
+
+        final TracingControllerAndroid tracingController = new TracingControllerAndroid(activity);
+        Assert.assertFalse(tracingController.isTracing());
+
+        // This should obtain an empty buffer usage, since we aren't tracing.
+        TestCallback<Pair<Float, Long>> callback = new TestCallback<>();
+        ThreadUtils.runOnUiThreadBlocking(
+                () -> { Assert.assertTrue(tracingController.getTraceBufferUsage(callback)); });
+
+        Assert.assertTrue(callback.mWasCalled.block(TIMEOUT_MILLIS));
+        Assert.assertEquals(0f, (double) callback.mResult.first, 0.5f);
+        Assert.assertEquals(0, (long) callback.mResult.second);
+        tracingController.destroy();
+    }
+
+    @Test
+    @MediumTest
+    @Feature({"GPU"})
+    public void testStopCallbackAndCompression() throws Exception {
+        ContentShellActivity activity = mActivityTestRule.launchContentShellWithUrl("about:blank");
+        mActivityTestRule.waitForActiveShellToBeDoneLoading();
+
+        final TracingControllerAndroid tracingController = new TracingControllerAndroid(activity);
+        Assert.assertFalse(tracingController.isTracing());
+        Assert.assertNull(tracingController.getOutputPath());
+
+        ThreadUtils.runOnUiThreadBlocking(() -> {
+            Assert.assertTrue(
+                    tracingController.startTracing(null, true, "*", "record-until-full", true));
+        });
+
+        Assert.assertTrue(tracingController.isTracing());
+        File file = new File(tracingController.getOutputPath());
+
+        TestCallback<Void> callback = new TestCallback<>();
+        ThreadUtils.runOnUiThreadBlocking(() -> { tracingController.stopTracing(callback); });
+
+        // Callback should be run once stopped.
+        Assert.assertTrue(callback.mWasCalled.block(TIMEOUT_MILLIS));
+
+        // Should have written the output file, which should start with the gzip header.
+        Assert.assertTrue(file.exists());
+        FileInputStream stream = new FileInputStream(file);
+        byte[] bytes = new byte[2];
+        Assert.assertEquals(2, stream.read(bytes));
+        Assert.assertEquals((byte) 0x1f, bytes[0]);
+        Assert.assertEquals((byte) 0x8b, bytes[1]);
+        Assert.assertTrue(file.delete());
+        tracingController.destroy();
+    }
 }
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h
index e55f518..88dfe1d 100644
--- a/content/public/browser/content_browser_client.h
+++ b/content/public/browser/content_browser_client.h
@@ -632,6 +632,11 @@
   virtual net::CookieStore* OverrideCookieStoreForURL(const GURL& url,
                                                       ResourceContext* context);
 
+#if defined(OS_CHROMEOS)
+  // Notification that a trust anchor was used by the given user.
+  virtual void OnUsedTrustAnchor(const std::string& username_hash) {}
+#endif
+
   // Allows the embedder to override the LocationProvider implementation.
   // Return nullptr to indicate the default one for the platform should be
   // created.
diff --git a/content/public/browser/web_contents.h b/content/public/browser/web_contents.h
index f26f7e5..c3b7c35 100644
--- a/content/public/browser/web_contents.h
+++ b/content/public/browser/web_contents.h
@@ -527,10 +527,10 @@
   // potential discard without causing the dialog to appear.
   virtual void DispatchBeforeUnload(bool auto_cancel) = 0;
 
-  // Attaches this inner WebContents to its container frame
-  // |outer_contents_frame| in |outer_web_contents|.
+  // Attaches |current_web_contents| to its container frame
+  // |outer_contents_frame|.
   virtual void AttachToOuterWebContentsFrame(
-      WebContents* outer_web_contents,
+      std::unique_ptr<WebContents> current_web_contents,
       RenderFrameHost* outer_contents_frame) = 0;
 
   // Returns the outer WebContents of this WebContents if any.
diff --git a/content/public/common/BUILD.gn b/content/public/common/BUILD.gn
index a7c2ce1..c91df37 100644
--- a/content/public/common/BUILD.gn
+++ b/content/public/common/BUILD.gn
@@ -169,6 +169,8 @@
     "mhtml_generation_params.h",
     "mime_handler_view_mode.cc",
     "mime_handler_view_mode.h",
+    "network_service_util.cc",
+    "network_service_util.h",
     "origin_util.h",
     "page_importance_signals.h",
     "page_state.cc",
diff --git a/content/public/common/cdm_info.h b/content/public/common/cdm_info.h
index 2a695f6..f638e87 100644
--- a/content/public/common/cdm_info.h
+++ b/content/public/common/cdm_info.h
@@ -38,6 +38,12 @@
   // TODO(crbug.com/796725) Find a way to include profiles and levels.
   std::vector<media::VideoCodec> video_codecs;
 
+  // When VP9 is supported in |video_codecs|, whether profile 2 is supported.
+  // This is needed because there are older CDMs that only supports profile 0.
+  // TODO(xhwang): Remove this after older CDMs that only supports VP9 profile 0
+  // are obsolete.
+  bool supports_vp9_profile2 = false;
+
   // List of encryption schemes supported by the CDM (e.g. cenc).
   base::flat_set<media::EncryptionMode> encryption_schemes;
 
diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc
index 9c1e708..32965e3 100644
--- a/content/public/common/content_switches.cc
+++ b/content/public/common/content_switches.cc
@@ -244,10 +244,6 @@
 // Prevent renderer process backgrounding when set.
 const char kDisableRendererBackgrounding[]  = "disable-renderer-backgrounding";
 
-// Whether the resize lock is disabled. Default is false. This is generally only
-// useful for tests that want to force disabling.
-const char kDisableResizeLock[] = "disable-resize-lock";
-
 // Whether the ResourceScheduler is disabled.  Note this is only useful for C++
 // Headless embedders who need to implement their own resource scheduling.
 const char kDisableResourceScheduler[] = "disable-resource-scheduler";
@@ -268,6 +264,9 @@
 // Disables the Web Speech API.
 const char kDisableSpeechAPI[]              = "disable-speech-api";
 
+// Disables adding the test certs in the network process.
+const char kDisableTestCerts[] = "disable-test-root-certs";
+
 // Disable multithreaded GPU compositing of web content.
 const char kDisableThreadedCompositing[]     = "disable-threaded-compositing";
 
diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h
index 7535856..9698445 100644
--- a/content/public/common/content_switches.h
+++ b/content/public/common/content_switches.h
@@ -85,13 +85,13 @@
 CONTENT_EXPORT extern const char kDisableRemotePlaybackAPI[];
 extern const char kDisableRendererAccessibility[];
 CONTENT_EXPORT extern const char kDisableRendererBackgrounding[];
-CONTENT_EXPORT extern const char kDisableResizeLock[];
 CONTENT_EXPORT extern const char kDisableResourceScheduler[];
 CONTENT_EXPORT extern const char kDisableSharedWorkers[];
 CONTENT_EXPORT extern const char kDisableSkiaRuntimeOpts[];
 CONTENT_EXPORT extern const char kDisableSmoothScrolling[];
 CONTENT_EXPORT extern const char kDisableSoftwareRasterizer[];
 CONTENT_EXPORT extern const char kDisableSpeechAPI[];
+CONTENT_EXPORT extern const char kDisableTestCerts[];
 CONTENT_EXPORT extern const char kDisableThreadedCompositing[];
 CONTENT_EXPORT extern const char kDisableThreadedScrolling[];
 extern const char kDisableV8IdleTasks[];
diff --git a/content/public/common/network_service_util.cc b/content/public/common/network_service_util.cc
new file mode 100644
index 0000000..abe006c5
--- /dev/null
+++ b/content/public/common/network_service_util.cc
@@ -0,0 +1,21 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/public/common/network_service_util.h"
+
+#include "base/command_line.h"
+#include "content/public/common/content_features.h"
+#include "content/public/common/content_switches.h"
+#include "services/network/public/cpp/features.h"
+
+namespace content {
+
+bool IsOutOfProcessNetworkService() {
+  return base::FeatureList::IsEnabled(network::features::kNetworkService) &&
+         !base::FeatureList::IsEnabled(features::kNetworkServiceInProcess) &&
+         !base::CommandLine::ForCurrentProcess()->HasSwitch(
+             switches::kSingleProcess);
+}
+
+}  // namespace content
diff --git a/content/public/common/network_service_util.h b/content/public/common/network_service_util.h
new file mode 100644
index 0000000..42c078f
--- /dev/null
+++ b/content/public/common/network_service_util.h
@@ -0,0 +1,18 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_PUBLIC_COMMON_NETWORK_SERVICE_UTIL_H_
+#define CONTENT_PUBLIC_COMMON_NETWORK_SERVICE_UTIL_H_
+
+#include "content/common/content_export.h"
+
+namespace content {
+
+// Returns true if the network service is enabled and it's running in a separate
+// process.
+CONTENT_EXPORT bool IsOutOfProcessNetworkService();
+
+}  // namespace content
+
+#endif  // CONTENT_PUBLIC_COMMON_NETWORK_SERVICE_UTIL_H_
diff --git a/content/public/test/browser_test_base.cc b/content/public/test/browser_test_base.cc
index 022e004..86f3b6f 100644
--- a/content/public/test/browser_test_base.cc
+++ b/content/public/test/browser_test_base.cc
@@ -36,6 +36,7 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/main_function_params.h"
+#include "content/public/common/network_service_util.h"
 #include "content/public/common/service_manager_connection.h"
 #include "content/public/common/service_names.mojom.h"
 #include "content/public/test/browser_test_utils.h"
@@ -51,7 +52,6 @@
 #include "services/service_manager/embedder/switches.h"
 #include "services/service_manager/public/cpp/connector.h"
 #include "ui/base/platform_window_defaults.h"
-#include "ui/base/test/material_design_controller_test_api.h"
 #include "ui/compositor/compositor_switches.h"
 #include "ui/display/display_switches.h"
 #include "ui/gl/gl_implementation.h"
@@ -167,10 +167,6 @@
 
 void BrowserTestBase::SetUp() {
   set_up_called_ = true;
-  // ContentTestSuiteBase might have already initialized
-  // MaterialDesignController in browser_tests suite.
-  // Uninitialize here to let the browser process do it.
-  ui::test::MaterialDesignControllerTestAPI::Uninitialize();
 
   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
 
@@ -503,10 +499,8 @@
 
   // Send the host resolver rules to the network service if it's in use. No need
   // to do this if it's running in the browser process though.
-  if (!base::FeatureList::IsEnabled(network::features::kNetworkService) ||
-      IsNetworkServiceRunningInProcess()) {
+  if (!IsOutOfProcessNetworkService())
     return;
-  }
 
   net::RuleBasedHostResolverProc::RuleList rules = host_resolver()->GetRules();
   std::vector<network::mojom::RulePtr> mojo_rules;
diff --git a/content/public/test/network_service_test_helper.cc b/content/public/test/network_service_test_helper.cc
index c5c55f6..b9b56267 100644
--- a/content/public/test/network_service_test_helper.cc
+++ b/content/public/test/network_service_test_helper.cc
@@ -226,13 +226,16 @@
 #if defined(OS_ANDROID)
     base::InitAndroidTestPaths(base::android::GetIsolatedTestRoot());
 #endif
-    net::EmbeddedTestServer::RegisterTestCerts();
-    net::SpawnedTestServer::RegisterTestCerts();
 
-    // Also add the QUIC test certificate.
-    net::TestRootCerts* root_certs = net::TestRootCerts::GetInstance();
-    root_certs->AddFromFile(
-        net::GetTestCertsDirectory().AppendASCII("quic-root.pem"));
+    if (!command_line->HasSwitch(switches::kDisableTestCerts)) {
+      net::EmbeddedTestServer::RegisterTestCerts();
+      net::SpawnedTestServer::RegisterTestCerts();
+
+      // Also add the QUIC test certificate.
+      net::TestRootCerts* root_certs = net::TestRootCerts::GetInstance();
+      root_certs->AddFromFile(
+          net::GetTestCertsDirectory().AppendASCII("quic-root.pem"));
+    }
   }
 }
 
diff --git a/content/public/test/test_launcher.cc b/content/public/test/test_launcher.cc
index 10ced16..d7d72a1 100644
--- a/content/public/test/test_launcher.cc
+++ b/content/public/test/test_launcher.cc
@@ -661,7 +661,8 @@
 
   base::MessageLoopForIO message_loop;
 #if defined(OS_POSIX)
-  base::FileDescriptorWatcher file_descriptor_watcher(&message_loop);
+  base::FileDescriptorWatcher file_descriptor_watcher(
+      message_loop->task_runner());
 #endif
 
   launcher_delegate->PreSharding();
diff --git a/content/public/test/test_renderer_host.cc b/content/public/test/test_renderer_host.cc
index 51ac4f6f..664fa117 100644
--- a/content/public/test/test_renderer_host.cc
+++ b/content/public/test/test_renderer_host.cc
@@ -35,7 +35,6 @@
 #include "content/test/test_web_contents.h"
 #include "net/base/network_change_notifier.h"
 #include "ui/base/material_design/material_design_controller.h"
-#include "ui/base/test/material_design_controller_test_api.h"
 
 #if defined(OS_ANDROID)
 #include "ui/android/dummy_screen_android.h"
@@ -267,9 +266,6 @@
   // tests.
   network_change_notifier_.reset(net::NetworkChangeNotifier::CreateMock());
 
-  // ContentTestSuiteBase might have already initialized
-  // MaterialDesignController in unit_tests suite.
-  ui::test::MaterialDesignControllerTestAPI::Uninitialize();
   ui::MaterialDesignController::Initialize();
 
   rvh_test_enabler_.reset(new RenderViewHostTestEnabler);
diff --git a/content/public/test/test_utils.cc b/content/public/test/test_utils.cc
index 04d890a..7eb5c087 100644
--- a/content/public/test/test_utils.cc
+++ b/content/public/test/test_utils.cc
@@ -263,12 +263,13 @@
 
   WebContents::CreateParams inner_params(outer_contents->GetBrowserContext());
 
-  // TODO(erikchen): Fix ownership semantics for guest views.
-  // https://crbug.com/832879.
-  WebContents* inner_contents = WebContents::Create(inner_params).release();
+  std::unique_ptr<WebContents> inner_contents_ptr =
+      WebContents::Create(inner_params);
 
   // Attach. |inner_contents| becomes owned by |outer_contents|.
-  inner_contents->AttachToOuterWebContentsFrame(outer_contents, rfh);
+  WebContents* inner_contents = inner_contents_ptr.get();
+  inner_contents->AttachToOuterWebContentsFrame(std::move(inner_contents_ptr),
+                                                rfh);
 
   // |guest_delegate| becomes owned by |inner_contents|.
   guest_delegate.release()->SetInnerWebContents(inner_contents);
diff --git a/content/renderer/frame_blame_context.cc b/content/renderer/frame_blame_context.cc
index 096f10d..ae48d17 100644
--- a/content/renderer/frame_blame_context.cc
+++ b/content/renderer/frame_blame_context.cc
@@ -4,7 +4,7 @@
 
 #include "content/renderer/frame_blame_context.h"
 
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "content/renderer/render_frame_impl.h"
 #include "content/renderer/top_level_blame_context.h"
 #include "third_party/blink/public/platform/platform.h"
diff --git a/content/renderer/service_worker/service_worker_context_client.cc b/content/renderer/service_worker/service_worker_context_client.cc
index 1884cdab..4a44ca4a 100644
--- a/content/renderer/service_worker/service_worker_context_client.cc
+++ b/content/renderer/service_worker/service_worker_context_client.cc
@@ -23,6 +23,7 @@
 #include "content/common/service_worker/service_worker.mojom.h"
 #include "content/common/service_worker/service_worker_utils.h"
 #include "content/public/common/content_features.h"
+#include "content/public/common/network_service_util.h"
 #include "content/public/common/referrer.h"
 #include "content/public/renderer/content_renderer_client.h"
 #include "content/public/renderer/document_state.h"
@@ -178,13 +179,6 @@
   std::unique_ptr<ServiceWorkerTimeoutTimer::StayAwakeToken> token_;
 };
 
-bool IsOutOfProcessNetworkService() {
-  return base::FeatureList::IsEnabled(network::features::kNetworkService) &&
-         !base::FeatureList::IsEnabled(features::kNetworkServiceInProcess) &&
-         !base::CommandLine::ForCurrentProcess()->HasSwitch(
-             switches::kSingleProcess);
-}
-
 blink::mojom::RequestContextType GetBlinkRequestContext(
     blink::mojom::RequestContextType request_context_type) {
   return static_cast<blink::mojom::RequestContextType>(request_context_type);
diff --git a/content/renderer/shared_worker/embedded_shared_worker_stub.cc b/content/renderer/shared_worker/embedded_shared_worker_stub.cc
index 8b9dfc0..ff2339a 100644
--- a/content/renderer/shared_worker/embedded_shared_worker_stub.cc
+++ b/content/renderer/shared_worker/embedded_shared_worker_stub.cc
@@ -16,6 +16,7 @@
 #include "content/public/common/content_client.h"
 #include "content/public/common/content_features.h"
 #include "content/public/common/content_switches.h"
+#include "content/public/common/network_service_util.h"
 #include "content/public/common/origin_util.h"
 #include "content/public/common/renderer_preferences.h"
 #include "content/public/renderer/content_renderer_client.h"
@@ -203,14 +204,6 @@
   std::unique_ptr<NavigationResponseOverrideParameters> response_override_;
 };
 
-// "ForSharedWorker" is to avoid collisions in Jumbo builds.
-bool IsOutOfProcessNetworkServiceForSharedWorker() {
-  return base::FeatureList::IsEnabled(network::features::kNetworkService) &&
-         !base::FeatureList::IsEnabled(features::kNetworkServiceInProcess) &&
-         !base::CommandLine::ForCurrentProcess()->HasSwitch(
-             switches::kSingleProcess);
-}
-
 }  // namespace
 
 EmbeddedSharedWorkerStub::EmbeddedSharedWorkerStub(
@@ -292,7 +285,7 @@
     // The default factory might not be to the network service if a feature like
     // AppCache set itself to the default, but treat a connection error as fatal
     // anyway so clients don't get stuck.
-    if (IsOutOfProcessNetworkServiceForSharedWorker()) {
+    if (IsOutOfProcessNetworkService()) {
       default_factory_connection_error_handler_holder_.Bind(
           std::move(factory_bundle->default_factory_info()));
       default_factory_connection_error_handler_holder_->Clone(
diff --git a/content/shell/app/shell_main_delegate.cc b/content/shell/app/shell_main_delegate.cc
index 80debcc..fe768c59 100644
--- a/content/shell/app/shell_main_delegate.cc
+++ b/content/shell/app/shell_main_delegate.cc
@@ -209,7 +209,6 @@
       return true;
     }
 #endif
-    command_line.AppendSwitch(switches::kDisableResizeLock);
     command_line.AppendSwitch(cc::switches::kEnableGpuBenchmarking);
     command_line.AppendSwitch(switches::kEnableLogging);
     command_line.AppendSwitch(switches::kAllowFileAccessFromFiles);
diff --git a/content/test/data/media/image_capture_test.html b/content/test/data/media/image_capture_test.html
index 5239163..d73c5aa 100644
--- a/content/test/data/media/image_capture_test.html
+++ b/content/test/data/media/image_capture_test.html
@@ -209,6 +209,68 @@
       });
 }
 
+// Tries to read, set and read back the exposureTime capability if available.
+function testManipulateExposureTime() {
+    var newExposureTime = -1;
+    var imageCapturer;
+    var exposureTimeTolerance;
+    navigator.mediaDevices.getUserMedia({"video": CONSTRAINTS})
+        .then(stream => {
+            assertEquals('video', stream.getVideoTracks()[0].kind);
+            return new ImageCapture(stream.getVideoTracks()[0]);
+        })
+        .then(capturer => {
+            imageCapturer = capturer;
+            // TODO(mcasas): Before accesing synchronous track APIs we need a delay,
+            // use instead a round trip of capabilities: https://crbug.com/711524.
+            return capturer.getPhotoCapabilities();
+        })
+        .then(capabilities => {
+            const trackCapabilities = imageCapturer.track.getCapabilities();
+            if (trackCapabilities.exposureTime === undefined) {
+                console.log('exposureTime not supported, skipping test');
+                reportTestSuccess();
+                return;
+            }
+
+            const currentExposureTime = imageCapturer.track.getSettings().exposureTime;
+            newExposureTime = currentExposureTime + trackCapabilities.exposureTime
+                .step;
+            newExposureTime = Math.min(newExposureTime, trackCapabilities.exposureTime
+                .max);
+            console.log("Setting exposureTime from " + currentExposureTime +
+                " to " +
+                newExposureTime);
+            exposureTimeTolerance = trackCapabilities.exposureTime.step /
+                10;
+
+            currentExposureMode = imageCapturer.track.getSettings().exposureMode;
+            console.log(" exposureMode == " + currentExposureMode);
+            exposureModeCapabilities = trackCapabilities.exposureMode;
+            console.log(" exposureModeCapabilities == " +
+                exposureModeCapabilities);
+
+            return imageCapturer.track.applyConstraints({
+                advanced: [{
+                    exposureMode: "manual",
+                    exposureTime: newExposureTime
+                }]
+            });
+        })
+        .then(() => {
+            assertEquals(newExposureTime,
+                imageCapturer.track.getConstraints().advanced[0].exposureTime
+            );
+            assertTrue(Math.abs(newExposureTime - imageCapturer.track.getSettings()
+                    .exposureTime) <
+                exposureTimeTolerance);
+            reportTestSuccess();
+        })
+        .catch(err => {
+            return failTest(err.toString());
+        });
+}
+
 </script>
 </body>
 </html>
diff --git a/dbus/bus_unittest.cc b/dbus/bus_unittest.cc
index 5e7173a..738c64cc 100644
--- a/dbus/bus_unittest.cc
+++ b/dbus/bus_unittest.cc
@@ -321,7 +321,8 @@
   base::MessageLoopForIO message_loop;
 
   // This enables FileDescriptorWatcher, which is required by dbus::Watch.
-  base::FileDescriptorWatcher file_descriptor_watcher(&message_loop);
+  base::FileDescriptorWatcher file_descriptor_watcher(
+      message_loop.task_runner());
 
   RunLoopWithExpectedCount run_loop_state;
 
diff --git a/dbus/object_proxy_unittest.cc b/dbus/object_proxy_unittest.cc
index 904e0d76..4ae25f3 100644
--- a/dbus/object_proxy_unittest.cc
+++ b/dbus/object_proxy_unittest.cc
@@ -4,10 +4,9 @@
 
 #include "dbus/object_proxy.h"
 #include "base/bind.h"
-#include "base/files/file_descriptor_watcher_posix.h"
 #include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
+#include "base/test/scoped_task_environment.h"
 #include "dbus/bus.h"
 #include "dbus/test_service.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -17,7 +16,7 @@
 
 class ObjectProxyTest : public testing::Test {
  protected:
-  ObjectProxyTest() : file_descriptor_watcher_(&message_loop_) {}
+  ObjectProxyTest() {}
 
   void SetUp() override {
     Bus::Options bus_options;
@@ -28,10 +27,8 @@
 
   void TearDown() override { bus_->ShutdownAndBlock(); }
 
-  base::MessageLoopForIO message_loop_;
-
-  // This enables FileDescriptorWatcher, which is required by dbus::Watch.
-  base::FileDescriptorWatcher file_descriptor_watcher_;
+  base::test::ScopedTaskEnvironment task_environment_{
+      base::test::ScopedTaskEnvironment::MainThreadType::IO};
 
   scoped_refptr<Bus> bus_;
 };
diff --git a/device/fido/attestation_object.cc b/device/fido/attestation_object.cc
index 217ee4d..2369573 100644
--- a/device/fido/attestation_object.cc
+++ b/device/fido/attestation_object.cc
@@ -59,24 +59,24 @@
 }
 
 std::vector<uint8_t> AttestationObject::SerializeToCBOREncodedBytes() const {
-  cbor::CBORValue::MapValue map;
-  map[cbor::CBORValue(kFormatKey)] =
-      cbor::CBORValue(attestation_statement_->format_name());
-  map[cbor::CBORValue(kAuthDataKey)] =
-      cbor::CBORValue(authenticator_data_.SerializeToByteArray());
-  map[cbor::CBORValue(kAttestationStatementKey)] =
-      cbor::CBORValue(attestation_statement_->GetAsCBORMap());
-  return cbor::CBORWriter::Write(cbor::CBORValue(std::move(map)))
+  cbor::Value::MapValue map;
+  map[cbor::Value(kFormatKey)] =
+      cbor::Value(attestation_statement_->format_name());
+  map[cbor::Value(kAuthDataKey)] =
+      cbor::Value(authenticator_data_.SerializeToByteArray());
+  map[cbor::Value(kAttestationStatementKey)] =
+      cbor::Value(attestation_statement_->GetAsCBORMap());
+  return cbor::Writer::Write(cbor::Value(std::move(map)))
       .value_or(std::vector<uint8_t>());
 }
 
 std::vector<uint8_t> SerializeToCtapStyleCborEncodedBytes(
     const AttestationObject& object) {
-  cbor::CBORValue::MapValue map;
+  cbor::Value::MapValue map;
   map.emplace(1, object.attestation_statement().format_name());
   map.emplace(2, object.authenticator_data().SerializeToByteArray());
   map.emplace(3, object.attestation_statement().GetAsCBORMap());
-  auto encoded_bytes = cbor::CBORWriter::Write(cbor::CBORValue(std::move(map)));
+  auto encoded_bytes = cbor::Writer::Write(cbor::Value(std::move(map)));
   DCHECK(encoded_bytes);
   return std::move(*encoded_bytes);
 }
diff --git a/device/fido/attestation_statement.cc b/device/fido/attestation_statement.cc
index 04c96b5..44bc680 100644
--- a/device/fido/attestation_statement.cc
+++ b/device/fido/attestation_statement.cc
@@ -35,8 +35,8 @@
   return base::nullopt;
 }
 
-cbor::CBORValue::MapValue NoneAttestationStatement::GetAsCBORMap() const {
-  return cbor::CBORValue::MapValue();
+cbor::Value::MapValue NoneAttestationStatement::GetAsCBORMap() const {
+  return cbor::Value::MapValue();
 }
 
 }  // namespace device
diff --git a/device/fido/attestation_statement.h b/device/fido/attestation_statement.h
index cf542131..59d26891 100644
--- a/device/fido/attestation_statement.h
+++ b/device/fido/attestation_statement.h
@@ -31,7 +31,7 @@
   // https://www.w3.org/TR/2017/WD-webauthn-20170505/#defined-attestation-formats
   // This is not a CBOR-encoded byte array, but the map that will be
   // nested within another CBOR object and encoded then.
-  virtual cbor::CBORValue::MapValue GetAsCBORMap() const = 0;
+  virtual cbor::Value::MapValue GetAsCBORMap() const = 0;
 
   // Returns true if the attestation is a "self" attestation, i.e. is just the
   // private key signing itself to show that it is fresh.
@@ -68,7 +68,7 @@
 
   bool IsSelfAttestation() override;
   bool IsAttestationCertificateInappropriatelyIdentifying() override;
-  cbor::CBORValue::MapValue GetAsCBORMap() const override;
+  cbor::Value::MapValue GetAsCBORMap() const override;
   base::Optional<base::span<const uint8_t>> GetLeafCertificate() const override;
 
  private:
diff --git a/device/fido/attestation_statement_formats.cc b/device/fido/attestation_statement_formats.cc
index ae93103..dfa057b 100644
--- a/device/fido/attestation_statement_formats.cc
+++ b/device/fido/attestation_statement_formats.cc
@@ -119,18 +119,18 @@
 
 FidoAttestationStatement::~FidoAttestationStatement() = default;
 
-cbor::CBORValue::MapValue FidoAttestationStatement::GetAsCBORMap() const {
-  cbor::CBORValue::MapValue attestation_statement_map;
-  attestation_statement_map[cbor::CBORValue(kSignatureKey)] =
-      cbor::CBORValue(signature_);
+cbor::Value::MapValue FidoAttestationStatement::GetAsCBORMap() const {
+  cbor::Value::MapValue attestation_statement_map;
+  attestation_statement_map[cbor::Value(kSignatureKey)] =
+      cbor::Value(signature_);
 
-  std::vector<cbor::CBORValue> certificate_array;
+  std::vector<cbor::Value> certificate_array;
   for (const auto& cert : x509_certificates_) {
-    certificate_array.push_back(cbor::CBORValue(cert));
+    certificate_array.push_back(cbor::Value(cert));
   }
 
-  attestation_statement_map[cbor::CBORValue(kX509CertKey)] =
-      cbor::CBORValue(std::move(certificate_array));
+  attestation_statement_map[cbor::Value(kX509CertKey)] =
+      cbor::Value(std::move(certificate_array));
 
   return attestation_statement_map;
 }
@@ -174,22 +174,22 @@
 
 PackedAttestationStatement::~PackedAttestationStatement() = default;
 
-cbor::CBORValue::MapValue PackedAttestationStatement::GetAsCBORMap() const {
-  cbor::CBORValue::MapValue attestation_statement_map;
+cbor::Value::MapValue PackedAttestationStatement::GetAsCBORMap() const {
+  cbor::Value::MapValue attestation_statement_map;
   // alg
-  attestation_statement_map[cbor::CBORValue(kAlgorithmKey)] =
-      cbor::CBORValue(static_cast<int>(algorithm_));
+  attestation_statement_map[cbor::Value(kAlgorithmKey)] =
+      cbor::Value(static_cast<int>(algorithm_));
   // sig
-  attestation_statement_map[cbor::CBORValue(kSignatureKey)] =
-      cbor::CBORValue(signature_);
+  attestation_statement_map[cbor::Value(kSignatureKey)] =
+      cbor::Value(signature_);
   // x5c (optional)
   if (!x509_certificates_.empty()) {
-    std::vector<cbor::CBORValue> certificate_array;
+    std::vector<cbor::Value> certificate_array;
     for (const auto& cert : x509_certificates_) {
-      certificate_array.push_back(cbor::CBORValue(cert));
+      certificate_array.push_back(cbor::Value(cert));
     }
-    attestation_statement_map[cbor::CBORValue(kX509CertKey)] =
-        cbor::CBORValue(std::move(certificate_array));
+    attestation_statement_map[cbor::Value(kX509CertKey)] =
+        cbor::Value(std::move(certificate_array));
   }
   return attestation_statement_map;
 }
diff --git a/device/fido/attestation_statement_formats.h b/device/fido/attestation_statement_formats.h
index 2db98dd..5c1ac23 100644
--- a/device/fido/attestation_statement_formats.h
+++ b/device/fido/attestation_statement_formats.h
@@ -30,7 +30,7 @@
   ~FidoAttestationStatement() override;
 
   // AttestationStatement
-  cbor::CBORValue::MapValue GetAsCBORMap() const override;
+  cbor::Value::MapValue GetAsCBORMap() const override;
   bool IsSelfAttestation() override;
   bool IsAttestationCertificateInappropriatelyIdentifying() override;
   base::Optional<base::span<const uint8_t>> GetLeafCertificate() const override;
@@ -57,7 +57,7 @@
   ~PackedAttestationStatement() override;
 
   // AttestationStatement
-  cbor::CBORValue::MapValue GetAsCBORMap() const override;
+  cbor::Value::MapValue GetAsCBORMap() const override;
   bool IsSelfAttestation() override;
   bool IsAttestationCertificateInappropriatelyIdentifying() override;
   base::Optional<base::span<const uint8_t>> GetLeafCertificate() const override;
diff --git a/device/fido/attestation_statement_formats_unittest.cc b/device/fido/attestation_statement_formats_unittest.cc
index 4bed60b..bcd69e2 100644
--- a/device/fido/attestation_statement_formats_unittest.cc
+++ b/device/fido/attestation_statement_formats_unittest.cc
@@ -83,17 +83,17 @@
 
 TEST(PackedAttestationStatementTest, CBOR) {
   EXPECT_THAT(
-      *cbor::CBORWriter::Write(
-          cbor::CBORValue(PackedAttestationStatement(
-                              CoseAlgorithmIdentifier::kCoseEs256,
-                              fido_parsing_utils::Materialize(kSignature),
-                              {fido_parsing_utils::Materialize(kCertificates)})
-                              .GetAsCBORMap())),
+      *cbor::Writer::Write(
+          cbor::Value(PackedAttestationStatement(
+                          CoseAlgorithmIdentifier::kCoseEs256,
+                          fido_parsing_utils::Materialize(kSignature),
+                          {fido_parsing_utils::Materialize(kCertificates)})
+                          .GetAsCBORMap())),
       testing::ElementsAreArray(test_data::kPackedAttestationStatementCBOR));
 }
 
 TEST(PackedAttestationStatementTest, CBOR_NoCerts) {
-  EXPECT_THAT(*cbor::CBORWriter::Write(cbor::CBORValue(
+  EXPECT_THAT(*cbor::Writer::Write(cbor::Value(
                   PackedAttestationStatement(
                       CoseAlgorithmIdentifier::kCoseEs256,
                       fido_parsing_utils::Materialize(kSignature), {})
@@ -104,7 +104,7 @@
 
 TEST(OpaqueAttestationStatementTest, GetLeafCertificate) {
   auto attestation_map =
-      cbor::CBORReader::Read(test_data::kPackedAttestationStatementCBOR);
+      cbor::Reader::Read(test_data::kPackedAttestationStatementCBOR);
   ASSERT_TRUE(attestation_map);
   OpaqueAttestationStatement statement("packed", std::move(*attestation_map));
   EXPECT_FALSE(statement.IsSelfAttestation());
diff --git a/device/fido/attested_credential_data.cc b/device/fido/attested_credential_data.cc
index a78e9abc..ab05a59 100644
--- a/device/fido/attested_credential_data.cc
+++ b/device/fido/attested_credential_data.cc
@@ -45,7 +45,7 @@
   // CBOR parser needs to be invoked to find its length, even though the result
   // is discarded.
   size_t bytes_read;
-  if (!cbor::CBORReader::Read(buffer, &bytes_read)) {
+  if (!cbor::Reader::Read(buffer, &bytes_read)) {
     return base::nullopt;
   }
   auto credential_public_key_data =
diff --git a/device/fido/authenticator_data.cc b/device/fido/authenticator_data.cc
index c6ef825..207d0732 100644
--- a/device/fido/authenticator_data.cc
+++ b/device/fido/authenticator_data.cc
@@ -41,9 +41,9 @@
     std::tie(attested_credential_data, auth_data) = std::move(*maybe_result);
   }
 
-  base::Optional<cbor::CBORValue> extensions;
+  base::Optional<cbor::Value> extensions;
   if (flag_byte & static_cast<uint8_t>(Flag::kExtensionDataIncluded)) {
-    extensions = cbor::CBORReader::Read(auth_data);
+    extensions = cbor::Reader::Read(auth_data);
     if (!extensions || !extensions->is_map()) {
       return base::nullopt;
     }
@@ -61,7 +61,7 @@
     uint8_t flags,
     base::span<const uint8_t, kSignCounterLength> counter,
     base::Optional<AttestedCredentialData> data,
-    base::Optional<cbor::CBORValue> extensions)
+    base::Optional<cbor::Value> extensions)
     : application_parameter_(
           fido_parsing_utils::Materialize(application_parameter)),
       flags_(flags),
@@ -102,7 +102,7 @@
   }
 
   if (extensions_) {
-    const auto maybe_extensions = cbor::CBORWriter::Write(*extensions_);
+    const auto maybe_extensions = cbor::Writer::Write(*extensions_);
     if (maybe_extensions) {
       fido_parsing_utils::Append(&authenticator_data, *maybe_extensions);
     }
diff --git a/device/fido/authenticator_data.h b/device/fido/authenticator_data.h
index 53ceedf..5bec5ab 100644
--- a/device/fido/authenticator_data.h
+++ b/device/fido/authenticator_data.h
@@ -43,7 +43,7 @@
       uint8_t flags,
       base::span<const uint8_t, kSignCounterLength> counter,
       base::Optional<AttestedCredentialData> data,
-      base::Optional<cbor::CBORValue> extensions = base::nullopt);
+      base::Optional<cbor::Value> extensions = base::nullopt);
 
   // Moveable.
   AuthenticatorData(AuthenticatorData&& other);
@@ -72,9 +72,7 @@
 
   // If a value is returned then the result of calling |is_map()| on it can be
   // assumed to be true.
-  const base::Optional<cbor::CBORValue>& extensions() const {
-    return extensions_;
-  }
+  const base::Optional<cbor::Value>& extensions() const { return extensions_; }
 
   const std::array<uint8_t, kRpIdHashLength>& application_parameter() const {
     return application_parameter_;
@@ -117,7 +115,7 @@
   std::array<uint8_t, kSignCounterLength> counter_;
   base::Optional<AttestedCredentialData> attested_data_;
   // If |extensions_| has a value, then it will be a CBOR map.
-  base::Optional<cbor::CBORValue> extensions_;
+  base::Optional<cbor::Value> extensions_;
 
   DISALLOW_COPY_AND_ASSIGN(AuthenticatorData);
 };
diff --git a/device/fido/authenticator_get_assertion_response.cc b/device/fido/authenticator_get_assertion_response.cc
index a02868d4..3ef8a04 100644
--- a/device/fido/authenticator_get_assertion_response.cc
+++ b/device/fido/authenticator_get_assertion_response.cc
@@ -93,7 +93,7 @@
 
 std::vector<uint8_t> GetSerializedCtapDeviceResponse(
     const AuthenticatorGetAssertionResponse& response) {
-  cbor::CBORValue::MapValue response_map;
+  cbor::Value::MapValue response_map;
   if (response.credential())
     response_map.emplace(1, response.credential()->ConvertToCBOR());
 
@@ -106,7 +106,7 @@
   // Multiple account selection is not supported.
   response_map.emplace(5, 1);
   auto encoded_response =
-      cbor::CBORWriter::Write(cbor::CBORValue(std::move(response_map)));
+      cbor::Writer::Write(cbor::Value(std::move(response_map)));
   DCHECK(encoded_response);
   return *encoded_response;
 }
diff --git a/device/fido/authenticator_get_info_response.cc b/device/fido/authenticator_get_info_response.cc
index 37de6493..b0f66c7 100644
--- a/device/fido/authenticator_get_info_response.cc
+++ b/device/fido/authenticator_get_info_response.cc
@@ -15,8 +15,8 @@
 namespace {
 
 template <typename Container>
-cbor::CBORValue::ArrayValue ToArrayValue(const Container& container) {
-  cbor::CBORValue::ArrayValue value;
+cbor::Value::ArrayValue ToArrayValue(const Container& container) {
+  cbor::Value::ArrayValue value;
   value.reserve(container.size());
   for (const auto& item : container)
     value.emplace_back(item);
@@ -65,12 +65,12 @@
 
 std::vector<uint8_t> EncodeToCBOR(
     const AuthenticatorGetInfoResponse& response) {
-  cbor::CBORValue::ArrayValue version_array;
+  cbor::Value::ArrayValue version_array;
   for (const auto& version : response.versions()) {
     version_array.emplace_back(version == ProtocolVersion::kCtap ? kCtap2Version
                                                                  : kU2fVersion);
   }
-  cbor::CBORValue::MapValue device_info_map;
+  cbor::Value::MapValue device_info_map;
   device_info_map.emplace(1, std::move(version_array));
 
   if (response.extensions())
@@ -89,7 +89,7 @@
   }
 
   auto encoded_bytes =
-      cbor::CBORWriter::Write(cbor::CBORValue(std::move(device_info_map)));
+      cbor::Writer::Write(cbor::Value(std::move(device_info_map)));
   DCHECK(encoded_bytes);
   return *encoded_bytes;
 }
diff --git a/device/fido/authenticator_supported_options.cc b/device/fido/authenticator_supported_options.cc
index af08a3c..06a7ccd 100644
--- a/device/fido/authenticator_supported_options.cc
+++ b/device/fido/authenticator_supported_options.cc
@@ -54,8 +54,8 @@
   return *this;
 }
 
-cbor::CBORValue ConvertToCBOR(const AuthenticatorSupportedOptions& options) {
-  cbor::CBORValue::MapValue option_map;
+cbor::Value ConvertToCBOR(const AuthenticatorSupportedOptions& options) {
+  cbor::Value::MapValue option_map;
   option_map.emplace(kResidentKeyMapKey, options.supports_resident_key());
   option_map.emplace(kUserPresenceMapKey, options.user_presence_required());
   option_map.emplace(kPlatformDeviceMapKey, options.is_platform_device());
@@ -88,7 +88,7 @@
       break;
   }
 
-  return cbor::CBORValue(std::move(option_map));
+  return cbor::Value(std::move(option_map));
 }
 
 }  // namespace device
diff --git a/device/fido/authenticator_supported_options.h b/device/fido/authenticator_supported_options.h
index 0c6bed03..2aaeb7c 100644
--- a/device/fido/authenticator_supported_options.h
+++ b/device/fido/authenticator_supported_options.h
@@ -79,7 +79,7 @@
 };
 
 COMPONENT_EXPORT(DEVICE_FIDO)
-cbor::CBORValue ConvertToCBOR(const AuthenticatorSupportedOptions& options);
+cbor::Value ConvertToCBOR(const AuthenticatorSupportedOptions& options);
 
 }  // namespace device
 
diff --git a/device/fido/ble/fido_ble_discovery_base.cc b/device/fido/ble/fido_ble_discovery_base.cc
index 240513c7..19c24c1 100644
--- a/device/fido/ble/fido_ble_discovery_base.cc
+++ b/device/fido/ble/fido_ble_discovery_base.cc
@@ -83,23 +83,9 @@
 }
 
 void FidoBleDiscoveryBase::StartInternal() {
-  auto& factory = BluetoothAdapterFactory::Get();
-  auto callback = base::BindOnce(&FidoBleDiscoveryBase::OnGetAdapter,
-                                 weak_factory_.GetWeakPtr());
-#if defined(OS_MACOSX)
-  // BluetoothAdapter may invoke the callback synchronously on Mac, but
-  // StartInternal() never wants to invoke to NotifyDiscoveryStarted()
-  // immediately, so ensure there is at least post-task at this bottleneck.
-  // See: https://crbug.com/823686.
-  callback = base::BindOnce(
-      [](BluetoothAdapterFactory::AdapterCallback callback,
-         scoped_refptr<BluetoothAdapter> adapter) {
-        base::ThreadTaskRunnerHandle::Get()->PostTask(
-            FROM_HERE, base::BindOnce(std::move(callback), adapter));
-      },
-      base::AdaptCallbackForRepeating(std::move(callback)));
-#endif  // defined(OS_MACOSX)
-  factory.GetAdapter(base::AdaptCallbackForRepeating(std::move(callback)));
+  BluetoothAdapterFactory::Get().GetAdapter(
+      base::AdaptCallbackForRepeating(base::BindOnce(
+          &FidoBleDiscoveryBase::OnGetAdapter, weak_factory_.GetWeakPtr())));
 }
 
 }  // namespace device
diff --git a/device/fido/ble/fido_ble_discovery_unittest.cc b/device/fido/ble/fido_ble_discovery_unittest.cc
index 1b62da3..77f8234 100644
--- a/device/fido/ble/fido_ble_discovery_unittest.cc
+++ b/device/fido/ble/fido_ble_discovery_unittest.cc
@@ -120,6 +120,7 @@
   EXPECT_CALL(*adapter(), SetPowered).Times(0);
   EXPECT_CALL(*observer(), DiscoveryStarted(discovery(), false));
   discovery()->Start();
+  scoped_task_environment_.FastForwardUntilNoTasksRemain();
 }
 
 TEST_F(FidoBleDiscoveryTest, FidoBleDiscoveryResumeScanningAfterPoweredOn) {
@@ -131,6 +132,7 @@
   // starts again.
   EXPECT_CALL(*adapter(), StartDiscoverySessionWithFilterRaw);
   discovery()->Start();
+  scoped_task_environment_.FastForwardUntilNoTasksRemain();
   adapter()->NotifyAdapterPoweredChanged(true);
 }
 
@@ -305,6 +307,7 @@
   EXPECT_CALL(*observer(), AuthenticatorIdChanged(discovery(), kAuthenticatorId,
                                                   kAuthenticatorChangedId));
   discovery()->Start();
+  scoped_task_environment_.FastForwardUntilNoTasksRemain();
 
   adapter()->NotifyDeviceChanged(mock_device.get());
   ASSERT_TRUE(::testing::Mock::VerifyAndClearExpectations(mock_device.get()));
@@ -328,6 +331,7 @@
 
   const auto device_id = FidoBleDevice::GetId(kDeviceAddress);
   discovery()->Start();
+  scoped_task_environment_.FastForwardUntilNoTasksRemain();
 
   ::testing::InSequence sequence;
   EXPECT_CALL(*observer(),
@@ -350,6 +354,7 @@
 
   const auto device_id = FidoBleDevice::GetId(kDeviceAddress);
   discovery()->Start();
+  scoped_task_environment_.FastForwardUntilNoTasksRemain();
 
   ::testing::InSequence sequence;
   EXPECT_CALL(*observer(),
diff --git a/device/fido/cable/fido_cable_handshake_handler.cc b/device/fido/cable/fido_cable_handshake_handler.cc
index a227377..b7d40dbc 100644
--- a/device/fido/cable/fido_cable_handshake_handler.cc
+++ b/device/fido/cable/fido_cable_handshake_handler.cc
@@ -44,10 +44,10 @@
 base::Optional<std::array<uint8_t, kClientHelloMessageSize>>
 ConstructHandshakeMessage(base::StringPiece handshake_key,
                           base::span<const uint8_t, 16> client_random_nonce) {
-  cbor::CBORValue::MapValue map;
+  cbor::Value::MapValue map;
   map.emplace(0, kCableClientHelloMessage);
   map.emplace(1, client_random_nonce);
-  auto client_hello = cbor::CBORWriter::Write(cbor::CBORValue(std::move(map)));
+  auto client_hello = cbor::Writer::Write(cbor::Value(std::move(map)));
   DCHECK(client_hello);
 
   crypto::HMAC hmac(crypto::HMAC::SHA256);
@@ -125,15 +125,14 @@
     return false;
   }
 
-  const auto authenticator_hello_cbor =
-      cbor::CBORReader::Read(authenticator_hello);
+  const auto authenticator_hello_cbor = cbor::Reader::Read(authenticator_hello);
   if (!authenticator_hello_cbor || !authenticator_hello_cbor->is_map() ||
       authenticator_hello_cbor->GetMap().size() != 2) {
     return false;
   }
 
   const auto authenticator_hello_msg =
-      authenticator_hello_cbor->GetMap().find(cbor::CBORValue(0));
+      authenticator_hello_cbor->GetMap().find(cbor::Value(0));
   if (authenticator_hello_msg == authenticator_hello_cbor->GetMap().end() ||
       !authenticator_hello_msg->second.is_string() ||
       authenticator_hello_msg->second.GetString() !=
@@ -142,7 +141,7 @@
   }
 
   const auto authenticator_random_nonce =
-      authenticator_hello_cbor->GetMap().find(cbor::CBORValue(1));
+      authenticator_hello_cbor->GetMap().find(cbor::Value(1));
   if (authenticator_random_nonce == authenticator_hello_cbor->GetMap().end() ||
       !authenticator_random_nonce->second.is_bytestring() ||
       authenticator_random_nonce->second.GetBytestring().size() != 16) {
diff --git a/device/fido/cable/fido_cable_handshake_handler_unittest.cc b/device/fido/cable/fido_cable_handshake_handler_unittest.cc
index 49ea55d..175b0cce 100644
--- a/device/fido/cable/fido_cable_handshake_handler_unittest.cc
+++ b/device/fido/cable/fido_cable_handshake_handler_unittest.cc
@@ -208,13 +208,13 @@
       return false;
     }
 
-    const auto& client_hello_cbor = cbor::CBORReader::Read(client_hello);
+    const auto& client_hello_cbor = cbor::Reader::Read(client_hello);
     if (!client_hello_cbor)
       return false;
 
     const auto& message_map = client_hello_cbor->GetMap();
-    auto hello_message_it = message_map.find(cbor::CBORValue(0));
-    auto client_random_nonce_it = message_map.find(cbor::CBORValue(1));
+    auto hello_message_it = message_map.find(cbor::Value(0));
+    auto client_random_nonce_it = message_map.find(cbor::Value(1));
     if (hello_message_it == message_map.end() ||
         client_random_nonce_it == message_map.end())
       return false;
diff --git a/device/fido/ctap_get_assertion_request.cc b/device/fido/ctap_get_assertion_request.cc
index 64285cb..6b09b056 100644
--- a/device/fido/ctap_get_assertion_request.cc
+++ b/device/fido/ctap_get_assertion_request.cc
@@ -19,7 +19,7 @@
 namespace {
 
 bool AreGetAssertionRequestMapKeysCorrect(
-    const cbor::CBORValue::MapValue& request_map) {
+    const cbor::Value::MapValue& request_map) {
   return std::all_of(request_map.begin(), request_map.end(),
                      [](const auto& param) {
                        if (!param.first.is_integer())
@@ -31,7 +31,7 @@
 }
 
 bool IsGetAssertionOptionMapFormatCorrect(
-    const cbor::CBORValue::MapValue& option_map) {
+    const cbor::Value::MapValue& option_map) {
   return std::all_of(
       option_map.begin(), option_map.end(), [](const auto& param) {
         if (!param.first.is_string())
@@ -66,46 +66,44 @@
 CtapGetAssertionRequest::~CtapGetAssertionRequest() = default;
 
 std::vector<uint8_t> CtapGetAssertionRequest::EncodeAsCBOR() const {
-  cbor::CBORValue::MapValue cbor_map;
-  cbor_map[cbor::CBORValue(1)] = cbor::CBORValue(rp_id_);
-  cbor_map[cbor::CBORValue(2)] = cbor::CBORValue(client_data_hash_);
+  cbor::Value::MapValue cbor_map;
+  cbor_map[cbor::Value(1)] = cbor::Value(rp_id_);
+  cbor_map[cbor::Value(2)] = cbor::Value(client_data_hash_);
 
   if (allow_list_) {
-    cbor::CBORValue::ArrayValue allow_list_array;
+    cbor::Value::ArrayValue allow_list_array;
     for (const auto& descriptor : *allow_list_) {
       allow_list_array.push_back(descriptor.ConvertToCBOR());
     }
-    cbor_map[cbor::CBORValue(3)] = cbor::CBORValue(std::move(allow_list_array));
+    cbor_map[cbor::Value(3)] = cbor::Value(std::move(allow_list_array));
   }
 
   if (pin_auth_) {
-    cbor_map[cbor::CBORValue(6)] = cbor::CBORValue(*pin_auth_);
+    cbor_map[cbor::Value(6)] = cbor::Value(*pin_auth_);
   }
 
   if (pin_protocol_) {
-    cbor_map[cbor::CBORValue(7)] = cbor::CBORValue(*pin_protocol_);
+    cbor_map[cbor::Value(7)] = cbor::Value(*pin_protocol_);
   }
 
-  cbor::CBORValue::MapValue option_map;
+  cbor::Value::MapValue option_map;
 
   // User presence is required by default.
   if (!user_presence_required_) {
-    option_map[cbor::CBORValue(kUserPresenceMapKey)] =
-        cbor::CBORValue(user_presence_required_);
+    option_map[cbor::Value(kUserPresenceMapKey)] =
+        cbor::Value(user_presence_required_);
   }
 
   // User verification is not required by default.
   if (user_verification_ == UserVerificationRequirement::kRequired) {
-    option_map[cbor::CBORValue(kUserVerificationMapKey)] =
-        cbor::CBORValue(true);
+    option_map[cbor::Value(kUserVerificationMapKey)] = cbor::Value(true);
   }
 
   if (!option_map.empty()) {
-    cbor_map[cbor::CBORValue(5)] = cbor::CBORValue(std::move(option_map));
+    cbor_map[cbor::Value(5)] = cbor::Value(std::move(option_map));
   }
 
-  auto serialized_param =
-      cbor::CBORWriter::Write(cbor::CBORValue(std::move(cbor_map)));
+  auto serialized_param = cbor::Writer::Write(cbor::Value(std::move(cbor_map)));
   DCHECK(serialized_param);
 
   std::vector<uint8_t> cbor_request({base::strict_cast<uint8_t>(
@@ -169,7 +167,7 @@
 
 base::Optional<CtapGetAssertionRequest> ParseCtapGetAssertionRequest(
     base::span<const uint8_t> request_bytes) {
-  const auto& cbor_request = cbor::CBORReader::Read(request_bytes);
+  const auto& cbor_request = cbor::Reader::Read(request_bytes);
   if (!cbor_request || !cbor_request->is_map())
     return base::nullopt;
 
@@ -177,11 +175,11 @@
   if (!AreGetAssertionRequestMapKeysCorrect(request_map))
     return base::nullopt;
 
-  const auto rp_id_it = request_map.find(cbor::CBORValue(1));
+  const auto rp_id_it = request_map.find(cbor::Value(1));
   if (rp_id_it == request_map.end() || !rp_id_it->second.is_string())
     return base::nullopt;
 
-  const auto client_data_hash_it = request_map.find(cbor::CBORValue(2));
+  const auto client_data_hash_it = request_map.find(cbor::Value(2));
   if (client_data_hash_it == request_map.end() ||
       !client_data_hash_it->second.is_bytestring())
     return base::nullopt;
@@ -192,7 +190,7 @@
   CtapGetAssertionRequest request(rp_id_it->second.GetString(),
                                   client_data_hash);
 
-  const auto allow_list_it = request_map.find(cbor::CBORValue(3));
+  const auto allow_list_it = request_map.find(cbor::Value(3));
   if (allow_list_it != request_map.end()) {
     if (!allow_list_it->second.is_array())
       return base::nullopt;
@@ -211,7 +209,7 @@
     request.SetAllowList(std::move(allow_list));
   }
 
-  const auto option_it = request_map.find(cbor::CBORValue(5));
+  const auto option_it = request_map.find(cbor::Value(5));
   if (option_it != request_map.end()) {
     if (!option_it->second.is_map())
       return base::nullopt;
@@ -221,12 +219,12 @@
       return base::nullopt;
 
     const auto user_presence_option =
-        option_map.find(cbor::CBORValue(kUserPresenceMapKey));
+        option_map.find(cbor::Value(kUserPresenceMapKey));
     if (user_presence_option != option_map.end())
       request.SetUserPresenceRequired(user_presence_option->second.GetBool());
 
     const auto uv_option =
-        option_map.find(cbor::CBORValue(kUserVerificationMapKey));
+        option_map.find(cbor::Value(kUserVerificationMapKey));
     if (uv_option != option_map.end())
       request.SetUserVerification(
           uv_option->second.GetBool()
@@ -234,14 +232,14 @@
               : UserVerificationRequirement::kPreferred);
   }
 
-  const auto pin_auth_it = request_map.find(cbor::CBORValue(6));
+  const auto pin_auth_it = request_map.find(cbor::Value(6));
   if (pin_auth_it != request_map.end()) {
     if (!pin_auth_it->second.is_bytestring())
       return base::nullopt;
     request.SetPinAuth(pin_auth_it->second.GetBytestring());
   }
 
-  const auto pin_protocol_it = request_map.find(cbor::CBORValue(7));
+  const auto pin_protocol_it = request_map.find(cbor::Value(7));
   if (pin_protocol_it != request_map.end()) {
     if (!pin_protocol_it->second.is_unsigned() ||
         pin_protocol_it->second.GetUnsigned() >
diff --git a/device/fido/ctap_make_credential_request.cc b/device/fido/ctap_make_credential_request.cc
index 7f573b03..9991f8e2 100644
--- a/device/fido/ctap_make_credential_request.cc
+++ b/device/fido/ctap_make_credential_request.cc
@@ -19,7 +19,7 @@
 namespace {
 
 bool AreMakeCredentialRequestMapKeysCorrect(
-    const cbor::CBORValue::MapValue& request_map) {
+    const cbor::Value::MapValue& request_map) {
   return std::all_of(request_map.begin(), request_map.end(),
                      [](const auto& param) {
                        if (!param.first.is_integer())
@@ -31,7 +31,7 @@
 }
 
 bool IsMakeCredentialOptionMapFormatCorrect(
-    const cbor::CBORValue::MapValue& option_map) {
+    const cbor::Value::MapValue& option_map) {
   return std::all_of(
       option_map.begin(), option_map.end(), [](const auto& param) {
         if (!param.first.is_string())
@@ -70,54 +70,52 @@
 CtapMakeCredentialRequest::~CtapMakeCredentialRequest() = default;
 
 std::vector<uint8_t> CtapMakeCredentialRequest::EncodeAsCBOR() const {
-  cbor::CBORValue::MapValue cbor_map;
-  cbor_map[cbor::CBORValue(1)] = cbor::CBORValue(client_data_hash_);
-  cbor_map[cbor::CBORValue(2)] = rp_.ConvertToCBOR();
-  cbor_map[cbor::CBORValue(3)] = user_.ConvertToCBOR();
-  cbor_map[cbor::CBORValue(4)] = public_key_credential_params_.ConvertToCBOR();
+  cbor::Value::MapValue cbor_map;
+  cbor_map[cbor::Value(1)] = cbor::Value(client_data_hash_);
+  cbor_map[cbor::Value(2)] = rp_.ConvertToCBOR();
+  cbor_map[cbor::Value(3)] = user_.ConvertToCBOR();
+  cbor_map[cbor::Value(4)] = public_key_credential_params_.ConvertToCBOR();
   if (exclude_list_) {
-    cbor::CBORValue::ArrayValue exclude_list_array;
+    cbor::Value::ArrayValue exclude_list_array;
     for (const auto& descriptor : *exclude_list_) {
       exclude_list_array.push_back(descriptor.ConvertToCBOR());
     }
-    cbor_map[cbor::CBORValue(5)] =
-        cbor::CBORValue(std::move(exclude_list_array));
+    cbor_map[cbor::Value(5)] = cbor::Value(std::move(exclude_list_array));
   }
 
   if (hmac_secret_) {
-    cbor::CBORValue::MapValue extensions;
-    extensions[cbor::CBORValue(kExtensionHmacSecret)] = cbor::CBORValue(true);
-    cbor_map[cbor::CBORValue(6)] = cbor::CBORValue(std::move(extensions));
+    cbor::Value::MapValue extensions;
+    extensions[cbor::Value(kExtensionHmacSecret)] = cbor::Value(true);
+    cbor_map[cbor::Value(6)] = cbor::Value(std::move(extensions));
   }
 
   if (pin_auth_) {
-    cbor_map[cbor::CBORValue(8)] = cbor::CBORValue(*pin_auth_);
+    cbor_map[cbor::Value(8)] = cbor::Value(*pin_auth_);
   }
 
   if (pin_protocol_) {
-    cbor_map[cbor::CBORValue(9)] = cbor::CBORValue(*pin_protocol_);
+    cbor_map[cbor::Value(9)] = cbor::Value(*pin_protocol_);
   }
 
-  cbor::CBORValue::MapValue option_map;
+  cbor::Value::MapValue option_map;
 
   // Resident keys are not supported by default.
   if (resident_key_supported_) {
-    option_map[cbor::CBORValue(kResidentKeyMapKey)] =
-        cbor::CBORValue(resident_key_supported_);
+    option_map[cbor::Value(kResidentKeyMapKey)] =
+        cbor::Value(resident_key_supported_);
   }
 
   // User verification is not required by default.
   if (user_verification_required_) {
-    option_map[cbor::CBORValue(kUserVerificationMapKey)] =
-        cbor::CBORValue(user_verification_required_);
+    option_map[cbor::Value(kUserVerificationMapKey)] =
+        cbor::Value(user_verification_required_);
   }
 
   if (!option_map.empty()) {
-    cbor_map[cbor::CBORValue(7)] = cbor::CBORValue(std::move(option_map));
+    cbor_map[cbor::Value(7)] = cbor::Value(std::move(option_map));
   }
 
-  auto serialized_param =
-      cbor::CBORWriter::Write(cbor::CBORValue(std::move(cbor_map)));
+  auto serialized_param = cbor::Writer::Write(cbor::Value(std::move(cbor_map)));
   DCHECK(serialized_param);
 
   std::vector<uint8_t> cbor_request({base::strict_cast<uint8_t>(
@@ -173,7 +171,7 @@
 
 base::Optional<CtapMakeCredentialRequest> ParseCtapMakeCredentialRequest(
     base::span<const uint8_t> request_bytes) {
-  const auto& cbor_request = cbor::CBORReader::Read(request_bytes);
+  const auto& cbor_request = cbor::Reader::Read(request_bytes);
   if (!cbor_request || !cbor_request->is_map())
     return base::nullopt;
 
@@ -181,7 +179,7 @@
   if (!AreMakeCredentialRequestMapKeysCorrect(request_map))
     return base::nullopt;
 
-  const auto client_data_hash_it = request_map.find(cbor::CBORValue(1));
+  const auto client_data_hash_it = request_map.find(cbor::Value(1));
   if (client_data_hash_it == request_map.end() ||
       !client_data_hash_it->second.is_bytestring())
     return base::nullopt;
@@ -190,7 +188,7 @@
       base::make_span(client_data_hash_it->second.GetBytestring())
           .subspan<0, kClientDataHashLength>();
 
-  const auto rp_entity_it = request_map.find(cbor::CBORValue(2));
+  const auto rp_entity_it = request_map.find(cbor::Value(2));
   if (rp_entity_it == request_map.end() || !rp_entity_it->second.is_map())
     return base::nullopt;
 
@@ -199,7 +197,7 @@
   if (!rp_entity)
     return base::nullopt;
 
-  const auto user_entity_it = request_map.find(cbor::CBORValue(3));
+  const auto user_entity_it = request_map.find(cbor::Value(3));
   if (user_entity_it == request_map.end() || !user_entity_it->second.is_map())
     return base::nullopt;
 
@@ -208,7 +206,7 @@
   if (!user_entity)
     return base::nullopt;
 
-  const auto credential_params_it = request_map.find(cbor::CBORValue(4));
+  const auto credential_params_it = request_map.find(cbor::Value(4));
   if (credential_params_it == request_map.end())
     return base::nullopt;
 
@@ -221,7 +219,7 @@
                                     std::move(*user_entity),
                                     std::move(*credential_params));
 
-  const auto exclude_list_it = request_map.find(cbor::CBORValue(5));
+  const auto exclude_list_it = request_map.find(cbor::Value(5));
   if (exclude_list_it != request_map.end()) {
     if (!exclude_list_it->second.is_array())
       return base::nullopt;
@@ -240,7 +238,7 @@
     request.SetExcludeList(std::move(exclude_list));
   }
 
-  const auto extensions_it = request_map.find(cbor::CBORValue(6));
+  const auto extensions_it = request_map.find(cbor::Value(6));
   if (extensions_it != request_map.end()) {
     if (!extensions_it->second.is_map()) {
       return base::nullopt;
@@ -248,7 +246,7 @@
 
     const auto& extensions = extensions_it->second.GetMap();
     const auto hmac_secret_it =
-        extensions.find(cbor::CBORValue(kExtensionHmacSecret));
+        extensions.find(cbor::Value(kExtensionHmacSecret));
     if (hmac_secret_it != extensions.end()) {
       if (!hmac_secret_it->second.is_bool()) {
         return base::nullopt;
@@ -257,7 +255,7 @@
     }
   }
 
-  const auto option_it = request_map.find(cbor::CBORValue(7));
+  const auto option_it = request_map.find(cbor::Value(7));
   if (option_it != request_map.end()) {
     if (!option_it->second.is_map())
       return base::nullopt;
@@ -267,24 +265,24 @@
       return base::nullopt;
 
     const auto resident_key_option =
-        option_map.find(cbor::CBORValue(kResidentKeyMapKey));
+        option_map.find(cbor::Value(kResidentKeyMapKey));
     if (resident_key_option != option_map.end())
       request.SetResidentKeySupported(resident_key_option->second.GetBool());
 
     const auto uv_option =
-        option_map.find(cbor::CBORValue(kUserVerificationMapKey));
+        option_map.find(cbor::Value(kUserVerificationMapKey));
     if (uv_option != option_map.end())
       request.SetUserVerificationRequired(uv_option->second.GetBool());
   }
 
-  const auto pin_auth_it = request_map.find(cbor::CBORValue(8));
+  const auto pin_auth_it = request_map.find(cbor::Value(8));
   if (pin_auth_it != request_map.end()) {
     if (!pin_auth_it->second.is_bytestring())
       return base::nullopt;
     request.SetPinAuth(pin_auth_it->second.GetBytestring());
   }
 
-  const auto pin_protocol_it = request_map.find(cbor::CBORValue(9));
+  const auto pin_protocol_it = request_map.find(cbor::Value(9));
   if (pin_protocol_it != request_map.end()) {
     if (!pin_protocol_it->second.is_unsigned() ||
         pin_protocol_it->second.GetUnsigned() >
diff --git a/device/fido/ctap_response_unittest.cc b/device/fido/ctap_response_unittest.cc
index d946f6ae..cc8cc8f 100644
--- a/device/fido/ctap_response_unittest.cc
+++ b/device/fido/ctap_response_unittest.cc
@@ -318,43 +318,43 @@
       FidoTransportProtocol::kUsbHumanInterfaceDevice,
       test_data::kTestMakeCredentialResponse);
   ASSERT_TRUE(make_credential_response);
-  auto cbor_attestation_object = cbor::CBORReader::Read(
+  auto cbor_attestation_object = cbor::Reader::Read(
       make_credential_response->GetCBOREncodedAttestationObject());
   ASSERT_TRUE(cbor_attestation_object);
   ASSERT_TRUE(cbor_attestation_object->is_map());
 
   const auto& attestation_object_map = cbor_attestation_object->GetMap();
-  auto it = attestation_object_map.find(cbor::CBORValue(kFormatKey));
+  auto it = attestation_object_map.find(cbor::Value(kFormatKey));
   ASSERT_TRUE(it != attestation_object_map.end());
   ASSERT_TRUE(it->second.is_string());
   EXPECT_EQ(it->second.GetString(), "packed");
 
-  it = attestation_object_map.find(cbor::CBORValue(kAuthDataKey));
+  it = attestation_object_map.find(cbor::Value(kAuthDataKey));
   ASSERT_TRUE(it != attestation_object_map.end());
   ASSERT_TRUE(it->second.is_bytestring());
   EXPECT_THAT(
       it->second.GetBytestring(),
       ::testing::ElementsAreArray(test_data::kCtap2MakeCredentialAuthData));
 
-  it = attestation_object_map.find(cbor::CBORValue(kAttestationStatementKey));
+  it = attestation_object_map.find(cbor::Value(kAttestationStatementKey));
   ASSERT_TRUE(it != attestation_object_map.end());
   ASSERT_TRUE(it->second.is_map());
 
   const auto& attestation_statement_map = it->second.GetMap();
-  auto attStmt_it = attestation_statement_map.find(cbor::CBORValue("alg"));
+  auto attStmt_it = attestation_statement_map.find(cbor::Value("alg"));
 
   ASSERT_TRUE(attStmt_it != attestation_statement_map.end());
   ASSERT_TRUE(attStmt_it->second.is_integer());
   EXPECT_EQ(attStmt_it->second.GetInteger(), -7);
 
-  attStmt_it = attestation_statement_map.find(cbor::CBORValue("sig"));
+  attStmt_it = attestation_statement_map.find(cbor::Value("sig"));
   ASSERT_TRUE(attStmt_it != attestation_statement_map.end());
   ASSERT_TRUE(attStmt_it->second.is_bytestring());
   EXPECT_THAT(
       attStmt_it->second.GetBytestring(),
       ::testing::ElementsAreArray(test_data::kCtap2MakeCredentialSignature));
 
-  attStmt_it = attestation_statement_map.find(cbor::CBORValue("x5c"));
+  attStmt_it = attestation_statement_map.find(cbor::Value("x5c"));
   ASSERT_TRUE(attStmt_it != attestation_statement_map.end());
   const auto& certificate = attStmt_it->second;
   ASSERT_TRUE(certificate.is_array());
@@ -425,8 +425,8 @@
       FidoAttestationStatement::CreateFromU2fRegisterResponse(
           test_data::kTestU2fRegisterResponse);
   ASSERT_TRUE(fido_attestation_statement);
-  auto cbor = cbor::CBORWriter::Write(
-      cbor::CBORValue(fido_attestation_statement->GetAsCBORMap()));
+  auto cbor = cbor::Writer::Write(
+      cbor::Value(fido_attestation_statement->GetAsCBORMap()));
   ASSERT_TRUE(cbor);
   EXPECT_THAT(*cbor, ::testing::ElementsAreArray(
                          test_data::kU2fAttestationStatementCBOR));
@@ -642,11 +642,11 @@
                                        signature_counter,
                                        std::move(attested_credential_data));
 
-  cbor::CBORValue::MapValue attestation_map;
+  cbor::Value::MapValue attestation_map;
   attestation_map.emplace("alg", -7);
   attestation_map.emplace("sig", fido_parsing_utils::Materialize(
                                      test_data::kCtap2MakeCredentialSignature));
-  cbor::CBORValue::ArrayValue certificate_chain;
+  cbor::Value::ArrayValue certificate_chain;
   certificate_chain.emplace_back(fido_parsing_utils::Materialize(
       test_data::kCtap2MakeCredentialCertificate));
   attestation_map.emplace("x5c", std::move(certificate_chain));
@@ -655,7 +655,7 @@
       AttestationObject(
           std::move(authenticator_data),
           std::make_unique<OpaqueAttestationStatement>(
-              "packed", cbor::CBORValue(std::move(attestation_map)))));
+              "packed", cbor::Value(std::move(attestation_map)))));
   EXPECT_THAT(
       GetSerializedCtapDeviceResponse(response),
       ::testing::ElementsAreArray(
diff --git a/device/fido/device_response_converter.cc b/device/fido/device_response_converter.cc
index 4cfe62b..7060524 100644
--- a/device/fido/device_response_converter.cc
+++ b/device/fido/device_response_converter.cc
@@ -36,7 +36,7 @@
 
 }  // namespace
 
-using CBOR = cbor::CBORValue;
+using CBOR = cbor::Value;
 
 CtapDeviceResponseCode GetResponseCode(base::span<const uint8_t> buffer) {
   if (buffer.empty())
@@ -56,8 +56,7 @@
   if (buffer.size() <= kResponseCodeLength)
     return base::nullopt;
 
-  base::Optional<CBOR> decoded_response =
-      cbor::CBORReader::Read(buffer.subspan(1));
+  base::Optional<CBOR> decoded_response = cbor::Reader::Read(buffer.subspan(1));
   if (!decoded_response || !decoded_response->is_map())
     return base::nullopt;
 
@@ -92,8 +91,7 @@
   if (buffer.size() <= kResponseCodeLength)
     return base::nullopt;
 
-  base::Optional<CBOR> decoded_response =
-      cbor::CBORReader::Read(buffer.subspan(1));
+  base::Optional<CBOR> decoded_response = cbor::Reader::Read(buffer.subspan(1));
 
   if (!decoded_response || !decoded_response->is_map())
     return base::nullopt;
@@ -151,8 +149,7 @@
       GetResponseCode(buffer) != CtapDeviceResponseCode::kSuccess)
     return base::nullopt;
 
-  base::Optional<CBOR> decoded_response =
-      cbor::CBORReader::Read(buffer.subspan(1));
+  base::Optional<CBOR> decoded_response = cbor::Reader::Read(buffer.subspan(1));
 
   if (!decoded_response || !decoded_response->is_map())
     return base::nullopt;
diff --git a/device/fido/ec_public_key.cc b/device/fido/ec_public_key.cc
index effded9..61ad96d 100644
--- a/device/fido/ec_public_key.cc
+++ b/device/fido/ec_public_key.cc
@@ -65,13 +65,13 @@
 ECPublicKey::~ECPublicKey() = default;
 
 std::vector<uint8_t> ECPublicKey::EncodeAsCOSEKey() const {
-  cbor::CBORValue::MapValue map;
-  map[cbor::CBORValue(1)] = cbor::CBORValue(2);
-  map[cbor::CBORValue(3)] = cbor::CBORValue(-7);
-  map[cbor::CBORValue(-1)] = cbor::CBORValue(1);
-  map[cbor::CBORValue(-2)] = cbor::CBORValue(x_coordinate_);
-  map[cbor::CBORValue(-3)] = cbor::CBORValue(y_coordinate_);
-  return *cbor::CBORWriter::Write(cbor::CBORValue(std::move(map)));
+  cbor::Value::MapValue map;
+  map[cbor::Value(1)] = cbor::Value(2);
+  map[cbor::Value(3)] = cbor::Value(-7);
+  map[cbor::Value(-1)] = cbor::Value(1);
+  map[cbor::Value(-2)] = cbor::Value(x_coordinate_);
+  map[cbor::Value(-3)] = cbor::Value(y_coordinate_);
+  return *cbor::Writer::Write(cbor::Value(std::move(map)));
 }
 
 }  // namespace device
diff --git a/device/fido/fido_device_discovery.cc b/device/fido/fido_device_discovery.cc
index fe7fbe1a..3024078 100644
--- a/device/fido/fido_device_discovery.cc
+++ b/device/fido/fido_device_discovery.cc
@@ -7,6 +7,7 @@
 #include <utility>
 
 #include "base/bind.h"
+#include "base/threading/sequenced_task_runner_handle.h"
 #include "build/build_config.h"
 #include "device/fido/ble/fido_ble_discovery.h"
 #include "device/fido/cable/fido_cable_discovery.h"
@@ -90,10 +91,12 @@
 void FidoDeviceDiscovery::Start() {
   DCHECK_EQ(state_, State::kIdle);
   state_ = State::kStarting;
-  // TODO(hongjunchoi): Fix so that NotifiyStarted() is never called
-  // synchronously after StartInternal().
-  // See: https://crbug.com/823686
-  StartInternal();
+
+  // To ensure that that NotifiyStarted() is never invoked synchronously,
+  // post task asynchronously.
+  base::SequencedTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::BindOnce(&FidoDeviceDiscovery::StartInternal,
+                                weak_factory_.GetWeakPtr()));
 }
 
 void FidoDeviceDiscovery::NotifyDiscoveryStarted(bool success) {
diff --git a/device/fido/fido_device_discovery_unittest.cc b/device/fido/fido_device_discovery_unittest.cc
index 9e984c94..f4d092bb 100644
--- a/device/fido/fido_device_discovery_unittest.cc
+++ b/device/fido/fido_device_discovery_unittest.cc
@@ -59,6 +59,8 @@
 }
 
 TEST(FidoDiscoveryTest, TestNotificationsOnSuccessfulStart) {
+  base::test::ScopedTaskEnvironment scoped_task_environment_;
+
   ConcreteFidoDiscovery discovery(FidoTransportProtocol::kBluetoothLowEnergy);
   MockFidoDiscoveryObserver observer;
   discovery.set_observer(&observer);
@@ -68,6 +70,8 @@
 
   EXPECT_CALL(discovery, StartInternal());
   discovery.Start();
+  scoped_task_environment_.RunUntilIdle();
+
   EXPECT_TRUE(discovery.is_start_requested());
   EXPECT_FALSE(discovery.is_running());
   ::testing::Mock::VerifyAndClearExpectations(&discovery);
@@ -80,11 +84,14 @@
 }
 
 TEST(FidoDiscoveryTest, TestNotificationsOnFailedStart) {
+  base::test::ScopedTaskEnvironment scoped_task_environment_;
+
   ConcreteFidoDiscovery discovery(FidoTransportProtocol::kBluetoothLowEnergy);
   MockFidoDiscoveryObserver observer;
   discovery.set_observer(&observer);
 
   discovery.Start();
+  scoped_task_environment_.RunUntilIdle();
 
   EXPECT_CALL(observer, DiscoveryStarted(&discovery, false));
   discovery.NotifyDiscoveryStarted(false);
diff --git a/device/fido/mac/credential_metadata.cc b/device/fido/mac/credential_metadata.cc
index 60d9fea..ee292fa 100644
--- a/device/fido/mac/credential_metadata.cc
+++ b/device/fido/mac/credential_metadata.cc
@@ -19,9 +19,9 @@
 namespace fido {
 namespace mac {
 
-using cbor::CBORWriter;
-using cbor::CBORReader;
-using cbor::CBORValue;
+using cbor::Writer;
+using cbor::Reader;
+using cbor::Value;
 
 // static
 std::string CredentialMetadata::GenerateRandomSecret() {
@@ -93,13 +93,12 @@
 
   // The remaining bytes are the CBOR-encoded UserEntity, encrypted with
   // AES-256-GCM and authenticated with the version and RP ID.
-  CBORValue::ArrayValue cbor_user;
-  cbor_user.emplace_back(CBORValue(user.id));
-  cbor_user.emplace_back(CBORValue(user.name, CBORValue::Type::BYTE_STRING));
-  cbor_user.emplace_back(
-      CBORValue(user.display_name, CBORValue::Type::BYTE_STRING));
+  Value::ArrayValue cbor_user;
+  cbor_user.emplace_back(Value(user.id));
+  cbor_user.emplace_back(Value(user.name, Value::Type::BYTE_STRING));
+  cbor_user.emplace_back(Value(user.display_name, Value::Type::BYTE_STRING));
   base::Optional<std::vector<uint8_t>> pt =
-      CBORWriter::Write(CBORValue(std::move(cbor_user)));
+      Writer::Write(Value(std::move(cbor_user)));
   if (!pt) {
     return base::nullopt;
   }
@@ -138,12 +137,12 @@
   }
 
   // The recovered plaintext should decode into the UserEntity struct.
-  base::Optional<CBORValue> maybe_array = CBORReader::Read(base::make_span(
+  base::Optional<Value> maybe_array = Reader::Read(base::make_span(
       reinterpret_cast<const uint8_t*>(plaintext->data()), plaintext->size()));
   if (!maybe_array || !maybe_array->is_array()) {
     return base::nullopt;
   }
-  const CBORValue::ArrayValue& array = maybe_array->GetArray();
+  const Value::ArrayValue& array = maybe_array->GetArray();
   if (array.size() != 3 || !array[0].is_bytestring() ||
       !array[1].is_bytestring() || !array[2].is_bytestring()) {
     return base::nullopt;
diff --git a/device/fido/mac/util.mm b/device/fido/mac/util.mm
index b91556f..3bda144 100644
--- a/device/fido/mac/util.mm
+++ b/device/fido/mac/util.mm
@@ -28,8 +28,8 @@
 
 using base::ScopedCFTypeRef;
 using base::scoped_nsobject;
-using cbor::CBORWriter;
-using cbor::CBORValue;
+using cbor::Writer;
+using cbor::Value;
 
 // WebAuthn requires an all-zero AAGUID for authenticators using
 // self-attestation.
diff --git a/device/fido/opaque_attestation_statement.cc b/device/fido/opaque_attestation_statement.cc
index 8d6da11f..7bf7793 100644
--- a/device/fido/opaque_attestation_statement.cc
+++ b/device/fido/opaque_attestation_statement.cc
@@ -8,22 +8,22 @@
 
 #include "components/cbor/cbor_values.h"
 
-using cbor::CBORValue;
+using cbor::Value;
 
 namespace device {
 
 OpaqueAttestationStatement::OpaqueAttestationStatement(
     std::string attestation_format,
-    CBORValue attestation_statement_map)
+    Value attestation_statement_map)
     : AttestationStatement(std::move(attestation_format)),
       attestation_statement_map_(std::move(attestation_statement_map)) {}
 
 OpaqueAttestationStatement::~OpaqueAttestationStatement() = default;
 
 // Returns the deep copied cbor map value of |attestation_statement_map_|.
-CBORValue::MapValue OpaqueAttestationStatement::GetAsCBORMap() const {
+Value::MapValue OpaqueAttestationStatement::GetAsCBORMap() const {
   DCHECK(attestation_statement_map_.is_map());
-  CBORValue::MapValue new_map;
+  Value::MapValue new_map;
   new_map.reserve(attestation_statement_map_.GetMap().size());
   for (const auto& map_it : attestation_statement_map_.GetMap()) {
     new_map.try_emplace(new_map.end(), map_it.first.Clone(),
@@ -34,9 +34,9 @@
 
 bool OpaqueAttestationStatement::IsSelfAttestation() {
   DCHECK(attestation_statement_map_.is_map());
-  const CBORValue::MapValue& m(attestation_statement_map_.GetMap());
-  const CBORValue alg("alg");
-  const CBORValue sig("sig");
+  const Value::MapValue& m(attestation_statement_map_.GetMap());
+  const Value alg("alg");
+  const Value sig("sig");
 
   return format_ == "packed" && m.size() == 2 && m.count(std::move(alg)) == 1 &&
          m.count(std::move(sig)) == 1;
@@ -50,14 +50,14 @@
 base::Optional<base::span<const uint8_t>>
 OpaqueAttestationStatement::GetLeafCertificate() const {
   DCHECK(attestation_statement_map_.is_map());
-  const CBORValue::MapValue& m(attestation_statement_map_.GetMap());
-  const CBORValue x5c("x5c");
+  const Value::MapValue& m(attestation_statement_map_.GetMap());
+  const Value x5c("x5c");
   const auto it = m.find(x5c);
   if (it == m.end() || !it->second.is_array()) {
     return base::nullopt;
   }
 
-  const CBORValue::ArrayValue& certs = it->second.GetArray();
+  const Value::ArrayValue& certs = it->second.GetArray();
   if (certs.empty() || !certs[0].is_bytestring()) {
     return base::nullopt;
   }
diff --git a/device/fido/opaque_attestation_statement.h b/device/fido/opaque_attestation_statement.h
index 98bb2b97..4606931d 100644
--- a/device/fido/opaque_attestation_statement.h
+++ b/device/fido/opaque_attestation_statement.h
@@ -19,17 +19,17 @@
     : public AttestationStatement {
  public:
   OpaqueAttestationStatement(std::string attestation_format,
-                             cbor::CBORValue attestation_statement_map);
+                             cbor::Value attestation_statement_map);
   ~OpaqueAttestationStatement() override;
 
   // AttestationStatement:
-  cbor::CBORValue::MapValue GetAsCBORMap() const override;
+  cbor::Value::MapValue GetAsCBORMap() const override;
   bool IsSelfAttestation() override;
   bool IsAttestationCertificateInappropriatelyIdentifying() override;
   base::Optional<base::span<const uint8_t>> GetLeafCertificate() const override;
 
  private:
-  cbor::CBORValue attestation_statement_map_;
+  cbor::Value attestation_statement_map_;
 
   DISALLOW_COPY_AND_ASSIGN(OpaqueAttestationStatement);
 };
diff --git a/device/fido/public_key_credential_descriptor.cc b/device/fido/public_key_credential_descriptor.cc
index 8bce337c..f0afd12 100644
--- a/device/fido/public_key_credential_descriptor.cc
+++ b/device/fido/public_key_credential_descriptor.cc
@@ -18,19 +18,18 @@
 
 // static
 base::Optional<PublicKeyCredentialDescriptor>
-PublicKeyCredentialDescriptor::CreateFromCBORValue(
-    const cbor::CBORValue& cbor) {
+PublicKeyCredentialDescriptor::CreateFromCBORValue(const cbor::Value& cbor) {
   if (!cbor.is_map()) {
     return base::nullopt;
   }
 
-  const cbor::CBORValue::MapValue& map = cbor.GetMap();
-  auto type = map.find(cbor::CBORValue(kCredentialTypeKey));
+  const cbor::Value::MapValue& map = cbor.GetMap();
+  auto type = map.find(cbor::Value(kCredentialTypeKey));
   if (type == map.end() || !type->second.is_string() ||
       type->second.GetString() != kPublicKey)
     return base::nullopt;
 
-  auto id = map.find(cbor::CBORValue(kCredentialIdKey));
+  auto id = map.find(cbor::Value(kCredentialIdKey));
   if (id == map.end() || !id->second.is_bytestring())
     return base::nullopt;
 
@@ -72,12 +71,12 @@
 
 PublicKeyCredentialDescriptor::~PublicKeyCredentialDescriptor() = default;
 
-cbor::CBORValue PublicKeyCredentialDescriptor::ConvertToCBOR() const {
-  cbor::CBORValue::MapValue cbor_descriptor_map;
-  cbor_descriptor_map[cbor::CBORValue(kCredentialIdKey)] = cbor::CBORValue(id_);
-  cbor_descriptor_map[cbor::CBORValue(kCredentialTypeKey)] =
-      cbor::CBORValue(CredentialTypeToString(credential_type_));
-  return cbor::CBORValue(std::move(cbor_descriptor_map));
+cbor::Value PublicKeyCredentialDescriptor::ConvertToCBOR() const {
+  cbor::Value::MapValue cbor_descriptor_map;
+  cbor_descriptor_map[cbor::Value(kCredentialIdKey)] = cbor::Value(id_);
+  cbor_descriptor_map[cbor::Value(kCredentialTypeKey)] =
+      cbor::Value(CredentialTypeToString(credential_type_));
+  return cbor::Value(std::move(cbor_descriptor_map));
 }
 
 }  // namespace device
diff --git a/device/fido/public_key_credential_descriptor.h b/device/fido/public_key_credential_descriptor.h
index 626832666..bf23a52 100644
--- a/device/fido/public_key_credential_descriptor.h
+++ b/device/fido/public_key_credential_descriptor.h
@@ -25,7 +25,7 @@
 class COMPONENT_EXPORT(DEVICE_FIDO) PublicKeyCredentialDescriptor {
  public:
   static base::Optional<PublicKeyCredentialDescriptor> CreateFromCBORValue(
-      const cbor::CBORValue& cbor);
+      const cbor::Value& cbor);
 
   PublicKeyCredentialDescriptor(CredentialType credential_type,
                                 std::vector<uint8_t> id);
@@ -41,7 +41,7 @@
       PublicKeyCredentialDescriptor&& other);
   ~PublicKeyCredentialDescriptor();
 
-  cbor::CBORValue ConvertToCBOR() const;
+  cbor::Value ConvertToCBOR() const;
 
   CredentialType credential_type() const { return credential_type_; }
   const std::vector<uint8_t>& id() const { return id_; }
diff --git a/device/fido/public_key_credential_params.cc b/device/fido/public_key_credential_params.cc
index d9bc3b4a..0ea270a8 100644
--- a/device/fido/public_key_credential_params.cc
+++ b/device/fido/public_key_credential_params.cc
@@ -10,8 +10,7 @@
 
 // static
 base::Optional<PublicKeyCredentialParams>
-PublicKeyCredentialParams::CreateFromCBORValue(
-    const cbor::CBORValue& cbor_value) {
+PublicKeyCredentialParams::CreateFromCBORValue(const cbor::Value& cbor_value) {
   if (!cbor_value.is_array())
     return base::nullopt;
 
@@ -22,9 +21,9 @@
 
     const auto& credential_map = credential.GetMap();
     const auto credential_type_it =
-        credential_map.find(cbor::CBORValue(kCredentialTypeMapKey));
+        credential_map.find(cbor::Value(kCredentialTypeMapKey));
     const auto algorithm_type_it =
-        credential_map.find(cbor::CBORValue(kCredentialAlgorithmMapKey));
+        credential_map.find(cbor::Value(kCredentialAlgorithmMapKey));
 
     if (credential_type_it == credential_map.end() ||
         !credential_type_it->second.is_string() ||
@@ -59,19 +58,19 @@
 
 PublicKeyCredentialParams::~PublicKeyCredentialParams() = default;
 
-cbor::CBORValue PublicKeyCredentialParams::ConvertToCBOR() const {
-  cbor::CBORValue::ArrayValue credential_param_array;
+cbor::Value PublicKeyCredentialParams::ConvertToCBOR() const {
+  cbor::Value::ArrayValue credential_param_array;
   credential_param_array.reserve(public_key_credential_params_.size());
 
   for (const auto& credential : public_key_credential_params_) {
-    cbor::CBORValue::MapValue cbor_credential_map;
+    cbor::Value::MapValue cbor_credential_map;
     cbor_credential_map.emplace(kCredentialTypeMapKey,
                                 CredentialTypeToString(credential.type));
     cbor_credential_map.emplace(kCredentialAlgorithmMapKey,
                                 credential.algorithm);
     credential_param_array.emplace_back(std::move(cbor_credential_map));
   }
-  return cbor::CBORValue(std::move(credential_param_array));
+  return cbor::Value(std::move(credential_param_array));
 }
 
 }  // namespace device
diff --git a/device/fido/public_key_credential_params.h b/device/fido/public_key_credential_params.h
index 06d2dc3..f7f3c0d 100644
--- a/device/fido/public_key_credential_params.h
+++ b/device/fido/public_key_credential_params.h
@@ -29,7 +29,7 @@
   };
 
   static base::Optional<PublicKeyCredentialParams> CreateFromCBORValue(
-      const cbor::CBORValue& cbor_value);
+      const cbor::Value& cbor_value);
 
   explicit PublicKeyCredentialParams(
       std::vector<CredentialInfo> credential_params);
@@ -39,7 +39,7 @@
   PublicKeyCredentialParams& operator=(PublicKeyCredentialParams&& other);
   ~PublicKeyCredentialParams();
 
-  cbor::CBORValue ConvertToCBOR() const;
+  cbor::Value ConvertToCBOR() const;
   const std::vector<CredentialInfo>& public_key_credential_params() const {
     return public_key_credential_params_;
   }
diff --git a/device/fido/public_key_credential_rp_entity.cc b/device/fido/public_key_credential_rp_entity.cc
index 7b83513..c46d0df 100644
--- a/device/fido/public_key_credential_rp_entity.cc
+++ b/device/fido/public_key_credential_rp_entity.cc
@@ -13,7 +13,7 @@
 
 // static
 base::Optional<PublicKeyCredentialRpEntity>
-PublicKeyCredentialRpEntity::CreateFromCBORValue(const cbor::CBORValue& cbor) {
+PublicKeyCredentialRpEntity::CreateFromCBORValue(const cbor::Value& cbor) {
   if (!cbor.is_map() || cbor.GetMap().size() > 3)
     return base::nullopt;
 
@@ -31,9 +31,9 @@
   if (!is_rp_map_format_correct)
     return base::nullopt;
 
-  const auto& id_it = rp_map.find(cbor::CBORValue(kEntityIdMapKey));
-  const auto& name_it = rp_map.find(cbor::CBORValue(kEntityNameMapKey));
-  const auto& icon_it = rp_map.find(cbor::CBORValue(kIconUrlMapKey));
+  const auto& id_it = rp_map.find(cbor::Value(kEntityIdMapKey));
+  const auto& name_it = rp_map.find(cbor::Value(kEntityNameMapKey));
+  const auto& icon_it = rp_map.find(cbor::Value(kIconUrlMapKey));
   if (id_it == rp_map.end())
     return base::nullopt;
   PublicKeyCredentialRpEntity rp(id_it->second.GetString());
@@ -76,8 +76,8 @@
   return *this;
 }
 
-cbor::CBORValue PublicKeyCredentialRpEntity::ConvertToCBOR() const {
-  cbor::CBORValue::MapValue rp_map;
+cbor::Value PublicKeyCredentialRpEntity::ConvertToCBOR() const {
+  cbor::Value::MapValue rp_map;
   rp_map.emplace(kEntityIdMapKey, rp_id_);
   if (rp_name_)
     rp_map.emplace(kEntityNameMapKey, *rp_name_);
@@ -85,7 +85,7 @@
   if (rp_icon_url_)
     rp_map.emplace(kIconUrlMapKey, rp_icon_url_->spec());
 
-  return cbor::CBORValue(std::move(rp_map));
+  return cbor::Value(std::move(rp_map));
 }
 
 }  // namespace device
diff --git a/device/fido/public_key_credential_rp_entity.h b/device/fido/public_key_credential_rp_entity.h
index d8c16e3a..03ac8ea 100644
--- a/device/fido/public_key_credential_rp_entity.h
+++ b/device/fido/public_key_credential_rp_entity.h
@@ -22,7 +22,7 @@
 class COMPONENT_EXPORT(DEVICE_FIDO) PublicKeyCredentialRpEntity {
  public:
   static base::Optional<PublicKeyCredentialRpEntity> CreateFromCBORValue(
-      const cbor::CBORValue& cbor);
+      const cbor::Value& cbor);
 
   explicit PublicKeyCredentialRpEntity(std::string rp_id);
   PublicKeyCredentialRpEntity(const PublicKeyCredentialRpEntity& other);
@@ -32,7 +32,7 @@
   PublicKeyCredentialRpEntity& operator=(PublicKeyCredentialRpEntity&& other);
   ~PublicKeyCredentialRpEntity();
 
-  cbor::CBORValue ConvertToCBOR() const;
+  cbor::Value ConvertToCBOR() const;
 
   PublicKeyCredentialRpEntity& SetRpName(std::string rp_name);
   PublicKeyCredentialRpEntity& SetRpIconUrl(GURL icon_url);
diff --git a/device/fido/public_key_credential_user_entity.cc b/device/fido/public_key_credential_user_entity.cc
index 114f1a2..7db7cb8 100644
--- a/device/fido/public_key_credential_user_entity.cc
+++ b/device/fido/public_key_credential_user_entity.cc
@@ -12,31 +12,30 @@
 
 // static
 base::Optional<PublicKeyCredentialUserEntity>
-PublicKeyCredentialUserEntity::CreateFromCBORValue(
-    const cbor::CBORValue& cbor) {
+PublicKeyCredentialUserEntity::CreateFromCBORValue(const cbor::Value& cbor) {
   if (!cbor.is_map())
     return base::nullopt;
 
-  const cbor::CBORValue::MapValue& cbor_map = cbor.GetMap();
+  const cbor::Value::MapValue& cbor_map = cbor.GetMap();
 
-  auto user_id = cbor_map.find(cbor::CBORValue(kEntityIdMapKey));
+  auto user_id = cbor_map.find(cbor::Value(kEntityIdMapKey));
   if (user_id == cbor_map.end() || !user_id->second.is_bytestring())
     return base::nullopt;
 
   PublicKeyCredentialUserEntity user(user_id->second.GetBytestring());
 
-  auto user_name = cbor_map.find(cbor::CBORValue(kEntityNameMapKey));
+  auto user_name = cbor_map.find(cbor::Value(kEntityNameMapKey));
   if (user_name != cbor_map.end() && user_name->second.is_string()) {
     user.SetUserName(user_name->second.GetString());
   }
 
-  auto user_display_name = cbor_map.find(cbor::CBORValue(kDisplayNameMapKey));
+  auto user_display_name = cbor_map.find(cbor::Value(kDisplayNameMapKey));
   if (user_display_name != cbor_map.end() &&
       user_display_name->second.is_string()) {
     user.SetDisplayName(user_display_name->second.GetString());
   }
 
-  auto user_icon_url = cbor_map.find(cbor::CBORValue(kIconUrlMapKey));
+  auto user_icon_url = cbor_map.find(cbor::Value(kIconUrlMapKey));
   if (user_icon_url != cbor_map.end() && user_icon_url->second.is_string()) {
     user.SetIconUrl(GURL(user_icon_url->second.GetString()));
   }
@@ -62,8 +61,8 @@
 
 PublicKeyCredentialUserEntity::~PublicKeyCredentialUserEntity() = default;
 
-cbor::CBORValue PublicKeyCredentialUserEntity::ConvertToCBOR() const {
-  cbor::CBORValue::MapValue user_map;
+cbor::Value PublicKeyCredentialUserEntity::ConvertToCBOR() const {
+  cbor::Value::MapValue user_map;
   user_map.emplace(kEntityIdMapKey, user_id_);
   if (user_name_)
     user_map.emplace(kEntityNameMapKey, *user_name_);
@@ -72,7 +71,7 @@
   if (user_display_name_) {
     user_map.emplace(kDisplayNameMapKey, *user_display_name_);
   }
-  return cbor::CBORValue(std::move(user_map));
+  return cbor::Value(std::move(user_map));
 }
 
 PublicKeyCredentialUserEntity& PublicKeyCredentialUserEntity::SetUserName(
diff --git a/device/fido/public_key_credential_user_entity.h b/device/fido/public_key_credential_user_entity.h
index d2d7bf5c..810dc4b 100644
--- a/device/fido/public_key_credential_user_entity.h
+++ b/device/fido/public_key_credential_user_entity.h
@@ -23,7 +23,7 @@
 class COMPONENT_EXPORT(DEVICE_FIDO) PublicKeyCredentialUserEntity {
  public:
   static base::Optional<PublicKeyCredentialUserEntity> CreateFromCBORValue(
-      const cbor::CBORValue& cbor);
+      const cbor::Value& cbor);
 
   explicit PublicKeyCredentialUserEntity(std::vector<uint8_t> user_id);
   PublicKeyCredentialUserEntity(const PublicKeyCredentialUserEntity& other);
@@ -34,7 +34,7 @@
       PublicKeyCredentialUserEntity&& other);
   ~PublicKeyCredentialUserEntity();
 
-  cbor::CBORValue ConvertToCBOR() const;
+  cbor::Value ConvertToCBOR() const;
   PublicKeyCredentialUserEntity& SetUserName(std::string user_name);
   PublicKeyCredentialUserEntity& SetDisplayName(std::string display_name);
   PublicKeyCredentialUserEntity& SetIconUrl(GURL icon_url);
diff --git a/device/fido/virtual_ctap2_device.cc b/device/fido/virtual_ctap2_device.cc
index 9cf51aad..e69ffec6 100644
--- a/device/fido/virtual_ctap2_device.cc
+++ b/device/fido/virtual_ctap2_device.cc
@@ -112,12 +112,12 @@
     const base::Optional<std::vector<uint8_t>> attestation_certificate,
     base::span<const uint8_t> signature,
     AuthenticatorData authenticator_data) {
-  cbor::CBORValue::MapValue attestation_map;
+  cbor::Value::MapValue attestation_map;
   attestation_map.emplace("alg", -7);
   attestation_map.emplace("sig", fido_parsing_utils::Materialize(signature));
 
   if (attestation_certificate) {
-    cbor::CBORValue::ArrayValue certificate_chain;
+    cbor::Value::ArrayValue certificate_chain;
     certificate_chain.emplace_back(std::move(*attestation_certificate));
     attestation_map.emplace("x5c", std::move(certificate_chain));
   }
@@ -127,7 +127,7 @@
       AttestationObject(
           std::move(authenticator_data),
           std::make_unique<OpaqueAttestationStatement>(
-              "packed", cbor::CBORValue(std::move(attestation_map)))));
+              "packed", cbor::Value(std::move(attestation_map)))));
   return GetSerializedCtapDeviceResponse(make_credential_response);
 }
 
@@ -267,12 +267,12 @@
   AttestedCredentialData attested_credential_data(
       aaguid, sha256_length, key_handle, ConstructECPublicKey(public_key));
 
-  base::Optional<cbor::CBORValue> extensions;
+  base::Optional<cbor::Value> extensions;
   if (request->hmac_secret()) {
-    cbor::CBORValue::MapValue extensions_map;
-    extensions_map.emplace(cbor::CBORValue(kExtensionHmacSecret),
-                           cbor::CBORValue(true));
-    extensions = cbor::CBORValue(std::move(extensions_map));
+    cbor::Value::MapValue extensions_map;
+    extensions_map.emplace(cbor::Value(kExtensionHmacSecret),
+                           cbor::Value(true));
+    extensions = cbor::Value(std::move(extensions_map));
   }
 
   auto authenticator_data = ConstructAuthenticatorData(
@@ -377,7 +377,7 @@
     base::span<const uint8_t, kRpIdHashLength> rp_id_hash,
     uint32_t current_signature_count,
     base::Optional<AttestedCredentialData> attested_credential_data,
-    base::Optional<cbor::CBORValue> extensions) {
+    base::Optional<cbor::Value> extensions) {
   uint8_t flag =
       base::strict_cast<uint8_t>(AuthenticatorData::Flag::kTestOfUserPresence);
   std::array<uint8_t, kSignCounterLength> signature_counter;
diff --git a/device/fido/virtual_ctap2_device.h b/device/fido/virtual_ctap2_device.h
index a716eaa..4c5f96ed 100644
--- a/device/fido/virtual_ctap2_device.h
+++ b/device/fido/virtual_ctap2_device.h
@@ -52,7 +52,7 @@
       base::span<const uint8_t, kRpIdHashLength> rp_id_hash,
       uint32_t current_signature_count,
       base::Optional<AttestedCredentialData> attested_credential_data,
-      base::Optional<cbor::CBORValue> extensions);
+      base::Optional<cbor::Value> extensions);
 
   AuthenticatorGetInfoResponse device_info_;
   base::WeakPtrFactory<FidoDevice> weak_factory_;
diff --git a/docs/accessibility/brltty.md b/docs/accessibility/brltty.md
index 94fd260f..37eb2c54 100644
--- a/docs/accessibility/brltty.md
+++ b/docs/accessibility/brltty.md
@@ -63,3 +63,79 @@
 ```
 
 Note that you shouldn't need to run cros_workon.
+
+## Uprevving Brltty
+
+This section outlines the process to upgrade Brltty to a major release.
+
+### Prerequisites
+
+First, download the latest brltty release tarball
+http://mielke.cc/brltty/archive
+E.g.
+brltty-5.6.tar.gz
+
+The server holding all Chrome OS source packages is Google Cloud Storage. In
+order to update Brltty, you will need to first get started with GCS.
+[Google-internal only](https://sites.google.com/a/google.com/chromeos/resources/engineering/releng/localmirror)
+
+If you follow the alternative cli workflow, you should have the ability to
+list the Chrome OS GCS bucket:
+
+
+```gsutil ls gs://chromeos-localmirror/```
+
+for example:
+gs://chromeos-localmirror/distfiles/brltty-5.6.tar.gz
+is the latest release as of writing.
+
+It will also be handy to checkout brltty.
+
+```Git clone http://github.com/brltty/brltty```
+
+And follow the instructions in the readme to configure/build.
+
+### Upload the latest stable release of brltty.
+
+You can do this via ```gsutil cp```.
+
+After copying, you will likely want the package to be world readable:
+
+    
+```
+gsutil acl ch -u AllUsers:R gs://chromeos-localmirror/distfiles/brltty-5.6.tar.gz
+
+```
+
+### Upreving
+
+Next, you will need to uprev the ebuild. Do this by renaming all files from the previous version to the new one.
+E.g.
+Brltty-5.4.ebuild -> brltty-5.6.ebuild
+
+Note: Manifest has various checksums computed based on the release you uploaded to GCS. Each of these will need to be replaced/updated.
+
+This should be enough to kick off a build. It is likely patches won’t apply cleanly.
+Apply patches
+It is often much easier to apply patches to your local checkout of brltty from github, an build there.
+
+```git tags```
+
+Will ensure you find the right release. You can then checkout that release via
+
+```Git checkout tags/<tag_name>```
+
+### Testing
+
+Once you have a build deployed on a machine, here are a few useful things
+to check:
+* Routing keys within a text field
+* Routing keys on a link
+* Basic braille output
+* Chorded commands (e.g. space + s to toggle speech)
+* Typing (e.g. dots 1-2-3 within a text field)
+* Display specific hardware keys
+* Unload ChromeVox (ctrl+alt+z), plug in a display; ChromeVox should auto
+start
+
+Try to test with at least two displays.
diff --git a/google_apis/drive/auth_service.cc b/google_apis/drive/auth_service.cc
index bf48938..90d91fe 100644
--- a/google_apis/drive/auth_service.cc
+++ b/google_apis/drive/auth_service.cc
@@ -69,7 +69,7 @@
 
   access_token_fetcher_ = identity_manager->CreateAccessTokenFetcherForAccount(
       account_id, "auth_service", url_loader_factory,
-      OAuth2TokenService::ScopeSet(scopes.begin(), scopes.end()),
+      identity::ScopeSet(scopes.begin(), scopes.end()),
       base::BindOnce(&AuthRequest::OnAccessTokenFetchComplete,
                      base::Unretained(this)),
       identity::AccessTokenFetcher::Mode::kImmediate);
diff --git a/gpu/command_buffer/service/scheduler.cc b/gpu/command_buffer/service/scheduler.cc
index 33f2b0c..677c410 100644
--- a/gpu/command_buffer/service/scheduler.cc
+++ b/gpu/command_buffer/service/scheduler.cc
@@ -10,7 +10,7 @@
 #include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
 #include "base/trace_event/trace_event.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "gpu/command_buffer/service/sync_point_manager.h"
 
 namespace gpu {
diff --git a/headless/lib/browser/protocol/protocol_string.cc b/headless/lib/browser/protocol/protocol_string.cc
index 5e82611..b6b10854 100644
--- a/headless/lib/browser/protocol/protocol_string.cc
+++ b/headless/lib/browser/protocol/protocol_string.cc
@@ -190,25 +190,13 @@
 }
 
 // static
-Binary Binary::fromVector(std::vector<uint8_t>&& data) {
+Binary Binary::fromVector(std::vector<uint8_t> data) {
   return Binary(base::RefCountedBytes::TakeVector(&data));
 }
 
 // static
-Binary Binary::fromVector(const std::vector<uint8_t>& data) {
-  std::vector<uint8_t> copied_data(data);
-  return Binary(base::RefCountedBytes::TakeVector(&copied_data));
-}
-
-// static
-Binary Binary::fromString(std::string&& data) {
+Binary Binary::fromString(std::string data) {
   return Binary(base::RefCountedString::TakeString(&data));
 }
-
-// static
-Binary Binary::fromString(const std::string& data) {
-  std::string copied_data(data);
-  return Binary(base::RefCountedString::TakeString(&copied_data));
-}
 }  // namespace protocol
 }  // namespace headless
diff --git a/headless/lib/browser/protocol/protocol_string.h b/headless/lib/browser/protocol/protocol_string.h
index f6d988ca..3f0bf13 100644
--- a/headless/lib/browser/protocol/protocol_string.h
+++ b/headless/lib/browser/protocol/protocol_string.h
@@ -98,10 +98,8 @@
   String toBase64() const;
   static Binary fromBase64(const String& base64, bool* success);
   static Binary fromRefCounted(scoped_refptr<base::RefCountedMemory> memory);
-  static Binary fromVector(std::vector<uint8_t>&& data);
-  static Binary fromVector(const std::vector<uint8_t>& data);
-  static Binary fromString(std::string&& data);
-  static Binary fromString(const std::string& data);
+  static Binary fromVector(std::vector<uint8_t> data);
+  static Binary fromString(std::string data);
 
  private:
   explicit Binary(scoped_refptr<base::RefCountedMemory> bytes);
diff --git a/ios/chrome/browser/about_flags.mm b/ios/chrome/browser/about_flags.mm
index bf618c1..745e175 100644
--- a/ios/chrome/browser/about_flags.mm
+++ b/ios/chrome/browser/about_flags.mm
@@ -236,6 +236,13 @@
      flags_ui::kOsIos,
      FEATURE_VALUE_TYPE(
          autofill::features::kAutofillUpstreamUseGooglePayBrandingOnMobile)},
+    {"enable-autofill-save-credit-card-uses-strike-system",
+     flag_descriptions::kEnableAutofillSaveCreditCardUsesStrikeSystemName,
+     flag_descriptions::
+         kEnableAutofillSaveCreditCardUsesStrikeSystemDescription,
+     flags_ui::kOsIos,
+     FEATURE_VALUE_TYPE(
+         autofill::features::kAutofillSaveCreditCardUsesStrikeSystem)},
     {"use-sync-sandbox", flag_descriptions::kSyncSandboxName,
      flag_descriptions::kSyncSandboxDescription, flags_ui::kOsIos,
      SINGLE_VALUE_TYPE_AND_VALUE(
diff --git a/ios/chrome/browser/ios_chrome_flag_descriptions.cc b/ios/chrome/browser/ios_chrome_flag_descriptions.cc
index b849042..d1a6b50 100644
--- a/ios/chrome/browser/ios_chrome_flag_descriptions.cc
+++ b/ios/chrome/browser/ios_chrome_flag_descriptions.cc
@@ -40,6 +40,12 @@
     "If enabled, changes the server save card prompt's explanation to mention "
     "the saving of the billing address.";
 
+const char kEnableAutofillSaveCreditCardUsesStrikeSystemName[] =
+    "Enable limit on offering to save the same credit card repeatedly";
+const char kEnableAutofillSaveCreditCardUsesStrikeSystemDescription[] =
+    "If enabled, prevents popping up the credit card offer-to-save prompt if "
+    "it has repeatedly been ignored, declined, or failed.";
+
 const char kSyncSandboxName[] = "Use Chrome Sync sandbox";
 const char kSyncSandboxDescription[] =
     "Connects to the testing server for Chrome Sync.";
diff --git a/ios/chrome/browser/ios_chrome_flag_descriptions.h b/ios/chrome/browser/ios_chrome_flag_descriptions.h
index 6abce5d..0431b0e 100644
--- a/ios/chrome/browser/ios_chrome_flag_descriptions.h
+++ b/ios/chrome/browser/ios_chrome_flag_descriptions.h
@@ -30,6 +30,12 @@
 extern const char
     kEnableAutofillCreditCardUploadUpdatePromptExplanationDescription[];
 
+// Title and description for the flag to control if credit card save should
+// utilize the Autofill StrikeDatabase when determining whether save should be
+// offered.
+extern const char kEnableAutofillSaveCreditCardUsesStrikeSystemName[];
+extern const char kEnableAutofillSaveCreditCardUsesStrikeSystemDescription[];
+
 // Title and description for the flag to control if Chrome Sync should use the
 // sandbox servers.
 extern const char kSyncSandboxName[];
diff --git a/ios/chrome/browser/sync/profile_sync_service_factory.cc b/ios/chrome/browser/sync/profile_sync_service_factory.cc
index a75971c..350e7918 100644
--- a/ios/chrome/browser/sync/profile_sync_service_factory.cc
+++ b/ios/chrome/browser/sync/profile_sync_service_factory.cc
@@ -11,6 +11,7 @@
 #include "base/time/time.h"
 #include "components/browser_sync/profile_sync_service.h"
 #include "components/invalidation/impl/invalidation_switches.h"
+#include "components/invalidation/impl/profile_invalidation_provider.h"
 #include "components/keyed_service/ios/browser_state_dependency_manager.h"
 #include "components/network_time/network_time_tracker.h"
 #include "components/signin/core/browser/device_id_helper.h"
@@ -114,12 +115,9 @@
   DependsOn(IdentityManagerFactory::GetInstance());
   DependsOn(IOSChromeGCMProfileServiceFactory::GetInstance());
   DependsOn(IOSChromePasswordStoreFactory::GetInstance());
-  if (base::FeatureList::IsEnabled(invalidation::switches::kFCMInvalidations)) {
-    DependsOn(IOSChromeProfileInvalidationProviderFactory::GetInstance());
-  } else {
-    DependsOn(
-        IOSChromeDeprecatedProfileInvalidationProviderFactory::GetInstance());
-  }
+  DependsOn(IOSChromeProfileInvalidationProviderFactory::GetInstance());
+  DependsOn(
+      IOSChromeDeprecatedProfileInvalidationProviderFactory::GetInstance());
   DependsOn(ModelTypeStoreServiceFactory::GetInstance());
   DependsOn(ReadingListModelFactory::GetInstance());
   DependsOn(SessionSyncServiceFactory::GetInstance());
@@ -159,6 +157,29 @@
   init_params.user_events_separate_pref_group =
       unified_consent::IsUnifiedConsentFeatureEnabled();
 
+  bool use_fcm_invalidations =
+      base::FeatureList::IsEnabled(invalidation::switches::kFCMInvalidations);
+  if (use_fcm_invalidations) {
+    auto* fcm_invalidation_provider =
+        IOSChromeProfileInvalidationProviderFactory::GetForBrowserState(
+            browser_state);
+    if (fcm_invalidation_provider) {
+      init_params.invalidations_identity_providers.push_back(
+          fcm_invalidation_provider->GetIdentityProvider());
+    }
+  }
+  // This code should stay here until all invalidation client are
+  // migrated from deprecated invalidation  infructructure.
+  // Since invalidations will work only if ProfileSyncService calls
+  // SetActiveAccountId for all identity providers.
+  auto* deprecated_invalidation_provider =
+      IOSChromeDeprecatedProfileInvalidationProviderFactory::GetForBrowserState(
+          browser_state);
+  if (deprecated_invalidation_provider) {
+    init_params.invalidations_identity_providers.push_back(
+        deprecated_invalidation_provider->GetIdentityProvider());
+  }
+
   auto pss = std::make_unique<ProfileSyncService>(std::move(init_params));
   pss->Initialize();
   return pss;
diff --git a/ios/chrome/browser/ui/autofill/BUILD.gn b/ios/chrome/browser/ui/autofill/BUILD.gn
index 11940562..c9a66d9 100644
--- a/ios/chrome/browser/ui/autofill/BUILD.gn
+++ b/ios/chrome/browser/ui/autofill/BUILD.gn
@@ -7,8 +7,6 @@
   sources = [
     "autofill_ui_type_util.h",
     "autofill_ui_type_util.mm",
-    "card_unmask_prompt_view_bridge.h",
-    "card_unmask_prompt_view_bridge.mm",
     "chrome_autofill_client_ios.h",
     "chrome_autofill_client_ios.mm",
     "form_input_accessory_coordinator.h",
@@ -18,6 +16,7 @@
   ]
   deps = [
     ":autofill_ui",
+    ":bridges",
     "//base",
     "//components/autofill/core/browser",
     "//components/autofill/core/common",
@@ -61,6 +60,32 @@
   libs = [ "UIKit.framework" ]
 }
 
+source_set("bridges") {
+  configs += [ "//build/config/compiler:enable_arc" ]
+  sources = [
+    "card_unmask_prompt_view_bridge.h",
+    "card_unmask_prompt_view_bridge.mm",
+  ]
+  deps = [
+    ":autofill_ui",
+    "//base",
+    "//components/autofill/core/browser",
+    "//components/strings",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui/autofill/cells",
+    "//ios/chrome/browser/ui/collection_view/cells",
+    "//ios/chrome/browser/ui/colors",
+    "//ios/third_party/material_components_ios",
+    "//ios/third_party/material_roboto_font_loader_ios",
+    "//ios/web",
+    "//ui/base",
+  ]
+  public_deps = [
+    "//ios/chrome/browser/ui/collection_view",
+  ]
+  libs = [ "UIKit.framework" ]
+}
+
 source_set("autofill_ui") {
   configs += [ "//build/config/compiler:enable_arc" ]
   sources = [
diff --git a/ios/chrome/browser/ui/payments/BUILD.gn b/ios/chrome/browser/ui/payments/BUILD.gn
index 3ecf90f..f107c16 100644
--- a/ios/chrome/browser/ui/payments/BUILD.gn
+++ b/ios/chrome/browser/ui/payments/BUILD.gn
@@ -29,8 +29,6 @@
     "credit_card_edit_coordinator.mm",
     "credit_card_edit_mediator.h",
     "credit_card_edit_mediator.mm",
-    "full_card_requester.h",
-    "full_card_requester.mm",
     "js_payment_request_manager.h",
     "js_payment_request_manager.mm",
     "payment_items_display_coordinator.h",
@@ -62,6 +60,7 @@
   ]
   deps = [
     ":payments_ui",
+    ":requesters",
     "resources:ic_add",
     "//base",
     "//components/autofill/core/browser",
@@ -99,6 +98,25 @@
   libs = [ "UIKit.framework" ]
 }
 
+source_set("requesters") {
+  configs += [ "//build/config/compiler:enable_arc" ]
+  sources = [
+    "full_card_requester.h",
+    "full_card_requester.mm",
+  ]
+  deps = [
+    ":payments_ui",
+    "resources:ic_add",
+    "//base",
+    "//components/autofill/core/browser",
+    "//components/autofill/ios/browser",
+    "//ios/chrome/browser/browser_state",
+    "//ios/chrome/browser/ui/autofill:bridges",
+    "//ui/base",
+  ]
+  libs = [ "UIKit.framework" ]
+}
+
 source_set("payments_ui") {
   configs += [ "//build/config/compiler:enable_arc" ]
   sources = [
@@ -190,6 +208,7 @@
   deps = [
     ":payments",
     ":payments_ui",
+    ":requesters",
     "//base",
     "//base/test:test_support",
     "//components/autofill/core/browser",
@@ -210,6 +229,7 @@
     "//ios/chrome/browser/signin",
     "//ios/chrome/browser/ui/autofill",
     "//ios/chrome/browser/ui/autofill:autofill_ui",
+    "//ios/chrome/browser/ui/autofill:bridges",
     "//ios/chrome/browser/ui/autofill/cells",
     "//ios/chrome/browser/ui/collection_view:test_support",
     "//ios/chrome/browser/ui/collection_view/cells",
@@ -267,6 +287,7 @@
     "//ios/chrome/browser/browser_state",
     "//ios/chrome/browser/payments",
     "//ios/chrome/browser/ui/autofill",
+    "//ios/chrome/browser/ui/autofill:bridges",
     "//ios/chrome/browser/ui/payments/cells",
     "//ios/chrome/browser/ui/popup_menu:constants",
     "//ios/chrome/test/app:test_support",
diff --git a/ios/chrome/browser/ui/settings/passwords_settings_egtest.mm b/ios/chrome/browser/ui/settings/passwords_settings_egtest.mm
index d79ba38..c7dbd61 100644
--- a/ios/chrome/browser/ui/settings/passwords_settings_egtest.mm
+++ b/ios/chrome/browser/ui/settings/passwords_settings_egtest.mm
@@ -1643,6 +1643,41 @@
       assertWithMatcher:grey_notNil()];
 }
 
+// Test search and delete all passwords and blacklisted items.
+- (void)testSearchAndDeleteAllPasswords {
+  SaveExamplePasswordForms();
+  SaveExampleBlacklistedForms();
+
+  OpenPasswordSettings();
+
+  [[EarlGrey selectElementWithMatcher:SearchTextField()]
+      performAction:grey_typeText(@"u\n")];
+
+  TapEdit();
+
+  // Select all.
+  [GetInteractionForPasswordEntry(@"example11.com, user1")
+      performAction:grey_tap()];
+  [GetInteractionForPasswordEntry(@"example12.com, user2")
+      performAction:grey_tap()];
+  [GetInteractionForPasswordEntry(@"exclude1.com") performAction:grey_tap()];
+  [GetInteractionForPasswordEntry(@"exclude2.com") performAction:grey_tap()];
+
+  // Delete them.
+  [[EarlGrey selectElementWithMatcher:DeleteButtonAtBottom()]
+      performAction:grey_tap()];
+
+  // All should be gone.
+  [GetInteractionForPasswordEntry(@"example11.com, user1")
+      assertWithMatcher:grey_nil()];
+  [GetInteractionForPasswordEntry(@"example12.com, user2")
+      assertWithMatcher:grey_nil()];
+  [GetInteractionForPasswordEntry(@"exclude1.com")
+      assertWithMatcher:grey_nil()];
+  [GetInteractionForPasswordEntry(@"exclude2.com")
+      assertWithMatcher:grey_nil()];
+}
+
 // Test that user can't search passwords while in edit mode.
 - (void)testCantSearchPasswordsWhileInEditMode {
   SaveExamplePasswordForms();
diff --git a/ios/chrome/browser/ui/settings/save_passwords_collection_view_controller.mm b/ios/chrome/browser/ui/settings/save_passwords_collection_view_controller.mm
index bcb7fc09..d78bc90 100644
--- a/ios/chrome/browser/ui/settings/save_passwords_collection_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/save_passwords_collection_view_controller.mm
@@ -830,11 +830,14 @@
     SavePasswordsCollectionViewController* strongSelf = weakSelf;
     if (!strongSelf)
       return;
-    [strongSelf clearSectionWithIdentifier:SectionIdentifierSavedPasswords
-                                   ifEmpty:strongSelf->savedForms_.empty()];
+    // Delete in reverse order of section indexes (bottom up of section
+    // displayed), so that indexes in model matches those in the view.  if we
+    // don't we'll cause a crash.
     [strongSelf
         clearSectionWithIdentifier:SectionIdentifierBlacklist
                            ifEmpty:strongSelf->blacklistedForms_.empty()];
+    [strongSelf clearSectionWithIdentifier:SectionIdentifierSavedPasswords
+                                   ifEmpty:strongSelf->savedForms_.empty()];
     [strongSelf
         clearSectionWithIdentifier:SectionIdentifierSearchPasswordsBox
                            ifEmpty:strongSelf->savedForms_.empty() &&
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm
index fe1f969..ae57adf 100644
--- a/ios/web/web_state/ui/crw_web_controller.mm
+++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -174,16 +174,6 @@
   BACK_FORWARD_NAVIGATION_TYPE_COUNT
 };
 
-// Constants for storing the source of NSErrors received by WKWebViews:
-// - Errors received by |-webView:didFailProvisionalNavigation:withError:| are
-//   recorded using WKWebViewErrorSource::PROVISIONAL_LOAD.  These should be
-//   cancelled.
-// - Errors received by |-webView:didFailNavigation:withError:| are recorded
-//   using WKWebViewsource::NAVIGATION.  These errors should not be cancelled,
-//   as the WKWebView will automatically retry the load.
-NSString* const kWKWebViewErrorSourceKey = @"ErrorSource";
-typedef enum { NONE = 0, PROVISIONAL_LOAD, NAVIGATION } WKWebViewErrorSource;
-
 // Represents cert verification error, which happened inside
 // |webView:didReceiveAuthenticationChallenge:completionHandler:| and should
 // be checked inside |webView:didFailProvisionalNavigation:withError:|.
@@ -204,21 +194,6 @@
 // stored errors is not expected to be high.
 const CertVerificationErrorsCacheType::size_type kMaxCertErrorsCount = 100;
 
-// Utility function for getting the source of NSErrors received by WKWebViews.
-WKWebViewErrorSource WKWebViewErrorSourceFromError(NSError* error) {
-  DCHECK(error);
-  return static_cast<WKWebViewErrorSource>(
-      [error.userInfo[kWKWebViewErrorSourceKey] integerValue]);
-}
-// Utility function for converting the WKWebViewErrorSource to the NSError
-// received by WKWebViews.
-NSError* WKWebViewErrorWithSource(NSError* error, WKWebViewErrorSource source) {
-  DCHECK(error);
-  NSMutableDictionary* userInfo = [error.userInfo mutableCopy];
-  [userInfo setObject:@(source) forKey:kWKWebViewErrorSourceKey];
-  return
-      [NSError errorWithDomain:error.domain code:error.code userInfo:userInfo];
-}
 }  // namespace
 
 #pragma mark -
@@ -911,15 +886,19 @@
                                        transition:
                                            (ui::PageTransition)pageTransition;
 // Called when a load ends in an error.
-- (void)handleLoadError:(NSError*)error forNavigation:(WKNavigation*)navigation;
+- (void)handleLoadError:(NSError*)error
+          forNavigation:(WKNavigation*)navigation
+        provisionalLoad:(BOOL)provisionalLoad;
 
 // Handles cancelled load in WKWebView (error with NSURLErrorCancelled code).
 - (void)handleCancelledError:(NSError*)error
-               forNavigation:(WKNavigation*)navigation;
+               forNavigation:(WKNavigation*)navigation
+             provisionalLoad:(BOOL)provisionalLoad;
 
 // Used to decide whether a load that generates errors with the
 // NSURLErrorCancelled code should be cancelled.
-- (BOOL)shouldCancelLoadForCancelledError:(NSError*)error;
+- (BOOL)shouldCancelLoadForCancelledError:(NSError*)error
+                          provisionalLoad:(BOOL)provisionalLoad;
 
 // Returns YES if response should be rendered in WKWebView.
 - (BOOL)shouldRenderResponse:(WKNavigationResponse*)WKResponse;
@@ -3066,9 +3045,12 @@
 }
 
 - (void)handleLoadError:(NSError*)error
-          forNavigation:(WKNavigation*)navigation {
+          forNavigation:(WKNavigation*)navigation
+        provisionalLoad:(BOOL)provisionalLoad {
   if (error.code == NSURLErrorCancelled) {
-    [self handleCancelledError:error forNavigation:navigation];
+    [self handleCancelledError:error
+                 forNavigation:navigation
+               provisionalLoad:provisionalLoad];
     // NSURLErrorCancelled errors that aren't handled by aborting the load will
     // automatically be retried by the web view, so early return in this case.
     return;
@@ -3129,12 +3111,11 @@
   if (item) {
     GURL errorURL =
         net::GURLWithNSURL(error.userInfo[NSURLErrorFailingURLErrorKey]);
-    WKWebViewErrorSource source = WKWebViewErrorSourceFromError(error);
     web::ErrorRetryCommand command = web::ErrorRetryCommand::kDoNothing;
-    if (source == PROVISIONAL_LOAD) {
+    if (provisionalLoad) {
       command = item->error_retry_state_machine().DidFailProvisionalNavigation(
           net::GURLWithNSURL(_webView.URL), errorURL);
-    } else if (source == NAVIGATION) {
+    } else {
       command = item->error_retry_state_machine().DidFailNavigation(
           net::GURLWithNSURL(_webView.URL), errorURL);
     }
@@ -3147,16 +3128,17 @@
     self.navigationManagerImpl->CommitPendingItem();
   }
 
-  if ([_navigationStates stateForNavigation:navigation] ==
-      web::WKNavigationState::PROVISIONALY_FAILED) {
+  if (provisionalLoad) {
     _webStateImpl->OnNavigationFinished(navigationContext);
   }
   [self loadCompleteWithSuccess:NO forNavigation:navigation];
 }
 
 - (void)handleCancelledError:(NSError*)error
-               forNavigation:(WKNavigation*)navigation {
-  if ([self shouldCancelLoadForCancelledError:error]) {
+               forNavigation:(WKNavigation*)navigation
+             provisionalLoad:(BOOL)provisionalLoad {
+  if ([self shouldCancelLoadForCancelledError:error
+                              provisionalLoad:provisionalLoad]) {
     [self loadCancelled];
     self.navigationManagerImpl->DiscardNonCommittedItems();
     // If discarding the non-committed entries results in native content URL,
@@ -3174,14 +3156,14 @@
     web::NavigationContextImpl* navigationContext =
         [_navigationStates contextForNavigation:navigation];
 
-    if ([_navigationStates stateForNavigation:navigation] ==
-        web::WKNavigationState::PROVISIONALY_FAILED) {
+    if (provisionalLoad) {
       _webStateImpl->OnNavigationFinished(navigationContext);
     }
   }
 }
 
-- (BOOL)shouldCancelLoadForCancelledError:(NSError*)error {
+- (BOOL)shouldCancelLoadForCancelledError:(NSError*)error
+                          provisionalLoad:(BOOL)provisionalLoad {
   DCHECK(error.code == NSURLErrorCancelled ||
          error.code == web::kWebKitErrorFrameLoadInterruptedByPolicyChange);
   // Do not cancel the load if it is for an app specific URL, as such errors
@@ -3191,10 +3173,7 @@
   if (web::GetWebClient()->IsAppSpecificURL(errorURL))
     return NO;
 
-  // Don't cancel NSURLErrorCancelled errors originating from navigation
-  // as the WKWebView will automatically retry these loads.
-  WKWebViewErrorSource source = WKWebViewErrorSourceFromError(error);
-  return source != NAVIGATION;
+  return provisionalLoad;
 }
 
 - (void)didReceiveWebViewNavigationDelegateCallback {
@@ -3836,7 +3815,7 @@
     // |info.cert| can be null if certChain in NSError is empty or can not be
     // parsed, in this case do not ask delegate if error should be allowed, it
     // should not be.
-    [self handleLoadError:error forNavigation:navigation];
+    [self handleLoadError:error forNavigation:navigation provisionalLoad:YES];
     return;
   }
 
@@ -4137,7 +4116,9 @@
           messageRouter:messageRouter
       completionHandler:^(NSError* loadError) {
         if (loadError)
-          [self handleLoadError:loadError forNavigation:nil];
+          [self handleLoadError:loadError
+                  forNavigation:nil
+                provisionalLoad:YES];
         else
           self.webStateImpl->SetContentsMimeType("text/html");
       }];
@@ -4741,18 +4722,19 @@
   // Handle load cancellation for directly cancelled navigations without
   // handling their potential errors. Otherwise, handle the error.
   if ([_pendingNavigationInfo cancelled]) {
-    [self handleCancelledError:error forNavigation:navigation];
+    [self handleCancelledError:error
+                 forNavigation:navigation
+               provisionalLoad:YES];
   } else if (error.code == NSURLErrorUnsupportedURL &&
              _webStateImpl->HasWebUI()) {
     // This is a navigation to WebUI page.
     DCHECK(web::GetWebClient()->IsAppSpecificURL(
         net::GURLWithNSURL(error.userInfo[NSURLErrorFailingURLErrorKey])));
   } else {
-    error = WKWebViewErrorWithSource(error, PROVISIONAL_LOAD);
     if (web::IsWKWebViewSSLCertError(error)) {
       [self handleSSLCertError:error forNavigation:navigation];
     } else {
-      [self handleLoadError:error forNavigation:navigation];
+      [self handleLoadError:error forNavigation:navigation provisionalLoad:YES];
     }
   }
 
@@ -5084,8 +5066,7 @@
   [_navigationStates setState:web::WKNavigationState::FAILED
                 forNavigation:navigation];
 
-  [self handleLoadError:WKWebViewErrorWithSource(error, NAVIGATION)
-          forNavigation:navigation];
+  [self handleLoadError:error forNavigation:navigation provisionalLoad:NO];
 
   [self removeAllWebFrames];
   _certVerificationErrors->Clear();
diff --git a/ios/web_view/internal/sync/web_view_profile_sync_service_factory.mm b/ios/web_view/internal/sync/web_view_profile_sync_service_factory.mm
index 2381906..a6fded4 100644
--- a/ios/web_view/internal/sync/web_view_profile_sync_service_factory.mm
+++ b/ios/web_view/internal/sync/web_view_profile_sync_service_factory.mm
@@ -93,10 +93,10 @@
       &signin::GetSigninScopedDeviceId, browser_state->GetPrefs());
   init_params.network_connection_tracker =
       ApplicationContext::GetInstance()->GetNetworkConnectionTracker();
-  init_params.invalidations_identity_provider =
+  init_params.invalidations_identity_providers.push_back(
       WebViewProfileInvalidationProviderFactory::GetForBrowserState(
           browser_state)
-          ->GetIdentityProvider();
+          ->GetIdentityProvider());
 
   auto profile_sync_service =
       std::make_unique<ProfileSyncService>(std::move(init_params));
diff --git a/media/audio/audio_manager.cc b/media/audio/audio_manager.cc
index d016814..b82cf28 100644
--- a/media/audio/audio_manager.cc
+++ b/media/audio/audio_manager.cc
@@ -17,6 +17,7 @@
 #include "base/power_monitor/power_monitor.h"
 #include "base/single_thread_task_runner.h"
 #include "base/strings/stringprintf.h"
+#include "base/thread_annotations.h"
 #include "build/build_config.h"
 #include "media/audio/fake_audio_log_factory.h"
 #include "media/base/media_switches.h"
@@ -219,8 +220,8 @@
   scoped_refptr<base::SingleThreadTaskRunner> audio_task_runner_;
 
   base::Lock hang_lock_;
-  bool hang_detection_enabled_ = true;
-  base::TimeTicks last_audio_thread_timer_tick_;
+  bool hang_detection_enabled_ GUARDED_BY(hang_lock_) = true;
+  base::TimeTicks last_audio_thread_timer_tick_ GUARDED_BY(hang_lock_);
   uint32_t failed_pings_ = 0;
   bool io_task_running_ = false;
   bool audio_task_running_ = false;
diff --git a/media/audio/audio_output_device.h b/media/audio/audio_output_device.h
index be9a5ff..4e0344f 100644
--- a/media/audio/audio_output_device.h
+++ b/media/audio/audio_output_device.h
@@ -70,6 +70,7 @@
 #include "base/macros.h"
 #include "base/memory/unsafe_shared_memory_region.h"
 #include "base/synchronization/waitable_event.h"
+#include "base/thread_annotations.h"
 #include "base/time/time.h"
 #include "media/audio/audio_device_thread.h"
 #include "media/audio/audio_output_ipc.h"
@@ -207,7 +208,8 @@
   // guard to control stopping and starting the audio thread.
   base::Lock audio_thread_lock_;
   std::unique_ptr<AudioOutputDeviceThreadCallback> audio_callback_;
-  std::unique_ptr<AudioDeviceThread> audio_thread_;
+  std::unique_ptr<AudioDeviceThread> audio_thread_
+      GUARDED_BY(audio_thread_lock_);
 
   // Temporary hack to ignore OnStreamCreated() due to the user calling Stop()
   // so we don't start the audio thread pointing to a potentially freed
diff --git a/media/audio/audio_output_stream_sink.h b/media/audio/audio_output_stream_sink.h
index 8407e9e..40bbecf0 100644
--- a/media/audio/audio_output_stream_sink.h
+++ b/media/audio/audio_output_stream_sink.h
@@ -13,6 +13,7 @@
 #include "base/macros.h"
 #include "base/single_thread_task_runner.h"
 #include "base/synchronization/lock.h"
+#include "base/thread_annotations.h"
 #include "base/time/time.h"
 #include "media/audio/audio_io.h"
 #include "media/base/audio_renderer_sink.h"
@@ -75,7 +76,7 @@
   // |active_params_| is set on the audio thread and therefore does not need
   // synchronization.
   AudioParameters active_params_;
-  RenderCallback* active_render_callback_;
+  RenderCallback* active_render_callback_ GUARDED_BY(callback_lock_);
 
   // Lock to synchronize setting and clearing of |active_render_callback_|.
   base::Lock callback_lock_;
diff --git a/media/audio/simple_sources.cc b/media/audio/simple_sources.cc
index 1eebf23..aea38bb 100644
--- a/media/audio/simple_sources.cc
+++ b/media/audio/simple_sources.cc
@@ -11,6 +11,7 @@
 #include "base/files/file.h"
 #include "base/logging.h"
 #include "base/numerics/math_constants.h"
+#include "base/thread_annotations.h"
 #include "base/time/time.h"
 #include "media/audio/sounds/wav_audio_handler.h"
 #include "media/base/audio_bus.h"
@@ -87,8 +88,8 @@
 
  private:
   mutable base::Lock lock_;
-  bool beep_once_;
-  bool automatic_beep_;
+  bool beep_once_ GUARDED_BY(lock_);
+  bool automatic_beep_ GUARDED_BY(lock_);
 };
 
 BeepContext* GetBeepContext() {
diff --git a/media/audio/simple_sources.h b/media/audio/simple_sources.h
index 9b62b97..ebc3aa3 100644
--- a/media/audio/simple_sources.h
+++ b/media/audio/simple_sources.h
@@ -11,6 +11,7 @@
 
 #include "base/files/file_path.h"
 #include "base/synchronization/lock.h"
+#include "base/thread_annotations.h"
 #include "base/time/time.h"
 #include "media/audio/audio_io.h"
 #include "media/base/audio_converter.h"
@@ -47,10 +48,10 @@
   int errors() { return errors_; }
 
  protected:
-  int channels_;
-  double f_;
-  int time_state_;
-  int cap_;
+  const int channels_;
+  const double f_;
+  int time_state_ GUARDED_BY(time_lock_);
+  int cap_ GUARDED_BY(time_lock_);
   int callbacks_;
   int errors_;
   base::Lock time_lock_;
diff --git a/media/audio/virtual_audio_input_stream.h b/media/audio/virtual_audio_input_stream.h
index e1973054..174a5f7c 100644
--- a/media/audio/virtual_audio_input_stream.h
+++ b/media/audio/virtual_audio_input_stream.h
@@ -13,6 +13,7 @@
 
 #include "base/macros.h"
 #include "base/synchronization/lock.h"
+#include "base/thread_annotations.h"
 #include "base/threading/thread_checker.h"
 #include "media/audio/audio_io.h"
 #include "media/base/audio_converter.h"
@@ -96,14 +97,14 @@
 
   // AudioConverters associated with the attached VirtualAudioOutputStreams,
   // partitioned by common AudioParameters.
-  AudioConvertersMap converters_;
+  AudioConvertersMap converters_ GUARDED_BY(converter_network_lock_);
 
   // AudioConverter that takes all the audio converters and mixes them into one
   // final audio stream.
-  AudioConverter mixer_;
+  AudioConverter mixer_ GUARDED_BY(converter_network_lock_);
 
   // Number of currently attached VirtualAudioOutputStreams.
-  int num_attached_output_streams_;
+  int num_attached_output_streams_ GUARDED_BY(converter_network_lock_);
 
   // Handles callback timing for consumption of audio data.
   FakeAudioWorker fake_worker_;
diff --git a/media/audio/virtual_audio_sink.h b/media/audio/virtual_audio_sink.h
index 84179151..d6eb6cd 100644
--- a/media/audio/virtual_audio_sink.h
+++ b/media/audio/virtual_audio_sink.h
@@ -9,6 +9,7 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/synchronization/lock.h"
+#include "base/thread_annotations.h"
 #include "media/audio/audio_io.h"
 #include "media/audio/audio_source_diverter.h"
 #include "media/base/audio_converter.h"
@@ -47,7 +48,7 @@
 
   const AudioParameters params_;
   VirtualAudioInputStream* const target_;
-  AudioShifter shifter_;
+  AudioShifter shifter_ GUARDED_BY(shifter_lock_);
   base::Lock shifter_lock_;
   AfterCloseCallback after_close_callback_;
 
diff --git a/media/base/cdm_promise_adapter.cc b/media/base/cdm_promise_adapter.cc
index 3ff34ee..6b9fe52 100644
--- a/media/base/cdm_promise_adapter.cc
+++ b/media/base/cdm_promise_adapter.cc
@@ -34,7 +34,7 @@
                                        const T&... result) {
   std::unique_ptr<CdmPromise> promise = TakePromise(promise_id);
   if (!promise) {
-    NOTREACHED() << "Promise not found for " << promise_id;
+    LOG(ERROR) << "Promise not found for " << promise_id;
     return;
   }
 
@@ -42,7 +42,7 @@
   CdmPromise::ResolveParameterType type = promise->GetResolveParameterType();
   CdmPromise::ResolveParameterType expected = CdmPromiseTraits<T...>::kType;
   if (type != expected) {
-    NOTREACHED() << "Promise type mismatch: " << type << " vs " << expected;
+    LOG(ERROR) << "Promise type mismatch: " << type << " vs " << expected;
     return;
   }
 
@@ -55,7 +55,7 @@
                                       const std::string& error_message) {
   std::unique_ptr<CdmPromise> promise = TakePromise(promise_id);
   if (!promise) {
-    NOTREACHED() << "No promise found for promise_id " << promise_id;
+    LOG(ERROR) << "Promise not found for " << promise_id;
     return;
   }
 
@@ -77,6 +77,7 @@
   auto it = promises_.find(promise_id);
   if (it == promises_.end())
     return nullptr;
+
   std::unique_ptr<CdmPromise> result = std::move(it->second);
   promises_.erase(it);
   return result;
diff --git a/media/base/user_input_monitor_unittest.cc b/media/base/user_input_monitor_unittest.cc
index e6b7e7b6..f174daff 100644
--- a/media/base/user_input_monitor_unittest.cc
+++ b/media/base/user_input_monitor_unittest.cc
@@ -7,8 +7,9 @@
 #include <memory>
 #include <utility>
 
-#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
+#include "base/test/scoped_task_environment.h"
+#include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -20,14 +21,15 @@
 
 TEST(UserInputMonitorTest, CreatePlatformSpecific) {
 #if defined(OS_LINUX)
-  base::MessageLoopForIO message_loop;
-  base::FileDescriptorWatcher file_descriptor_watcher(&message_loop);
+  base::test::ScopedTaskEnvironment task_environment(
+      base::test::ScopedTaskEnvironment::MainThreadType::IO);
 #else
-  base::MessageLoopForUI message_loop;
+  base::test::ScopedTaskEnvironment task_environment(
+      base::test::ScopedTaskEnvironment::MainThreadType::UI);
 #endif  // defined(OS_LINUX)
 
   std::unique_ptr<UserInputMonitor> monitor = UserInputMonitor::Create(
-      message_loop.task_runner(), message_loop.task_runner());
+      base::ThreadTaskRunnerHandle::Get(), base::ThreadTaskRunnerHandle::Get());
 
   if (!monitor)
     return;
@@ -41,14 +43,15 @@
 
 TEST(UserInputMonitorTest, CreatePlatformSpecificWithMapping) {
 #if defined(OS_LINUX)
-  base::MessageLoopForIO message_loop;
-  base::FileDescriptorWatcher file_descriptor_watcher(&message_loop);
+  base::test::ScopedTaskEnvironment task_environment(
+      base::test::ScopedTaskEnvironment::MainThreadType::IO);
 #else
-  base::MessageLoopForUI message_loop;
+  base::test::ScopedTaskEnvironment task_environment(
+      base::test::ScopedTaskEnvironment::MainThreadType::UI);
 #endif  // defined(OS_LINUX)
 
   std::unique_ptr<UserInputMonitor> monitor = UserInputMonitor::Create(
-      message_loop.task_runner(), message_loop.task_runner());
+      base::ThreadTaskRunnerHandle::Get(), base::ThreadTaskRunnerHandle::Get());
 
   if (!monitor)
     return;
diff --git a/media/base/video_frame.cc b/media/base/video_frame.cc
index 4c1f02d..50bcef7 100644
--- a/media/base/video_frame.cc
+++ b/media/base/video_frame.cc
@@ -114,6 +114,8 @@
     case PIXEL_FORMAT_RGB24:
     case PIXEL_FORMAT_RGB32:
     case PIXEL_FORMAT_Y16:
+    case PIXEL_FORMAT_ABGR:
+    case PIXEL_FORMAT_XBGR:
       return false;
     case PIXEL_FORMAT_NV12:
     case PIXEL_FORMAT_NV21:
@@ -169,7 +171,7 @@
     return true;
 
   // Make sure new formats are properly accounted for in the method.
-  static_assert(PIXEL_FORMAT_MAX == 26,
+  static_assert(PIXEL_FORMAT_MAX == 28,
                 "Added pixel format, please review IsValidConfig()");
 
   if (format == PIXEL_FORMAT_UNKNOWN) {
@@ -667,6 +669,8 @@
     case PIXEL_FORMAT_ARGB:
     case PIXEL_FORMAT_XRGB:
     case PIXEL_FORMAT_RGB32:
+    case PIXEL_FORMAT_ABGR:
+    case PIXEL_FORMAT_XBGR:
       return 4;
     case PIXEL_FORMAT_RGB24:
       return 3;
@@ -1187,6 +1191,8 @@
         case PIXEL_FORMAT_RGB24:
         case PIXEL_FORMAT_RGB32:
         case PIXEL_FORMAT_MJPEG:
+        case PIXEL_FORMAT_ABGR:
+        case PIXEL_FORMAT_XBGR:
           break;
       }
   }
diff --git a/media/base/video_frame_layout.cc b/media/base/video_frame_layout.cc
index 9841ae1..df4a040 100644
--- a/media/base/video_frame_layout.cc
+++ b/media/base/video_frame_layout.cc
@@ -50,6 +50,8 @@
     case PIXEL_FORMAT_RGB32:
     case PIXEL_FORMAT_MJPEG:
     case PIXEL_FORMAT_Y16:
+    case PIXEL_FORMAT_ABGR:
+    case PIXEL_FORMAT_XBGR:
       return 1;
     case PIXEL_FORMAT_NV12:
     case PIXEL_FORMAT_NV21:
diff --git a/media/base/video_frame_unittest.cc b/media/base/video_frame_unittest.cc
index a8f89f90..56576fc9 100644
--- a/media/base/video_frame_unittest.cc
+++ b/media/base/video_frame_unittest.cc
@@ -627,6 +627,8 @@
       case PIXEL_FORMAT_XRGB:
       case PIXEL_FORMAT_I420A:
       case PIXEL_FORMAT_RGB32:
+      case PIXEL_FORMAT_ABGR:
+      case PIXEL_FORMAT_XBGR:
         EXPECT_EQ(60u, VideoFrame::AllocationSize(format, size))
             << VideoPixelFormatToString(format);
         break;
diff --git a/media/base/video_types.cc b/media/base/video_types.cc
index 6eb554e..815fb5d 100644
--- a/media/base/video_types.cc
+++ b/media/base/video_types.cc
@@ -63,6 +63,10 @@
       return "PIXEL_FORMAT_YUV444P12";
     case PIXEL_FORMAT_Y16:
       return "PIXEL_FORMAT_Y16";
+    case PIXEL_FORMAT_ABGR:
+      return "PIXEL_FORMAT_ABGR";
+    case PIXEL_FORMAT_XBGR:
+      return "PIXEL_FORMAT_XBGR";
   }
   NOTREACHED() << "Invalid VideoPixelFormat provided: " << format;
   return "";
@@ -114,6 +118,8 @@
     case PIXEL_FORMAT_RGB32:
     case PIXEL_FORMAT_MJPEG:
     case PIXEL_FORMAT_Y16:
+    case PIXEL_FORMAT_ABGR:
+    case PIXEL_FORMAT_XBGR:
       return false;
   }
   return false;
@@ -144,10 +150,12 @@
     case PIXEL_FORMAT_YUV422P12:
     case PIXEL_FORMAT_YUV444P12:
     case PIXEL_FORMAT_Y16:
+    case PIXEL_FORMAT_XBGR:
       return true;
     case PIXEL_FORMAT_I420A:
     case PIXEL_FORMAT_ARGB:
     case PIXEL_FORMAT_RGB32:
+    case PIXEL_FORMAT_ABGR:
       break;
   }
   return false;
@@ -173,6 +181,8 @@
     case PIXEL_FORMAT_RGB32:
     case PIXEL_FORMAT_MJPEG:
     case PIXEL_FORMAT_MT21:
+    case PIXEL_FORMAT_ABGR:
+    case PIXEL_FORMAT_XBGR:
       return 8;
     case PIXEL_FORMAT_YUV420P9:
     case PIXEL_FORMAT_YUV422P9:
diff --git a/media/base/video_types.h b/media/base/video_types.h
index 0ce0d3ff..5590f14 100644
--- a/media/base/video_types.h
+++ b/media/base/video_types.h
@@ -68,9 +68,12 @@
   /* PIXEL_FORMAT_Y8 = 25, Deprecated */
   PIXEL_FORMAT_Y16 = 26,  // single 16bpp plane.
 
+  PIXEL_FORMAT_ABGR = 27, // 32bpp RGBA, 1 plane.
+  PIXEL_FORMAT_XBGR = 28, // 24bpp RGB, 1 plane.
+
   // Please update UMA histogram enumeration when adding new formats here.
   PIXEL_FORMAT_MAX =
-      PIXEL_FORMAT_Y16,  // Must always be equal to largest entry logged.
+      PIXEL_FORMAT_XBGR,  // Must always be equal to largest entry logged.
 };
 
 // Color space or color range used for the pixels.
diff --git a/media/capture/mojom/video_capture_types.mojom b/media/capture/mojom/video_capture_types.mojom
index 05755aa..a09b3103 100644
--- a/media/capture/mojom/video_capture_types.mojom
+++ b/media/capture/mojom/video_capture_types.mojom
@@ -37,7 +37,9 @@
   YUV420P12,
   YUV422P12,
   YUV444P12,
-  Y16
+  Y16,
+  ABGR,
+  XBGR,
 };
 
 enum ResolutionChangePolicy {
@@ -305,4 +307,3 @@
   SharedMemoryViaRawFileDescriptor shared_memory_via_raw_file_descriptor;
   MailboxBufferHandleSet mailbox_handles;
 };
-
diff --git a/media/capture/mojom/video_capture_types_mojom_traits.cc b/media/capture/mojom/video_capture_types_mojom_traits.cc
index cead8cc..5baf263f 100644
--- a/media/capture/mojom/video_capture_types_mojom_traits.cc
+++ b/media/capture/mojom/video_capture_types_mojom_traits.cc
@@ -139,6 +139,10 @@
       return media::mojom::VideoCapturePixelFormat::YUV444P12;
     case media::VideoPixelFormat::PIXEL_FORMAT_Y16:
       return media::mojom::VideoCapturePixelFormat::Y16;
+    case media::VideoPixelFormat::PIXEL_FORMAT_ABGR:
+      return media::mojom::VideoCapturePixelFormat::ABGR;
+    case media::VideoPixelFormat::PIXEL_FORMAT_XBGR:
+      return media::mojom::VideoCapturePixelFormat::XBGR;
   }
   NOTREACHED();
   return media::mojom::VideoCapturePixelFormat::I420;
@@ -228,6 +232,12 @@
     case media::mojom::VideoCapturePixelFormat::Y16:
       *output = media::PIXEL_FORMAT_Y16;
       return true;
+    case media::mojom::VideoCapturePixelFormat::ABGR:
+      *output = media::PIXEL_FORMAT_ABGR;
+      return true;
+    case media::mojom::VideoCapturePixelFormat::XBGR:
+      *output = media::PIXEL_FORMAT_XBGR;
+      return true;
   }
   NOTREACHED();
   return false;
diff --git a/media/capture/video/fake_video_capture_device.cc b/media/capture/video/fake_video_capture_device.cc
index f03273c..3ea1f3d 100644
--- a/media/capture/video/fake_video_capture_device.cc
+++ b/media/capture/video/fake_video_capture_device.cc
@@ -42,6 +42,10 @@
 static const double kMaxZoom = 400.0;
 static const double kZoomStep = 1.0;
 
+static const double kMinExposureTime = 10.0;
+static const double kMaxExposureTime = 100.0;
+static const double kExposureTimeStep = 5.0;
+
 // Larger int means better.
 enum class PixelFormatMatchType : int {
   INCOMPATIBLE = 0,
@@ -457,11 +461,21 @@
   mojom::PhotoStatePtr photo_state = mojo::CreateEmptyPhotoState();
 
   photo_state->current_white_balance_mode = mojom::MeteringMode::NONE;
-  photo_state->current_exposure_mode = mojom::MeteringMode::NONE;
+
+  photo_state->supported_exposure_modes.push_back(mojom::MeteringMode::MANUAL);
+  photo_state->supported_exposure_modes.push_back(
+      mojom::MeteringMode::CONTINUOUS);
+  photo_state->current_exposure_mode = fake_device_state_->exposure_mode;
   photo_state->current_focus_mode = mojom::MeteringMode::NONE;
 
   photo_state->exposure_compensation = mojom::Range::New();
+
   photo_state->exposure_time = mojom::Range::New();
+  photo_state->exposure_time->current = fake_device_state_->exposure_time;
+  photo_state->exposure_time->max = kMaxExposureTime;
+  photo_state->exposure_time->min = kMinExposureTime;
+  photo_state->exposure_time->step = kExposureTimeStep;
+
   photo_state->color_temperature = mojom::Range::New();
   photo_state->iso = mojom::Range::New();
   photo_state->iso->current = 100.0;
@@ -522,6 +536,12 @@
     device_state_write_access->zoom =
         std::max(kMinZoom, std::min(settings->zoom, kMaxZoom));
   }
+  if (settings->has_exposure_time) {
+    device_state_write_access->exposure_time = std::max(
+        kMinExposureTime, std::min(settings->exposure_time, kMaxExposureTime));
+  }
+  if (settings->has_exposure_mode)
+    device_state_write_access->exposure_mode = mojom::MeteringMode::MANUAL;
 
   std::move(callback).Run(true);
 }
diff --git a/media/capture/video/fake_video_capture_device.h b/media/capture/video/fake_video_capture_device.h
index 6f2ab1a..81be3ea 100644
--- a/media/capture/video/fake_video_capture_device.h
+++ b/media/capture/video/fake_video_capture_device.h
@@ -102,10 +102,19 @@
 // This is a separate struct because read-access to it is shared with several
 // collaborating classes.
 struct FakeDeviceState {
-  FakeDeviceState(float zoom, float frame_rate, VideoPixelFormat pixel_format)
-      : zoom(zoom), format(gfx::Size(), frame_rate, pixel_format) {}
+  FakeDeviceState(float zoom,
+                  float exposure_time,
+                  mojom::MeteringMode exposure_mode,
+                  float frame_rate,
+                  VideoPixelFormat pixel_format)
+      : zoom(zoom),
+        exposure_time(exposure_time),
+        exposure_mode(exposure_mode),
+        format(gfx::Size(), frame_rate, pixel_format) {}
 
   uint32_t zoom;
+  uint32_t exposure_time;
+  mojom::MeteringMode exposure_mode;
   VideoCaptureFormat format;
 };
 
diff --git a/media/capture/video/fake_video_capture_device_factory.cc b/media/capture/video/fake_video_capture_device_factory.cc
index 4f568ed..9ec17464 100644
--- a/media/capture/video/fake_video_capture_device_factory.cc
+++ b/media/capture/video/fake_video_capture_device_factory.cc
@@ -36,6 +36,9 @@
 static constexpr std::array<float, 1> kDefaultFrameRates{{20.0f}};
 
 static const double kInitialZoom = 100.0;
+static const double kInitialExposureTime = 50.0;
+static const media::mojom::MeteringMode kExposureMode =
+    media::mojom::MeteringMode::MANUAL;
 
 static const media::VideoPixelFormat kSupportedPixelFormats[] = {
     media::PIXEL_FORMAT_I420, media::PIXEL_FORMAT_Y16,
@@ -133,7 +136,8 @@
 
   const VideoCaptureFormat& initial_format = settings.supported_formats.front();
   auto device_state = std::make_unique<FakeDeviceState>(
-      kInitialZoom, initial_format.frame_rate, initial_format.pixel_format);
+      kInitialZoom, kInitialExposureTime, kExposureMode,
+      initial_format.frame_rate, initial_format.pixel_format);
 
   auto photo_frame_painter = std::make_unique<PacmanFramePainter>(
       PacmanFramePainter::Format::SK_N32, device_state.get());
diff --git a/media/capture/video/fake_video_capture_device_unittest.cc b/media/capture/video/fake_video_capture_device_unittest.cc
index 4a6e160..eb8b0be 100644
--- a/media/capture/video/fake_video_capture_device_unittest.cc
+++ b/media/capture/video/fake_video_capture_device_unittest.cc
@@ -363,17 +363,17 @@
   const mojom::PhotoState* state = image_capture_client_->state();
   ASSERT_TRUE(state);
   EXPECT_EQ(mojom::MeteringMode::NONE, state->current_white_balance_mode);
-  EXPECT_EQ(mojom::MeteringMode::NONE, state->current_exposure_mode);
+  EXPECT_EQ(mojom::MeteringMode::MANUAL, state->current_exposure_mode);
   EXPECT_EQ(mojom::MeteringMode::NONE, state->current_focus_mode);
 
   EXPECT_EQ(0, state->exposure_compensation->min);
   EXPECT_EQ(0, state->exposure_compensation->max);
   EXPECT_EQ(0, state->exposure_compensation->current);
   EXPECT_EQ(0, state->exposure_compensation->step);
-  EXPECT_EQ(0, state->exposure_time->min);
-  EXPECT_EQ(0, state->exposure_time->max);
-  EXPECT_EQ(0, state->exposure_time->current);
-  EXPECT_EQ(0, state->exposure_time->step);
+  EXPECT_EQ(10, state->exposure_time->min);
+  EXPECT_EQ(100, state->exposure_time->max);
+  EXPECT_EQ(50, state->exposure_time->current);
+  EXPECT_EQ(5, state->exposure_time->step);
   EXPECT_EQ(0, state->color_temperature->min);
   EXPECT_EQ(0, state->color_temperature->max);
   EXPECT_EQ(0, state->color_temperature->current);
diff --git a/media/capture/video/linux/v4l2_capture_delegate.cc b/media/capture/video/linux/v4l2_capture_delegate.cc
index 8b634c4..0de024e6 100644
--- a/media/capture/video/linux/v4l2_capture_delegate.cc
+++ b/media/capture/video/linux/v4l2_capture_delegate.cc
@@ -468,7 +468,15 @@
             : MeteringMode::CONTINUOUS;
   }
 
+  // Exposure compensation is valid if V4L2_CID_EXPOSURE_AUTO control is set to
+  // AUTO, SHUTTER_PRIORITY or APERTURE_PRIORITY. Drivers should interpret the
+  // values as 0.001 EV units, where the value 1000 stands for +1 EV.
   photo_capabilities->exposure_compensation =
+      RetrieveUserControlRange(V4L2_CID_AUTO_EXPOSURE_BIAS);
+
+  // Determines the exposure time of the camera sensor. Drivers interpret values
+  // as 100 µs units, same as specs.
+  photo_capabilities->exposure_time =
       RetrieveUserControlRange(V4L2_CID_EXPOSURE_ABSOLUTE);
 
   photo_capabilities->color_temperature =
@@ -577,15 +585,32 @@
     v4l2_control auto_exposure_current = {};
     auto_exposure_current.id = V4L2_CID_EXPOSURE_AUTO;
     const int result = DoIoctl(VIDIOC_G_CTRL, &auto_exposure_current);
-    // Exposure Compensation can only be applied if Auto Exposure is off.
-    if (result >= 0 && auto_exposure_current.value == V4L2_EXPOSURE_MANUAL) {
+    // Exposure Compensation is effective only when V4L2_CID_EXPOSURE_AUTO
+    // control is set to AUTO, SHUTTER_PRIORITY or APERTURE_PRIORITY.
+    if (result >= 0 && auto_exposure_current.value != V4L2_EXPOSURE_MANUAL) {
       v4l2_control set_exposure = {};
-      set_exposure.id = V4L2_CID_EXPOSURE_ABSOLUTE;
+      set_exposure.id = V4L2_CID_AUTO_EXPOSURE_BIAS;
       set_exposure.value = settings->exposure_compensation;
       DoIoctl(VIDIOC_S_CTRL, &set_exposure);
     }
   }
 
+  if (settings->has_exposure_time) {
+    v4l2_control exposure_time_current = {};
+    exposure_time_current.id = V4L2_CID_EXPOSURE_AUTO;
+    const int result = DoIoctl(VIDIOC_G_CTRL, &exposure_time_current);
+    // Exposure time can only be applied if V4L2_CID_EXPOSURE_AUTO is set to
+    // V4L2_EXPOSURE_MANUAL or V4L2_EXPOSURE_SHUTTER_PRIORITY.
+    if (result >= 0 &&
+        (exposure_time_current.value == V4L2_EXPOSURE_MANUAL ||
+         exposure_time_current.value == V4L2_EXPOSURE_SHUTTER_PRIORITY)) {
+      v4l2_control set_exposure_time = {};
+      set_exposure_time.id = V4L2_CID_EXPOSURE_ABSOLUTE;
+      set_exposure_time.value = settings->exposure_time;
+      DoIoctl(VIDIOC_S_CTRL, &set_exposure_time);
+    }
+  }
+
   if (settings->has_brightness) {
     v4l2_control current = {};
     current.id = V4L2_CID_BRIGHTNESS;
diff --git a/media/cast/BUILD.gn b/media/cast/BUILD.gn
index 20a5bf5..964d1c90 100644
--- a/media/cast/BUILD.gn
+++ b/media/cast/BUILD.gn
@@ -533,6 +533,7 @@
     deps = [
       ":test_support",
       "//base",
+      "//base/test:test_support",
       "//media",
       "//net",
     ]
diff --git a/media/cast/test/utility/tap_proxy.cc b/media/cast/test/utility/tap_proxy.cc
index e446011..1adc993 100644
--- a/media/cast/test/utility/tap_proxy.cc
+++ b/media/cast/test/utility/tap_proxy.cc
@@ -28,11 +28,11 @@
 #include "base/containers/circular_deque.h"
 #include "base/files/file_descriptor_watcher_posix.h"
 #include "base/logging.h"
-#include "base/message_loop/message_loop.h"
 #include "base/rand_util.h"
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
 #include "base/synchronization/waitable_event.h"
+#include "base/test/scoped_task_environment.h"
 #include "base/threading/thread.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/default_tick_clock.h"
@@ -305,8 +305,8 @@
   int fd1 = tun_alloc(argv[1], IFF_TAP);
   int fd2 = tun_alloc(argv[2], IFF_TAP);
 
-  base::MessageLoopForIO message_loop;
-  base::FileDescriptorWatcher file_descriptor_watcher(&message_loop);
+  base::test::ScopedTaskEnvironment task_environment(
+      base::test::ScopedTaskEnvironment::MainThreadType::IO);
   last_printout = base::TimeTicks::Now();
   media::cast::test::QueueManager qm1(fd1, fd2, std::move(in_pipe));
   media::cast::test::QueueManager qm2(fd2, fd1, std::move(out_pipe));
diff --git a/media/filters/vp9_parser.cc b/media/filters/vp9_parser.cc
index 6bfda73..32731a8 100644
--- a/media/filters/vp9_parser.cc
+++ b/media/filters/vp9_parser.cc
@@ -161,6 +161,44 @@
   return !show_existing_frame && (frame_type == KEYFRAME || intra_only);
 }
 
+VideoColorSpace Vp9FrameHeader::GetColorSpace() const {
+  VideoColorSpace ret;
+  ret.range = color_range ? gfx::ColorSpace::RangeID::FULL
+                          : gfx::ColorSpace::RangeID::LIMITED;
+  switch (color_space) {
+    case Vp9ColorSpace::RESERVED:
+    case Vp9ColorSpace::UNKNOWN:
+      break;
+    case Vp9ColorSpace::BT_601:
+    case Vp9ColorSpace::SMPTE_170:
+      ret.primaries = VideoColorSpace::PrimaryID::SMPTE170M;
+      ret.transfer = VideoColorSpace::TransferID::SMPTE170M;
+      ret.matrix = VideoColorSpace::MatrixID::SMPTE170M;
+      break;
+    case Vp9ColorSpace::BT_709:
+      ret.primaries = VideoColorSpace::PrimaryID::BT709;
+      ret.transfer = VideoColorSpace::TransferID::BT709;
+      ret.matrix = VideoColorSpace::MatrixID::BT709;
+      break;
+    case Vp9ColorSpace::SMPTE_240:
+      ret.primaries = VideoColorSpace::PrimaryID::SMPTE240M;
+      ret.transfer = VideoColorSpace::TransferID::SMPTE240M;
+      ret.matrix = VideoColorSpace::MatrixID::SMPTE240M;
+      break;
+    case Vp9ColorSpace::BT_2020:
+      ret.primaries = VideoColorSpace::PrimaryID::BT2020;
+      ret.transfer = VideoColorSpace::TransferID::BT2020_10;
+      ret.matrix = VideoColorSpace::MatrixID::BT2020_NCL;
+      break;
+    case Vp9ColorSpace::SRGB:
+      ret.primaries = VideoColorSpace::PrimaryID::BT709;
+      ret.transfer = VideoColorSpace::TransferID::IEC61966_2_1;
+      ret.matrix = VideoColorSpace::MatrixID::BT709;
+      break;
+  }
+  return ret;
+}
+
 Vp9Parser::FrameInfo::FrameInfo(const uint8_t* ptr, off_t size)
     : ptr(ptr), size(size) {}
 
diff --git a/media/filters/vp9_parser.h b/media/filters/vp9_parser.h
index 489c3c20..3d2106f 100644
--- a/media/filters/vp9_parser.h
+++ b/media/filters/vp9_parser.h
@@ -23,6 +23,7 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "media/base/media_export.h"
+#include "media/base/video_color_space.h"
 
 namespace media {
 
@@ -195,6 +196,7 @@
   bool RefreshFlag(size_t i) const {
     return !!(refresh_frame_flags & (1u << i));
   }
+  VideoColorSpace GetColorSpace() const;
 
   uint8_t profile;
 
diff --git a/media/filters/vp9_parser_unittest.cc b/media/filters/vp9_parser_unittest.cc
index f5d4fe6..db9cb84 100644
--- a/media/filters/vp9_parser_unittest.cc
+++ b/media/filters/vp9_parser_unittest.cc
@@ -343,4 +343,13 @@
 
 INSTANTIATE_TEST_CASE_P(, Vp9ParserTest, ::testing::ValuesIn(kTestParams));
 
+TEST_F(Vp9ParserTest, CheckColorSpace) {
+  Vp9FrameHeader fhdr{};
+  EXPECT_FALSE(fhdr.GetColorSpace().IsSpecified());
+  fhdr.color_space = Vp9ColorSpace::BT_709;
+  EXPECT_EQ(VideoColorSpace::REC709(), fhdr.GetColorSpace());
+  fhdr.color_space = Vp9ColorSpace::BT_601;
+  EXPECT_EQ(VideoColorSpace::REC601(), fhdr.GetColorSpace());
+}
+
 }  // namespace media
diff --git a/media/gpu/BUILD.gn b/media/gpu/BUILD.gn
index fee1e4e..3c32b3f 100644
--- a/media/gpu/BUILD.gn
+++ b/media/gpu/BUILD.gn
@@ -122,6 +122,7 @@
     "//gpu/command_buffer/common:gles2_utils",
     "//gpu/command_buffer/service:gles2",
     "//gpu/ipc/service",
+    "//third_party/libyuv",
     "//ui/base",
     "//ui/display/types",
     "//ui/gl",
@@ -202,7 +203,6 @@
       "//gpu/ipc/common:ipc_common_sources",
       "//media/mojo:buildflags",
       "//services/service_manager/public/cpp:cpp",
-      "//third_party/libyuv",
       "//ui/gl:gl_jni_headers",
     ]
 
@@ -214,16 +214,21 @@
     }
   }
 
+  if (is_fuchsia) {
+    sources += [
+      "fuchsia/fuchsia_video_decoder.cc",
+      "fuchsia/fuchsia_video_decoder.h",
+    ]
+    deps += [ "//third_party/fuchsia-sdk/sdk:mediacodec" ]
+  }
+
   if (use_v4lplugin) {
     sources += get_target_outputs(":libv4l2_generate_stubs")
     deps += [ ":libv4l2_generate_stubs" ]
   }
 
   if (use_v4l2_codec) {
-    deps += [
-      "//third_party/libyuv",
-      "//ui/ozone",
-    ]
+    deps += [ "//ui/ozone" ]
     sources += [
       "v4l2/generic_v4l2_device.cc",
       "v4l2/generic_v4l2_device.h",
@@ -288,7 +293,6 @@
     public_deps += [ "//media/base/win" ]
     deps += [
       "//third_party/angle:includes",
-      "//third_party/libyuv",
       "//ui/display",
     ]
     libs += [
@@ -435,6 +439,12 @@
         "test/generic_dmabuf_video_frame_mapper.cc",
         "test/generic_dmabuf_video_frame_mapper.h",
       ]
+      if (use_vaapi) {
+        sources += [
+          "test/vaapi_dmabuf_video_frame_mapper.cc",
+          "test/vaapi_dmabuf_video_frame_mapper.h",
+        ]
+      }
     }
 
     if (use_x11) {
@@ -635,6 +645,9 @@
   if (use_v4l2_codec || use_vaapi) {
     sources += [ "vp8_decoder_unittest.cc" ]
   }
+  if (is_fuchsia) {
+    sources += [ "fuchsia/fuchsia_video_decoder_unittest.cc" ]
+  }
   if (is_win && enable_library_cdms) {
     sources += [
       "windows/d3d11_cdm_proxy_unittest.cc",
diff --git a/media/gpu/fuchsia/fuchsia_video_decoder.cc b/media/gpu/fuchsia/fuchsia_video_decoder.cc
new file mode 100644
index 0000000..25b27d3
--- /dev/null
+++ b/media/gpu/fuchsia/fuchsia_video_decoder.cc
@@ -0,0 +1,793 @@
+// 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 "media/gpu/fuchsia/fuchsia_video_decoder.h"
+
+#include <fuchsia/mediacodec/cpp/fidl.h>
+#include <zircon/rights.h>
+
+#include "base/callback_helpers.h"
+#include "base/fuchsia/component_context.h"
+#include "base/fuchsia/fuchsia_logging.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "media/base/bind_to_current_loop.h"
+#include "media/base/video_decoder.h"
+#include "media/base/video_decoder_config.h"
+#include "media/base/video_frame.h"
+#include "media/base/video_util.h"
+#include "third_party/libyuv/include/libyuv/video_common.h"
+
+namespace media {
+
+namespace {
+
+const zx_rights_t kReadOnlyVmoRights =
+    ZX_DEFAULT_VMO_RIGHTS &
+    ~(ZX_RIGHT_WRITE | ZX_RIGHT_EXECUTE | ZX_RIGHT_SET_PROPERTY);
+
+// Value passed to the codec as packet_count_for_client. It's number of output
+// buffers that we expect to hold on to in the renderer.
+//
+// TODO(sergeyu): Figure out the right number of buffers to request. Currently
+// the codec doesn't allow to reserve more than 2 client buffers, but it still
+// works properly when the client holds to more than that.
+const uint32_t kMaxUsedOutputFrames = 8;
+
+zx::vmo CreateContiguousVmo(size_t size, const zx::handle& bti_handle) {
+  zx::vmo vmo;
+  zx_status_t status =
+      zx_vmo_create_contiguous(bti_handle.get(), size, /*alignment_log2=*/0,
+                               vmo.reset_and_get_address());
+  if (status != ZX_OK) {
+    ZX_DLOG(ERROR, status) << "zx_vmo_create_contiguous";
+    return zx::vmo();
+  }
+
+  return vmo;
+}
+
+zx::vmo CreateVmo(size_t size) {
+  zx::vmo vmo;
+  zx_status_t status = zx::vmo::create(size, ZX_VMO_NON_RESIZABLE, &vmo);
+  if (status != ZX_OK) {
+    ZX_DLOG(ERROR, status) << "zx_vmo_create";
+    return zx::vmo();
+  }
+
+  return vmo;
+}
+
+class PendingDecode {
+ public:
+  PendingDecode(scoped_refptr<DecoderBuffer> buffer,
+                VideoDecoder::DecodeCB decode_cb)
+      : buffer_(buffer), decode_cb_(decode_cb) {
+    DCHECK(buffer_);
+  }
+  ~PendingDecode() {
+    if (decode_cb_) {
+      std::move(decode_cb_).Run(DecodeStatus::ABORTED);
+    }
+  }
+
+  PendingDecode(PendingDecode&& other) = default;
+  PendingDecode& operator=(PendingDecode&& other) = default;
+
+  const DecoderBuffer& buffer() { return *buffer_; }
+
+  const uint8_t* data() const { return buffer_->data() + buffer_pos_; }
+  size_t bytes_left() const { return buffer_->data_size() - buffer_pos_; }
+  void AdvanceCurrentPos(size_t bytes) {
+    DCHECK_LE(bytes, bytes_left());
+    buffer_pos_ += bytes;
+  }
+  VideoDecoder::DecodeCB TakeDecodeCallback() { return std::move(decode_cb_); }
+
+ private:
+  scoped_refptr<DecoderBuffer> buffer_;
+  size_t buffer_pos_ = 0;
+  VideoDecoder::DecodeCB decode_cb_;
+
+  DISALLOW_COPY_AND_ASSIGN(PendingDecode);
+};
+
+class CodecBuffer {
+ public:
+  CodecBuffer() = default;
+
+  bool Initialize(
+      const fuchsia::mediacodec::CodecBufferConstraints& constraints) {
+    size_ = constraints.per_packet_buffer_bytes_recommended;
+
+    if (constraints.is_physically_contiguous_required) {
+      vmo_ =
+          CreateContiguousVmo(size_, constraints.very_temp_kludge_bti_handle);
+    } else {
+      vmo_ = CreateVmo(size_);
+    }
+    return vmo_.is_valid();
+  }
+
+  const zx::vmo& vmo() const { return vmo_; }
+  size_t size() const { return size_; }
+
+  bool ToFidlCodecBuffer(uint64_t buffer_lifetime_ordinal,
+                         uint32_t buffer_index,
+                         bool read_only,
+                         fuchsia::mediacodec::CodecBuffer* buffer) {
+    zx::vmo vmo_dup;
+    zx_status_t status = vmo_.duplicate(
+        read_only ? kReadOnlyVmoRights : ZX_RIGHT_SAME_RIGHTS, &vmo_dup);
+    if (status != ZX_OK) {
+      ZX_DLOG(ERROR, status) << "zx_handle_duplicate";
+      return false;
+    }
+
+    fuchsia::mediacodec::CodecBufferDataVmo buf_data;
+    buf_data.vmo_handle = std::move(vmo_dup);
+
+    buf_data.vmo_usable_start = 0;
+    buf_data.vmo_usable_size = size_;
+
+    buffer->data.set_vmo(std::move(buf_data));
+    buffer->buffer_lifetime_ordinal = buffer_lifetime_ordinal;
+    buffer->buffer_index = buffer_index;
+
+    return true;
+  }
+
+ private:
+  zx::vmo vmo_;
+  size_t size_ = 0;
+
+  DISALLOW_COPY_AND_ASSIGN(CodecBuffer);
+};
+
+class InputBuffer {
+ public:
+  InputBuffer() = default;
+
+  ~InputBuffer() { CallDecodeCallbackIfAny(DecodeStatus::ABORTED); }
+
+  InputBuffer(InputBuffer&& other) = default;
+  InputBuffer& operator=(InputBuffer&& other) = default;
+
+  bool Initialize(
+      const fuchsia::mediacodec::CodecBufferConstraints& constraints) {
+    return buffer_.Initialize(constraints);
+  }
+
+  CodecBuffer& buffer() { return buffer_; }
+  bool is_used() const { return is_used_; }
+
+  // Copies as much data as possible from |pending_decode| to this input buffer.
+  size_t FillFromDecodeBuffer(PendingDecode* pending_decode) {
+    DCHECK(!is_used_);
+    is_used_ = true;
+
+    size_t bytes_to_fill =
+        std::min(buffer_.size(), pending_decode->bytes_left());
+
+    zx_status_t status =
+        buffer_.vmo().write(pending_decode->data(), 0, bytes_to_fill);
+    ZX_CHECK(status == ZX_OK, status) << "zx_vmo_write";
+
+    pending_decode->AdvanceCurrentPos(bytes_to_fill);
+
+    if (pending_decode->bytes_left() == 0) {
+      DCHECK(!decode_cb_);
+      decode_cb_ = pending_decode->TakeDecodeCallback();
+    }
+
+    return bytes_to_fill;
+  }
+
+  void CallDecodeCallbackIfAny(DecodeStatus status) {
+    if (decode_cb_) {
+      std::move(decode_cb_).Run(status);
+    }
+  }
+
+  void OnDoneDecoding(DecodeStatus status) {
+    DCHECK(is_used_);
+    is_used_ = false;
+    CallDecodeCallbackIfAny(status);
+  }
+
+ private:
+  CodecBuffer buffer_;
+
+  // Set to true when this buffer is being used by the codec.
+  bool is_used_ = false;
+
+  // Decode callback for the DecodeBuffer of which this InputBuffer is a part.
+  // This is only set on the final InputBuffer in each DecodeBuffer.
+  VideoDecoder::DecodeCB decode_cb_;
+
+  DISALLOW_COPY_AND_ASSIGN(InputBuffer);
+};
+
+// Output buffer used to pass decoded frames from the decoder. Ref-counted
+// to make it possible to share the buffers with VideoFrames, in case when a
+// frame outlives the decoder.UnsafeSharedMemoryRegion
+class OutputBuffer : public base::RefCountedThreadSafe<OutputBuffer> {
+ public:
+  OutputBuffer() = default;
+
+  OutputBuffer(OutputBuffer&& other) = default;
+  OutputBuffer& operator=(OutputBuffer&& other) = default;
+
+  bool Initialize(
+      const fuchsia::mediacodec::CodecBufferConstraints& constraints) {
+    if (!buffer_.Initialize(constraints)) {
+      return false;
+    }
+
+    zx_status_t status = zx::vmar::root_self()->map(
+        /*vmar_offset=*/0, buffer_.vmo(), 0, buffer_.size(),
+        ZX_VM_REQUIRE_NON_RESIZABLE | ZX_VM_FLAG_PERM_READ, &mapped_memory_);
+
+    if (status != ZX_OK) {
+      ZX_DLOG(ERROR, status) << "zx_vmar_map";
+      mapped_memory_ = 0;
+      return false;
+    }
+
+    return true;
+  }
+
+  CodecBuffer& buffer() { return buffer_; }
+
+  const uint8_t* mapped_memory() {
+    DCHECK(mapped_memory_);
+    return reinterpret_cast<uint8_t*>(mapped_memory_);
+  }
+
+ private:
+  friend class RefCountedThreadSafe<OutputBuffer>;
+
+  ~OutputBuffer() {
+    if (mapped_memory_) {
+      zx_status_t status =
+          zx::vmar::root_self()->unmap(mapped_memory_, buffer_.size());
+      if (status != ZX_OK) {
+        ZX_LOG(FATAL, status) << "zx_vmar_unmap";
+      }
+    }
+  }
+
+  CodecBuffer buffer_;
+
+  uintptr_t mapped_memory_ = 0;
+
+  DISALLOW_COPY_AND_ASSIGN(OutputBuffer);
+};
+
+}  // namespace
+
+class FuchsiaVideoDecoder : public VideoDecoder {
+ public:
+  FuchsiaVideoDecoder();
+  ~FuchsiaVideoDecoder() override;
+
+  // VideoDecoder implementation.
+  std::string GetDisplayName() const override;
+  void Initialize(
+      const VideoDecoderConfig& config,
+      bool low_delay,
+      CdmContext* cdm_context,
+      const InitCB& init_cb,
+      const OutputCB& output_cb,
+      const WaitingForDecryptionKeyCB& waiting_for_decryption_key_cb) override;
+  void Decode(scoped_refptr<DecoderBuffer> buffer,
+              const DecodeCB& decode_cb) override;
+  void Reset(const base::Closure& closure) override;
+  bool NeedsBitstreamConversion() const override;
+  bool CanReadWithoutStalling() const override;
+  int GetMaxDecodeRequests() const override;
+
+ private:
+  // Event handlers for |codec_|.
+  void OnStreamFailed(uint64_t stream_lifetime_ordinal);
+  void OnInputConstraints(
+      fuchsia::mediacodec::CodecBufferConstraints input_constraints);
+  void OnFreeInputPacket(
+      fuchsia::mediacodec::CodecPacketHeader free_input_packet);
+  void OnOutputConfig(fuchsia::mediacodec::CodecOutputConfig output_config);
+  void OnOutputPacket(fuchsia::mediacodec::CodecPacket output_packet,
+                      bool error_detected_before,
+                      bool error_detected_during);
+  void OnOutputEndOfStream(uint64_t stream_lifetime_ordinal,
+                           bool error_detected_before);
+
+  void OnError();
+
+  // Called by OnInputConstraints() to initialize input buffers.
+  bool InitializeInputBuffers(
+      fuchsia::mediacodec::CodecBufferConstraints constraints);
+
+  // Pumps |pending_decodes_| to the decoder.
+  void PumpInput();
+
+  // Called by OnInputConstraints() to initialize input buffers.
+  bool InitializeOutputBuffers(
+      fuchsia::mediacodec::CodecBufferConstraints constraints);
+
+  // Destruction callback for the output VideoFrame instances.
+  void OnFrameDestroyed(scoped_refptr<OutputBuffer> buffer,
+                        uint64_t buffer_lifetime_ordinal,
+                        uint32_t packet_index);
+
+  OutputCB output_cb_;
+
+  // Aspect ratio specified in container, or 1.0 if it's not specified. This
+  // value is used only if the aspect ratio is not specified in the bitstream.
+  float container_pixel_aspect_ratio_ = 1.0;
+
+  fuchsia::mediacodec::CodecPtr codec_;
+
+  uint64_t stream_lifetime_ordinal_ = 1;
+
+  // Set to true if we've sent an input packet with the current
+  // stream_lifetime_ordinal_.
+  bool active_stream_ = false;
+
+  std::list<PendingDecode> pending_decodes_;
+  uint64_t input_buffer_lifetime_ordinal_ = 1;
+  std::vector<InputBuffer> input_buffers_;
+  int num_used_input_buffers_ = 0;
+
+  fuchsia::mediacodec::VideoUncompressedFormat output_format_;
+  uint64_t output_buffer_lifetime_ordinal_ = 1;
+  std::vector<scoped_refptr<OutputBuffer>> output_buffers_;
+  int num_used_output_buffers_ = 0;
+  int max_used_output_buffers_ = 0;
+
+  // Non-null when flush is pending.
+  VideoDecoder::DecodeCB pending_flush_cb_;
+
+  base::WeakPtr<FuchsiaVideoDecoder> weak_this_;
+  base::WeakPtrFactory<FuchsiaVideoDecoder> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(FuchsiaVideoDecoder);
+};
+
+FuchsiaVideoDecoder::FuchsiaVideoDecoder() : weak_factory_(this) {
+  weak_this_ = weak_factory_.GetWeakPtr();
+}
+
+FuchsiaVideoDecoder::~FuchsiaVideoDecoder() = default;
+
+std::string FuchsiaVideoDecoder::GetDisplayName() const {
+  return "FuchsiaVideoDecoder";
+}
+
+void FuchsiaVideoDecoder::Initialize(
+    const VideoDecoderConfig& config,
+    bool low_delay,
+    CdmContext* cdm_context,
+    const InitCB& init_cb,
+    const OutputCB& output_cb,
+    const WaitingForDecryptionKeyCB& waiting_for_decryption_key_cb) {
+  output_cb_ = output_cb;
+  container_pixel_aspect_ratio_ = config.GetPixelAspectRatio();
+
+  auto done_callback = BindToCurrentLoop(init_cb);
+
+  fuchsia::mediacodec::CreateDecoder_Params codec_params;
+  codec_params.input_details.format_details_version_ordinal = 0;
+
+  switch (config.codec()) {
+    case kCodecH264:
+      codec_params.input_details.mime_type = "video/h264";
+      break;
+    case kCodecVP8:
+      codec_params.input_details.mime_type = "video/vp8";
+      break;
+    case kCodecVP9:
+      codec_params.input_details.mime_type = "video/vp9";
+      break;
+    case kCodecHEVC:
+      codec_params.input_details.mime_type = "video/hevc";
+      break;
+    case kCodecAV1:
+      codec_params.input_details.mime_type = "video/av1";
+      break;
+
+    default:
+      done_callback.Run(false);
+      return;
+  }
+
+  codec_params.promise_separate_access_units_on_input = true;
+  codec_params.require_hw = true;
+
+  auto codec_factory =
+      base::fuchsia::ComponentContext::GetDefault()
+          ->ConnectToService<fuchsia::mediacodec::CodecFactory>();
+  codec_factory->CreateDecoder(std::move(codec_params), codec_.NewRequest());
+
+  codec_.set_error_handler([this]() {
+    LOG(ERROR) << "The fuchsia.mediacodec.Codec channel was terminated.";
+    OnError();
+  });
+
+  codec_.events().OnStreamFailed =
+      fit::bind_member(this, &FuchsiaVideoDecoder::OnStreamFailed);
+  codec_.events().OnInputConstraints =
+      fit::bind_member(this, &FuchsiaVideoDecoder::OnInputConstraints);
+  codec_.events().OnFreeInputPacket =
+      fit::bind_member(this, &FuchsiaVideoDecoder::OnFreeInputPacket);
+  codec_.events().OnOutputConfig =
+      fit::bind_member(this, &FuchsiaVideoDecoder::OnOutputConfig);
+  codec_.events().OnOutputPacket =
+      fit::bind_member(this, &FuchsiaVideoDecoder::OnOutputPacket);
+  codec_.events().OnOutputEndOfStream =
+      fit::bind_member(this, &FuchsiaVideoDecoder::OnOutputEndOfStream);
+
+  codec_->EnableOnStreamFailed();
+
+  done_callback.Run(true);
+}
+
+void FuchsiaVideoDecoder::Decode(scoped_refptr<DecoderBuffer> buffer,
+                                 const DecodeCB& decode_cb) {
+  DCHECK_LT(static_cast<int>(pending_decodes_.size()) + num_used_input_buffers_,
+            GetMaxDecodeRequests());
+
+  if (!codec_) {
+    decode_cb.Run(DecodeStatus::DECODE_ERROR);
+    return;
+  }
+
+  pending_decodes_.push_back(PendingDecode(buffer, decode_cb));
+  PumpInput();
+}
+
+void FuchsiaVideoDecoder::Reset(const base::Closure& closure) {
+  // Call DecodeCB(ABORTED) for all active decode requests.
+  for (auto& buffer : input_buffers_) {
+    buffer.CallDecodeCallbackIfAny(DecodeStatus::ABORTED);
+  }
+
+  // Will call DecodeCB(ABORTED) for all pending decode requests.
+  pending_decodes_.clear();
+
+  if (active_stream_) {
+    codec_->CloseCurrentStream(stream_lifetime_ordinal_,
+                               /*release_input_buffers=*/false,
+                               /*release_output_buffers=*/false);
+    stream_lifetime_ordinal_ += 2;
+    active_stream_ = false;
+  }
+
+  BindToCurrentLoop(closure).Run();
+}
+
+bool FuchsiaVideoDecoder::NeedsBitstreamConversion() const {
+  return true;
+}
+
+bool FuchsiaVideoDecoder::CanReadWithoutStalling() const {
+  return num_used_output_buffers_ < max_used_output_buffers_;
+}
+
+int FuchsiaVideoDecoder::GetMaxDecodeRequests() const {
+  // Add one extra request to be able to send new InputBuffer immediately after
+  // OnFreeInputPacket().
+  return input_buffers_.size() + 1;
+}
+
+void FuchsiaVideoDecoder::OnStreamFailed(uint64_t stream_lifetime_ordinal) {
+  if (stream_lifetime_ordinal_ != stream_lifetime_ordinal) {
+    return;
+  }
+
+  OnError();
+}
+
+void FuchsiaVideoDecoder::OnInputConstraints(
+    fuchsia::mediacodec::CodecBufferConstraints input_constraints) {
+  if (!InitializeInputBuffers(std::move(input_constraints))) {
+    DLOG(ERROR) << "Failed to initialize input buffers.";
+    OnError();
+    return;
+  }
+
+  PumpInput();
+}
+
+void FuchsiaVideoDecoder::OnFreeInputPacket(
+    fuchsia::mediacodec::CodecPacketHeader free_input_packet) {
+  if (free_input_packet.buffer_lifetime_ordinal !=
+      input_buffer_lifetime_ordinal_) {
+    return;
+  }
+
+  if (free_input_packet.packet_index >= input_buffers_.size()) {
+    DLOG(ERROR) << "fuchsia.mediacodec sent OnFreeInputPacket() for an unknown "
+                   "packet: buffer_lifetime_ordinal="
+                << free_input_packet.buffer_lifetime_ordinal
+                << " packet_index=" << free_input_packet.packet_index;
+    OnError();
+    return;
+  }
+
+  DCHECK_GT(num_used_input_buffers_, 0);
+  num_used_input_buffers_--;
+  input_buffers_[free_input_packet.packet_index].OnDoneDecoding(
+      DecodeStatus::OK);
+
+  // Try to pump input in case it was blocked.
+  PumpInput();
+}
+
+void FuchsiaVideoDecoder::OnOutputConfig(
+    fuchsia::mediacodec::CodecOutputConfig output_config) {
+  if (output_config.stream_lifetime_ordinal != stream_lifetime_ordinal_)
+    return;
+
+  auto& format = output_config.format_details;
+
+  if (!format.domain->is_video() || !format.domain->video().is_uncompressed()) {
+    DLOG(ERROR) << "Received OnOutputConfig() with invalid format.";
+    OnError();
+    return;
+  }
+
+  if (output_config.buffer_constraints_action_required) {
+    if (!InitializeOutputBuffers(std::move(output_config.buffer_constraints))) {
+      DLOG(ERROR) << "Failed to initialize output buffers.";
+      OnError();
+      return;
+    }
+  }
+
+  output_format_ = std::move(format.domain->video().uncompressed());
+}
+
+void FuchsiaVideoDecoder::OnOutputPacket(
+    fuchsia::mediacodec::CodecPacket output_packet,
+    bool error_detected_before,
+    bool error_detected_during) {
+  VideoPixelFormat pixel_format;
+  switch (output_format_.fourcc) {
+    case libyuv::FOURCC_NV12:
+      pixel_format = PIXEL_FORMAT_NV12;
+      break;
+    default:
+      LOG(ERROR) << "unknown fourcc: "
+                 << std::string(reinterpret_cast<char*>(&output_format_.fourcc),
+                                4);
+      return;
+  }
+
+  base::TimeDelta timestamp;
+  if (output_packet.has_timestamp_ish)
+    timestamp = base::TimeDelta::FromNanoseconds(output_packet.timestamp_ish);
+
+  auto packet_index = output_packet.header.packet_index;
+  auto& buffer = output_buffers_[packet_index];
+
+  DCHECK_LT(num_used_output_buffers_, static_cast<int>(output_buffers_.size()));
+  num_used_output_buffers_++;
+
+  float pixel_aspect_ratio;
+  if (output_format_.has_pixel_aspect_ratio) {
+    pixel_aspect_ratio =
+        static_cast<float>(output_format_.pixel_aspect_ratio_width) /
+        static_cast<float>(output_format_.pixel_aspect_ratio_height);
+  } else {
+    pixel_aspect_ratio = container_pixel_aspect_ratio_;
+  }
+
+  auto display_rect = gfx::Rect(output_format_.primary_display_width_pixels,
+                                output_format_.primary_display_height_pixels);
+
+  // TODO(sergeyu): Returned frame is correct only when stride=width, which
+  // is not always the case. Currently VideoFrame::WrapExternalData() doesn't
+  // allow custom frame layout.
+  auto frame = VideoFrame::WrapExternalData(
+      pixel_format,
+      gfx::Size(output_format_.primary_width_pixels,
+                output_format_.primary_height_pixels),
+      display_rect, GetNaturalSize(display_rect, pixel_aspect_ratio),
+      const_cast<uint8_t*>(buffer->mapped_memory()) +
+          output_format_.primary_start_offset,
+      buffer->buffer().size() - output_format_.primary_start_offset, timestamp);
+
+  // Pass a reference to the buffer to the destruction callback to ensure it's
+  // not destroyed while the frame is being used.
+  frame->AddDestructionObserver(BindToCurrentLoop(
+      base::BindOnce(&FuchsiaVideoDecoder::OnFrameDestroyed, weak_this_, buffer,
+                     output_buffer_lifetime_ordinal_, packet_index)));
+
+  output_cb_.Run(std::move(frame));
+}
+
+void FuchsiaVideoDecoder::OnOutputEndOfStream(uint64_t stream_lifetime_ordinal,
+                                              bool error_detected_before) {
+  if (stream_lifetime_ordinal != stream_lifetime_ordinal_) {
+    return;
+  }
+
+  stream_lifetime_ordinal_ += 2;
+  active_stream_ = false;
+
+  std::move(pending_flush_cb_).Run(DecodeStatus::OK);
+}
+
+void FuchsiaVideoDecoder::OnError() {
+  codec_.Unbind();
+
+  auto weak_this = weak_this_;
+
+  // Call decode callback with DECODE_ERROR before clearing input_buffers_.
+  // Otherwise InputBuffer destructor would call it with ABORTED.
+  for (auto& buffer : input_buffers_) {
+    if (buffer.is_used()) {
+      buffer.OnDoneDecoding(DecodeStatus::DECODE_ERROR);
+
+      // DecodeCB(DECODE_ERROR) may destroy |this|.
+      if (!weak_this) {
+        return;
+      }
+    }
+  }
+
+  // Will call DecodeCB(ABORTED) for all pending decode requests.
+  pending_decodes_.clear();
+
+  num_used_input_buffers_ = 0;
+  input_buffers_.clear();
+
+  num_used_output_buffers_ = 0;
+  output_buffers_.clear();
+}
+
+bool FuchsiaVideoDecoder::InitializeInputBuffers(
+    fuchsia::mediacodec::CodecBufferConstraints constraints) {
+  input_buffer_lifetime_ordinal_ += 2;
+
+  auto settings = constraints.default_settings;
+  settings.buffer_lifetime_ordinal = input_buffer_lifetime_ordinal_;
+  settings.packet_count_for_client = 0;
+  codec_->SetInputBufferSettings(settings);
+
+  int total_buffers =
+      settings.packet_count_for_codec + settings.packet_count_for_client;
+  std::vector<InputBuffer> new_buffers(total_buffers);
+
+  for (int i = 0; i < total_buffers; ++i) {
+    fuchsia::mediacodec::CodecBuffer codec_buffer;
+
+    if (!new_buffers[i].Initialize(constraints) ||
+        !new_buffers[i].buffer().ToFidlCodecBuffer(
+            input_buffer_lifetime_ordinal_, i, /*read_only=*/true,
+            &codec_buffer)) {
+      return false;
+    }
+
+    codec_->AddInputBuffer(std::move(codec_buffer));
+  }
+
+  num_used_input_buffers_ = 0;
+  input_buffers_ = std::move(new_buffers);
+
+  return true;
+}
+
+void FuchsiaVideoDecoder::PumpInput() {
+  // Nothing to do if a codec error has occurred or input buffers have not been
+  // initialized (which happens in response to OnInputConstraints() event).
+  if (!codec_ || input_buffers_.empty())
+    return;
+
+  while (!pending_decodes_.empty()) {
+    // Decode() is not supposed to be called while Decode(EOS) is pending.
+    DCHECK(!pending_flush_cb_);
+
+    if (pending_decodes_.front().buffer().end_of_stream()) {
+      active_stream_ = true;
+      codec_->QueueInputEndOfStream(stream_lifetime_ordinal_);
+      codec_->FlushEndOfStreamAndCloseStream(stream_lifetime_ordinal_);
+      pending_flush_cb_ = pending_decodes_.front().TakeDecodeCallback();
+      pending_decodes_.pop_front();
+      continue;
+    }
+
+    DCHECK_LE(num_used_input_buffers_, static_cast<int>(input_buffers_.size()));
+    if (num_used_input_buffers_ == static_cast<int>(input_buffers_.size())) {
+      // No input buffer available.
+      return;
+    }
+
+    auto input_buffer =
+        std::find_if(input_buffers_.begin(), input_buffers_.end(),
+                     [](const InputBuffer& buf) { return !buf.is_used(); });
+    CHECK(input_buffer != input_buffers_.end());
+
+    num_used_input_buffers_++;
+    size_t bytes_filled =
+        input_buffer->FillFromDecodeBuffer(&pending_decodes_.front());
+
+    fuchsia::mediacodec::CodecPacket packet;
+    packet.header.buffer_lifetime_ordinal = input_buffer_lifetime_ordinal_;
+    packet.header.packet_index = input_buffer - input_buffers_.begin();
+    packet.has_timestamp_ish = true;
+    packet.timestamp_ish =
+        pending_decodes_.front().buffer().timestamp().InNanoseconds();
+    packet.stream_lifetime_ordinal = stream_lifetime_ordinal_;
+    packet.start_offset = 0;
+    packet.valid_length_bytes = bytes_filled;
+
+    active_stream_ = true;
+    codec_->QueueInputPacket(std::move(packet));
+
+    if (pending_decodes_.front().bytes_left() == 0) {
+      pending_decodes_.pop_front();
+    }
+  }
+}
+
+bool FuchsiaVideoDecoder::InitializeOutputBuffers(
+    fuchsia::mediacodec::CodecBufferConstraints constraints) {
+  // mediacodec API expects odd buffer lifetime ordinal, which is incremented by
+  // 2 for each buffer generation.
+  output_buffer_lifetime_ordinal_ += 2;
+
+  auto settings = constraints.default_settings;
+  settings.buffer_lifetime_ordinal = output_buffer_lifetime_ordinal_;
+
+  max_used_output_buffers_ =
+      std::min(kMaxUsedOutputFrames, constraints.packet_count_for_client_max);
+  settings.packet_count_for_client = max_used_output_buffers_;
+
+  codec_->SetOutputBufferSettings(std::move(settings));
+
+  int total_buffers =
+      settings.packet_count_for_codec + settings.packet_count_for_client;
+  std::vector<scoped_refptr<OutputBuffer>> new_buffers(total_buffers);
+
+  for (int i = 0; i < total_buffers; ++i) {
+    fuchsia::mediacodec::CodecBuffer codec_buffer;
+    new_buffers[i] = new OutputBuffer();
+    if (!new_buffers[i]->Initialize(constraints) ||
+        !new_buffers[i]->buffer().ToFidlCodecBuffer(
+            output_buffer_lifetime_ordinal_, i, /*read_only=*/false,
+            &codec_buffer)) {
+      return false;
+    }
+
+    codec_->AddOutputBuffer(std::move(codec_buffer));
+  }
+
+  num_used_output_buffers_ = 0;
+  output_buffers_ = std::move(new_buffers);
+
+  return true;
+}
+
+void FuchsiaVideoDecoder::OnFrameDestroyed(scoped_refptr<OutputBuffer> buffer,
+                                           uint64_t buffer_lifetime_ordinal,
+                                           uint32_t packet_index) {
+  if (!codec_)
+    return;
+
+  if (buffer_lifetime_ordinal == output_buffer_lifetime_ordinal_) {
+    DCHECK_GT(num_used_output_buffers_, 0);
+    num_used_output_buffers_--;
+    codec_->RecycleOutputPacket(fuchsia::mediacodec::CodecPacketHeader{
+        buffer_lifetime_ordinal, packet_index});
+  }
+}
+
+std::unique_ptr<VideoDecoder> CreateFuchsiaVideoDecoder() {
+  return std::make_unique<FuchsiaVideoDecoder>();
+}
+
+}  // namespace media
diff --git a/media/gpu/fuchsia/fuchsia_video_decoder.h b/media/gpu/fuchsia/fuchsia_video_decoder.h
new file mode 100644
index 0000000..8388025
--- /dev/null
+++ b/media/gpu/fuchsia/fuchsia_video_decoder.h
@@ -0,0 +1,21 @@
+// 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 MEDIA_GPU_FUCHSIA_FUCHSIA_VIDEO_DECODER_H_
+#define MEDIA_GPU_FUCHSIA_FUCHSIA_VIDEO_DECODER_H_
+
+#include <memory>
+
+#include "media/gpu/media_gpu_export.h"
+
+namespace media {
+
+class VideoDecoder;
+
+// Creates VideoDecoder that uses fuchsia.mediacodec API.
+MEDIA_GPU_EXPORT std::unique_ptr<VideoDecoder> CreateFuchsiaVideoDecoder();
+
+}  // namespace media
+
+#endif  // MEDIA_GPU_FUCHSIA_FUCHSIA_VIDEO_DECODER_H_
diff --git a/media/gpu/fuchsia/fuchsia_video_decoder_unittest.cc b/media/gpu/fuchsia/fuchsia_video_decoder_unittest.cc
new file mode 100644
index 0000000..4ff26656
--- /dev/null
+++ b/media/gpu/fuchsia/fuchsia_video_decoder_unittest.cc
@@ -0,0 +1,116 @@
+// 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 "media/gpu/fuchsia/fuchsia_video_decoder.h"
+
+#include "base/bind.h"
+#include "base/message_loop/message_loop.h"
+#include "media/base/test_data_util.h"
+#include "media/base/test_helpers.h"
+#include "media/base/video_decoder.h"
+#include "media/base/video_frame.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace media {
+
+class FuchsiaVideoDecoderTest : public testing::Test {
+ public:
+  FuchsiaVideoDecoderTest() { decoder_ = CreateFuchsiaVideoDecoder(); }
+  ~FuchsiaVideoDecoderTest() override = default;
+
+  bool Initialize(VideoDecoderConfig config) WARN_UNUSED_RESULT {
+    base::RunLoop run_loop;
+    bool init_cb_result = false;
+    decoder_->Initialize(
+        config, true, /*cdm_context=*/nullptr,
+        base::BindRepeating(
+            [](bool* init_cb_result, base::RunLoop* run_loop, bool result) {
+              *init_cb_result = result;
+              run_loop->Quit();
+            },
+            &init_cb_result, &run_loop),
+        base::BindRepeating(&FuchsiaVideoDecoderTest::OnVideoFrame,
+                            base::Unretained(this)),
+        VideoDecoder::WaitingForDecryptionKeyCB());
+
+    run_loop.Run();
+    return init_cb_result;
+  }
+
+  void OnVideoFrame(const scoped_refptr<VideoFrame>& frame) {
+    num_output_frames_++;
+    output_frames_.push_back(frame);
+    while (output_frames_.size() > frames_to_keep_) {
+      output_frames_.pop_front();
+    }
+    if (on_frame_)
+      on_frame_.Run();
+  }
+
+  DecodeStatus DecodeBuffer(scoped_refptr<DecoderBuffer> buffer) {
+    base::RunLoop run_loop;
+    DecodeStatus status;
+    decoder_->Decode(buffer,
+                     base::BindRepeating(
+                         [](DecodeStatus* status, base::RunLoop* run_loop,
+                            DecodeStatus result) {
+                           *status = result;
+                           run_loop->Quit();
+                         },
+                         &status, &run_loop));
+
+    run_loop.Run();
+
+    return status;
+  }
+
+  DecodeStatus ReadAndDecodeFrame(const std::string& name) {
+    return DecodeBuffer(ReadTestDataFile(name));
+  }
+
+ protected:
+  base::MessageLoopForIO message_loop_;
+  std::unique_ptr<VideoDecoder> decoder_;
+
+  std::list<scoped_refptr<VideoFrame>> output_frames_;
+  int num_output_frames_ = 0;
+
+  // Number of frames that OnVideoFrame() should keep in |output_frames_|.
+  size_t frames_to_keep_ = 2;
+
+  base::RepeatingClosure on_frame_;
+};
+
+// All tests are disabled because they currently depend on HW decoder that
+// doesn't work on test bots.
+TEST_F(FuchsiaVideoDecoderTest, DISABLED_CreateAndDestroy) {}
+
+TEST_F(FuchsiaVideoDecoderTest, DISABLED_CreateInitDestroy) {
+  EXPECT_TRUE(Initialize(TestVideoConfig::NormalH264()));
+}
+
+TEST_F(FuchsiaVideoDecoderTest, DISABLED_VP9) {
+  ASSERT_TRUE(Initialize(TestVideoConfig::Normal(kCodecVP9)));
+
+  ASSERT_TRUE(ReadAndDecodeFrame("vp9-I-frame-320x240") == DecodeStatus::OK);
+  ASSERT_TRUE(DecodeBuffer(DecoderBuffer::CreateEOSBuffer()) ==
+              DecodeStatus::OK);
+
+  EXPECT_EQ(num_output_frames_, 1);
+}
+
+TEST_F(FuchsiaVideoDecoderTest, DISABLED_H264) {
+  ASSERT_TRUE(Initialize(TestVideoConfig::NormalH264()));
+
+  ASSERT_TRUE(ReadAndDecodeFrame("h264-320x180-frame-0") == DecodeStatus::OK);
+  ASSERT_TRUE(ReadAndDecodeFrame("h264-320x180-frame-1") == DecodeStatus::OK);
+  ASSERT_TRUE(ReadAndDecodeFrame("h264-320x180-frame-2") == DecodeStatus::OK);
+  ASSERT_TRUE(ReadAndDecodeFrame("h264-320x180-frame-3") == DecodeStatus::OK);
+  ASSERT_TRUE(DecodeBuffer(DecoderBuffer::CreateEOSBuffer()) ==
+              DecodeStatus::OK);
+
+  EXPECT_EQ(num_output_frames_, 4);
+}
+
+}  // namespace media
\ No newline at end of file
diff --git a/media/gpu/test/vaapi_dmabuf_video_frame_mapper.cc b/media/gpu/test/vaapi_dmabuf_video_frame_mapper.cc
new file mode 100644
index 0000000..15846c6
--- /dev/null
+++ b/media/gpu/test/vaapi_dmabuf_video_frame_mapper.cc
@@ -0,0 +1,171 @@
+// 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 "media/gpu/test/vaapi_dmabuf_video_frame_mapper.h"
+
+#include "base/bind_helpers.h"
+#include "base/memory/ptr_util.h"
+#include "media/gpu/format_utils.h"
+#include "media/gpu/vaapi/vaapi_picture_factory.h"
+#include "media/gpu/vaapi/vaapi_utils.h"
+#include "media/gpu/vaapi/vaapi_wrapper.h"
+#include "media/video/picture.h"
+
+#define VLOGF(level) VLOG(level) << __func__ << "(): "
+
+namespace media {
+namespace test {
+
+namespace {
+
+constexpr uint32_t kDummyPictureBufferId = 0;
+// This is equal to GBM_FORMAT_MOD_NONE.
+constexpr uint64_t kDummyGbmModifier = 0;
+constexpr VAImageFormat kImageFormatI420{.fourcc = VA_FOURCC_I420,
+                                         .byte_order = VA_LSB_FIRST,
+                                         .bits_per_pixel = 12};
+
+gfx::GpuMemoryBufferHandle CreateGMBHandleFromVideoFrame(
+    const VideoFrame* const video_frame) {
+  DCHECK(video_frame->HasDmaBufs());
+
+  gfx::GpuMemoryBufferHandle handle;
+  handle.type = gfx::NATIVE_PIXMAP;
+
+  const VideoFrameLayout& layout = video_frame->layout();
+  size_t num_planes = layout.num_planes();
+  const std::vector<VideoFrameLayout::Plane>& planes = layout.planes();
+  for (size_t i = 0; i < num_planes; i++) {
+    handle.native_pixmap_handle.planes.emplace_back(
+        planes[i].stride, planes[i].offset, i, kDummyGbmModifier);
+  }
+
+  const auto& fds = video_frame->DmabufFds();
+  for (const auto& fd : fds) {
+    int dup_fd = HANDLE_EINTR(dup(fd.get()));
+    if (dup_fd == -1) {
+      VLOGF(1) << "Failed duplicating dmabuf fd";
+      return gfx::GpuMemoryBufferHandle();
+    }
+    handle.native_pixmap_handle.fds.emplace_back(
+        base::FileDescriptor(dup_fd, true));
+  }
+  return handle;
+}
+
+void DeallocateBuffers(std::unique_ptr<ScopedVAImage> va_image) {
+  // Destructing ScopedVAImage releases its owned memory.
+  DCHECK(va_image->IsValid());
+}
+
+scoped_refptr<VideoFrame> CreateMappedVideoFrame(
+    const VideoFrameLayout& layout,
+    const gfx::Rect& visible_rect,
+    std::unique_ptr<ScopedVAImage> va_image) {
+  // ScopedVAImage manages the resource of mapped data. That is, ScopedVAImage's
+  // dtor releases the mapped resource.
+  const size_t num_planes = layout.num_planes();
+  if (num_planes != va_image->image()->num_planes) {
+    VLOGF(1) << "The number of planes is not same between layout and VAImage, "
+             << "(layout: " << num_planes
+             << ", VAImage: " << va_image->image()->num_planes << ")";
+    return nullptr;
+  }
+
+  std::vector<int32_t> strides(num_planes, 0);
+  std::vector<uint8_t*> addrs(num_planes, nullptr);
+  for (size_t i = 0; i < num_planes; i++) {
+    strides[i] = va_image->image()->pitches[i];
+    addrs[i] = static_cast<uint8_t*>(va_image->va_buffer()->data()) +
+               va_image->image()->offsets[i];
+  }
+
+  auto video_frame = VideoFrame::WrapExternalYuvData(
+      layout.format(), layout.coded_size(), visible_rect, visible_rect.size(),
+      strides[0], strides[1], strides[2], addrs[0], addrs[1], addrs[2],
+      base::TimeDelta());
+  if (!video_frame)
+    return nullptr;
+
+  video_frame->AddDestructionObserver(
+      base::BindOnce(DeallocateBuffers, std::move(va_image)));
+  return video_frame;
+}
+
+}  // namespace
+
+// static
+std::unique_ptr<VideoFrameMapper> VaapiDmaBufVideoFrameMapper::Create() {
+  auto video_frame_mapper = base::WrapUnique(new VaapiDmaBufVideoFrameMapper);
+  if (video_frame_mapper->vaapi_wrapper_ == nullptr) {
+    return nullptr;
+  }
+  return video_frame_mapper;
+}
+
+// While kDecode and H264PROFILE_MAIN are set here,  the mode and profile are
+// not required for VaapiWrapper to perform pixel format conversion.
+// TODO(crbug.com/898423): Create a VaapiWrapper only for pixel format
+// conversion. Either mode or profile isn't required to create the VaapiWrapper.
+VaapiDmaBufVideoFrameMapper::VaapiDmaBufVideoFrameMapper()
+    : vaapi_wrapper_(VaapiWrapper::CreateForVideoCodec(VaapiWrapper::kDecode,
+                                                       H264PROFILE_MAIN,
+                                                       base::DoNothing())),
+      vaapi_picture_factory_(new VaapiPictureFactory()) {}
+
+VaapiDmaBufVideoFrameMapper::~VaapiDmaBufVideoFrameMapper() {}
+
+scoped_refptr<VideoFrame> VaapiDmaBufVideoFrameMapper::Map(
+    scoped_refptr<VideoFrame> video_frame) const {
+  DCHECK(vaapi_wrapper_);
+  DCHECK(vaapi_picture_factory_);
+  if (!video_frame->HasDmaBufs()) {
+    return nullptr;
+  }
+  const gfx::Size& coded_size = video_frame->coded_size();
+
+  // Passing empty callbacks is ok, because given PictureBuffer doesn't have
+  // texture id and thus these callbacks will never called.
+  auto va_picture = vaapi_picture_factory_->Create(
+      vaapi_wrapper_, MakeGLContextCurrentCallback(), BindGLImageCallback(),
+      PictureBuffer(kDummyPictureBufferId, coded_size));
+  if (!va_picture) {
+    VLOGF(1) << "Failed to create VaapiPicture.";
+    return nullptr;
+  }
+
+  auto gmb_handle = CreateGMBHandleFromVideoFrame(video_frame.get());
+  if (gmb_handle.is_null()) {
+    VLOGF(1) << "Failed to CreateGMBHandleFromVideoFrame.";
+    return nullptr;
+  }
+  if (!va_picture->ImportGpuMemoryBufferHandle(
+          VideoPixelFormatToGfxBufferFormat(video_frame->format()),
+          std::move(gmb_handle))) {
+    VLOGF(1) << "Failed in ImportGpuMemoryBufferHandle.";
+    return nullptr;
+  }
+
+  // Map and Convert tiled buffer into I420 format buffer.
+  constexpr VideoPixelFormat kConvertedFormat = PIXEL_FORMAT_I420;
+  VAImageFormat va_image_format = kImageFormatI420;
+  auto va_image = vaapi_wrapper_->CreateVaImage(
+      va_picture->va_surface_id(), &va_image_format, video_frame->coded_size());
+  if (!va_image || !va_image->IsValid()) {
+    VLOGF(1) << "Failed in CreateVaImage.";
+    return nullptr;
+  }
+
+  auto layout =
+      VideoFrameLayout::Create(kConvertedFormat, video_frame->coded_size());
+  if (!layout) {
+    VLOGF(1) << "Failed to create VideoFrameLayout.";
+    return nullptr;
+  }
+  return CreateMappedVideoFrame(*layout, video_frame->visible_rect(),
+                                std::move(va_image));
+}
+
+}  // namespace test
+}  // namespace media
diff --git a/media/gpu/test/vaapi_dmabuf_video_frame_mapper.h b/media/gpu/test/vaapi_dmabuf_video_frame_mapper.h
new file mode 100644
index 0000000..687a97f
--- /dev/null
+++ b/media/gpu/test/vaapi_dmabuf_video_frame_mapper.h
@@ -0,0 +1,46 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MEDIA_GPU_TEST_VAAPI_DMABUF_VIDEO_FRAME_MAPPER_H_
+#define MEDIA_GPU_TEST_VAAPI_DMABUF_VIDEO_FRAME_MAPPER_H_
+
+#include <memory>
+
+#include "media/gpu/test/video_frame_mapper.h"
+
+namespace media {
+
+class VaapiPictureFactory;
+class VaapiWrapper;
+
+namespace test {
+
+// VideoFrameMapper that gains access to the memory referred by DMABuf-backed
+// video frame using VA-API.
+// VaapiDmaBufVideoFrameMapper creates a new VaapiPicture from the given
+// VideoFrame and use a VaapiWrapper to access the memory there.
+class VaapiDmaBufVideoFrameMapper : public VideoFrameMapper {
+ public:
+  ~VaapiDmaBufVideoFrameMapper() override;
+
+  static std::unique_ptr<VideoFrameMapper> Create();
+
+  // VideoFrameMapper override.
+  scoped_refptr<VideoFrame> Map(
+      scoped_refptr<VideoFrame> video_frame) const override;
+
+ private:
+  VaapiDmaBufVideoFrameMapper();
+
+  // Vaapi components for mapping.
+  const scoped_refptr<VaapiWrapper> vaapi_wrapper_;
+  const std::unique_ptr<VaapiPictureFactory> vaapi_picture_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(VaapiDmaBufVideoFrameMapper);
+};
+
+}  // namespace test
+}  // namespace media
+
+#endif  // MEDIA_GPU_TEST_VAAPI_DMABUF_VIDEO_FRAME_MAPPER_H_
diff --git a/media/gpu/test/video_frame_mapper.h b/media/gpu/test/video_frame_mapper.h
index b288f6e0..4e5a5be 100644
--- a/media/gpu/test/video_frame_mapper.h
+++ b/media/gpu/test/video_frame_mapper.h
@@ -30,4 +30,5 @@
 
 }  // namespace test
 }  // namespace media
+
 #endif  // MEDIA_GPU_TEST_VIDEO_FRAME_MAPPER_H_
diff --git a/media/gpu/test/video_frame_mapper_factory.cc b/media/gpu/test/video_frame_mapper_factory.cc
index bddcddef..54e5b9a5 100644
--- a/media/gpu/test/video_frame_mapper_factory.cc
+++ b/media/gpu/test/video_frame_mapper_factory.cc
@@ -4,9 +4,16 @@
 
 #include "media/gpu/test/video_frame_mapper_factory.h"
 
+#include "media/gpu/buildflags.h"
+
 #if defined(OS_CHROMEOS)
 #include "media/gpu/test/generic_dmabuf_video_frame_mapper.h"
-#endif
+
+#if BUILDFLAG(USE_VAAPI)
+#include "media/gpu/test/vaapi_dmabuf_video_frame_mapper.h"
+#endif  // BUILDFLAG(USE_VAAPI)
+
+#endif  // defined(OS_CHROMEOS)
 
 namespace media {
 namespace test {
@@ -14,8 +21,15 @@
 // static
 std::unique_ptr<VideoFrameMapper> VideoFrameMapperFactory::CreateMapper() {
 #if defined(OS_CHROMEOS)
+
+#if BUILDFLAG(USE_VAAPI)
+  return VaapiDmaBufVideoFrameMapper::Create();
+#else
   return std::make_unique<GenericDmaBufVideoFrameMapper>();
+#endif  // BUILDFLAG(USE_VAAPI)
+
 #endif  // defined(OS_CHROMEOS)
+
   NOTREACHED();
   return nullptr;
 }
diff --git a/media/gpu/test/video_frame_mapper_factory.h b/media/gpu/test/video_frame_mapper_factory.h
index 18385c0..5716525 100644
--- a/media/gpu/test/video_frame_mapper_factory.h
+++ b/media/gpu/test/video_frame_mapper_factory.h
@@ -22,4 +22,5 @@
 
 }  // namespace test
 }  // namespace media
+
 #endif  // MEDIA_GPU_TEST_GENERIC_VIDEO_FRAME_MAPPER_FACTORY_H_
diff --git a/media/gpu/test/video_frame_validator.h b/media/gpu/test/video_frame_validator.h
index e9b77ae..6efb1c7 100644
--- a/media/gpu/test/video_frame_validator.h
+++ b/media/gpu/test/video_frame_validator.h
@@ -102,4 +102,5 @@
 };
 }  // namespace test
 }  // namespace media
+
 #endif  // MEDIA_GPU_TEST_VIDEO_FRAME_VALIDATOR_H_
diff --git a/media/gpu/vaapi/vaapi_video_decode_accelerator.cc b/media/gpu/vaapi/vaapi_video_decode_accelerator.cc
index 2008fdee..1e17dbd 100644
--- a/media/gpu/vaapi/vaapi_video_decode_accelerator.cc
+++ b/media/gpu/vaapi/vaapi_video_decode_accelerator.cc
@@ -219,7 +219,8 @@
         std::make_unique<VaapiVP8Accelerator>(this, vaapi_wrapper_)));
   } else if (profile >= VP9PROFILE_MIN && profile <= VP9PROFILE_MAX) {
     decoder_.reset(new VP9Decoder(
-        std::make_unique<VaapiVP9Accelerator>(this, vaapi_wrapper_)));
+        std::make_unique<VaapiVP9Accelerator>(this, vaapi_wrapper_),
+        config.container_color_space));
   } else {
     VLOGF(1) << "Unsupported profile " << GetProfileName(profile);
     return false;
diff --git a/media/gpu/vp9_decoder.cc b/media/gpu/vp9_decoder.cc
index 72375b260..3b40f0ef 100644
--- a/media/gpu/vp9_decoder.cc
+++ b/media/gpu/vp9_decoder.cc
@@ -17,8 +17,10 @@
 
 VP9Decoder::VP9Accelerator::~VP9Accelerator() {}
 
-VP9Decoder::VP9Decoder(std::unique_ptr<VP9Accelerator> accelerator)
+VP9Decoder::VP9Decoder(std::unique_ptr<VP9Accelerator> accelerator,
+                       const VideoColorSpace& container_color_space)
     : state_(kNeedStreamMetadata),
+      container_color_space_(container_color_space),
       accelerator_(std::move(accelerator)),
       parser_(accelerator_->IsFrameContextRequired()) {
   ref_frames_.resize(kVp9NumRefFrames);
@@ -176,6 +178,13 @@
 
     pic->set_visible_rect(new_render_rect);
     pic->set_bitstream_id(stream_id_);
+
+    // For VP9, container color spaces override video stream color spaces.
+    if (container_color_space_.IsSpecified()) {
+      pic->set_colorspace(container_color_space_);
+    } else if (curr_frame_hdr_) {
+      pic->set_colorspace(curr_frame_hdr_->GetColorSpace());
+    }
     pic->frame_hdr = std::move(curr_frame_hdr_);
 
     if (!DecodeAndOutputPicture(pic)) {
diff --git a/media/gpu/vp9_decoder.h b/media/gpu/vp9_decoder.h
index de746ba..3bf20061 100644
--- a/media/gpu/vp9_decoder.h
+++ b/media/gpu/vp9_decoder.h
@@ -92,7 +92,8 @@
     DISALLOW_COPY_AND_ASSIGN(VP9Accelerator);
   };
 
-  explicit VP9Decoder(std::unique_ptr<VP9Accelerator> accelerator);
+  VP9Decoder(std::unique_ptr<VP9Accelerator> accelerator,
+             const VideoColorSpace& container_color_space = VideoColorSpace());
   ~VP9Decoder() override;
 
   // AcceleratedVideoDecoder implementation.
@@ -140,6 +141,9 @@
   // Current frame header to be used in decoding the next picture.
   std::unique_ptr<Vp9FrameHeader> curr_frame_hdr_;
 
+  // Color space provided by the container.
+  const VideoColorSpace container_color_space_;
+
   // Reference frames currently in use.
   std::vector<scoped_refptr<VP9Picture>> ref_frames_;
 
diff --git a/media/gpu/windows/d3d11_video_decoder.cc b/media/gpu/windows/d3d11_video_decoder.cc
index 1611bc7..5d63543 100644
--- a/media/gpu/windows/d3d11_video_decoder.cc
+++ b/media/gpu/windows/d3d11_video_decoder.cc
@@ -113,10 +113,11 @@
     CdmProxyContext* proxy_context,
     Microsoft::WRL::ComPtr<ID3D11VideoDecoder> video_decoder) {
   if (IsVP9(config)) {
-    accelerated_video_decoder_ =
-        std::make_unique<VP9Decoder>(std::make_unique<D3D11VP9Accelerator>(
-            this, media_log_.get(), proxy_context, video_decoder, video_device_,
-            video_context_));
+    accelerated_video_decoder_ = std::make_unique<VP9Decoder>(
+        std::make_unique<D3D11VP9Accelerator>(this, media_log_.get(),
+                                              proxy_context, video_decoder,
+                                              video_device_, video_context_),
+        config.color_space_info());
     return;
   }
 
diff --git a/media/gpu/windows/dxva_video_decode_accelerator_win.cc b/media/gpu/windows/dxva_video_decode_accelerator_win.cc
index 36a51b73..d7dfc417 100644
--- a/media/gpu/windows/dxva_video_decode_accelerator_win.cc
+++ b/media/gpu/windows/dxva_video_decode_accelerator_win.cc
@@ -621,45 +621,7 @@
     Vp9FrameHeader fhdr;
     while (parser_.ParseNextFrame(&fhdr) == Vp9Parser::kOk) {
       visible_rect_ = gfx::Rect(fhdr.render_width, fhdr.render_height);
-
-      // TODO(hubbe): move the conversion from Vp9FrameHeader to VideoColorSpace
-      // into a common, reusable location.
-      color_space_.range = fhdr.color_range ? gfx::ColorSpace::RangeID::FULL
-                                            : gfx::ColorSpace::RangeID::INVALID;
-      color_space_.primaries = VideoColorSpace::PrimaryID::INVALID;
-      color_space_.transfer = VideoColorSpace::TransferID::INVALID;
-      color_space_.matrix = VideoColorSpace::MatrixID::INVALID;
-      switch (fhdr.color_space) {
-        case Vp9ColorSpace::RESERVED:
-        case Vp9ColorSpace::UNKNOWN:
-          break;
-        case Vp9ColorSpace::BT_601:
-        case Vp9ColorSpace::SMPTE_170:
-          color_space_.primaries = VideoColorSpace::PrimaryID::SMPTE170M;
-          color_space_.transfer = VideoColorSpace::TransferID::SMPTE170M;
-          color_space_.matrix = VideoColorSpace::MatrixID::SMPTE170M;
-          break;
-        case Vp9ColorSpace::BT_709:
-          color_space_.primaries = VideoColorSpace::PrimaryID::BT709;
-          color_space_.transfer = VideoColorSpace::TransferID::BT709;
-          color_space_.matrix = VideoColorSpace::MatrixID::BT709;
-          break;
-        case Vp9ColorSpace::SMPTE_240:
-          color_space_.primaries = VideoColorSpace::PrimaryID::SMPTE240M;
-          color_space_.transfer = VideoColorSpace::TransferID::SMPTE240M;
-          color_space_.matrix = VideoColorSpace::MatrixID::SMPTE240M;
-          break;
-        case Vp9ColorSpace::BT_2020:
-          color_space_.primaries = VideoColorSpace::PrimaryID::BT2020;
-          color_space_.transfer = VideoColorSpace::TransferID::BT2020_10;
-          color_space_.matrix = VideoColorSpace::MatrixID::BT2020_NCL;
-          break;
-        case Vp9ColorSpace::SRGB:
-          color_space_.primaries = VideoColorSpace::PrimaryID::BT709;
-          color_space_.transfer = VideoColorSpace::TransferID::IEC61966_2_1;
-          color_space_.matrix = VideoColorSpace::MatrixID::BT709;
-          break;
-      }
+      color_space_ = fhdr.GetColorSpace();
 
       gfx::Size new_size(fhdr.frame_width, fhdr.frame_height);
       if (!size_.IsEmpty() && !pending_config_changed_ && !config_changed_ &&
diff --git a/media/mojo/interfaces/key_system_support.mojom b/media/mojo/interfaces/key_system_support.mojom
index 6fe2f6d..bf40634 100644
--- a/media/mojo/interfaces/key_system_support.mojom
+++ b/media/mojo/interfaces/key_system_support.mojom
@@ -13,6 +13,7 @@
 struct KeySystemCapability {
   // Software secure codecs and encryption schemes supported by the CDM.
   array<VideoCodec> video_codecs;
+  bool supports_vp9_profile2;
   array<EncryptionMode> encryption_schemes;
 
   // Hardware secure codecs and encryption schemes supported by the CDM,
diff --git a/media/remoting/media_remoting_rpc.proto b/media/remoting/media_remoting_rpc.proto
index 579c21a..9bf902d2 100644
--- a/media/remoting/media_remoting_rpc.proto
+++ b/media/remoting/media_remoting_rpc.proto
@@ -221,6 +221,8 @@
     PIXEL_FORMAT_YUV444P12 = 24;
     PIXEL_FORMAT_Y8 = 25 [deprecated = true];
     PIXEL_FORMAT_Y16 = 26;
+    PIXEL_FORMAT_ABGR = 27;
+    PIXEL_FORMAT_XBGR = 28;
   };
 
   // Proto version of media::ColorSpace.
diff --git a/media/remoting/proto_enum_utils.cc b/media/remoting/proto_enum_utils.cc
index 9e65420..bc0ade8 100644
--- a/media/remoting/proto_enum_utils.cc
+++ b/media/remoting/proto_enum_utils.cc
@@ -362,7 +362,9 @@
     // PIXEL_FORMAT_Y8 is deprecated .
     case pb::VideoDecoderConfig_Format_PIXEL_FORMAT_Y8:
       return base::nullopt;
-   CASE_RETURN_OTHER(PIXEL_FORMAT_Y16);
+      CASE_RETURN_OTHER(PIXEL_FORMAT_Y16);
+      CASE_RETURN_OTHER(PIXEL_FORMAT_ABGR);
+      CASE_RETURN_OTHER(PIXEL_FORMAT_XBGR);
   }
   return base::nullopt;  // Not a 'default' to ensure compile-time checks.
 }
@@ -398,6 +400,8 @@
     CASE_RETURN_OTHER(PIXEL_FORMAT_YUV422P12);
     CASE_RETURN_OTHER(PIXEL_FORMAT_YUV444P12);
     CASE_RETURN_OTHER(PIXEL_FORMAT_Y16);
+    CASE_RETURN_OTHER(PIXEL_FORMAT_ABGR);
+    CASE_RETURN_OTHER(PIXEL_FORMAT_XBGR);
   }
   return base::nullopt;  // Not a 'default' to ensure compile-time checks.
 }
diff --git a/media/renderers/paint_canvas_video_renderer.cc b/media/renderers/paint_canvas_video_renderer.cc
index a77bb913..f0dd1c7 100644
--- a/media/renderers/paint_canvas_video_renderer.cc
+++ b/media/renderers/paint_canvas_video_renderer.cc
@@ -908,6 +908,8 @@
     case PIXEL_FORMAT_RGB32:
     case PIXEL_FORMAT_MJPEG:
     case PIXEL_FORMAT_MT21:
+    case PIXEL_FORMAT_ABGR:
+    case PIXEL_FORMAT_XBGR:
     case PIXEL_FORMAT_UNKNOWN:
       NOTREACHED() << "Only YUV formats and Y16 are supported, got: "
                    << media::VideoPixelFormatToString(video_frame->format());
diff --git a/media/renderers/video_resource_updater.cc b/media/renderers/video_resource_updater.cc
index 5b4abce..73617f4 100644
--- a/media/renderers/video_resource_updater.cc
+++ b/media/renderers/video_resource_updater.cc
@@ -112,6 +112,8 @@
     case PIXEL_FORMAT_YUV422P12:
     case PIXEL_FORMAT_YUV444P12:
     case PIXEL_FORMAT_Y16:
+    case PIXEL_FORMAT_ABGR:
+    case PIXEL_FORMAT_XBGR:
     case PIXEL_FORMAT_UNKNOWN:
       break;
   }
diff --git a/media/video/gpu_memory_buffer_video_frame_pool.cc b/media/video/gpu_memory_buffer_video_frame_pool.cc
index 9983fe3..86b0d69 100644
--- a/media/video/gpu_memory_buffer_video_frame_pool.cc
+++ b/media/video/gpu_memory_buffer_video_frame_pool.cc
@@ -680,6 +680,8 @@
     case PIXEL_FORMAT_YUV422P12:
     case PIXEL_FORMAT_YUV444P12:
     case PIXEL_FORMAT_Y16:
+    case PIXEL_FORMAT_ABGR:
+    case PIXEL_FORMAT_XBGR:
     case PIXEL_FORMAT_UNKNOWN:
       if (is_software_backed_video_frame) {
         UMA_HISTOGRAM_ENUMERATION(
diff --git a/mojo/core/handle_table_unittest.cc b/mojo/core/handle_table_unittest.cc
index 493f71e..910b14e 100644
--- a/mojo/core/handle_table_unittest.cc
+++ b/mojo/core/handle_table_unittest.cc
@@ -10,7 +10,7 @@
 #include "base/trace_event/memory_allocator_dump.h"
 #include "base/trace_event/memory_dump_request_args.h"
 #include "base/trace_event/process_memory_dump.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "mojo/core/dispatcher.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/net/BUILD.gn b/net/BUILD.gn
index fe331806..d843ae4e 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -2186,7 +2186,10 @@
     }
 
     if (is_fuchsia) {
-      public_deps += [ "//third_party/fuchsia-sdk/sdk:netstack" ]
+      public_deps += [
+        "//third_party/fuchsia-sdk/sdk:ethernet",
+        "//third_party/fuchsia-sdk/sdk:netstack",
+      ]
     }
 
     if (use_platform_icu_alternatives) {
diff --git a/net/base/network_change_notifier_fuchsia_unittest.cc b/net/base/network_change_notifier_fuchsia_unittest.cc
index 07d202d..1ecfc2a 100644
--- a/net/base/network_change_notifier_fuchsia_unittest.cc
+++ b/net/base/network_change_notifier_fuchsia_unittest.cc
@@ -445,11 +445,10 @@
               OnNetworkChanged(NetworkChangeNotifier::CONNECTION_NONE));
   EXPECT_CALL(observer_,
               OnNetworkChanged(NetworkChangeNotifier::CONNECTION_WIFI));
-  netstack_.PushInterface(
-      CreateNetInterface(kDefaultNic, fuchsia::netstack::NetInterfaceFlagUp,
-                         fuchsia::netstack::interfaceFeatureWlan,
-                         CreateIPv4Address(169, 254, 0, 1),
-                         CreateIPv4Address(255, 255, 255, 0), {}));
+  netstack_.PushInterface(CreateNetInterface(
+      kDefaultNic, fuchsia::netstack::NetInterfaceFlagUp,
+      zircon::ethernet::INFO_FEATURE_WLAN, CreateIPv4Address(169, 254, 0, 1),
+      CreateIPv4Address(255, 255, 255, 0), {}));
   netstack_.NotifyInterfaces();
   base::RunLoop().RunUntilIdle();
 }
@@ -495,11 +494,10 @@
 }
 
 TEST_F(NetworkChangeNotifierFuchsiaTest, FoundWiFi) {
-  netstack_.PushInterface(
-      CreateNetInterface(kDefaultNic, fuchsia::netstack::NetInterfaceFlagUp,
-                         fuchsia::netstack::interfaceFeatureWlan,
-                         CreateIPv4Address(169, 254, 0, 1),
-                         CreateIPv4Address(255, 255, 255, 0), {}));
+  netstack_.PushInterface(CreateNetInterface(
+      kDefaultNic, fuchsia::netstack::NetInterfaceFlagUp,
+      zircon::ethernet::INFO_FEATURE_WLAN, CreateIPv4Address(169, 254, 0, 1),
+      CreateIPv4Address(255, 255, 255, 0), {}));
   CreateNotifier();
   EXPECT_EQ(NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI,
             notifier_->GetCurrentConnectionType());
diff --git a/net/base/network_interfaces_fuchsia.cc b/net/base/network_interfaces_fuchsia.cc
index abca21b..de08376 100644
--- a/net/base/network_interfaces_fuchsia.cc
+++ b/net/base/network_interfaces_fuchsia.cc
@@ -5,6 +5,7 @@
 #include "net/base/network_interfaces_fuchsia.h"
 
 #include <fuchsia/netstack/cpp/fidl.h>
+#include <zircon/ethernet/cpp/fidl.h>
 
 #include <string>
 #include <utility>
@@ -25,7 +26,7 @@
 
 ConnectionType ConvertConnectionType(
     const fuchsia::netstack::NetInterface& iface) {
-  return iface.features & fuchsia::netstack::interfaceFeatureWlan
+  return iface.features & zircon::ethernet::INFO_FEATURE_WLAN
              ? NetworkChangeNotifier::CONNECTION_WIFI
              : NetworkChangeNotifier::CONNECTION_UNKNOWN;
 }
@@ -81,7 +82,7 @@
     return output;
 
   // Skip loopback.
-  if (iface_in.features & fuchsia::netstack::interfaceFeatureLoopback)
+  if (iface_in.features & zircon::ethernet::INFO_FEATURE_LOOPBACK)
     return output;
 
   output.push_back(NetworkInterfaceFromAddress(iface_in, 0));
diff --git a/net/disk_cache/backend_unittest.cc b/net/disk_cache/backend_unittest.cc
index 297983c4..cbc1d32a 100644
--- a/net/disk_cache/backend_unittest.cc
+++ b/net/disk_cache/backend_unittest.cc
@@ -25,7 +25,7 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/trace_event/memory_allocator_dump.h"
 #include "base/trace_event/process_memory_dump.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "build/build_config.h"
 #include "net/base/cache_type.h"
 #include "net/base/completion_once_callback.h"
diff --git a/net/dns/mdns_client.cc b/net/dns/mdns_client.cc
index f690140..7e04ee0 100644
--- a/net/dns/mdns_client.cc
+++ b/net/dns/mdns_client.cc
@@ -27,20 +27,17 @@
                     dns_protocol::kDefaultPortMulticast);
 }
 
-int Bind(const IPEndPoint& multicast_addr,
+int Bind(AddressFamily address_family,
          uint32_t interface_index,
          DatagramServerSocket* socket) {
-  IPAddress address_any(IPAddress::AllZeros(multicast_addr.address().size()));
-  IPEndPoint bind_endpoint(address_any, multicast_addr.port());
-
-  socket->AllowAddressReuse();
+  socket->AllowAddressSharingForMulticast();
   socket->SetMulticastInterface(interface_index);
 
-  int rv = socket->Listen(bind_endpoint);
+  int rv = socket->Listen(GetMDnsReceiveEndPoint(address_family));
   if (rv < OK)
     return rv;
 
-  return socket->JoinGroup(multicast_addr.address());
+  return socket->JoinGroup(GetMDnsGroupEndPoint(address_family).address());
 }
 
 }  // namespace
@@ -58,7 +55,7 @@
   return std::unique_ptr<MDnsClient>(new MDnsClientImpl());
 }
 
-IPEndPoint GetMDnsIPEndPoint(AddressFamily address_family) {
+IPEndPoint GetMDnsGroupEndPoint(AddressFamily address_family) {
   switch (address_family) {
     case ADDRESS_FAMILY_IPV4:
       return GetMDnsIPEndPoint(kMDnsMulticastGroupIPv4);
@@ -70,6 +67,31 @@
   }
 }
 
+IPEndPoint GetMDnsReceiveEndPoint(AddressFamily address_family) {
+#ifdef OS_WIN
+  // With Windows, binding to a mulitcast group address is not allowed.
+  // Multicast messages will be received appropriate to the multicast groups the
+  // socket has joined. Sockets intending to receive multicast messages should
+  // bind to a wildcard address (e.g. 0.0.0.0).
+  switch (address_family) {
+    case ADDRESS_FAMILY_IPV4:
+      return IPEndPoint(IPAddress::IPv4AllZeros(),
+                        dns_protocol::kDefaultPortMulticast);
+    case ADDRESS_FAMILY_IPV6:
+      return IPEndPoint(IPAddress::IPv6AllZeros(),
+                        dns_protocol::kDefaultPortMulticast);
+    default:
+      NOTREACHED();
+      return IPEndPoint();
+  }
+#else   // !OS_WIN
+  // With POSIX, any socket can receive messages for multicast groups joined by
+  // any socket on the system. Sockets intending to receive messages for a
+  // specific multicast group should bind to that group address.
+  return GetMDnsGroupEndPoint(address_family);
+#endif  // !OS_WIN
+}
+
 InterfaceIndexFamilyList GetMDnsInterfacesToBind() {
   NetworkInterfaceList network_list;
   InterfaceIndexFamilyList interfaces;
@@ -96,11 +118,10 @@
   std::unique_ptr<DatagramServerSocket> socket(
       new UDPServerSocket(net_log, NetLogSource()));
 
-  IPEndPoint multicast_addr = GetMDnsIPEndPoint(address_family);
-  int rv = Bind(multicast_addr, interface_index, socket.get());
+  int rv = Bind(address_family, interface_index, socket.get());
   if (rv != OK) {
     socket.reset();
-    VLOG(1) << "Bind failed, endpoint=" << multicast_addr.ToStringWithoutPort()
+    VLOG(1) << "MDNS bind failed, address_family=" << address_family
             << ", error=" << rv;
   }
   return socket;
diff --git a/net/dns/mdns_client.h b/net/dns/mdns_client.h
index 8a6213f..53889373 100644
--- a/net/dns/mdns_client.h
+++ b/net/dns/mdns_client.h
@@ -177,7 +177,16 @@
   static std::unique_ptr<MDnsClient> CreateDefault();
 };
 
-NET_EXPORT IPEndPoint GetMDnsIPEndPoint(AddressFamily address_family);
+// Gets the endpoint for the multicast group a socket should join to receive
+// MDNS messages. Such sockets should also bind to the endpoint from
+// GetMDnsReceiveEndPoint().
+//
+// This is also the endpoint messages should be sent to to send MDNS messages.
+NET_EXPORT IPEndPoint GetMDnsGroupEndPoint(AddressFamily address_family);
+
+// Gets the endpoint sockets should be bound to to receive MDNS messages. Such
+// sockets should also join the multicast group from GetMDnsGroupEndPoint().
+NET_EXPORT IPEndPoint GetMDnsReceiveEndPoint(AddressFamily address_family);
 
 typedef std::vector<std::pair<uint32_t, AddressFamily>>
     InterfaceIndexFamilyList;
diff --git a/net/dns/mdns_client_impl.cc b/net/dns/mdns_client_impl.cc
index adc5e0f8..ec36c464 100644
--- a/net/dns/mdns_client_impl.cc
+++ b/net/dns/mdns_client_impl.cc
@@ -70,7 +70,7 @@
     return rv;
   DCHECK(end_point.GetFamily() == ADDRESS_FAMILY_IPV4 ||
          end_point.GetFamily() == ADDRESS_FAMILY_IPV6);
-  multicast_addr_ = GetMDnsIPEndPoint(end_point.GetFamily());
+  multicast_addr_ = GetMDnsGroupEndPoint(end_point.GetFamily());
   return DoLoop(0);
 }
 
diff --git a/net/dns/mock_mdns_socket_factory.cc b/net/dns/mock_mdns_socket_factory.cc
index 809ed15..c4037fdc 100644
--- a/net/dns/mock_mdns_socket_factory.cc
+++ b/net/dns/mock_mdns_socket_factory.cc
@@ -20,7 +20,7 @@
 
 MockMDnsDatagramServerSocket::MockMDnsDatagramServerSocket(
     AddressFamily address_family) {
-  local_address_ = GetMDnsIPEndPoint(address_family);
+  local_address_ = GetMDnsReceiveEndPoint(address_family);
 }
 
 MockMDnsDatagramServerSocket::~MockMDnsDatagramServerSocket() = default;
diff --git a/net/dns/mock_mdns_socket_factory.h b/net/dns/mock_mdns_socket_factory.h
index b48b3af..8f0d5b59 100644
--- a/net/dns/mock_mdns_socket_factory.h
+++ b/net/dns/mock_mdns_socket_factory.h
@@ -69,6 +69,7 @@
 
   MOCK_METHOD0(AllowAddressReuse, void());
   MOCK_METHOD0(AllowBroadcast, void());
+  MOCK_METHOD0(AllowAddressSharingForMulticast, void());
 
   MOCK_CONST_METHOD1(JoinGroup, int(const IPAddress& group_address));
   MOCK_CONST_METHOD1(LeaveGroup, int(const IPAddress& address));
diff --git a/net/extras/sqlite/sqlite_persistent_cookie_store.cc b/net/extras/sqlite/sqlite_persistent_cookie_store.cc
index 26414e2..abf4fd7 100644
--- a/net/extras/sqlite/sqlite_persistent_cookie_store.cc
+++ b/net/extras/sqlite/sqlite_persistent_cookie_store.cc
@@ -44,9 +44,14 @@
 namespace {
 
 // Changes the recommended priority of |background_task_runner| to
-// USER_BLOCKING.
-const base::Feature kCookieStorePriorityBoost{
-    "CookieStorePriorityBoost", base::FEATURE_DISABLED_BY_DEFAULT};
+// USER_BLOCKING. ENABLED_BY_DEFAULT because we have verified that this is on
+// the critical path of page load. Still an experiment to allow assessing the
+// impact when the WindowsThreadModeBackground feature is enabled.
+//
+// TODO(fdoray): Remove this feature when experiment is complete.
+// https://crbug.com/872820
+const base::Feature kCookieStorePriorityBoost{"CookieStorePriorityBoost",
+                                              base::FEATURE_ENABLED_BY_DEFAULT};
 
 std::unique_ptr<base::Value> CookieKeyedLoadNetLogCallback(
     const std::string& key,
diff --git a/net/http/http_cache_unittest.cc b/net/http/http_cache_unittest.cc
index 68e3e00..d224ce5c 100644
--- a/net/http/http_cache_unittest.cc
+++ b/net/http/http_cache_unittest.cc
@@ -27,7 +27,7 @@
 #include "base/trace_event/memory_allocator_dump.h"
 #include "base/trace_event/memory_dump_request_args.h"
 #include "base/trace_event/process_memory_dump.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "net/base/cache_type.h"
 #include "net/base/elements_upload_data_stream.h"
 #include "net/base/host_port_pair.h"
diff --git a/net/socket/datagram_server_socket.h b/net/socket/datagram_server_socket.h
index 9793af3..b826d01b 100644
--- a/net/socket/datagram_server_socket.h
+++ b/net/socket/datagram_server_socket.h
@@ -63,14 +63,31 @@
   // Returns a net error code.
   virtual int SetSendBufferSize(int32_t size) = 0;
 
-  // Allow the socket to share the local address to which the socket will
-  // be bound with other processes. Should be called before Listen().
+  // Allow the socket to share the local address to which the socket will be
+  // bound with other processes. If multiple processes are bound to the same
+  // local address at the same time, behavior is undefined; e.g., it is not
+  // guaranteed that incoming messages will be sent to all listening sockets.
+  //
+  // Should be called before Listen().
   virtual void AllowAddressReuse() = 0;
 
   // Allow sending and receiving packets to and from broadcast addresses.
   // Should be called before Listen().
   virtual void AllowBroadcast() = 0;
 
+  // Allow the socket to share the local address to which the socket will be
+  // bound with other processes and attempt to allow all such sockets to receive
+  // the same multicast messages.
+  //
+  // For best cross-platform results in allowing the messages to be shared, all
+  // sockets sharing the same address should join the same multicast group and
+  // interface. Also, the socket should listen to the specific multicast group
+  // address rather than a wildcard address (e.g. 0.0.0.0) on platforms where
+  // doing so is allowed.
+  //
+  // Should be called before Listen().
+  virtual void AllowAddressSharingForMulticast() = 0;
+
   // Join the multicast group with address |group_address|.
   // Returns a network error code.
   virtual int JoinGroup(const IPAddress& group_address) const = 0;
diff --git a/net/socket/udp_server_socket.cc b/net/socket/udp_server_socket.cc
index aae96ac..eb04381 100644
--- a/net/socket/udp_server_socket.cc
+++ b/net/socket/udp_server_socket.cc
@@ -14,7 +14,8 @@
                                  const net::NetLogSource& source)
     : socket_(DatagramSocket::DEFAULT_BIND, net_log, source),
       allow_address_reuse_(false),
-      allow_broadcast_(false) {}
+      allow_broadcast_(false),
+      allow_address_sharing_for_multicast_(false) {}
 
 UDPServerSocket::~UDPServerSocket() = default;
 
@@ -39,6 +40,14 @@
     }
   }
 
+  if (allow_address_sharing_for_multicast_) {
+    rv = socket_.AllowAddressSharingForMulticast();
+    if (rv != OK) {
+      socket_.Close();
+      return rv;
+    }
+  }
+
   return socket_.Bind(address);
 }
 
@@ -96,6 +105,10 @@
   allow_broadcast_ = true;
 }
 
+void UDPServerSocket::AllowAddressSharingForMulticast() {
+  allow_address_sharing_for_multicast_ = true;
+}
+
 int UDPServerSocket::JoinGroup(const IPAddress& group_address) const {
   return socket_.JoinGroup(group_address);
 }
diff --git a/net/socket/udp_server_socket.h b/net/socket/udp_server_socket.h
index a2e9a178..37ba36bba 100644
--- a/net/socket/udp_server_socket.h
+++ b/net/socket/udp_server_socket.h
@@ -47,6 +47,7 @@
   const NetLogWithSource& NetLog() const override;
   void AllowAddressReuse() override;
   void AllowBroadcast() override;
+  void AllowAddressSharingForMulticast() override;
   int JoinGroup(const IPAddress& group_address) const override;
   int LeaveGroup(const IPAddress& group_address) const override;
   int SetMulticastInterface(uint32_t interface_index) override;
@@ -59,6 +60,7 @@
   UDPSocket socket_;
   bool allow_address_reuse_;
   bool allow_broadcast_;
+  bool allow_address_sharing_for_multicast_;
   DISALLOW_COPY_AND_ASSIGN(UDPServerSocket);
 };
 
diff --git a/net/socket/udp_socket_posix.cc b/net/socket/udp_socket_posix.cc
index 04b9e07..b1a5fdb 100644
--- a/net/socket/udp_socket_posix.cc
+++ b/net/socket/udp_socket_posix.cc
@@ -669,6 +669,30 @@
   return rv == 0 ? OK : MapSystemError(errno);
 }
 
+int UDPSocketPosix::AllowAddressSharingForMulticast() {
+  DCHECK_NE(socket_, kInvalidSocket);
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(!is_connected());
+
+  int rv = AllowAddressReuse();
+  if (rv != OK)
+    return rv;
+
+#ifdef SO_REUSEPORT
+  // Attempt to set SO_REUSEPORT if available. On some platforms, this is
+  // necessary to allow the address to be fully shared between separate sockets.
+  // On platforms where the option does not exist, SO_REUSEADDR should be
+  // sufficient to share multicast packets if such sharing is at all possible.
+  int value = 1;
+  rv = setsockopt(socket_, SOL_SOCKET, SO_REUSEPORT, &value, sizeof(value));
+  // Ignore errors that the option does not exist.
+  if (rv != 0 && rv != ENOPROTOOPT)
+    return MapSystemError(errno);
+#endif  // SO_REUSEPORT
+
+  return OK;
+}
+
 void UDPSocketPosix::ReadWatcher::OnFileCanReadWithoutBlocking(int) {
   TRACE_EVENT0(kNetTracingCategory,
                "UDPSocketPosix::ReadWatcher::OnFileCanReadWithoutBlocking");
diff --git a/net/socket/udp_socket_posix.h b/net/socket/udp_socket_posix.h
index 63edbbf..9d9158f 100644
--- a/net/socket/udp_socket_posix.h
+++ b/net/socket/udp_socket_posix.h
@@ -81,7 +81,7 @@
 class NET_EXPORT UDPSocketPosixSender
     : public base::RefCountedThreadSafe<UDPSocketPosixSender> {
  public:
-  explicit UDPSocketPosixSender();
+  UDPSocketPosixSender();
 
   SendResult SendBuffers(int fd, DatagramBuffers buffers);
 
@@ -290,6 +290,19 @@
   // Returns a net error code.
   int SetBroadcast(bool broadcast);
 
+  // Sets socket options to allow the socket to share the local address to which
+  // the socket will be bound with other processes and attempt to allow all such
+  // sockets to receive the same multicast messages. Returns a net error code.
+  //
+  // Ability and requirements for different sockets to receive the same messages
+  // varies between POSIX platforms.  For best results in allowing the messages
+  // to be shared, all sockets sharing the same address should join the same
+  // multicast group and interface. Also, the socket should listen to the
+  // specific multicast address rather than a wildcard address (e.g. 0.0.0.0).
+  //
+  // Should be called between Open() and Bind().
+  int AllowAddressSharingForMulticast();
+
   // Joins the multicast group.
   // |group_address| is the group address to join, could be either
   // an IPv4 or IPv6 address.
@@ -371,7 +384,7 @@
   void enable_experimental_recv_optimization() {
     DCHECK_EQ(kInvalidSocket, socket_);
     experimental_recv_optimization_enabled_ = true;
-  };
+  }
 
  protected:
   // WriteAsync batching etc. are to improve throughput of large high
diff --git a/net/socket/udp_socket_unittest.cc b/net/socket/udp_socket_unittest.cc
index 9a20ccb..c97bde6 100644
--- a/net/socket/udp_socket_unittest.cc
+++ b/net/socket/udp_socket_unittest.cc
@@ -12,6 +12,7 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/run_loop.h"
+#include "base/scoped_clear_last_error.h"
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
@@ -74,8 +75,8 @@
   std::string RecvFromSocket(UDPServerSocket* socket) {
     TestCompletionCallback callback;
 
-    int rv = socket->RecvFrom(
-        buffer_.get(), kMaxRead, &recv_from_address_, callback.callback());
+    int rv = socket->RecvFrom(buffer_.get(), kMaxRead, &recv_from_address_,
+                              callback.callback());
     rv = callback.GetResult(rv);
     if (rv < 0)
       return std::string();
@@ -475,13 +476,11 @@
   EXPECT_THAT(rv, IsOk());
 
   // Server2 sends reply.
-  rv = SendToSocket(&server2, foreign_message,
-                    client_address);
+  rv = SendToSocket(&server2, foreign_message, client_address);
   EXPECT_EQ(foreign_message.length(), static_cast<size_t>(rv));
 
   // Server1 sends reply.
-  rv = SendToSocket(&server1, simple_message,
-                    client_address);
+  rv = SendToSocket(&server1, simple_message, client_address);
   EXPECT_EQ(simple_message.length(), static_cast<size_t>(rv));
 
   // Client waits for response.
@@ -495,17 +494,17 @@
     std::string local_address;
     bool may_fail;
   } tests[] = {
-    { "127.0.00.1", "127.0.0.1", false },
-    { "::1", "::1", true },
+    {"127.0.00.1", "127.0.0.1", false},
+    {"::1", "::1", true},
 #if !defined(OS_ANDROID) && !defined(OS_IOS)
     // Addresses below are disabled on Android. See crbug.com/161248
     // They are also disabled on iOS. See https://crbug.com/523225
-    { "192.168.1.1", "127.0.0.1", false },
-    { "2001:db8:0::42", "::1", true },
+    {"192.168.1.1", "127.0.0.1", false},
+    {"2001:db8:0::42", "::1", true},
 #endif
   };
   for (size_t i = 0; i < arraysize(tests); i++) {
-    SCOPED_TRACE(std::string("Connecting from ") +  tests[i].local_address +
+    SCOPED_TRACE(std::string("Connecting from ") + tests[i].local_address +
                  std::string(" to ") + tests[i].remote_address);
 
     IPAddress ip_address;
@@ -533,7 +532,7 @@
     //                The port is dynamically generated by the udp stack.
     //                The IP is the real IP of the client, not necessarily
     //                loopback.
-    //EXPECT_EQ(local_address.address(), fetched_local_address.address());
+    // EXPECT_EQ(local_address.address(), fetched_local_address.address());
 
     IPEndPoint fetched_remote_address;
     rv = client.GetPeerAddress(&fetched_remote_address);
@@ -629,23 +628,21 @@
   EXPECT_FALSE(callback.have_result());
 }
 
-#if defined(OS_ANDROID)
 // Some Android devices do not support multicast socket.
 // The ones supporting multicast need WifiManager.MulitcastLock to enable it.
 // http://goo.gl/jjAk9
-#define MAYBE_JoinMulticastGroup DISABLED_JoinMulticastGroup
-#else
-#define MAYBE_JoinMulticastGroup JoinMulticastGroup
-#endif  // defined(OS_ANDROID)
-
-TEST_F(UDPSocketTest, MAYBE_JoinMulticastGroup) {
+#ifndef OS_ANDROID
+TEST_F(UDPSocketTest, JoinMulticastGroup) {
   const uint16_t kPort = 9999;
   const char kGroup[] = "237.132.100.17";
 
-  IPEndPoint bind_address;
-  ASSERT_TRUE(CreateUDPAddress("0.0.0.0", kPort, &bind_address));
   IPAddress group_ip;
   EXPECT_TRUE(group_ip.AssignFromIPLiteral(kGroup));
+#ifdef OS_WIN
+  IPEndPoint bind_address(IPAddress::AllZeros(group_ip.size()), kPort);
+#else
+  IPEndPoint bind_address(group_ip, kPort);
+#endif  // OS_WIN
 
   UDPSocket socket(DatagramSocket::DEFAULT_BIND, nullptr, NetLogSource());
   EXPECT_THAT(socket.Open(bind_address.GetFamily()), IsOk());
@@ -672,6 +669,58 @@
   socket.Close();
 }
 
+TEST_F(UDPSocketTest, SharedMulticastAddress) {
+  const uint16_t kPort = 9999;
+  const char kGroup[] = "224.0.0.251";
+
+  IPAddress group_ip;
+  ASSERT_TRUE(group_ip.AssignFromIPLiteral(kGroup));
+  IPEndPoint send_address(group_ip, kPort);
+#ifdef OS_WIN
+  IPEndPoint receive_address(IPAddress::AllZeros(group_ip.size()), kPort);
+#else
+  IPEndPoint receive_address(send_address);
+#endif  // OS_WINDOWS
+
+  NetworkInterfaceList interfaces;
+  ASSERT_TRUE(GetNetworkList(&interfaces, 0));
+  ASSERT_FALSE(interfaces.empty());
+
+  // Setup first receiving socket.
+  UDPServerSocket socket1(nullptr, NetLogSource());
+  socket1.AllowAddressSharingForMulticast();
+  ASSERT_THAT(socket1.SetMulticastInterface(interfaces[0].interface_index),
+              IsOk());
+  ASSERT_THAT(socket1.Listen(receive_address), IsOk());
+  ASSERT_THAT(socket1.JoinGroup(group_ip), IsOk());
+
+  // Setup second receiving socket.
+  UDPServerSocket socket2(nullptr, NetLogSource());
+  socket2.AllowAddressSharingForMulticast(), IsOk();
+  ASSERT_THAT(socket2.SetMulticastInterface(interfaces[0].interface_index),
+              IsOk());
+  ASSERT_THAT(socket2.Listen(receive_address), IsOk());
+  ASSERT_THAT(socket2.JoinGroup(group_ip), IsOk());
+
+  // Setup client socket.
+  UDPClientSocket client_socket(DatagramSocket::DEFAULT_BIND, nullptr,
+                                NetLogSource());
+  ASSERT_THAT(client_socket.Connect(send_address), IsOk());
+
+#ifndef OS_CHROMEOS
+  // Send a message via the multicast group. That message is expected be be
+  // received by both receving sockets.
+  //
+  // Skip on ChromeOS where it's known to sometimes not work.
+  // TODO(crbug.com/898964): If possible, fix and reenable.
+  const char kMessage[] = "hello!";
+  ASSERT_GE(WriteSocket(&client_socket, kMessage), 0);
+  EXPECT_EQ(kMessage, RecvFromSocket(&socket1));
+  EXPECT_EQ(kMessage, RecvFromSocket(&socket2));
+#endif  // OS_CHROMEOS
+}
+#endif  // OS_ANDROID
+
 TEST_F(UDPSocketTest, MulticastOptions) {
   const uint16_t kPort = 9999;
   IPEndPoint bind_address;
@@ -741,9 +790,9 @@
       base::android::SDK_VERSION_LOLLIPOP) {
     EXPECT_EQ(ERR_NOT_IMPLEMENTED, rv);
   } else if (base::android::BuildInfo::GetInstance()->sdk_int() >=
-             base::android::SDK_VERSION_LOLLIPOP &&
+                 base::android::SDK_VERSION_LOLLIPOP &&
              base::android::BuildInfo::GetInstance()->sdk_int() <
-             base::android::SDK_VERSION_MARSHMALLOW) {
+                 base::android::SDK_VERSION_MARSHMALLOW) {
     // On Lollipop, we assume if the user has a NetworkHandle that they must
     // have gotten it from a legitimate source, so if binding to the network
     // fails it's assumed to be because the network went away so
@@ -780,37 +829,36 @@
 
 namespace {
 
-const HANDLE kFakeHandle = (HANDLE)19;
+const HANDLE kFakeHandle1 = (HANDLE)12;
+const HANDLE kFakeHandle2 = (HANDLE)13;
+
 const QOS_FLOWID kFakeFlowId1 = (QOS_FLOWID)27;
 const QOS_FLOWID kFakeFlowId2 = (QOS_FLOWID)38;
 
 class TestUDPSocketWin : public UDPSocketWin {
  public:
-  TestUDPSocketWin(QwaveAPI& qos,
+  TestUDPSocketWin(QwaveApi* qos,
                    DatagramSocket::BindType bind_type,
                    net::NetLog* net_log,
                    const net::NetLogSource& source)
       : UDPSocketWin(bind_type, net_log, source), qos_(qos) {}
 
-  // Overriding GetQwaveAPI causes the test class to use the injected mock
-  // QwaveAPI instance instead of the singleton.  Ensure close is called in the
-  // child destructor before our mock CloseHandle is uninstalled.
-  ~TestUDPSocketWin() override { UDPSocketWin::Close(); }
-
-  QwaveAPI& GetQwaveAPI() override { return qos_; }
+  // Overriding GetQwaveApi causes the test class to use the injected mock
+  // QwaveApi instance instead of the singleton.
+  QwaveApi* GetQwaveApi() const override { return qos_; }
 
  private:
-  QwaveAPI& qos_;
+  QwaveApi* qos_;
 
   DISALLOW_COPY_AND_ASSIGN(TestUDPSocketWin);
 };
 
-class MockQwaveAPI : public QwaveAPI {
+class MockQwaveApi : public QwaveApi {
  public:
-  bool qwave_supported() const override { return true; }
+  MOCK_CONST_METHOD0(qwave_supported, bool());
+  MOCK_METHOD0(OnFatalError, void());
   MOCK_METHOD2(CreateHandle, BOOL(PQOS_VERSION version, PHANDLE handle));
   MOCK_METHOD1(CloseHandle, BOOL(HANDLE handle));
-
   MOCK_METHOD6(AddSocketToFlow,
                BOOL(HANDLE handle,
                     SOCKET socket,
@@ -832,50 +880,69 @@
                     LPOVERLAPPED overlapped));
 };
 
-std::unique_ptr<UDPSocket> OpenedDscpTestClient(QwaveAPI& qos,
+std::unique_ptr<UDPSocket> OpenedDscpTestClient(QwaveApi* api,
                                                 IPEndPoint bind_address) {
   auto client = std::make_unique<TestUDPSocketWin>(
-      qos, DatagramSocket::DEFAULT_BIND, nullptr, NetLogSource());
+      api, DatagramSocket::DEFAULT_BIND, nullptr, NetLogSource());
   int rv = client->Open(bind_address.GetFamily());
   EXPECT_THAT(rv, IsOk());
 
   return client;
 }
 
-std::unique_ptr<UDPSocket> ConnectedDscpTestClient(QwaveAPI& qos) {
+std::unique_ptr<UDPSocket> ConnectedDscpTestClient(QwaveApi* api) {
   IPEndPoint bind_address;
   // We need a real IP, but we won't actually send anything to it.
   EXPECT_TRUE(CreateUDPAddress("8.8.8.8", 9999, &bind_address));
-  auto client = OpenedDscpTestClient(qos, bind_address);
+  auto client = OpenedDscpTestClient(api, bind_address);
   EXPECT_THAT(client->Connect(bind_address), IsOk());
   return client;
 }
 
-std::unique_ptr<UDPSocket> UnconnectedDscpTestClient(QwaveAPI& qos) {
+std::unique_ptr<UDPSocket> UnconnectedDscpTestClient(QwaveApi* api) {
   IPEndPoint bind_address;
   EXPECT_TRUE(CreateUDPAddress("0.0.0.0", 9999, &bind_address));
-  auto client = OpenedDscpTestClient(qos, bind_address);
+  auto client = OpenedDscpTestClient(api, bind_address);
   EXPECT_THAT(client->Bind(bind_address), IsOk());
   return client;
 }
 
 }  // namespace
 
-using ::testing::_;
 using ::testing::Return;
 using ::testing::SetArgPointee;
+using ::testing::_;
 
 TEST_F(UDPSocketTest, SetDSCPNoopIfPassedNoChange) {
-  MockQwaveAPI qos;
-  std::unique_ptr<UDPSocket> client = ConnectedDscpTestClient(qos);
+  MockQwaveApi api;
+  EXPECT_CALL(api, qwave_supported()).WillRepeatedly(Return(true));
+
+  EXPECT_CALL(api, AddSocketToFlow(_, _, _, _, _, _)).Times(0);
+  std::unique_ptr<UDPSocket> client = ConnectedDscpTestClient(&api);
   EXPECT_THAT(client->SetDiffServCodePoint(DSCP_NO_CHANGE), IsOk());
 }
 
-TEST_F(UDPSocketTest, SetDSCPFailsIfQOSHandleCanNotBeCreated) {
-  MockQwaveAPI qos;
-  EXPECT_CALL(qos, CreateHandle(_, _)).WillOnce(Return(false));
-  std::unique_ptr<UDPSocket> client = ConnectedDscpTestClient(qos);
+TEST_F(UDPSocketTest, SetDSCPFailsIfQOSDoesntLink) {
+  MockQwaveApi api;
+  EXPECT_CALL(api, qwave_supported()).WillRepeatedly(Return(false));
+  EXPECT_CALL(api, CreateHandle(_, _)).Times(0);
 
+  std::unique_ptr<UDPSocket> client = ConnectedDscpTestClient(&api);
+  EXPECT_EQ(ERR_NOT_IMPLEMENTED, client->SetDiffServCodePoint(DSCP_AF41));
+}
+
+TEST_F(UDPSocketTest, SetDSCPFailsIfHandleCantBeCreated) {
+  MockQwaveApi api;
+  EXPECT_CALL(api, qwave_supported()).WillRepeatedly(Return(true));
+  EXPECT_CALL(api, CreateHandle(_, _)).WillOnce(Return(false));
+  EXPECT_CALL(api, OnFatalError()).Times(1);
+
+  std::unique_ptr<UDPSocket> client = ConnectedDscpTestClient(&api);
+  EXPECT_EQ(ERR_INVALID_HANDLE, client->SetDiffServCodePoint(DSCP_AF41));
+
+  RunUntilIdle();
+
+  EXPECT_CALL(api, qwave_supported()).WillRepeatedly(Return(false));
   EXPECT_EQ(ERR_NOT_IMPLEMENTED, client->SetDiffServCodePoint(DSCP_AF41));
 }
 
@@ -883,61 +950,68 @@
   return *(DWORD*)arg == (DWORD)dscp;
 }
 
-TEST_F(UDPSocketTest, SetDSCPCallsQwaveFunctions) {
-  MockQwaveAPI qos;
-  std::unique_ptr<UDPSocket> client = ConnectedDscpTestClient(qos);
+TEST_F(UDPSocketTest, ConnectedSocketDelayedInitAndUpdate) {
+  MockQwaveApi api;
+  std::unique_ptr<UDPSocket> client = ConnectedDscpTestClient(&api);
+  EXPECT_CALL(api, qwave_supported()).WillRepeatedly(Return(true));
+  EXPECT_CALL(api, CreateHandle(_, _))
+      .WillOnce(DoAll(SetArgPointee<1>(kFakeHandle1), Return(true)));
 
-  EXPECT_CALL(qos, CreateHandle(_, _))
-      .WillOnce(DoAll(SetArgPointee<1>(kFakeHandle), Return(true)));
-  // AddSocketToFlow also sets flow_id, but we don't use that here
-  EXPECT_CALL(qos, AddSocketToFlow(_, _, _, QOSTrafficTypeAudioVideo, _, _))
-      .WillOnce(Return(true));
-  EXPECT_CALL(qos, SetFlow(_, _, QOSSetOutgoingDSCPValue, _,
-                           DscpPointee(DSCP_AF41), _, _));
-  EXPECT_THAT(client->SetDiffServCodePoint(DSCP_AF41), IsOk());
-  EXPECT_CALL(qos, CloseHandle(kFakeHandle));
-}
-
-TEST_F(UDPSocketTest, SecondSetDSCPCallsQwaveFunctions) {
-  MockQwaveAPI qos;
-  std::unique_ptr<UDPSocket> client = ConnectedDscpTestClient(qos);
-
-  EXPECT_CALL(qos, CreateHandle(_, _))
-      .WillOnce(DoAll(SetArgPointee<1>(kFakeHandle), Return(true)));
-
-  EXPECT_CALL(qos, AddSocketToFlow(_, _, _, _, _, _))
+  EXPECT_CALL(api, AddSocketToFlow(_, _, _, _, _, _))
       .WillOnce(DoAll(SetArgPointee<5>(kFakeFlowId1), Return(true)));
-  EXPECT_CALL(qos, SetFlow(_, _, _, _, _, _, _));
+  EXPECT_CALL(api, SetFlow(_, _, _, _, _, _, _));
+
+  // First set on connected sockets will fail since init is async and
+  // we haven't given the runloop a chance to execute the callback.
+  EXPECT_EQ(ERR_INVALID_HANDLE, client->SetDiffServCodePoint(DSCP_AF41));
+  RunUntilIdle();
   EXPECT_THAT(client->SetDiffServCodePoint(DSCP_AF41), IsOk());
 
   // New dscp value should reset the flow.
-  EXPECT_CALL(qos, RemoveSocketFromFlow(_, _, _, _));
-  EXPECT_CALL(qos, AddSocketToFlow(_, _, _, QOSTrafficTypeBestEffort, _, _))
+  EXPECT_CALL(api, RemoveSocketFromFlow(_, _, kFakeFlowId1, _));
+  EXPECT_CALL(api, AddSocketToFlow(_, _, _, QOSTrafficTypeBestEffort, _, _))
       .WillOnce(DoAll(SetArgPointee<5>(kFakeFlowId2), Return(true)));
-  EXPECT_CALL(qos, SetFlow(_, _, QOSSetOutgoingDSCPValue, _,
+  EXPECT_CALL(api, SetFlow(_, _, QOSSetOutgoingDSCPValue, _,
                            DscpPointee(DSCP_DEFAULT), _, _));
   EXPECT_THAT(client->SetDiffServCodePoint(DSCP_DEFAULT), IsOk());
 
   // Called from DscpManager destructor.
-  EXPECT_CALL(qos, RemoveSocketFromFlow(_, _, _, _));
-  EXPECT_CALL(qos, CloseHandle(kFakeHandle));
+  EXPECT_CALL(api, RemoveSocketFromFlow(_, _, kFakeFlowId2, _));
+  EXPECT_CALL(api, CloseHandle(kFakeHandle1));
+}
+
+TEST_F(UDPSocketTest, UnonnectedSocketDelayedInitAndUpdate) {
+  MockQwaveApi api;
+  EXPECT_CALL(api, qwave_supported()).WillRepeatedly(Return(true));
+  EXPECT_CALL(api, CreateHandle(_, _))
+      .WillOnce(DoAll(SetArgPointee<1>(kFakeHandle1), Return(true)));
+
+  // CreateHandle won't have completed yet.  Set passes.
+  std::unique_ptr<UDPSocket> client = UnconnectedDscpTestClient(&api);
+  EXPECT_THAT(client->SetDiffServCodePoint(DSCP_AF41), IsOk());
+
+  RunUntilIdle();
+  EXPECT_THAT(client->SetDiffServCodePoint(DSCP_AF42), IsOk());
+
+  // Called from DscpManager destructor.
+  EXPECT_CALL(api, CloseHandle(kFakeHandle1));
 }
 
 // TODO(zstein): Mocking out DscpManager might be simpler here
 // (just verify that DscpManager::Set and DscpManager::PrepareForSend are
 // called).
 TEST_F(UDPSocketTest, SendToCallsQwaveApis) {
-  MockQwaveAPI qos;
-  std::unique_ptr<UDPSocket> client = UnconnectedDscpTestClient(qos);
-
-  EXPECT_CALL(qos, CreateHandle(_, _))
-      .WillOnce(DoAll(SetArgPointee<1>(kFakeHandle), Return(true)));
+  MockQwaveApi api;
+  std::unique_ptr<UDPSocket> client = UnconnectedDscpTestClient(&api);
+  EXPECT_CALL(api, qwave_supported()).WillRepeatedly(Return(true));
+  EXPECT_CALL(api, CreateHandle(_, _))
+      .WillOnce(DoAll(SetArgPointee<1>(kFakeHandle1), Return(true)));
   EXPECT_THAT(client->SetDiffServCodePoint(DSCP_AF41), IsOk());
+  RunUntilIdle();
 
-  EXPECT_CALL(qos, AddSocketToFlow(_, _, _, _, _, _))
+  EXPECT_CALL(api, AddSocketToFlow(_, _, _, _, _, _))
       .WillOnce(DoAll(SetArgPointee<5>(kFakeFlowId1), Return(true)));
-  EXPECT_CALL(qos, SetFlow(_, _, _, _, _, _, _));
-
+  EXPECT_CALL(api, SetFlow(_, _, _, _, _, _, _));
   std::string simple_message("hello world");
   IPEndPoint server_address(IPAddress::IPv4Localhost(), 9438);
   int rv = SendToSocket(client.get(), simple_message, server_address);
@@ -949,89 +1023,175 @@
 
   // TODO(zstein): Move to third test case (Qwave APIs called for each
   // destination address).
-  EXPECT_CALL(qos, AddSocketToFlow(_, _, _, _, _, _)).WillOnce(Return(true));
+  EXPECT_CALL(api, AddSocketToFlow(_, _, _, _, _, _)).WillOnce(Return(true));
   IPEndPoint server_address2(IPAddress::IPv4Localhost(), 9439);
 
   rv = SendToSocket(client.get(), simple_message, server_address2);
   EXPECT_EQ(simple_message.length(), static_cast<size_t>(rv));
 
   // Called from DscpManager destructor.
-  EXPECT_CALL(qos, RemoveSocketFromFlow(_, _, _, _));
-  EXPECT_CALL(qos, CloseHandle(kFakeHandle));
+  EXPECT_CALL(api, RemoveSocketFromFlow(_, _, _, _));
+  EXPECT_CALL(api, CloseHandle(kFakeHandle1));
 }
 
-class DscpManagerTest : public testing::Test {
+TEST_F(UDPSocketTest, SendToCallsApisAfterDeferredInit) {
+  MockQwaveApi api;
+  std::unique_ptr<UDPSocket> client = UnconnectedDscpTestClient(&api);
+  EXPECT_CALL(api, qwave_supported()).WillRepeatedly(Return(true));
+  EXPECT_CALL(api, CreateHandle(_, _))
+      .WillOnce(DoAll(SetArgPointee<1>(kFakeHandle1), Return(true)));
+
+  // SetDiffServCodepoint works even if qos api hasn't finished initing.
+  EXPECT_THAT(client->SetDiffServCodePoint(DSCP_CS7), IsOk());
+
+  std::string simple_message("hello world");
+  IPEndPoint server_address(IPAddress::IPv4Localhost(), 9438);
+
+  // SendTo works, but doesn't yet apply TOS
+  EXPECT_CALL(api, AddSocketToFlow(_, _, _, _, _, _)).Times(0);
+  int rv = SendToSocket(client.get(), simple_message, server_address);
+  EXPECT_EQ(simple_message.length(), static_cast<size_t>(rv));
+
+  RunUntilIdle();
+  // Now we're initialized, SendTo triggers qos calls with correct codepoint.
+  EXPECT_CALL(api, AddSocketToFlow(_, _, _, QOSTrafficTypeControl, _, _))
+      .WillOnce(DoAll(SetArgPointee<5>(kFakeFlowId1), Return(true)));
+  EXPECT_CALL(api, SetFlow(_, _, _, _, _, _, _)).WillOnce(Return(true));
+  rv = SendToSocket(client.get(), simple_message, server_address);
+  EXPECT_EQ(simple_message.length(), static_cast<size_t>(rv));
+
+  // Called from DscpManager destructor.
+  EXPECT_CALL(api, RemoveSocketFromFlow(_, _, kFakeFlowId1, _));
+  EXPECT_CALL(api, CloseHandle(kFakeHandle1));
+}
+
+class DscpManagerTest : public TestWithScopedTaskEnvironment {
  protected:
-  DscpManagerTest() : dscp_manager_(qos_, INVALID_SOCKET, (HANDLE)0) {
+  DscpManagerTest() {
+    EXPECT_CALL(api_, qwave_supported()).WillRepeatedly(Return(true));
+    EXPECT_CALL(api_, CreateHandle(_, _))
+        .WillOnce(DoAll(SetArgPointee<1>(kFakeHandle1), Return(true)));
+    dscp_manager_ = std::make_unique<DscpManager>(&api_, INVALID_SOCKET);
+
     CreateUDPAddress("1.2.3.4", 9001, &address1_);
     CreateUDPAddress("1234:5678:90ab:cdef:1234:5678:90ab:cdef", 9002,
                      &address2_);
   }
 
-  MockQwaveAPI qos_;
-  DscpManager dscp_manager_;
+  MockQwaveApi api_;
+  std::unique_ptr<DscpManager> dscp_manager_;
 
   IPEndPoint address1_;
   IPEndPoint address2_;
 };
 
 TEST_F(DscpManagerTest, PrepareForSendIsNoopIfNoSet) {
-  dscp_manager_.PrepareForSend(address1_);
+  RunUntilIdle();
+  dscp_manager_->PrepareForSend(address1_);
 }
 
 TEST_F(DscpManagerTest, PrepareForSendCallsQwaveApisAfterSet) {
-  dscp_manager_.Set(DSCP_CS2);
+  RunUntilIdle();
+  dscp_manager_->Set(DSCP_CS2);
 
   // AddSocketToFlow should be called for each address.
-  EXPECT_CALL(qos_, AddSocketToFlow(_, _, _, _, _, _))
-      .WillOnce(DoAll(SetArgPointee<5>(kFakeFlowId1), Return(true)))
-      .WillOnce(Return(true));
   // SetFlow should only be called when the flow is first created.
-  EXPECT_CALL(qos_, SetFlow(_, _, _, _, _, _, _));
-  dscp_manager_.PrepareForSend(address1_);
-  EXPECT_CALL(qos_, SetFlow(_, _, _, _, _, _, _)).Times(0);
-  dscp_manager_.PrepareForSend(address2_);
+  EXPECT_CALL(api_, AddSocketToFlow(_, _, _, _, _, _))
+      .WillOnce(DoAll(SetArgPointee<5>(kFakeFlowId1), Return(true)));
+  EXPECT_CALL(api_, SetFlow(_, kFakeFlowId1, _, _, _, _, _));
+  dscp_manager_->PrepareForSend(address1_);
+
+  EXPECT_CALL(api_, AddSocketToFlow(_, _, _, _, _, _))
+      .WillOnce(DoAll(SetArgPointee<5>(kFakeFlowId1), Return(true)));
+  EXPECT_CALL(api_, SetFlow(_, _, _, _, _, _, _)).Times(0);
+  dscp_manager_->PrepareForSend(address2_);
 
   // Called from DscpManager destructor.
-  EXPECT_CALL(qos_, RemoveSocketFromFlow(_, _, _, _));
+  EXPECT_CALL(api_, RemoveSocketFromFlow(_, _, kFakeFlowId1, _));
+  EXPECT_CALL(api_, CloseHandle(kFakeHandle1));
 }
 
 TEST_F(DscpManagerTest, PrepareForSendCallsQwaveApisOncePerAddress) {
-  dscp_manager_.Set(DSCP_CS2);
+  RunUntilIdle();
+  dscp_manager_->Set(DSCP_CS2);
 
-  EXPECT_CALL(qos_, AddSocketToFlow(_, _, _, _, _, _))
+  EXPECT_CALL(api_, AddSocketToFlow(_, _, _, _, _, _))
       .WillOnce(DoAll(SetArgPointee<5>(kFakeFlowId1), Return(true)));
-  EXPECT_CALL(qos_, SetFlow(_, _, _, _, _, _, _));
-  dscp_manager_.PrepareForSend(address1_);
-  EXPECT_CALL(qos_, AddSocketToFlow(_, _, _, _, _, _)).Times(0);
-  EXPECT_CALL(qos_, SetFlow(_, _, _, _, _, _, _)).Times(0);
-  dscp_manager_.PrepareForSend(address1_);
+  EXPECT_CALL(api_, SetFlow(_, kFakeFlowId1, _, _, _, _, _));
+  dscp_manager_->PrepareForSend(address1_);
+  EXPECT_CALL(api_, AddSocketToFlow(_, _, _, _, _, _)).Times(0);
+  EXPECT_CALL(api_, SetFlow(_, _, _, _, _, _, _)).Times(0);
+  dscp_manager_->PrepareForSend(address1_);
 
   // Called from DscpManager destructor.
-  EXPECT_CALL(qos_, RemoveSocketFromFlow(_, _, _, _));
+  EXPECT_CALL(api_, RemoveSocketFromFlow(_, _, kFakeFlowId1, _));
+  EXPECT_CALL(api_, CloseHandle(kFakeHandle1));
 }
 
-TEST_F(DscpManagerTest, SetDestroysExistingFlowAndResetsPrepareState) {
-  dscp_manager_.Set(DSCP_CS2);
-  EXPECT_CALL(qos_, AddSocketToFlow(_, _, _, _, _, _))
+TEST_F(DscpManagerTest, SetDestroysExistingFlow) {
+  RunUntilIdle();
+  dscp_manager_->Set(DSCP_CS2);
+
+  EXPECT_CALL(api_, AddSocketToFlow(_, _, _, _, _, _))
       .WillOnce(DoAll(SetArgPointee<5>(kFakeFlowId1), Return(true)));
-  EXPECT_CALL(qos_, SetFlow(_, _, _, _, _, _, _));
-  dscp_manager_.PrepareForSend(address1_);
+  EXPECT_CALL(api_, SetFlow(_, kFakeFlowId1, _, _, _, _, _));
+  dscp_manager_->PrepareForSend(address1_);
 
   // Calling Set should destroy the existing flow.
   // TODO(zstein): Verify that RemoveSocketFromFlow with no address
   // destroys the flow for all destinations.
-  EXPECT_CALL(qos_, RemoveSocketFromFlow(_, NULL, kFakeFlowId1, _));
-  dscp_manager_.Set(DSCP_CS5);
+  EXPECT_CALL(api_, RemoveSocketFromFlow(_, NULL, kFakeFlowId1, _));
+  dscp_manager_->Set(DSCP_CS5);
 
-  EXPECT_CALL(qos_, AddSocketToFlow(_, _, _, _, _, _))
+  EXPECT_CALL(api_, AddSocketToFlow(_, _, _, _, _, _))
       .WillOnce(DoAll(SetArgPointee<5>(kFakeFlowId2), Return(true)));
-  EXPECT_CALL(qos_, SetFlow(_, _, _, _, _, _, _));
-  dscp_manager_.PrepareForSend(address1_);
+  EXPECT_CALL(api_, SetFlow(_, kFakeFlowId2, _, _, _, _, _));
+  dscp_manager_->PrepareForSend(address1_);
 
   // Called from DscpManager destructor.
-  EXPECT_CALL(qos_, RemoveSocketFromFlow(_, _, kFakeFlowId2, _));
+  EXPECT_CALL(api_, RemoveSocketFromFlow(_, _, kFakeFlowId2, _));
+  EXPECT_CALL(api_, CloseHandle(kFakeHandle1));
 }
+
+TEST_F(DscpManagerTest, SocketReAddedOnRecreateHandle) {
+  RunUntilIdle();
+  dscp_manager_->Set(DSCP_CS2);
+
+  // First Set and Send work fine.
+  EXPECT_CALL(api_, AddSocketToFlow(_, _, _, _, _, _))
+      .WillOnce(DoAll(SetArgPointee<5>(kFakeFlowId1), Return(true)));
+  EXPECT_CALL(api_, SetFlow(_, kFakeFlowId1, _, _, _, _, _))
+      .WillOnce(Return(true));
+  EXPECT_THAT(dscp_manager_->PrepareForSend(address1_), IsOk());
+
+  // Make Second flow operation fail (requires resetting the codepoint).
+  EXPECT_CALL(api_, RemoveSocketFromFlow(_, _, kFakeFlowId1, _))
+      .WillOnce(Return(true));
+  dscp_manager_->Set(DSCP_CS7);
+
+  auto error = std::make_unique<base::internal::ScopedClearLastError>();
+  ::SetLastError(ERROR_DEVICE_REINITIALIZATION_NEEDED);
+  EXPECT_CALL(api_, AddSocketToFlow(_, _, _, _, _, _)).WillOnce(Return(false));
+  EXPECT_CALL(api_, SetFlow(_, _, _, _, _, _, _)).Times(0);
+  EXPECT_CALL(api_, CloseHandle(kFakeHandle1));
+  EXPECT_CALL(api_, CreateHandle(_, _))
+      .WillOnce(DoAll(SetArgPointee<1>(kFakeHandle2), Return(true)));
+  EXPECT_EQ(ERR_INVALID_HANDLE, dscp_manager_->PrepareForSend(address1_));
+  error = nullptr;
+  RunUntilIdle();
+
+  // Next Send should work fine, without requiring another Set
+  EXPECT_CALL(api_, AddSocketToFlow(_, _, _, QOSTrafficTypeControl, _, _))
+      .WillOnce(DoAll(SetArgPointee<5>(kFakeFlowId2), Return(true)));
+  EXPECT_CALL(api_, SetFlow(_, kFakeFlowId2, _, _, _, _, _))
+      .WillOnce(Return(true));
+  EXPECT_THAT(dscp_manager_->PrepareForSend(address1_), IsOk());
+
+  // Called from DscpManager destructor.
+  EXPECT_CALL(api_, RemoveSocketFromFlow(_, _, kFakeFlowId2, _));
+  EXPECT_CALL(api_, CloseHandle(kFakeHandle2));
+}
+
 #endif
 
 TEST_F(UDPSocketTest, ReadWithSocketOptimization) {
diff --git a/net/socket/udp_socket_win.cc b/net/socket/udp_socket_win.cc
index d7c01f7..389b91b 100644
--- a/net/socket/udp_socket_win.cc
+++ b/net/socket/udp_socket_win.cc
@@ -13,6 +13,7 @@
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/rand_util.h"
+#include "base/task/post_task.h"
 #include "net/base/io_buffer.h"
 #include "net/base/ip_address.h"
 #include "net/base/ip_endpoint.h"
@@ -167,7 +168,7 @@
 }
 //-----------------------------------------------------------------------------
 
-QwaveAPI::QwaveAPI() : qwave_supported_(false) {
+QwaveApi::QwaveApi() : qwave_supported_(false) {
   HMODULE qwave = LoadLibrary(L"qwave.dll");
   if (!qwave)
     return;
@@ -188,60 +189,56 @@
   }
 }
 
-QwaveAPI& QwaveAPI::Get() {
-  static base::LazyInstance<QwaveAPI>::Leaky lazy_qwave =
-    LAZY_INSTANCE_INITIALIZER;
-  return lazy_qwave.Get();
+QwaveApi* QwaveApi::GetDefault() {
+  static base::LazyInstance<QwaveApi>::Leaky lazy_qwave =
+      LAZY_INSTANCE_INITIALIZER;
+  return lazy_qwave.Pointer();
 }
 
-bool QwaveAPI::qwave_supported() const {
+bool QwaveApi::qwave_supported() const {
   return qwave_supported_;
 }
-BOOL QwaveAPI::CreateHandle(PQOS_VERSION version, PHANDLE handle) {
+
+void QwaveApi::OnFatalError() {
+  // Disable everything moving forward.
+  qwave_supported_ = false;
+}
+
+BOOL QwaveApi::CreateHandle(PQOS_VERSION version, PHANDLE handle) {
   return create_handle_func_(version, handle);
 }
-BOOL QwaveAPI::CloseHandle(HANDLE handle) {
+
+BOOL QwaveApi::CloseHandle(HANDLE handle) {
   return close_handle_func_(handle);
 }
 
-BOOL QwaveAPI::AddSocketToFlow(HANDLE handle,
+BOOL QwaveApi::AddSocketToFlow(HANDLE handle,
                                SOCKET socket,
                                PSOCKADDR addr,
                                QOS_TRAFFIC_TYPE traffic_type,
                                DWORD flags,
                                PQOS_FLOWID flow_id) {
-  return add_socket_to_flow_func_(handle,
-                                  socket,
-                                  addr,
-                                  traffic_type,
-                                  flags,
+  return add_socket_to_flow_func_(handle, socket, addr, traffic_type, flags,
                                   flow_id);
 }
 
-BOOL QwaveAPI::RemoveSocketFromFlow(HANDLE handle,
+BOOL QwaveApi::RemoveSocketFromFlow(HANDLE handle,
                                     SOCKET socket,
                                     QOS_FLOWID flow_id,
                                     DWORD reserved) {
   return remove_socket_from_flow_func_(handle, socket, flow_id, reserved);
 }
 
-BOOL QwaveAPI::SetFlow(HANDLE handle,
+BOOL QwaveApi::SetFlow(HANDLE handle,
                        QOS_FLOWID flow_id,
                        QOS_SET_FLOW op,
                        ULONG size,
                        PVOID data,
                        DWORD reserved,
                        LPOVERLAPPED overlapped) {
-  return set_flow_func_(handle,
-                        flow_id,
-                        op,
-                        size,
-                        data,
-                        reserved,
-                        overlapped);
+  return set_flow_func_(handle, flow_id, op, size, data, reserved, overlapped);
 }
 
-
 //-----------------------------------------------------------------------------
 
 UDPSocketWin::UDPSocketWin(DatagramSocket::BindType bind_type,
@@ -259,7 +256,6 @@
       write_iobuffer_len_(0),
       recv_from_address_(nullptr),
       net_log_(NetLogWithSource::Make(net_log, NetLogSourceType::UDP_SOCKET)),
-      qos_handle_(nullptr),
       event_pending_(this) {
   EnsureWinsockInit();
   net_log_.BeginEvent(NetLogEventType::SOCKET_ALIVE,
@@ -295,11 +291,8 @@
   if (socket_ == INVALID_SOCKET)
     return;
 
-  if (qos_handle_) {
-    GetQwaveAPI().CloseHandle(qos_handle_);
-    dscp_manager_ = nullptr;
-    qos_handle_ = NULL;
-  }
+  // Remove socket_ from the QoS subsystem before we invalidate it.
+  dscp_manager_ = nullptr;
 
   // Zero out any pending read/write callback state.
   read_callback_.Reset();
@@ -600,6 +593,13 @@
   return rv == 0 ? OK : MapSystemError(WSAGetLastError());
 }
 
+int UDPSocketWin::AllowAddressSharingForMulticast() {
+  // When proper multicast groups are used, Windows further defines the address
+  // resuse option (SO_REUSEADDR) to ensure all listening sockets can receive
+  // all incoming messages for the multicast group.
+  return AllowAddressReuse();
+}
+
 void UDPSocketWin::DoReadCallback(int rv) {
   DCHECK_NE(rv, ERR_IO_PENDING);
   DCHECK(!read_callback_.is_null());
@@ -1015,8 +1015,8 @@
   return DoBind(IPEndPoint(address, 0));
 }
 
-QwaveAPI& UDPSocketWin::GetQwaveAPI() {
-  return QwaveAPI::Get();
+QwaveApi* UDPSocketWin::GetQwaveApi() const {
+  return QwaveApi::GetDefault();
 }
 
 int UDPSocketWin::JoinGroup(const IPAddress& group_address) const {
@@ -1178,22 +1178,13 @@
   if (!is_connected())
     return ERR_SOCKET_NOT_CONNECTED;
 
-  QwaveAPI& qos(GetQwaveAPI());
+  QwaveApi* api = GetQwaveApi();
 
-  if (!qos.qwave_supported())
+  if (!api->qwave_supported())
     return ERR_NOT_IMPLEMENTED;
 
-  if (!qos_handle_) {
-    QOS_VERSION version;
-    version.MajorVersion = 1;
-    version.MinorVersion = 0;
-    qos.CreateHandle(&version, &qos_handle_);
-    if (!qos_handle_)
-      return ERR_NOT_IMPLEMENTED;
-  }
-
   if (!dscp_manager_)
-    dscp_manager_ = std::make_unique<DscpManager>(qos, socket_, qos_handle_);
+    dscp_manager_ = std::make_unique<DscpManager>(api, socket_);
 
   dscp_manager_->Set(dscp);
   if (remote_address_)
@@ -1248,12 +1239,19 @@
   NOTIMPLEMENTED();
   return result;
 }
-DscpManager::DscpManager(QwaveAPI& qos, SOCKET socket, HANDLE qos_handle)
-    : qos_(qos), socket_(socket), qos_handle_(qos_handle) {}
+DscpManager::DscpManager(QwaveApi* api, SOCKET socket)
+    : api_(api), socket_(socket), weak_ptr_factory_(this) {
+  RequestHandle();
+}
 
 DscpManager::~DscpManager() {
+  if (!qos_handle_)
+    return;
+
   if (flow_id_ != 0)
-    qos_.RemoveSocketFromFlow(qos_handle_, NULL, flow_id_, 0);
+    api_->RemoveSocketFromFlow(qos_handle_, NULL, flow_id_, 0);
+
+  api_->CloseHandle(qos_handle_);
 }
 
 void DscpManager::Set(DiffServCodePoint dscp) {
@@ -1261,10 +1259,11 @@
     return;
 
   dscp_value_ = dscp;
+
   // TODO(zstein): We could reuse the flow when the value changes
   // by calling QOSSetFlow with the new traffic type and dscp value.
-  if (flow_id_ != 0) {
-    qos_.RemoveSocketFromFlow(qos_handle_, NULL, flow_id_, 0);
+  if (flow_id_ != 0 && qos_handle_) {
+    api_->RemoveSocketFromFlow(qos_handle_, NULL, flow_id_, 0);
     configured_.clear();
     flow_id_ = 0;
   }
@@ -1276,6 +1275,12 @@
     return OK;
   }
 
+  if (!api_->qwave_supported())
+    return ERR_NOT_IMPLEMENTED;
+
+  if (!qos_handle_)
+    return ERR_INVALID_HANDLE;  // The closest net error to try again later.
+
   if (configured_.find(remote_address) != configured_.end())
     return OK;
 
@@ -1283,7 +1288,7 @@
   if (!remote_address.ToSockAddr(storage.addr, &storage.addr_len))
     return ERR_ADDRESS_INVALID;
 
-  // We won't try again if we get an error.
+  // We won't try this address again if we get an error.
   configured_.emplace(remote_address);
 
   // We don't need to call SetFlow if we already have a qos flow.
@@ -1291,14 +1296,18 @@
 
   const QOS_TRAFFIC_TYPE traffic_type = DscpToTrafficType(dscp_value_);
 
-  if (!qos_.AddSocketToFlow(qos_handle_, socket_, storage.addr, traffic_type,
-                            QOS_NON_ADAPTIVE_FLOW, &flow_id_)) {
-    DWORD err = GetLastError();
+  if (!api_->AddSocketToFlow(qos_handle_, socket_, storage.addr, traffic_type,
+                             QOS_NON_ADAPTIVE_FLOW, &flow_id_)) {
+    DWORD err = ::GetLastError();
     if (err == ERROR_DEVICE_REINITIALIZATION_NEEDED) {
-      qos_.CloseHandle(qos_handle_);
+      // Reset. PrepareForSend is called for every packet.  Once RequestHandle
+      // completes asynchronously the next PrepareForSend call will re-register
+      // the address with the new QoS Handle.  In the meantime, sends will
+      // continue without DSCP.
+      RequestHandle();
+      configured_.clear();
       flow_id_ = 0;
-      qos_handle_ = 0;
-      dscp_value_ = DSCP_NO_CHANGE;
+      return ERR_INVALID_HANDLE;
     }
     return MapSystemError(err);
   }
@@ -1307,11 +1316,58 @@
     DWORD buf = dscp_value_;
     // This requires admin rights, and may fail, if so we ignore it
     // as AddSocketToFlow should still do *approximately* the right thing.
-    qos_.SetFlow(qos_handle_, flow_id_, QOSSetOutgoingDSCPValue, sizeof(buf),
-                 &buf, 0, nullptr);
+    api_->SetFlow(qos_handle_, flow_id_, QOSSetOutgoingDSCPValue, sizeof(buf),
+                  &buf, 0, nullptr);
   }
 
   return OK;
 }
 
+void DscpManager::RequestHandle() {
+  if (handle_is_initializing_)
+    return;
+
+  if (qos_handle_) {
+    api_->CloseHandle(qos_handle_);
+    qos_handle_ = NULL;
+  }
+
+  handle_is_initializing_ = true;
+  base::PostTaskWithTraitsAndReplyWithResult(
+      FROM_HERE, {base::MayBlock()},
+      base::BindOnce(&DscpManager::DoCreateHandle, api_),
+      base::BindOnce(&DscpManager::OnHandleCreated, api_,
+                     weak_ptr_factory_.GetWeakPtr()));
+}
+
+HANDLE DscpManager::DoCreateHandle(QwaveApi* api) {
+  QOS_VERSION version;
+  version.MajorVersion = 1;
+  version.MinorVersion = 0;
+
+  HANDLE handle = NULL;
+
+  // No access to net_log_ so swallow any errors here.
+  api->CreateHandle(&version, &handle);
+  return handle;
+}
+
+void DscpManager::OnHandleCreated(QwaveApi* api,
+                                  base::WeakPtr<DscpManager> dscp_manager,
+                                  HANDLE handle) {
+  if (!handle)
+    api->OnFatalError();
+
+  if (!dscp_manager) {
+    api->CloseHandle(handle);
+    return;
+  }
+
+  DCHECK(dscp_manager->handle_is_initializing_);
+  DCHECK(!dscp_manager->qos_handle_);
+
+  dscp_manager->qos_handle_ = handle;
+  dscp_manager->handle_is_initializing_ = false;
+}
+
 }  // namespace net
diff --git a/net/socket/udp_socket_win.h b/net/socket/udp_socket_win.h
index a9e7267cc..28adb1a0 100644
--- a/net/socket/udp_socket_win.h
+++ b/net/socket/udp_socket_win.h
@@ -43,7 +43,7 @@
 // longer works, so we have to use this API instead.
 // This class is meant to be used as a singleton. It exposes a few dynamically
 // loaded functions and a bool called "qwave_supported".
-class NET_EXPORT QwaveAPI {
+class NET_EXPORT QwaveApi {
   typedef BOOL(WINAPI* CreateHandleFn)(PQOS_VERSION, PHANDLE);
   typedef BOOL(WINAPI* CloseHandleFn)(HANDLE);
   typedef BOOL(WINAPI* AddSocketToFlowFn)(HANDLE,
@@ -65,12 +65,13 @@
                                   LPOVERLAPPED);
 
  public:
-  QwaveAPI();
-  virtual ~QwaveAPI() = default;
+  QwaveApi();
 
-  static QwaveAPI& Get();
+  static QwaveApi* GetDefault();
 
   virtual bool qwave_supported() const;
+  virtual void OnFatalError();
+
   virtual BOOL CreateHandle(PQOS_VERSION version, PHANDLE handle);
   virtual BOOL CloseHandle(HANDLE handle);
   virtual BOOL AddSocketToFlow(HANDLE handle,
@@ -92,16 +93,15 @@
                        LPOVERLAPPED overlapped);
 
  private:
-  FRIEND_TEST_ALL_PREFIXES(UDPSocketTest, SetDSCPFake);
+  std::atomic<bool> qwave_supported_;
 
-  bool qwave_supported_;
   CreateHandleFn create_handle_func_;
   CloseHandleFn close_handle_func_;
   AddSocketToFlowFn add_socket_to_flow_func_;
   RemoveSocketFromFlowFn remove_socket_from_flow_func_;
   SetFlowFn set_flow_func_;
 
-  DISALLOW_COPY_AND_ASSIGN(QwaveAPI);
+  DISALLOW_COPY_AND_ASSIGN(QwaveApi);
 };
 
 //-----------------------------------------------------------------------------
@@ -115,7 +115,7 @@
 // for Microsoft's documentation.
 class NET_EXPORT DscpManager {
  public:
-  DscpManager(QwaveAPI& qos, SOCKET socket, HANDLE qos_handle);
+  DscpManager(QwaveApi* api, SOCKET socket);
   ~DscpManager();
 
   // Remembers the latest |dscp| so PrepareToSend can add remote addresses to
@@ -128,15 +128,26 @@
   int PrepareForSend(const IPEndPoint& remote_address);
 
  private:
-  QwaveAPI& qos_;
-  SOCKET socket_;
-  HANDLE qos_handle_;
+  void RequestHandle();
+  static HANDLE DoCreateHandle(QwaveApi* api);
+  static void OnHandleCreated(QwaveApi* api,
+                              base::WeakPtr<DscpManager> dscp_manager,
+                              HANDLE handle);
+
+  QwaveApi* const api_;
+  const SOCKET socket_;
 
   DiffServCodePoint dscp_value_ = DSCP_NO_CHANGE;
   // The remote addresses currently in the flow.
   std::set<IPEndPoint> configured_;
+
+  HANDLE qos_handle_ = NULL;
+  bool handle_is_initializing_ = false;
   // 0 means no flow has been constructed.
   QOS_FLOWID flow_id_ = 0;
+  base::WeakPtrFactory<DscpManager> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(DscpManager);
 };
 
 //-----------------------------------------------------------------------------
@@ -250,16 +261,30 @@
 
   const NetLogWithSource& NetLog() const { return net_log_; }
 
-  // Sets corresponding flags in |socket_options_| to allow the socket
-  // to share the local address to which the socket will be bound with
-  // other processes. Should be called between Open() and Bind().
-  // Returns a net error code.
+  // Sets socket options to allow the socket to share the local address to which
+  // the socket will be bound with other processes. If multiple processes are
+  // bound to the same local address at the same time, behavior is undefined;
+  // e.g., it is not guaranteed that incoming  messages will be sent to all
+  // listening sockets. Returns a net error code.
+  //
+  // Should be called between Open() and Bind().
   int AllowAddressReuse();
 
-  // Sets corresponding flags in |socket_options_| to allow sending
-  // and receiving packets to and from broadcast addresses.
+  // Sets socket options to allow sending and receiving packets to and from
+  // broadcast addresses.
   int SetBroadcast(bool broadcast);
 
+  // Sets socket options to allow the socket to share the local address to which
+  // the socket will be bound with other processes and attempt to allow all such
+  // sockets to receive the same multicast messages. Returns a net error code.
+  //
+  // For Windows, multicast messages should always be shared between sockets
+  // configured thusly as long as the sockets join the same multicast group and
+  // interface.
+  //
+  // Should be called between Open() and Bind().
+  int AllowAddressSharingForMulticast();
+
   // Joins the multicast group.
   // |group_address| is the group address to join, could be either
   // an IPv4 or IPv6 address.
@@ -302,8 +327,10 @@
   // other applications on the same host. See MSDN: http://goo.gl/6vqbj
   int SetMulticastLoopbackMode(bool loopback);
 
-  // Sets the differentiated services flags on outgoing packets. May not
-  // do anything on some platforms.
+  // Sets the differentiated services flags on outgoing packets. May not do
+  // anything on some platforms.  A return value of ERR_INVALID_HANDLE indicates
+  // the value was not set but could succeed on a future call, because
+  // initialization is in progress.
   int SetDiffServCodePoint(DiffServCodePoint dscp);
 
   // Resets the thread to be used for thread-safety checks.
@@ -391,10 +418,10 @@
   // Binds to a random port on |address|.
   int RandomBind(const IPAddress& address);
 
-  // This is provided to allow QwaveAPI mocking in tests. |UDPSocketWin| method
-  // implementations should call |GetQwaveAPI()| instead of |QwaveAPI::Get()|
-  // directly.
-  virtual QwaveAPI& GetQwaveAPI();
+  // This is provided to allow QwaveApi mocking in tests. |UDPSocketWin| method
+  // implementations should call |GetQwaveApi()| instead of
+  // |QwaveApi::GetDefault()| directly.
+  virtual QwaveApi* GetQwaveApi() const;
 
   SOCKET socket_;
   int addr_family_;
@@ -455,9 +482,6 @@
 
   NetLogWithSource net_log_;
 
-  // QWAVE data. Used to set DSCP bits on outgoing packets.
-  HANDLE qos_handle_;
-
   // Maintains remote addresses for QWAVE qos management.
   std::unique_ptr<DscpManager> dscp_manager_;
 
diff --git a/net/spdy/spdy_session_pool_unittest.cc b/net/spdy/spdy_session_pool_unittest.cc
index 37eeb1c..bcac4d1 100644
--- a/net/spdy/spdy_session_pool_unittest.cc
+++ b/net/spdy/spdy_session_pool_unittest.cc
@@ -12,7 +12,7 @@
 #include "base/test/metrics/histogram_tester.h"
 #include "base/trace_event/memory_allocator_dump.h"
 #include "base/trace_event/process_memory_dump.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "build/build_config.h"
 #include "net/base/completion_once_callback.h"
 #include "net/dns/host_cache.h"
diff --git a/net/ssl/ssl_client_session_cache_unittest.cc b/net/ssl/ssl_client_session_cache_unittest.cc
index cdf3de2..adb1382b 100644
--- a/net/ssl/ssl_client_session_cache_unittest.cc
+++ b/net/ssl/ssl_client_session_cache_unittest.cc
@@ -11,7 +11,7 @@
 #include "base/time/time.h"
 #include "base/trace_event/memory_allocator_dump.h"
 #include "base/trace_event/process_memory_dump.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/boringssl/src/include/openssl/ssl.h"
diff --git a/net/url_request/url_request_quic_perftest.cc b/net/url_request/url_request_quic_perftest.cc
index 793a7ea..83fef9c 100644
--- a/net/url_request/url_request_quic_perftest.cc
+++ b/net/url_request/url_request_quic_perftest.cc
@@ -18,7 +18,7 @@
 #include "base/trace_event/memory_dump_request_args.h"
 #include "base/trace_event/process_memory_dump.h"
 #include "base/trace_event/trace_config.h"
-#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/traced_value.h"
 #include "net/base/load_timing_info.h"
 #include "net/cert/mock_cert_verifier.h"
 #include "net/dns/mapped_host_resolver.h"
diff --git a/remoting/base/auto_thread.cc b/remoting/base/auto_thread.cc
index 631ecb9..abb8d5f0 100644
--- a/remoting/base/auto_thread.cc
+++ b/remoting/base/auto_thread.cc
@@ -212,8 +212,8 @@
   // Allow threads running a MessageLoopForIO to use FileDescriptorWatcher.
   std::unique_ptr<base::FileDescriptorWatcher> file_descriptor_watcher;
   if (message_loop.type() == base::MessageLoop::TYPE_IO) {
-    file_descriptor_watcher.reset(new base::FileDescriptorWatcher(
-        static_cast<base::MessageLoopForIO*>(&message_loop)));
+    file_descriptor_watcher.reset(
+        new base::FileDescriptorWatcher(message_loop.task_runner()));
   }
 #endif
 
diff --git a/remoting/host/input_injector_x11.cc b/remoting/host/input_injector_x11.cc
index 99c6528..7e76bd3 100644
--- a/remoting/host/input_injector_x11.cc
+++ b/remoting/host/input_injector_x11.cc
@@ -302,21 +302,9 @@
       SetLockStates(caps_lock, num_lock);
     }
 
-    if (pressed_keys_.empty()) {
-      // Disable auto-repeat, if necessary, to avoid triggering auto-repeat
-      // if network congestion delays the key-up event from the client.
-      saved_auto_repeat_enabled_ = IsAutoRepeatEnabled();
-      if (saved_auto_repeat_enabled_)
-        SetAutoRepeatEnabled(false);
-    }
     pressed_keys_.insert(keycode);
   } else {
     pressed_keys_.erase(keycode);
-    if (pressed_keys_.empty()) {
-      // Re-enable auto-repeat, if necessary, when all keys are released.
-      if (saved_auto_repeat_enabled_)
-        SetAutoRepeatEnabled(true);
-    }
   }
 
   XTestFakeKeyEvent(display_, keycode, event.pressed(), x11::CurrentTime);
@@ -371,6 +359,7 @@
   XKeyboardControl control;
   control.auto_repeat_mode = mode ? AutoRepeatModeOn : AutoRepeatModeOff;
   XChangeKeyboardControl(display_, KBAutoRepeatMode, &control);
+  XFlush(display_);
 }
 
 bool InputInjectorX11::Core::IsLockKey(KeyCode keycode) {
@@ -644,6 +633,14 @@
 
   character_injector_.reset(
       new X11CharacterInjector(std::make_unique<X11KeyboardImpl>(display_)));
+
+  // Disable auto-repeat, if necessary, to avoid triggering auto-repeat
+  // if network congestion delays the key-up event from the client. This is
+  // done for the duration of the session because some window managers do
+  // not handle changes to this setting efficiently.
+  saved_auto_repeat_enabled_ = IsAutoRepeatEnabled();
+  if (saved_auto_repeat_enabled_)
+    SetAutoRepeatEnabled(false);
 }
 
 void InputInjectorX11::Core::Stop() {
@@ -654,6 +651,9 @@
 
   clipboard_.reset();
   character_injector_.reset();
+  // Re-enable auto-repeat, if necessary, on disconnect.
+  if (saved_auto_repeat_enabled_)
+    SetAutoRepeatEnabled(true);
 }
 
 }  // namespace
diff --git a/services/device/hid/input_service_linux_unittest.cc b/services/device/hid/input_service_linux_unittest.cc
index a084f4b0..a42137e 100644
--- a/services/device/hid/input_service_linux_unittest.cc
+++ b/services/device/hid/input_service_linux_unittest.cc
@@ -7,8 +7,8 @@
 #include <vector>
 
 #include "base/files/file_descriptor_watcher_posix.h"
-#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
+#include "base/test/scoped_task_environment.h"
 #include "services/device/hid/input_service_linux.h"
 #include "services/device/public/mojom/input_service.mojom.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -26,8 +26,8 @@
 }  // namespace
 
 TEST(InputServiceLinux, Simple) {
-  base::MessageLoopForIO message_loop;
-  base::FileDescriptorWatcher file_descriptor_watcher(&message_loop);
+  base::test::ScopedTaskEnvironment task_environment(
+      base::test::ScopedTaskEnvironment::MainThreadType::IO);
 
   InputServiceLinux* service = InputServiceLinux::GetInstance();
   ASSERT_TRUE(service);
diff --git a/services/identity/public/cpp/BUILD.gn b/services/identity/public/cpp/BUILD.gn
index fe28bfb..72feb6e 100644
--- a/services/identity/public/cpp/BUILD.gn
+++ b/services/identity/public/cpp/BUILD.gn
@@ -26,6 +26,7 @@
 
   public_deps = [
     "//components/signin/core/browser",
+    "//services/identity/public/cpp:cpp_types",
   ]
 }
 
diff --git a/services/identity/public/cpp/access_token_fetcher.cc b/services/identity/public/cpp/access_token_fetcher.cc
index 62b2fde..b7628d1 100644
--- a/services/identity/public/cpp/access_token_fetcher.cc
+++ b/services/identity/public/cpp/access_token_fetcher.cc
@@ -11,13 +11,12 @@
 
 namespace identity {
 
-AccessTokenFetcher::AccessTokenFetcher(
-    const std::string& account_id,
-    const std::string& oauth_consumer_name,
-    OAuth2TokenService* token_service,
-    const OAuth2TokenService::ScopeSet& scopes,
-    TokenCallback callback,
-    Mode mode)
+AccessTokenFetcher::AccessTokenFetcher(const std::string& account_id,
+                                       const std::string& oauth_consumer_name,
+                                       OAuth2TokenService* token_service,
+                                       const identity::ScopeSet& scopes,
+                                       TokenCallback callback,
+                                       Mode mode)
     : AccessTokenFetcher(account_id,
                          oauth_consumer_name,
                          token_service,
@@ -31,7 +30,7 @@
     const std::string& oauth_consumer_name,
     OAuth2TokenService* token_service,
     scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
-    const OAuth2TokenService::ScopeSet& scopes,
+    const identity::ScopeSet& scopes,
     TokenCallback callback,
     Mode mode)
     : OAuth2TokenService::Consumer(oauth_consumer_name),
diff --git a/services/identity/public/cpp/access_token_fetcher.h b/services/identity/public/cpp/access_token_fetcher.h
index 27bf7b61..c9c7cbe 100644
--- a/services/identity/public/cpp/access_token_fetcher.h
+++ b/services/identity/public/cpp/access_token_fetcher.h
@@ -14,6 +14,7 @@
 #include "google_apis/gaia/google_service_auth_error.h"
 #include "google_apis/gaia/oauth2_token_service.h"
 #include "services/identity/public/cpp/access_token_info.h"
+#include "services/identity/public/cpp/scope_set.h"
 
 namespace network {
 class SharedURLLoaderFactory;
@@ -52,7 +53,7 @@
   AccessTokenFetcher(const std::string& account_id,
                      const std::string& oauth_consumer_name,
                      OAuth2TokenService* token_service,
-                     const OAuth2TokenService::ScopeSet& scopes,
+                     const identity::ScopeSet& scopes,
                      TokenCallback callback,
                      Mode mode);
 
@@ -66,7 +67,7 @@
       const std::string& oauth_consumer_name,
       OAuth2TokenService* token_service,
       scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
-      const OAuth2TokenService::ScopeSet& scopes,
+      const identity::ScopeSet& scopes,
       TokenCallback callback,
       Mode mode);
 
@@ -99,7 +100,7 @@
   const std::string account_id_;
   OAuth2TokenService* token_service_;
   scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
-  const OAuth2TokenService::ScopeSet scopes_;
+  const identity::ScopeSet scopes_;
   const Mode mode_;
 
   // NOTE: This callback should only be invoked from |RunCallbackAndMaybeDie|,
diff --git a/services/identity/public/cpp/identity_manager.cc b/services/identity/public/cpp/identity_manager.cc
index 48421d7..0352aa5d 100644
--- a/services/identity/public/cpp/identity_manager.cc
+++ b/services/identity/public/cpp/identity_manager.cc
@@ -154,7 +154,7 @@
 IdentityManager::CreateAccessTokenFetcherForAccount(
     const std::string& account_id,
     const std::string& oauth_consumer_name,
-    const OAuth2TokenService::ScopeSet& scopes,
+    const identity::ScopeSet& scopes,
     AccessTokenFetcher::TokenCallback callback,
     AccessTokenFetcher::Mode mode) {
   return std::make_unique<AccessTokenFetcher>(account_id, oauth_consumer_name,
@@ -167,7 +167,7 @@
     const std::string& account_id,
     const std::string& oauth_consumer_name,
     scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
-    const OAuth2TokenService::ScopeSet& scopes,
+    const identity::ScopeSet& scopes,
     AccessTokenFetcher::TokenCallback callback,
     AccessTokenFetcher::Mode mode) {
   return std::make_unique<AccessTokenFetcher>(
@@ -177,7 +177,7 @@
 
 void IdentityManager::RemoveAccessTokenFromCache(
     const std::string& account_id,
-    const OAuth2TokenService::ScopeSet& scopes,
+    const identity::ScopeSet& scopes,
     const std::string& access_token) {
   // TODO(843510): Consider making the request to ProfileOAuth2TokenService
   // asynchronously once there are no direct clients of PO2TS. This change would
diff --git a/services/identity/public/cpp/identity_manager.h b/services/identity/public/cpp/identity_manager.h
index 8b3bf3d..f2552834 100644
--- a/services/identity/public/cpp/identity_manager.h
+++ b/services/identity/public/cpp/identity_manager.h
@@ -13,6 +13,7 @@
 #include "components/signin/core/browser/signin_manager_base.h"
 #include "components/signin/core/browser/signin_metrics.h"
 #include "services/identity/public/cpp/access_token_fetcher.h"
+#include "services/identity/public/cpp/scope_set.h"
 
 #if !defined(OS_CHROMEOS)
 #include "components/signin/core/browser/signin_manager.h"
@@ -129,10 +130,9 @@
     DiagnosticsObserver& operator=(const DiagnosticsObserver&) = delete;
 
     // Called when receiving request for access token.
-    virtual void OnAccessTokenRequested(
-        const std::string& account_id,
-        const std::string& consumer_id,
-        const OAuth2TokenService::ScopeSet& scopes) {}
+    virtual void OnAccessTokenRequested(const std::string& account_id,
+                                        const std::string& consumer_id,
+                                        const identity::ScopeSet& scopes) {}
   };
 
   IdentityManager(
@@ -234,7 +234,7 @@
   std::unique_ptr<AccessTokenFetcher> CreateAccessTokenFetcherForAccount(
       const std::string& account_id,
       const std::string& oauth_consumer_name,
-      const OAuth2TokenService::ScopeSet& scopes,
+      const identity::ScopeSet& scopes,
       AccessTokenFetcher::TokenCallback callback,
       AccessTokenFetcher::Mode mode);
 
@@ -244,7 +244,7 @@
       const std::string& account_id,
       const std::string& oauth_consumer_name,
       scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
-      const OAuth2TokenService::ScopeSet& scopes,
+      const identity::ScopeSet& scopes,
       AccessTokenFetcher::TokenCallback callback,
       AccessTokenFetcher::Mode mode);
 
@@ -253,7 +253,7 @@
   // request for |account_id| and |scopes| will fetch a new token from the
   // network. Otherwise, is a no-op.
   void RemoveAccessTokenFromCache(const std::string& account_id,
-                                  const OAuth2TokenService::ScopeSet& scopes,
+                                  const identity::ScopeSet& scopes,
                                   const std::string& access_token);
 
   // Returns pointer to the object used to change the signed-in state of the
diff --git a/services/identity/public/cpp/identity_manager_unittest.cc b/services/identity/public/cpp/identity_manager_unittest.cc
index 3aaafb12..df6b0d2d 100644
--- a/services/identity/public/cpp/identity_manager_unittest.cc
+++ b/services/identity/public/cpp/identity_manager_unittest.cc
@@ -360,16 +360,15 @@
   const std::string& token_requestor_consumer_id() {
     return token_requestor_consumer_id_;
   }
-  const OAuth2TokenService::ScopeSet& token_requestor_scopes() {
+  const identity::ScopeSet& token_requestor_scopes() {
     return token_requestor_scopes_;
   }
 
  private:
   // IdentityManager::DiagnosticsObserver:
-  void OnAccessTokenRequested(
-      const std::string& account_id,
-      const std::string& consumer_id,
-      const OAuth2TokenService::ScopeSet& scopes) override {
+  void OnAccessTokenRequested(const std::string& account_id,
+                              const std::string& consumer_id,
+                              const identity::ScopeSet& scopes) override {
     token_requestor_account_id_ = account_id;
     token_requestor_consumer_id_ = consumer_id;
     token_requestor_scopes_ = scopes;
@@ -382,7 +381,7 @@
   base::OnceClosure on_access_token_requested_callback_;
   std::string token_requestor_account_id_;
   std::string token_requestor_consumer_id_;
-  OAuth2TokenService::ScopeSet token_requestor_scopes_;
+  identity::ScopeSet token_requestor_scopes_;
 };
 
 }  // namespace
diff --git a/services/identity/public/cpp/identity_test_environment.cc b/services/identity/public/cpp/identity_test_environment.cc
index 6cb7c16..b9b604a 100644
--- a/services/identity/public/cpp/identity_test_environment.cc
+++ b/services/identity/public/cpp/identity_test_environment.cc
@@ -324,7 +324,7 @@
 void IdentityTestEnvironment::OnAccessTokenRequested(
     const std::string& account_id,
     const std::string& consumer_id,
-    const OAuth2TokenService::ScopeSet& scopes) {
+    const identity::ScopeSet& scopes) {
   // Post a task to handle this access token request in order to support the
   // case where the access token request is handled synchronously in the
   // production code, in which case this callback could be coming in ahead
diff --git a/services/identity/public/cpp/identity_test_environment.h b/services/identity/public/cpp/identity_test_environment.h
index 7ccdce14..f1380bf 100644
--- a/services/identity/public/cpp/identity_test_environment.h
+++ b/services/identity/public/cpp/identity_test_environment.h
@@ -260,10 +260,9 @@
       IdentityManager* identity_manager);
 
   // IdentityManager::DiagnosticsObserver:
-  void OnAccessTokenRequested(
-      const std::string& account_id,
-      const std::string& consumer_id,
-      const OAuth2TokenService::ScopeSet& scopes) override;
+  void OnAccessTokenRequested(const std::string& account_id,
+                              const std::string& consumer_id,
+                              const identity::ScopeSet& scopes) override;
 
   // Handles the notification that an access token request was received for
   // |account_id|. Invokes |on_access_token_request_callback_| if the latter
diff --git a/services/identity/public/cpp/primary_account_access_token_fetcher.cc b/services/identity/public/cpp/primary_account_access_token_fetcher.cc
index 08ddb0d1..0cbc38a 100644
--- a/services/identity/public/cpp/primary_account_access_token_fetcher.cc
+++ b/services/identity/public/cpp/primary_account_access_token_fetcher.cc
@@ -14,7 +14,7 @@
 PrimaryAccountAccessTokenFetcher::PrimaryAccountAccessTokenFetcher(
     const std::string& oauth_consumer_name,
     IdentityManager* identity_manager,
-    const OAuth2TokenService::ScopeSet& scopes,
+    const identity::ScopeSet& scopes,
     AccessTokenFetcher::TokenCallback callback,
     Mode mode)
     : oauth_consumer_name_(oauth_consumer_name),
diff --git a/services/identity/public/cpp/primary_account_access_token_fetcher.h b/services/identity/public/cpp/primary_account_access_token_fetcher.h
index 9de4cd76..3428c5c 100644
--- a/services/identity/public/cpp/primary_account_access_token_fetcher.h
+++ b/services/identity/public/cpp/primary_account_access_token_fetcher.h
@@ -45,7 +45,7 @@
   // the callback is not called.
   PrimaryAccountAccessTokenFetcher(const std::string& oauth_consumer_name,
                                    IdentityManager* identity_manager,
-                                   const OAuth2TokenService::ScopeSet& scopes,
+                                   const identity::ScopeSet& scopes,
                                    AccessTokenFetcher::TokenCallback callback,
                                    Mode mode);
 
@@ -76,7 +76,7 @@
 
   std::string oauth_consumer_name_;
   IdentityManager* identity_manager_;
-  OAuth2TokenService::ScopeSet scopes_;
+  identity::ScopeSet scopes_;
 
   // Per the contract of this class, it is allowed for clients to delete this
   // object as part of the invocation of |callback_|. Hence, this object must
diff --git a/services/identity/public/cpp/scope_set.h b/services/identity/public/cpp/scope_set.h
index f5017306..9f82544 100644
--- a/services/identity/public/cpp/scope_set.h
+++ b/services/identity/public/cpp/scope_set.h
@@ -6,6 +6,7 @@
 #define SERVICES_IDENTITY_PUBLIC_CPP_SCOPE_SET_H_
 
 #include <set>
+#include <string>
 
 namespace identity {
 
diff --git a/services/network/BUILD.gn b/services/network/BUILD.gn
index 723661b..22c5340 100644
--- a/services/network/BUILD.gn
+++ b/services/network/BUILD.gn
@@ -170,6 +170,15 @@
     ]
   }
 
+  if (is_chromeos) {
+    sources += [
+      "cert_verifier_with_trust_anchors.cc",
+      "cert_verifier_with_trust_anchors.h",
+      "cert_verify_proc_chromeos.cc",
+      "cert_verify_proc_chromeos.h",
+    ]
+  }
+
   configs += [ "//build/config/compiler:wexit_time_destructors" ]
 
   deps = [
@@ -299,12 +308,20 @@
     ]
   }
 
+  if (is_chromeos) {
+    sources += [
+      "cert_verifier_with_trust_anchors_unittest.cc",
+      "cert_verify_proc_chromeos_unittest.cc",
+    ]
+  }
+
   deps = [
     ":network_service",
     ":test_support",
     "//base",
     "//components/certificate_transparency",
     "//components/network_session_configurator/browser",
+    "//crypto:test_support",
     "//jingle:jingle_fake_socket",
     "//mojo/core/embedder",
     "//mojo/public/cpp/bindings",
diff --git a/services/network/OWNERS b/services/network/OWNERS
index 4182788..98a9813 100644
--- a/services/network/OWNERS
+++ b/services/network/OWNERS
@@ -12,6 +12,9 @@
 
 per-file expect_ct_reporter*=estark@chromium.org
 
+per-file cert_verifier_with_trust_anchors*=file://chromeos/policy/OWNERS
+per-file cert_verify_proc_chromeos*=file://chromeos/policy/OWNERS
+
 per-file manifest.json=set noparent
 per-file manifest.json=file://ipc/SECURITY_OWNERS
 per-file *_type_converter*.*=set noparent
diff --git a/chrome/browser/chromeos/policy/policy_cert_verifier.cc b/services/network/cert_verifier_with_trust_anchors.cc
similarity index 70%
rename from chrome/browser/chromeos/policy/policy_cert_verifier.cc
rename to services/network/cert_verifier_with_trust_anchors.cc
index 0512d74..0441894 100644
--- a/chrome/browser/chromeos/policy/policy_cert_verifier.cc
+++ b/services/network/cert_verifier_with_trust_anchors.cc
@@ -2,27 +2,24 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/chromeos/policy/policy_cert_verifier.h"
+#include "services/network/cert_verifier_with_trust_anchors.h"
 
 #include <utility>
 
 #include "base/bind.h"
 #include "base/logging.h"
-#include "chrome/browser/browser_process.h"
-#include "content/public/browser/browser_thread.h"
 #include "net/base/net_errors.h"
 #include "net/cert/caching_cert_verifier.h"
 #include "net/cert/cert_verify_proc.h"
 #include "net/cert/multi_threaded_cert_verifier.h"
 
-namespace policy {
+namespace network {
 
 namespace {
 
 void MaybeSignalAnchorUse(int error,
                           const base::Closure& anchor_used_callback,
                           const net::CertVerifyResult& verify_result) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
   if (error != net::OK || !verify_result.is_issued_by_additional_trust_anchor ||
       anchor_used_callback.is_null()) {
     return;
@@ -34,7 +31,6 @@
                                 net::CompletionOnceCallback completion_callback,
                                 const net::CertVerifyResult* verify_result,
                                 int error) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
   MaybeSignalAnchorUse(error, anchor_used_callback, *verify_result);
   std::move(completion_callback).Run(error);
 }
@@ -51,19 +47,19 @@
 
 }  // namespace
 
-PolicyCertVerifier::PolicyCertVerifier(
+CertVerifierWithTrustAnchors::CertVerifierWithTrustAnchors(
     const base::Closure& anchor_used_callback)
     : anchor_used_callback_(anchor_used_callback) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  DETACH_FROM_THREAD(thread_checker_);
 }
 
-PolicyCertVerifier::~PolicyCertVerifier() {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+CertVerifierWithTrustAnchors::~CertVerifierWithTrustAnchors() {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 }
 
-void PolicyCertVerifier::InitializeOnIOThread(
+void CertVerifierWithTrustAnchors::InitializeOnIOThread(
     const scoped_refptr<net::CertVerifyProc>& verify_proc) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   if (!verify_proc->SupportsAdditionalTrustAnchors()) {
     LOG(WARNING)
         << "Additional trust anchors not supported on the current platform!";
@@ -73,9 +69,9 @@
   delegate_->SetConfig(ExtendTrustAnchors(orig_config_, trust_anchors_));
 }
 
-void PolicyCertVerifier::SetTrustAnchors(
+void CertVerifierWithTrustAnchors::SetTrustAnchors(
     const net::CertificateList& trust_anchors) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   if (trust_anchors == trust_anchors_)
     return;
   trust_anchors_ = trust_anchors;
@@ -84,12 +80,13 @@
   delegate_->SetConfig(ExtendTrustAnchors(orig_config_, trust_anchors_));
 }
 
-int PolicyCertVerifier::Verify(const RequestParams& params,
-                               net::CertVerifyResult* verify_result,
-                               net::CompletionOnceCallback completion_callback,
-                               std::unique_ptr<Request>* out_req,
-                               const net::NetLogWithSource& net_log) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+int CertVerifierWithTrustAnchors::Verify(
+    const RequestParams& params,
+    net::CertVerifyResult* verify_result,
+    net::CompletionOnceCallback completion_callback,
+    std::unique_ptr<Request>* out_req,
+    const net::NetLogWithSource& net_log) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   DCHECK(delegate_);
   DCHECK(completion_callback);
   net::CompletionOnceCallback wrapped_callback =
@@ -102,10 +99,10 @@
   return error;
 }
 
-void PolicyCertVerifier::SetConfig(const Config& config) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+void CertVerifierWithTrustAnchors::SetConfig(const Config& config) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   orig_config_ = config;
   delegate_->SetConfig(ExtendTrustAnchors(orig_config_, trust_anchors_));
 }
 
-}  // namespace policy
+}  // namespace network
diff --git a/chrome/browser/chromeos/policy/policy_cert_verifier.h b/services/network/cert_verifier_with_trust_anchors.h
similarity index 64%
rename from chrome/browser/chromeos/policy/policy_cert_verifier.h
rename to services/network/cert_verifier_with_trust_anchors.h
index ab952c4..1104a36a 100644
--- a/chrome/browser/chromeos/policy/policy_cert_verifier.h
+++ b/services/network/cert_verifier_with_trust_anchors.h
@@ -2,16 +2,18 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_CHROMEOS_POLICY_POLICY_CERT_VERIFIER_H_
-#define CHROME_BROWSER_CHROMEOS_POLICY_POLICY_CERT_VERIFIER_H_
+#ifndef SERVICES_NETWORK_CERT_VERIFIER_WITH_TRUST_ANCHORS_H_
+#define SERVICES_NETWORK_CERT_VERIFIER_WITH_TRUST_ANCHORS_H_
 
 #include <memory>
 #include <vector>
 
 #include "base/callback.h"
 #include "base/compiler_specific.h"
+#include "base/component_export.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
+#include "base/threading/thread_checker.h"
 #include "net/base/completion_once_callback.h"
 #include "net/cert/cert_verifier.h"
 
@@ -19,24 +21,26 @@
 class CertVerifyProc;
 class CertVerifyResult;
 class X509Certificate;
-typedef std::vector<scoped_refptr<X509Certificate> > CertificateList;
-}
+typedef std::vector<scoped_refptr<X509Certificate>> CertificateList;
+}  // namespace net
 
-namespace policy {
+namespace network {
 
 // Wraps a MultiThreadedCertVerifier to make it use the additional trust anchors
 // configured by the ONC user policy.
-class PolicyCertVerifier : public net::CertVerifier {
+class COMPONENT_EXPORT(NETWORK_SERVICE) CertVerifierWithTrustAnchors
+    : public net::CertVerifier {
  public:
-  // Except for tests, PolicyCertVerifier should only be created by
-  // PolicyCertService, which is the counterpart of this class on the UI thread.
   // Except of the constructor, all methods and the destructor must be called on
-  // the IO thread. Calls |anchor_used_callback| on the IO thread everytime a
+  // the IO thread. Calls |anchor_used_callback| on the IO thread every time a
   // certificate from the additional trust anchors (set with SetTrustAnchors) is
   // used.
-  explicit PolicyCertVerifier(const base::Closure& anchor_used_callback);
-  ~PolicyCertVerifier() override;
+  explicit CertVerifierWithTrustAnchors(
+      const base::Closure& anchor_used_callback);
+  ~CertVerifierWithTrustAnchors() override;
 
+  // TODO(jam): once the network service is the only path, rename or get rid of
+  // this method.
   void InitializeOnIOThread(
       const scoped_refptr<net::CertVerifyProc>& verify_proc);
 
@@ -56,10 +60,11 @@
   net::CertificateList trust_anchors_;
   base::Closure anchor_used_callback_;
   std::unique_ptr<CertVerifier> delegate_;
+  THREAD_CHECKER(thread_checker_);
 
-  DISALLOW_COPY_AND_ASSIGN(PolicyCertVerifier);
+  DISALLOW_COPY_AND_ASSIGN(CertVerifierWithTrustAnchors);
 };
 
-}  // namespace policy
+}  // namespace network
 
-#endif  // CHROME_BROWSER_CHROMEOS_POLICY_POLICY_CERT_VERIFIER_H_
+#endif  // SERVICES_NETWORK_CERT_VERIFIER_WITH_TRUST_ANCHORS_H_
diff --git a/chrome/browser/chromeos/policy/policy_cert_verifier_unittest.cc b/services/network/cert_verifier_with_trust_anchors_unittest.cc
similarity index 89%
rename from chrome/browser/chromeos/policy/policy_cert_verifier_unittest.cc
rename to services/network/cert_verifier_with_trust_anchors_unittest.cc
index 1cc70f03..618356d 100644
--- a/chrome/browser/chromeos/policy/policy_cert_verifier_unittest.cc
+++ b/services/network/cert_verifier_with_trust_anchors_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/chromeos/policy/policy_cert_verifier.h"
+#include "services/network/cert_verifier_with_trust_anchors.h"
 
 #include <memory>
 #include <string>
@@ -12,9 +12,7 @@
 #include "base/callback.h"
 #include "base/memory/ref_counted.h"
 #include "base/run_loop.h"
-#include "chrome/browser/chromeos/net/cert_verify_proc_chromeos.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/test/test_browser_thread_bundle.h"
+#include "base/test/scoped_task_environment.h"
 #include "crypto/nss_util_internal.h"
 #include "crypto/scoped_test_nss_chromeos_user.h"
 #include "net/base/test_completion_callback.h"
@@ -25,16 +23,20 @@
 #include "net/log/net_log_with_source.h"
 #include "net/test/cert_test_util.h"
 #include "net/test/test_data_directory.h"
+#include "services/network/cert_verify_proc_chromeos.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-namespace policy {
+namespace network {
 
-class PolicyCertVerifierTest : public testing::Test {
+class CertVerifierWithTrustAnchorsTest : public testing::Test {
  public:
-  PolicyCertVerifierTest()
-      : trust_anchor_used_(false), test_nss_user_("user1") {}
+  CertVerifierWithTrustAnchorsTest()
+      : trust_anchor_used_(false),
+        test_nss_user_("user1"),
+        scoped_task_environment_(
+            base::test::ScopedTaskEnvironment::MainThreadType::IO) {}
 
-  ~PolicyCertVerifierTest() override {}
+  ~CertVerifierWithTrustAnchorsTest() override {}
 
   void SetUp() override {
     ASSERT_TRUE(test_nss_user_.constructed_successfully());
@@ -46,9 +48,10 @@
             test_nss_user_.username_hash(),
             base::RepeatingCallback<void(crypto::ScopedPK11Slot)>())));
 
-    cert_verifier_.reset(new PolicyCertVerifier(base::BindRepeating(
-        &PolicyCertVerifierTest::OnTrustAnchorUsed, base::Unretained(this))));
-    cert_verifier_->InitializeOnIOThread(new chromeos::CertVerifyProcChromeOS(
+    cert_verifier_.reset(new CertVerifierWithTrustAnchors(base::BindRepeating(
+        &CertVerifierWithTrustAnchorsTest::OnTrustAnchorUsed,
+        base::Unretained(this))));
+    cert_verifier_->InitializeOnIOThread(new network::CertVerifyProcChromeOS(
         crypto::GetPublicSlotForChromeOSUser(test_nss_user_.username_hash())));
 
     test_ca_cert_ = LoadCertificate("root_ca_cert.pem", net::CA_CERT);
@@ -104,7 +107,7 @@
   scoped_refptr<net::X509Certificate> test_server_cert_;
   net::ScopedCERTCertificateList test_ca_cert_list_;
   std::unique_ptr<net::NSSCertDatabaseChromeOS> test_cert_db_;
-  std::unique_ptr<PolicyCertVerifier> cert_verifier_;
+  std::unique_ptr<CertVerifierWithTrustAnchors> cert_verifier_;
 
  private:
   void OnTrustAnchorUsed() { trust_anchor_used_ = true; }
@@ -126,10 +129,10 @@
 
   bool trust_anchor_used_;
   crypto::ScopedTestNSSChromeOSUser test_nss_user_;
-  content::TestBrowserThreadBundle thread_bundle_;
+  base::test::ScopedTaskEnvironment scoped_task_environment_;
 };
 
-TEST_F(PolicyCertVerifierTest, VerifyUntrustedCert) {
+TEST_F(CertVerifierWithTrustAnchorsTest, VerifyUntrustedCert) {
   // |test_server_cert_| is untrusted, so Verify() fails.
   {
     net::CertVerifyResult verify_result;
@@ -155,7 +158,7 @@
   EXPECT_FALSE(WasTrustAnchorUsedAndReset());
 }
 
-TEST_F(PolicyCertVerifierTest, VerifyTrustedCert) {
+TEST_F(CertVerifierWithTrustAnchorsTest, VerifyTrustedCert) {
   // Make the database trust |test_ca_cert_|.
   net::NSSCertDatabase::ImportCertFailureList failure_list;
   ASSERT_TRUE(test_cert_db_->ImportCACerts(
@@ -182,7 +185,7 @@
   EXPECT_FALSE(WasTrustAnchorUsedAndReset());
 }
 
-TEST_F(PolicyCertVerifierTest, VerifyUsingAdditionalTrustAnchor) {
+TEST_F(CertVerifierWithTrustAnchorsTest, VerifyUsingAdditionalTrustAnchor) {
   ASSERT_TRUE(SupportsAdditionalTrustAnchors());
 
   // |test_server_cert_| is untrusted, so Verify() fails.
@@ -246,7 +249,7 @@
   EXPECT_FALSE(WasTrustAnchorUsedAndReset());
 }
 
-TEST_F(PolicyCertVerifierTest,
+TEST_F(CertVerifierWithTrustAnchorsTest,
        VerifyUsesAdditionalTrustAnchorsAfterConfigChange) {
   ASSERT_TRUE(SupportsAdditionalTrustAnchors());
 
@@ -300,4 +303,4 @@
   EXPECT_TRUE(WasTrustAnchorUsedAndReset());
 }
 
-}  // namespace policy
+}  // namespace network
diff --git a/chrome/browser/chromeos/net/cert_verify_proc_chromeos.cc b/services/network/cert_verify_proc_chromeos.cc
similarity index 92%
rename from chrome/browser/chromeos/net/cert_verify_proc_chromeos.cc
rename to services/network/cert_verify_proc_chromeos.cc
index d8670b20..5eac37c 100644
--- a/chrome/browser/chromeos/net/cert_verify_proc_chromeos.cc
+++ b/services/network/cert_verify_proc_chromeos.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/chromeos/net/cert_verify_proc_chromeos.h"
+#include "services/network/cert_verify_proc_chromeos.h"
 
 #include <utility>
 
@@ -14,10 +14,10 @@
 // See https://bugzilla.mozilla.org/show_bug.cgi?id=962413
 // Can be removed once chrome requires NSS version 3.16 to build.
 #ifndef CERT_LIST_TAIL
-#define CERT_LIST_TAIL(l) ((CERTCertListNode *)PR_LIST_TAIL(&l->list))
+#define CERT_LIST_TAIL(l) ((CERTCertListNode*)PR_LIST_TAIL(&l->list))
 #endif
 
-namespace chromeos {
+namespace network {
 
 namespace {
 
@@ -81,8 +81,7 @@
 
   for (net::CertificateList::const_iterator i =
            args->additional_trust_anchors.begin();
-       i != args->additional_trust_anchors.end();
-       ++i) {
+       i != args->additional_trust_anchors.end(); ++i) {
     if (net::x509_util::IsSameCertificate(cert, i->get())) {
       // Certs in the additional_trust_anchors should always be allowed, even if
       // they aren't stored in a slot that would be allowed by the
@@ -103,4 +102,4 @@
   return SECSuccess;
 }
 
-}  // namespace chromeos
+}  // namespace network
diff --git a/chrome/browser/chromeos/net/cert_verify_proc_chromeos.h b/services/network/cert_verify_proc_chromeos.h
similarity index 86%
rename from chrome/browser/chromeos/net/cert_verify_proc_chromeos.h
rename to services/network/cert_verify_proc_chromeos.h
index 346642f..45ee9fb 100644
--- a/chrome/browser/chromeos/net/cert_verify_proc_chromeos.h
+++ b/services/network/cert_verify_proc_chromeos.h
@@ -2,14 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_CHROMEOS_NET_CERT_VERIFY_PROC_CHROMEOS_H_
-#define CHROME_BROWSER_CHROMEOS_NET_CERT_VERIFY_PROC_CHROMEOS_H_
+#ifndef SERVICES_NETWORK_CERT_VERIFY_PROC_CHROMEOS_H_
+#define SERVICES_NETWORK_CERT_VERIFY_PROC_CHROMEOS_H_
 
+#include "base/component_export.h"
 #include "crypto/scoped_nss_types.h"
 #include "net/cert/cert_verify_proc_nss.h"
 #include "net/cert/nss_profile_filter_chromeos.h"
 
-namespace chromeos {
+namespace network {
 
 // Wrapper around CertVerifyProcNSS which allows filtering trust decisions on a
 // per-slot basis.
@@ -18,7 +19,8 @@
 // trust root, that root should not be trusted by CertVerifyProcChromeOS
 // instances using other slots). More complicated cases are not handled (like
 // two slots adding the same root cert but with different trust values).
-class CertVerifyProcChromeOS : public net::CertVerifyProcNSS {
+class COMPONENT_EXPORT(NETWORK_SERVICE) CertVerifyProcChromeOS
+    : public net::CertVerifyProcNSS {
  public:
   // Creates a CertVerifyProc that doesn't allow any user-provided trust roots.
   CertVerifyProcChromeOS();
@@ -54,6 +56,6 @@
   net::NSSProfileFilterChromeOS profile_filter_;
 };
 
-}  // namespace chromeos
+}  // namespace network
 
-#endif  // CHROME_BROWSER_CHROMEOS_NET_CERT_VERIFY_PROC_CHROMEOS_H_
+#endif  // SERVICES_NETWORK_CERT_VERIFY_PROC_CHROMEOS_H_
diff --git a/chrome/browser/chromeos/net/cert_verify_proc_chromeos_unittest.cc b/services/network/cert_verify_proc_chromeos_unittest.cc
similarity index 95%
rename from chrome/browser/chromeos/net/cert_verify_proc_chromeos_unittest.cc
rename to services/network/cert_verify_proc_chromeos_unittest.cc
index 2ccb03518..d0e2061 100644
--- a/chrome/browser/chromeos/net/cert_verify_proc_chromeos_unittest.cc
+++ b/services/network/cert_verify_proc_chromeos_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/chromeos/net/cert_verify_proc_chromeos.h"
+#include "services/network/cert_verify_proc_chromeos.h"
 
 #include <stddef.h>
 
@@ -18,7 +18,7 @@
 #include "net/test/test_data_directory.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-namespace chromeos {
+namespace network {
 
 namespace {
 
@@ -157,8 +157,8 @@
 
   // Import and trust the D root for user 1.
   net::NSSCertDatabase::ImportCertFailureList failed;
-  EXPECT_TRUE(db_1_->ImportCACerts(
-      root_1_, net::NSSCertDatabase::TRUSTED_SSL, &failed));
+  EXPECT_TRUE(db_1_->ImportCACerts(root_1_, net::NSSCertDatabase::TRUSTED_SSL,
+                                   &failed));
   EXPECT_EQ(0U, failed.size());
 
   // Imported CA certs are not trusted by default verifier.
@@ -173,8 +173,8 @@
 
   // Import and trust the E root for user 2.
   failed.clear();
-  EXPECT_TRUE(db_2_->ImportCACerts(
-      root_2_, net::NSSCertDatabase::TRUSTED_SSL, &failed));
+  EXPECT_TRUE(db_2_->ImportCACerts(root_2_, net::NSSCertDatabase::TRUSTED_SSL,
+                                   &failed));
   EXPECT_EQ(0U, failed.size());
 
   // Imported CA certs are not trusted by default verifier.
@@ -323,8 +323,8 @@
     expected_user1_result = net::OK;
     // Import and trust the D root for user 1.
     net::NSSCertDatabase::ImportCertFailureList failed;
-    EXPECT_TRUE(db_1_->ImportCACerts(
-        root_1_, net::NSSCertDatabase::TRUSTED_SSL, &failed));
+    EXPECT_TRUE(db_1_->ImportCACerts(root_1_, net::NSSCertDatabase::TRUSTED_SSL,
+                                     &failed));
     EXPECT_EQ(0U, failed.size());
     for (size_t i = 0; i < failed.size(); ++i) {
       LOG(ERROR) << "import fail " << failed[i].net_error << " for "
@@ -336,8 +336,8 @@
     expected_user2_result = net::OK;
     // Import and trust the E root for user 2.
     net::NSSCertDatabase::ImportCertFailureList failed;
-    EXPECT_TRUE(db_2_->ImportCACerts(
-        root_2_, net::NSSCertDatabase::TRUSTED_SSL, &failed));
+    EXPECT_TRUE(db_2_->ImportCACerts(root_2_, net::NSSCertDatabase::TRUSTED_SSL,
+                                     &failed));
     EXPECT_EQ(0U, failed.size());
     for (size_t i = 0; i < failed.size(); ++i) {
       LOG(ERROR) << "import fail " << failed[i].net_error << " for "
@@ -349,8 +349,7 @@
   for (int i = 0; i < 2; ++i) {
     SCOPED_TRACE(i);
     for (std::string::const_iterator j = test_order.begin();
-         j != test_order.end();
-         ++j) {
+         j != test_order.end(); ++j) {
       switch (*j) {
         case 'd':
           // Default verifier should always fail.
@@ -385,4 +384,4 @@
         ::testing::Range(0, 1 << 2),
         ::testing::Values("d12", "d21", "1d2", "12d", "2d1", "21d")));
 
-}  // namespace chromeos
+}  // namespace network
diff --git a/services/network/network_context.cc b/services/network/network_context.cc
index c78ae99..c848562 100644
--- a/services/network/network_context.cc
+++ b/services/network/network_context.cc
@@ -92,6 +92,14 @@
 #include "services/network/throttling/throttling_network_transaction_factory.h"
 #include "services/network/url_request_context_builder_mojo.h"
 
+#if defined(OS_CHROMEOS)
+#include "crypto/nss_util_internal.h"
+#include "net/cert/caching_cert_verifier.h"
+#include "net/cert/multi_threaded_cert_verifier.h"
+#include "services/network/cert_verifier_with_trust_anchors.h"
+#include "services/network/cert_verify_proc_chromeos.h"
+#endif
+
 #if !defined(OS_IOS)
 #include "services/network/websocket_factory.h"
 #endif  // !defined(OS_IOS)
@@ -276,6 +284,18 @@
 };
 #endif
 
+struct TestVerifyCertState {
+  net::CertVerifyResult result;
+  std::unique_ptr<net::CertVerifier::Request> request;
+};
+
+void TestVerifyCertCallback(
+    std::unique_ptr<TestVerifyCertState> request,
+    NetworkContext::VerifyCertificateForTestingCallback callback,
+    int result) {
+  std::move(callback).Run(result);
+}
+
 std::string HashesToBase64String(const net::HashValueVector& hashes) {
   std::string str;
   for (size_t i = 0; i != hashes.size(); ++i) {
@@ -880,6 +900,13 @@
                                          excluded_spkis, excluded_legacy_spkis);
 }
 
+#if defined(OS_CHROMEOS)
+void NetworkContext::UpdateTrustAnchors(
+    const net::CertificateList& trust_anchors) {
+  cert_verifier_with_trust_anchors_->SetTrustAnchors(trust_anchors);
+}
+#endif
+
 void NetworkContext::AddExpectCT(const std::string& domain,
                                  base::Time expiry,
                                  bool enforce,
@@ -1310,6 +1337,25 @@
   std::move(callback).Run();
 }
 
+void NetworkContext::VerifyCertificateForTesting(
+    const scoped_refptr<net::X509Certificate>& certificate,
+    const std::string& hostname,
+    const std::string& ocsp_response,
+    VerifyCertificateForTestingCallback callback) {
+  net::CertVerifier* cert_verifier = url_request_context_->cert_verifier();
+
+  auto state = std::make_unique<TestVerifyCertState>();
+  auto* request = &state->request;
+  auto* result = &state->result;
+
+  cert_verifier->Verify(net::CertVerifier::RequestParams(
+                            certificate.get(), hostname, 0, ocsp_response),
+                        result,
+                        base::BindOnce(TestVerifyCertCallback, std::move(state),
+                                       std::move(callback)),
+                        request, net::NetLogWithSource());
+}
+
 void NetworkContext::PreconnectSockets(uint32_t num_streams,
                                        const GURL& original_url,
                                        int32_t load_flags,
@@ -1748,15 +1794,40 @@
   const base::CommandLine* command_line =
       base::CommandLine::ForCurrentProcess();
 
+  std::unique_ptr<net::CertVerifier> cert_verifier;
   if (g_cert_verifier_for_testing) {
-    builder.SetCertVerifier(std::make_unique<WrappedTestingCertVerifier>());
+    cert_verifier = std::make_unique<WrappedTestingCertVerifier>();
   } else {
-    std::unique_ptr<net::CertVerifier> cert_verifier =
-        net::CertVerifier::CreateDefault();
-    builder.SetCertVerifier(IgnoreErrorsCertVerifier::MaybeWrapCertVerifier(
-        *command_line, nullptr, std::move(cert_verifier)));
+#if defined(OS_CHROMEOS)
+    if (params_->username_hash.empty()) {
+      cert_verifier = std::make_unique<net::CachingCertVerifier>(
+          std::make_unique<net::MultiThreadedCertVerifier>(
+              base::MakeRefCounted<CertVerifyProcChromeOS>()));
+    } else {
+      // Make sure NSS is initialized for the user.
+      crypto::InitializeNSSForChromeOSUser(params_->username_hash,
+                                           params_->nss_path.value());
+
+      crypto::ScopedPK11Slot public_slot =
+          crypto::GetPublicSlotForChromeOSUser(params_->username_hash);
+      scoped_refptr<net::CertVerifyProc> verify_proc(
+          new CertVerifyProcChromeOS(std::move(public_slot)));
+
+      cert_verifier_with_trust_anchors_ = new CertVerifierWithTrustAnchors(
+          base::Bind(&NetworkContext::TrustAnchorUsed, base::Unretained(this)));
+      cert_verifier_with_trust_anchors_->SetTrustAnchors(
+          params_->initial_trust_anchors);
+      cert_verifier_with_trust_anchors_->InitializeOnIOThread(verify_proc);
+      cert_verifier = base::WrapUnique(cert_verifier_with_trust_anchors_);
+    }
+#else
+    cert_verifier = net::CertVerifier::CreateDefault();
+#endif
   }
 
+  builder.SetCertVerifier(IgnoreErrorsCertVerifier::MaybeWrapCertVerifier(
+      *command_line, nullptr, std::move(cert_verifier)));
+
   std::unique_ptr<net::NetworkDelegate> network_delegate =
       std::make_unique<NetworkServiceNetworkDelegate>(this);
   builder.set_network_delegate(std::move(network_delegate));
@@ -1885,6 +1956,12 @@
       .Run(result, *pending_cert_verify->result.get(), ct_verify_result);
 }
 
+#if defined(OS_CHROMEOS)
+void NetworkContext::TrustAnchorUsed() {
+  network_service_->client()->OnUsedTrustAnchor(params_->username_hash);
+}
+#endif
+
 void NetworkContext::ForceReloadProxyConfig(
     ForceReloadProxyConfigCallback callback) {
   url_request_context()->proxy_resolution_service()->ForceReloadProxyConfig();
diff --git a/services/network/network_context.h b/services/network/network_context.h
index 16f03ea6..cdfbedb 100644
--- a/services/network/network_context.h
+++ b/services/network/network_context.h
@@ -62,6 +62,7 @@
 }  // namespace certificate_transparency
 
 namespace network {
+class CertVerifierWithTrustAnchors;
 class CookieManager;
 class ExpectCTReporter;
 class HostResolver;
@@ -200,6 +201,9 @@
       const std::vector<std::string>& excluded_hosts,
       const std::vector<std::string>& excluded_spkis,
       const std::vector<std::string>& excluded_legacy_spkis) override;
+#if defined(OS_CHROMEOS)
+  void UpdateTrustAnchors(const net::CertificateList& trust_anchors) override;
+#endif
   void AddExpectCT(const std::string& domain,
                    base::Time expiry,
                    bool enforce,
@@ -280,6 +284,11 @@
   void SetFailingHttpTransactionForTesting(
       int32_t rv,
       SetFailingHttpTransactionForTestingCallback callback) override;
+  void VerifyCertificateForTesting(
+      const scoped_refptr<net::X509Certificate>& certificate,
+      const std::string& hostname,
+      const std::string& ocsp_response,
+      VerifyCertificateForTestingCallback callback) override;
   void PreconnectSockets(uint32_t num_streams,
                          const GURL& url,
                          int32_t load_flags,
@@ -347,6 +356,10 @@
 
   void OnCertVerifyForSignedExchangeComplete(int cert_verify_id, int result);
 
+#if defined(OS_CHROMEOS)
+  void TrustAnchorUsed();
+#endif
+
   void OnSetExpectCTTestReportSuccess();
 
   void LazyCreateExpectCTReporter(net::URLRequestContext* url_request_context);
@@ -431,6 +444,10 @@
       require_ct_delegate_;
   std::unique_ptr<certificate_transparency::TreeStateTracker> ct_tree_tracker_;
 
+#if defined(OS_CHROMEOS)
+  CertVerifierWithTrustAnchors* cert_verifier_with_trust_anchors_ = nullptr;
+#endif
+
   // Created on-demand. Null if unused.
   std::unique_ptr<HostResolver> internal_host_resolver_;
   // Map values set to non-null only if that HostResolver has its own private
diff --git a/services/network/network_service.cc b/services/network/network_service.cc
index b353f8b2..b2ebfdd 100644
--- a/services/network/network_service.cc
+++ b/services/network/network_service.cc
@@ -24,6 +24,7 @@
 #include "mojo/public/cpp/bindings/type_converter.h"
 #include "net/base/logging_network_change_observer.h"
 #include "net/base/network_change_notifier.h"
+#include "net/cert/cert_database.h"
 #include "net/cert/ct_log_response_parser.h"
 #include "net/cert/signed_tree_head.h"
 #include "net/dns/dns_config_overrides.h"
@@ -449,6 +450,10 @@
   crl_set_distributor_->OnNewCRLSet(crl_set);
 }
 
+void NetworkService::OnCertDBChanged() {
+  net::CertDatabase::GetInstance()->NotifyObserversCertDBChanged();
+}
+
 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
 void NetworkService::SetCryptConfig(mojom::CryptConfigPtr crypt_config) {
 #if !defined(IS_CHROMECAST)
diff --git a/services/network/network_service.h b/services/network/network_service.h
index ed544fe..03495eb 100644
--- a/services/network/network_service.h
+++ b/services/network/network_service.h
@@ -148,6 +148,7 @@
       mojom::NetworkService::GetTotalNetworkUsagesCallback callback) override;
   void UpdateSignedTreeHead(const net::ct::SignedTreeHead& sth) override;
   void UpdateCRLSet(base::span<const uint8_t> crl_set) override;
+  void OnCertDBChanged() override;
 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
   void SetCryptConfig(mojom::CryptConfigPtr crypt_config) override;
 #endif
diff --git a/services/network/p2p/socket_manager.cc b/services/network/p2p/socket_manager.cc
index 938c3df..5429b9c 100644
--- a/services/network/p2p/socket_manager.cc
+++ b/services/network/p2p/socket_manager.cc
@@ -61,6 +61,14 @@
   return type >= 64 && type < 96;
 }
 
+// Names ending in ".local." are link-local and used with Multicast DNS as
+// described in RFC6762 (https://tools.ietf.org/html/rfc6762#section-3).
+constexpr char kLocalTld[] = ".local.";
+
+bool HasLocalTld(const std::string& host_name) {
+  return EndsWith(host_name, kLocalTld, base::CompareCase::INSENSITIVE_ASCII);
+}
+
 }  // namespace
 
 class P2PSocketManager::DnsRequest {
@@ -90,14 +98,18 @@
       host_name_ += '.';
 
     net::HostPortPair host(host_name_, 0);
-    if (enable_mdns_) {
-      // TODO(crbug.com/879746): Pass in a
-      // net::HostResolver::ResolveHostParameters with source set to MDNS if we
-      // have a ".local." TLD and enable_mdns_ is set (once MDNS is supported).
-    }
 
+    net::HostResolver::ResolveHostParameters parameters;
+    if (enable_mdns_ && HasLocalTld(host_name_)) {
+#if BUILDFLAG(ENABLE_MDNS)
+      // HostResolver/MDnsClient expects a key without a trailing dot.
+      host.set_host(host_name_.substr(0, host_name_.size() - 1));
+      parameters.source = net::HostResolverSource::MULTICAST_DNS;
+#endif  // ENABLE_MDNS
+    }
     request_ =
-        resolver_->CreateRequest(host, net::NetLogWithSource(), base::nullopt);
+        resolver_->CreateRequest(host, net::NetLogWithSource(), parameters);
+
     int result = request_->Start(base::BindOnce(
         &P2PSocketManager::DnsRequest::OnDone, base::Unretained(this)));
     if (result != net::ERR_IO_PENDING)
diff --git a/services/network/p2p/socket_udp.cc b/services/network/p2p/socket_udp.cc
index e7609dd6..7efbc8a 100644
--- a/services/network/p2p/socket_udp.cc
+++ b/services/network/p2p/socket_udp.cc
@@ -426,15 +426,9 @@
   }
 }
 
-// TODO(crbug.com/812137): We don't call SetDiffServCodePoint for the Windows
-// UDP socket, because this is known to cause a hanging thread.
 int P2PSocketUdp::SetSocketDiffServCodePointInternal(
     net::DiffServCodePoint dscp) {
-#if defined(OS_WIN)
-  return net::OK;
-#else
   return socket_->SetDiffServCodePoint(dscp);
-#endif
 }
 
 }  // namespace network
diff --git a/services/network/p2p/socket_udp_unittest.cc b/services/network/p2p/socket_udp_unittest.cc
index 21a946cf..6cb714e 100644
--- a/services/network/p2p/socket_udp_unittest.cc
+++ b/services/network/p2p/socket_udp_unittest.cc
@@ -148,6 +148,8 @@
 
   void AllowBroadcast() override { NOTIMPLEMENTED(); }
 
+  void AllowAddressSharingForMulticast() override { NOTIMPLEMENTED(); }
+
   int JoinGroup(const net::IPAddress& group_address) const override {
     NOTIMPLEMENTED();
     return net::ERR_NOT_IMPLEMENTED;
diff --git a/services/network/public/mojom/network_context.mojom b/services/network/public/mojom/network_context.mojom
index a1bb257..c3d6ac6 100644
--- a/services/network/public/mojom/network_context.mojom
+++ b/services/network/public/mojom/network_context.mojom
@@ -224,6 +224,19 @@
   // unrecognized.
   array<CTLogInfo> ct_logs;
 
+  // Specifies the path to the directory where NSS will store its database.
+  [EnableIf=is_chromeos]
+  mojo_base.mojom.FilePath? nss_path;
+
+  // This is used in combination with nss_path, to ensure that the NSS database
+  // isn't opened multiple times for NetworkContexts in the same profie.
+  [EnableIf=is_chromeos]
+  string username_hash;
+
+  // Initial list of additional trust anchors.
+  [EnableIf=is_chromeos]
+  array<X509Certificate> initial_trust_anchors;
+
   // Parameters for constructing the cookie manager.
   CookieManagerParams? cookie_manager_params;
 
@@ -473,6 +486,10 @@
               array<string> excluded_spkis,
               array<string> excluded_legacy_spkis);
 
+  // Updates the additional trust anchors for certificate verification.
+  [EnableIf=is_chromeos]
+  UpdateTrustAnchors(array<X509Certificate> trust_anchors);
+
   // Adds explicitly-specified data as if it was processed from an Expect-CT
   // header.
   AddExpectCT(string host, mojo_base.mojom.Time expiry,
@@ -689,4 +706,10 @@
   [Sync]
   // Will force the transaction to fail with the given error code.
   SetFailingHttpTransactionForTesting(int32 rv) => ();
+
+  [Sync]
+  // Verifies the given certificate using the context's CertVerifier.
+  VerifyCertificateForTesting(X509Certificate certificate,
+                              string hostname,
+                              string ocsp_response) => (int32 error_code);
 };
diff --git a/services/network/public/mojom/network_service.mojom b/services/network/public/mojom/network_service.mojom
index 7413d04d..c5a728d7 100644
--- a/services/network/public/mojom/network_service.mojom
+++ b/services/network/public/mojom/network_service.mojom
@@ -100,6 +100,11 @@
                         url.mojom.Url url,
                         SSLInfo ssl_info,
                         bool fatal) => (int32 net_error);
+
+  // Notification that a trust anchor was used for the given user.
+  [EnableIf=is_chromeos]
+  OnUsedTrustAnchor(string username_hash);
+
   // Called when file uploading was requested.
   // If the process that requested the uploads has permission to read all of
   // the files referenced by |file_paths|, the callback arguments will be
@@ -302,6 +307,9 @@
   // this call, will use the same CRLSet.
   UpdateCRLSet(mojo_base.mojom.ReadOnlyBuffer crl_set);
 
+  // Notification that the certificate database has been modified.
+  OnCertDBChanged();
+
   // Sets up OSCrypt for the network service process. Must be called before
   // encrypted cookies can be read or set.
   [EnableIf=needs_crypt_config]
diff --git a/services/network/public/mojom/udp_socket.mojom b/services/network/public/mojom/udp_socket.mojom
index baf71bf..04259e47 100644
--- a/services/network/public/mojom/udp_socket.mojom
+++ b/services/network/public/mojom/udp_socket.mojom
@@ -16,12 +16,23 @@
   // If true, this enables SO_REUSEADDR on the underlying socket.
   bool allow_address_reuse = false;
 
-  // It true, allows sending and receiving packets to and from broadcast
+  // If true, allows sending and receiving packets to and from broadcast
   // addresses. It's recommended this be used instead of SetBroadcast(), as
   // Bind() may fail on some platforms when reusing a UDP port and broadcast
   // is not enabled when the socket is created.
   bool allow_broadcast = false;
 
+  // If true, allows the socket to share the local address to which the socket
+  // will be bound with other processes and attempts to allow all such sockets
+  // to receive the same multicast messages.
+  //
+  // For best cross-platform results in allowing the messages to be shared, all
+  // sockets sharing the same address should join the same multicast group (via
+  // UDPSocket::JoinGroup()) and set the same |multicast_interface|. Also, the
+  // socket should bind to the specific multicast group address rather than a
+  // wildcard address (e.g. 0.0.0.0) on platforms where doing so is allowed.
+  bool allow_address_sharing_for_multicast = false;
+
   // Sets interface to use for multicast. Default value is 0, in which case the
   // default interface is used.
   uint32 multicast_interface = 0;
diff --git a/services/network/test/test_network_context.h b/services/network/test/test_network_context.h
index 1d5fa84..f706956 100644
--- a/services/network/test/test_network_context.h
+++ b/services/network/test/test_network_context.h
@@ -81,6 +81,9 @@
       const std::vector<std::string>& excluded_hosts,
       const std::vector<std::string>& excluded_spkis,
       const std::vector<std::string>& excluded_legacy_spkis) override {}
+#if defined(OS_CHROMEOS)
+  void UpdateTrustAnchors(const net::CertificateList& trust_anchors) override {}
+#endif
   void AddExpectCT(const std::string& domain,
                    base::Time expiry,
                    bool enforce,
@@ -156,6 +159,11 @@
   void SetFailingHttpTransactionForTesting(
       int32_t rv,
       SetFailingHttpTransactionForTestingCallback callback) override {}
+  void VerifyCertificateForTesting(
+      const scoped_refptr<net::X509Certificate>& certificate,
+      const std::string& hostname,
+      const std::string& ocsp_response,
+      VerifyCertificateForTestingCallback callback) override {}
   void PreconnectSockets(uint32_t num_streams,
                          const GURL& url,
                          int32_t load_flags,
diff --git a/services/network/test/test_network_service_client.cc b/services/network/test/test_network_service_client.cc
index f33dce7..62be932 100644
--- a/services/network/test/test_network_service_client.cc
+++ b/services/network/test/test_network_service_client.cc
@@ -79,6 +79,13 @@
   NOTREACHED();
 }
 
+#if defined(OS_CHROMEOS)
+void TestNetworkServiceClient::OnUsedTrustAnchor(
+    const std::string& username_hash) {
+  NOTREACHED();
+}
+#endif
+
 void TestNetworkServiceClient::OnFileUploadRequested(
     uint32_t process_id,
     bool async,
diff --git a/services/network/test/test_network_service_client.h b/services/network/test/test_network_service_client.h
index f270ad99..de4148a 100644
--- a/services/network/test/test_network_service_client.h
+++ b/services/network/test/test_network_service_client.h
@@ -61,6 +61,9 @@
                       const GURL& first_party_url,
                       const net::CanonicalCookie& cookie,
                       bool blocked_by_policy) override;
+#if defined(OS_CHROMEOS)
+  void OnUsedTrustAnchor(const std::string& username_hash) override;
+#endif
   void OnFileUploadRequested(uint32_t process_id,
                              bool async,
                              const std::vector<base::FilePath>& file_paths,
diff --git a/services/network/udp_socket.cc b/services/network/udp_socket.cc
index c2f6e70..5847ba9 100644
--- a/services/network/udp_socket.cc
+++ b/services/network/udp_socket.cc
@@ -116,6 +116,8 @@
     int result = net::OK;
     if (options->allow_address_reuse)
       result = socket_.AllowAddressReuse();
+    if (result == net::OK && options->allow_address_sharing_for_multicast)
+      result = socket_.AllowAddressSharingForMulticast();
     if (result == net::OK && options->allow_broadcast)
       result = socket_.SetBroadcast(true);
     if (result == net::OK && options->multicast_interface != 0)
diff --git a/services/network/udp_socket_unittest.cc b/services/network/udp_socket_unittest.cc
index a33ff22..0191117e 100644
--- a/services/network/udp_socket_unittest.cc
+++ b/services/network/udp_socket_unittest.cc
@@ -688,11 +688,13 @@
   // See https://fuchsia.atlassian.net/browse/NET-195 .
   options->multicast_interface = 1;
 #endif  // defined(OS_FUCHSIA)
+  options->allow_address_sharing_for_multicast = true;
 
   net::IPAddress bind_ip_address;
   EXPECT_TRUE(bind_ip_address.AssignFromIPLiteral("0.0.0.0"));
   net::IPEndPoint socket_address(bind_ip_address, 0);
-  ASSERT_EQ(net::OK, helper.BindSync(socket_address, nullptr, &socket_address));
+  ASSERT_EQ(net::OK, helper.BindSync(socket_address, std::move(options),
+                                     &socket_address));
   int port = socket_address.port();
   EXPECT_NE(0, port);
   EXPECT_EQ(net::OK, helper.JoinGroupSync(group_ip));
diff --git a/services/network/url_loader_unittest.cc b/services/network/url_loader_unittest.cc
index c606056..d7d4405 100644
--- a/services/network/url_loader_unittest.cc
+++ b/services/network/url_loader_unittest.cc
@@ -2211,6 +2211,12 @@
     NOTREACHED();
   }
 
+#if defined(OS_CHROMEOS)
+  void OnUsedTrustAnchor(const std::string& username_hash) override {
+    NOTREACHED();
+  }
+#endif
+
   void OnFileUploadRequested(uint32_t process_id,
                              bool async,
                              const std::vector<base::FilePath>& file_paths,
diff --git a/services/service_manager/sandbox/mac/common.sb b/services/service_manager/sandbox/mac/common.sb
index 51f6a4b9..711704a 100644
--- a/services/service_manager/sandbox/mac/common.sb
+++ b/services/service_manager/sandbox/mac/common.sb
@@ -20,6 +20,7 @@
 (define homedir-as-literal "USER_HOMEDIR_AS_LITERAL")
 (define elcap-or-later "ELCAP_OR_LATER")
 (define macos-1013 "MACOS_1013")
+(define field-trial-server-name "FIELD_TRIAL_SERVER_NAME")
 
 ; Consumes a subpath and appends it to the user's homedir path.
 (define (user-homedir-path subpath)
@@ -37,6 +38,8 @@
 ; Support for programmatically enabling verbose debugging.
 (if (param-true? enable-logging) (debug deny))
 
+(allow mach-lookup (global-name (param field-trial-server-name)))
+
 ; Allow sending signals to self - https://crbug.com/20370
 (allow signal (target self))
 
diff --git a/services/service_manager/sandbox/mac/common_v2.sb b/services/service_manager/sandbox/mac/common_v2.sb
index 9ce0a10a..d7a2798 100644
--- a/services/service_manager/sandbox/mac/common_v2.sb
+++ b/services/service_manager/sandbox/mac/common_v2.sb
@@ -74,9 +74,16 @@
 (allow process-exec (path (param executable-path)))
 (allow file-read* (path (param executable-path)))
 
-(allow mach-lookup (global-name (string-append (param bundle-id)
-                                               ".rohitfork."
-                                               (param browser-pid))))
+; The browser exposes Mach services at "bundle-id.service-name.browser-pid".
+; This macro is a helper for doing the string concatenation.
+(define (browser-service-name service-name)
+  (global-name (string-append (param bundle-id)
+                              "." service-name "."
+                              (param browser-pid))))
+
+(allow mach-lookup
+  (browser-service-name "FieldTrialMemoryServer")
+  (browser-service-name "rohitfork"))
 
 ; Allow realpath() to work.
 (allow file-read-metadata (subpath "/"))
diff --git a/services/service_manager/sandbox/mac/sandbox_mac.h b/services/service_manager/sandbox/mac/sandbox_mac.h
index 31df9dd5..9b3bb2e7 100644
--- a/services/service_manager/sandbox/mac/sandbox_mac.h
+++ b/services/service_manager/sandbox/mac/sandbox_mac.h
@@ -54,6 +54,7 @@
   // TODO(kerrnel): this is only for the legacy sandbox.
   static const char* kSandboxElCapOrLater;
   static const char* kSandboxMacOS1013;
+  static const char* kSandboxFieldTrialSeverName;
 
   static const char* kSandboxBundleVersionPath;
 
diff --git a/services/service_manager/sandbox/mac/sandbox_mac.mm b/services/service_manager/sandbox/mac/sandbox_mac.mm
index eb01a0ab..077a403 100644
--- a/services/service_manager/sandbox/mac/sandbox_mac.mm
+++ b/services/service_manager/sandbox/mac/sandbox_mac.mm
@@ -28,6 +28,7 @@
 #include "base/mac/scoped_nsautorelease_pool.h"
 #include "base/mac/scoped_nsobject.h"
 #include "base/macros.h"
+#include "base/metrics/field_trial_memory_mac.h"
 #include "base/rand_util.h"
 #include "base/strings/string16.h"
 #include "base/strings/string_piece.h"
@@ -96,6 +97,7 @@
 const char* SandboxMac::kSandboxOSVersion = "OS_VERSION";
 const char* SandboxMac::kSandboxElCapOrLater = "ELCAP_OR_LATER";
 const char* SandboxMac::kSandboxMacOS1013 = "MACOS_1013";
+const char* SandboxMac::kSandboxFieldTrialSeverName = "FIELD_TRIAL_SERVER_NAME";
 const char* SandboxMac::kSandboxBundleVersionPath = "BUNDLE_VERSION_PATH";
 
 // Warm up System APIs that empirically need to be accessed before the Sandbox
@@ -234,6 +236,13 @@
                                   home_dir_canonical.value())) {
     return false;
   }
+
+  if (!compiler.InsertStringParam(
+          kSandboxFieldTrialSeverName,
+          base::FieldTrialMemoryClient::GetBootstrapName())) {
+    return false;
+  }
+
   bool elcap_or_later = base::mac::IsAtLeastOS10_11();
   if (!compiler.InsertBooleanParam(kSandboxElCapOrLater, elcap_or_later))
     return false;
diff --git a/services/tracing/coordinator.cc b/services/tracing/coordinator.cc
index c253db5e..cebe4c4 100644
--- a/services/tracing/coordinator.cc
+++ b/services/tracing/coordinator.cc
@@ -62,10 +62,10 @@
         stream_is_empty_(true),
         json_field_name_written_(false) {}
 
-  // Destroyed on |background_task_runner_|.
+  // Destroyed on |backend_task_runner_|.
   ~TraceStreamer() = default;
 
-  // Called from |background_task_runner_|.
+  // Called from |backend_task_runner_|.
   void CreateAndSendRecorder(
       const std::string& label,
       mojom::TraceDataType type,
@@ -86,7 +86,7 @@
                                   agent_entry, std::move(ptr)));
   }
 
-  // Called from |background_task_runner_| to close the recorder proxy on the
+  // Called from |backend_task_runner_| to close the recorder proxy on the
   // correct task runner.
   void CloseRecorder(mojom::RecorderPtr recorder) {}
 
@@ -112,7 +112,7 @@
       mojo::BlockingCopyFromString(data, stream_);
   }
 
-  // Called from |background_task_runner_|.
+  // Called from |backend_task_runner_|.
   void OnRecorderDataChange(const std::string& label) {
     // Bail out if we are in the middle of writing events for another label to
     // the stream, since we do not want to interleave chunks for different
@@ -163,7 +163,7 @@
     }
   }
 
-  // Called from |background_task_runner_|.
+  // Called from |backend_task_runner_|.
   bool StreamEventsForCurrentLabel() {
     bool waiting_for_agents = false;
     mojom::TraceDataType data_type =
@@ -228,7 +228,7 @@
     return waiting_for_agents;
   }
 
-  // Called from |background_task_runner_|.
+  // Called from |backend_task_runner_|.
   void StreamMetadata() {
     if (!agent_label_.empty())
       return;
@@ -271,13 +271,17 @@
 Coordinator::Coordinator(AgentRegistry* agent_registry)
     : binding_(this),
       task_runner_(base::ThreadTaskRunnerHandle::Get()),
+      // USER_VISIBLE because the task posted from StopAndFlushAfterClockSync()
+      // is required to stop tracing from the UI.
+      // TODO(fdoray): Once we have support for dynamic priorities
+      // (https://crbug.com/889029), use BEST_EFFORT initially and increase the
+      // priority only when blocking the tracing UI.
+      backend_task_runner_(base::CreateSequencedTaskRunnerWithTraits(
+          {base::TaskPriority::USER_VISIBLE, base::MayBlock(),
+           base::WithBaseSyncPrimitives()})),
       agent_registry_(agent_registry),
       weak_ptr_factory_(this) {
   DCHECK(agent_registry_);
-  constexpr base::TaskTraits traits = {base::MayBlock(),
-                                       base::WithBaseSyncPrimitives(),
-                                       base::TaskPriority::BEST_EFFORT};
-  background_task_runner_ = base::CreateSequencedTaskRunnerWithTraits(traits);
 }
 
 Coordinator::~Coordinator() {
@@ -296,11 +300,11 @@
     // We are in the middle of flushing trace data. We need to
     // 1- Close the stream so that the TraceStreamer does not block on writing
     //    to it.
-    // 2- Delete the TraceStreamer on the background task runner; it owns
-    //    recorders that should be destructed on the background task runner
-    //    because they are bound on the background task runner.
+    // 2- Delete the TraceStreamer on the backend task runner; it owns recorders
+    //    that should be destructed on the backend task runner because they are
+    //    bound on the backend task runner.
     trace_streamer_->CloseStream();
-    background_task_runner_->DeleteSoon(FROM_HERE, trace_streamer_.release());
+    backend_task_runner_->DeleteSoon(FROM_HERE, trace_streamer_.release());
   }
 }
 
@@ -454,7 +458,7 @@
         if (!agent_entry->is_tracing())
           return;
         has_tracing_agents = true;
-        background_task_runner_->PostTask(
+        backend_task_runner_->PostTask(
             FROM_HERE,
             base::BindOnce(&Coordinator::TraceStreamer::CreateAndSendRecorder,
                            trace_streamer_->AsWeakPtr(), agent_entry->label(),
@@ -470,8 +474,8 @@
   if (agent_entry) {
     agent_entry->agent()->StopAndFlush(std::move(recorder));
   } else {
-    // Recorders are created and closed on |background_task_runner_|.
-    background_task_runner_->PostTask(
+    // Recorders are created and closed on |backend_task_runner_|.
+    backend_task_runner_->PostTask(
         FROM_HERE,
         base::BindOnce(&Coordinator::TraceStreamer::CloseRecorder,
                        trace_streamer_->AsWeakPtr(), std::move(recorder)));
@@ -481,7 +485,7 @@
 void Coordinator::OnFlushDone() {
   std::move(stop_and_flush_callback_)
       .Run(std::move(*trace_streamer_->GetMetadata()));
-  background_task_runner_->DeleteSoon(FROM_HERE, trace_streamer_.release());
+  backend_task_runner_->DeleteSoon(FROM_HERE, trace_streamer_.release());
   agent_registry_->ForAllAgents([](AgentRegistry::AgentEntry* agent_entry) {
     agent_entry->set_is_tracing(false);
   });
diff --git a/services/tracing/coordinator.h b/services/tracing/coordinator.h
index c233d8fe..ba773026 100644
--- a/services/tracing/coordinator.h
+++ b/services/tracing/coordinator.h
@@ -89,8 +89,8 @@
                                const std::string& categories);
 
   mojo::Binding<mojom::Coordinator> binding_;
-  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
-  scoped_refptr<base::SequencedTaskRunner> background_task_runner_;
+  const scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+  const scoped_refptr<base::SequencedTaskRunner> backend_task_runner_;
   AgentRegistry* agent_registry_;
   std::string config_;
   base::trace_event::TraceConfig parsed_config_;
diff --git a/services/tracing/perfetto/json_trace_exporter.cc b/services/tracing/perfetto/json_trace_exporter.cc
index d58f65e6..df3f0103 100644
--- a/services/tracing/perfetto/json_trace_exporter.cc
+++ b/services/tracing/perfetto/json_trace_exporter.cc
@@ -209,7 +209,7 @@
 
   // Start tracing.
   perfetto::TraceConfig trace_config;
-  trace_config.add_buffers()->set_size_kb(1024 * 32);
+  trace_config.add_buffers()->set_size_kb(4096 * 100);
 
   auto* trace_event_config = trace_config.add_data_sources()->mutable_config();
   trace_event_config->set_name(mojom::kTraceEventDataSourceName);
diff --git a/services/tracing/perfetto/perfetto_integration_unittest.cc b/services/tracing/perfetto/perfetto_integration_unittest.cc
index 237a1a5..94c6ce2 100644
--- a/services/tracing/perfetto/perfetto_integration_unittest.cc
+++ b/services/tracing/perfetto/perfetto_integration_unittest.cc
@@ -188,7 +188,7 @@
 
   void StartTracing() {
     perfetto::TraceConfig trace_config;
-    trace_config.add_buffers()->set_size_kb(1024 * 32);
+    trace_config.add_buffers()->set_size_kb(4096 * 100);
     auto* ds_config = trace_config.add_data_sources()->mutable_config();
     ds_config->set_name(data_source_name_);
     ds_config->set_target_buffer(0);
diff --git a/services/tracing/public/cpp/perfetto/trace_event_data_source.cc b/services/tracing/public/cpp/perfetto/trace_event_data_source.cc
index f7bec193..0eb900a 100644
--- a/services/tracing/public/cpp/perfetto/trace_event_data_source.cc
+++ b/services/tracing/public/cpp/perfetto/trace_event_data_source.cc
@@ -178,7 +178,7 @@
 
     int name_index = 0;
     int category_name_index = 0;
-    int arg_name_indices[base::trace_event::kTraceMaxNumArgs] = {0};
+    int arg_name_indices[base::trace_event::TraceArguments::kMaxSize] = {0};
 
     // Populate any new string table parts first; has to be done before
     // the add_trace_events() call (as the string table is part of the outer
@@ -192,8 +192,7 @@
       category_name_index = GetStringTableIndexForString(
           TraceLog::GetCategoryGroupName(trace_event.category_group_enabled()));
 
-      for (int i = 0;
-           i < base::trace_event::kTraceMaxNumArgs && trace_event.arg_name(i);
+      for (size_t i = 0; i < trace_event.arg_size() && trace_event.arg_name(i);
            ++i) {
         arg_name_indices[i] =
             GetStringTableIndexForString(trace_event.arg_name(i));
@@ -238,8 +237,7 @@
     char phase = trace_event.phase();
     new_trace_event->set_phase(phase);
 
-    for (int i = 0;
-         i < base::trace_event::kTraceMaxNumArgs && trace_event.arg_name(i);
+    for (size_t i = 0; i < trace_event.arg_size() && trace_event.arg_name(i);
          ++i) {
       auto type = trace_event.arg_type(i);
       auto* new_arg = new_trace_event->add_args();
diff --git a/services/viz/privileged/interfaces/compositing/renderer_settings.mojom b/services/viz/privileged/interfaces/compositing/renderer_settings.mojom
index d7211df..75632bc5 100644
--- a/services/viz/privileged/interfaces/compositing/renderer_settings.mojom
+++ b/services/viz/privileged/interfaces/compositing/renderer_settings.mojom
@@ -21,6 +21,7 @@
   int32 slow_down_compositing_scale_factor;
   bool use_skia_renderer;
   bool use_skia_deferred_display_list;
+  bool record_sk_picture;
   bool allow_overlays;
   bool requires_alpha_channel;
 
diff --git a/services/viz/privileged/interfaces/compositing/renderer_settings_struct_traits.cc b/services/viz/privileged/interfaces/compositing/renderer_settings_struct_traits.cc
index 0e3bcb2..abbd73a 100644
--- a/services/viz/privileged/interfaces/compositing/renderer_settings_struct_traits.cc
+++ b/services/viz/privileged/interfaces/compositing/renderer_settings_struct_traits.cc
@@ -28,6 +28,7 @@
   out->slow_down_compositing_scale_factor =
       data.slow_down_compositing_scale_factor();
   out->use_skia_renderer = data.use_skia_renderer();
+  out->record_sk_picture = data.record_sk_picture();
   out->use_skia_deferred_display_list = data.use_skia_deferred_display_list();
   out->allow_overlays = data.allow_overlays();
   out->requires_alpha_channel = data.requires_alpha_channel();
diff --git a/services/viz/privileged/interfaces/compositing/renderer_settings_struct_traits.h b/services/viz/privileged/interfaces/compositing/renderer_settings_struct_traits.h
index d363e9b..da832a2 100644
--- a/services/viz/privileged/interfaces/compositing/renderer_settings_struct_traits.h
+++ b/services/viz/privileged/interfaces/compositing/renderer_settings_struct_traits.h
@@ -69,6 +69,10 @@
     return input.use_skia_renderer;
   }
 
+  static bool record_sk_picture(const viz::RendererSettings& input) {
+    return input.record_sk_picture;
+  }
+
   static bool use_skia_deferred_display_list(
       const viz::RendererSettings& input) {
     return input.use_skia_deferred_display_list;
diff --git a/services/ws/client_root.cc b/services/ws/client_root.cc
index 188bf6e..1ca884b 100644
--- a/services/ws/client_root.cc
+++ b/services/ws/client_root.cc
@@ -239,7 +239,17 @@
   DCHECK_EQ(window, window_);
   DCHECK(window->GetHost());
   window->GetHost()->AddObserver(this);
-  CheckForScaleFactorChange();
+  window_tree_->window_tree_client_->OnWindowDisplayChanged(
+      window_tree_->TransportIdForWindow(window),
+      window->GetHost()->GetDisplayId());
+
+  // When the addition to a new root window isn't the result of moving across
+  // displays (e.g. destruction of the current display), the window bounds in
+  // screen change even though its bounds in the root window remain the same.
+  if (is_top_level_ && !is_moving_across_displays_)
+    HandleBoundsOrScaleFactorChange(window->GetBoundsInScreen());
+  else
+    CheckForScaleFactorChange();
 }
 
 void ClientRoot::OnWindowRemovingFromRootWindow(aura::Window* window,
@@ -258,9 +268,6 @@
 void ClientRoot::OnDidMoveWindowToDisplay(aura::Window* window) {
   DCHECK(is_moving_across_displays_);
   is_moving_across_displays_ = false;
-  window_tree_->window_tree_client_->OnWindowDisplayChanged(
-      window_tree_->TransportIdForWindow(window),
-      window->GetHost()->GetDisplayId());
   if (scheduled_change_old_bounds_) {
     HandleBoundsOrScaleFactorChange(scheduled_change_old_bounds_.value());
     scheduled_change_old_bounds_.reset();
diff --git a/services/ws/topmost_window_observer.cc b/services/ws/topmost_window_observer.cc
index d379605..219ee76 100644
--- a/services/ws/topmost_window_observer.cc
+++ b/services/ws/topmost_window_observer.cc
@@ -16,17 +16,6 @@
 #include "ui/gfx/geometry/point_f.h"
 #include "ui/wm/core/coordinate_conversion.h"
 
-namespace {
-
-gfx::Point GetLocationInScreen(const ui::LocatedEvent& event) {
-  gfx::Point location_in_screen = event.location();
-  ::wm::ConvertPointToScreen(static_cast<aura::Window*>(event.target()),
-                             &location_in_screen);
-  return location_in_screen;
-}
-
-}  // namespace
-
 namespace ws {
 
 TopmostWindowObserver::TopmostWindowObserver(WindowTree* window_tree,
@@ -35,50 +24,37 @@
     : window_tree_(window_tree),
       source_(source),
       last_target_(initial_target),
-      root_(initial_target->GetRootWindow()) {
-  root_->AddPreTargetHandler(this, ui::EventTarget::Priority::kSystem);
+      env_(initial_target->env()) {
+  std::set<ui::EventType> types;
   if (source == mojom::MoveLoopSource::MOUSE) {
-    last_location_ =
-        root_->GetHost()->dispatcher()->GetLastMouseLocationInRoot();
-    ::wm::ConvertPointToScreen(root_, &last_location_);
+    types.insert(ui::ET_MOUSE_MOVED);
+    types.insert(ui::ET_MOUSE_DRAGGED);
+    last_location_ = env_->last_mouse_location();
   } else {
+    types.insert(ui::ET_TOUCH_MOVED);
     gfx::PointF point;
-    ui::GestureRecognizer* gesture_recognizer =
-        initial_target->env()->gesture_recognizer();
+    ui::GestureRecognizer* gesture_recognizer = env_->gesture_recognizer();
     if (gesture_recognizer->GetLastTouchPointForTarget(last_target_, &point))
       last_location_ = gfx::Point(point.x(), point.y());
     ::wm::ConvertPointToScreen(last_target_, &last_location_);
   }
+  env_->AddEventObserver(this, env_, types);
   UpdateTopmostWindows();
 }
 
 TopmostWindowObserver::~TopmostWindowObserver() {
-  root_->RemovePreTargetHandler(this);
+  env_->RemoveEventObserver(this);
   if (topmost_)
     topmost_->RemoveObserver(this);
   if (real_topmost_ && topmost_ != real_topmost_)
     real_topmost_->RemoveObserver(this);
 }
 
-void TopmostWindowObserver::OnMouseEvent(ui::MouseEvent* event) {
-  CHECK_EQ(ui::EP_PRETARGET, event->phase());
-  if (source_ != mojom::MoveLoopSource::MOUSE)
-    return;
-  // The event target can change when the dragged browser tab is detached into a
-  // new window.
-  last_target_ = static_cast<aura::Window*>(event->target());
-  last_location_ = GetLocationInScreen(*event);
-  UpdateTopmostWindows();
-}
-
-void TopmostWindowObserver::OnTouchEvent(ui::TouchEvent* event) {
-  CHECK_EQ(ui::EP_PRETARGET, event->phase());
-  if (source_ != mojom::MoveLoopSource::TOUCH)
-    return;
-  // The event target can change when the dragged browser tab is detached into a
-  // new window.
-  last_target_ = static_cast<aura::Window*>(event->target());
-  last_location_ = GetLocationInScreen(*event);
+void TopmostWindowObserver::OnEvent(const ui::Event& event) {
+  CHECK(event.IsLocatedEvent());
+  last_target_ = static_cast<aura::Window*>(event.target());
+  last_location_ = event.AsLocatedEvent()->location();
+  ::wm::ConvertPointToScreen(last_target_, &last_location_);
   UpdateTopmostWindows();
 }
 
diff --git a/services/ws/topmost_window_observer.h b/services/ws/topmost_window_observer.h
index 7744dbf..14bc244 100644
--- a/services/ws/topmost_window_observer.h
+++ b/services/ws/topmost_window_observer.h
@@ -7,10 +7,11 @@
 
 #include "services/ws/public/mojom/window_tree.mojom.h"
 #include "ui/aura/window_observer.h"
-#include "ui/events/event_handler.h"
+#include "ui/events/event_observer.h"
 #include "ui/gfx/geometry/point.h"
 
 namespace aura {
+class Env;
 class Window;
 }
 
@@ -23,7 +24,7 @@
 
 // TODO(mukai): support multiple displays.
 class COMPONENT_EXPORT(WINDOW_SERVICE) TopmostWindowObserver
-    : public ui::EventHandler,
+    : public ui::EventObserver,
       public aura::WindowObserver {
  public:
   // |source| determines the type of the event, and |initial_target| is the
@@ -37,9 +38,8 @@
  private:
   friend class TopmostWindowObserverTest;
 
-  // ui::EventHandler:
-  void OnMouseEvent(ui::MouseEvent* event) override;
-  void OnTouchEvent(ui::TouchEvent* event) override;
+  // ui::EventObserver:
+  void OnEvent(const ui::Event& event) override;
 
   // aura::WindowObserver:
   void OnWindowVisibilityChanged(aura::Window* window, bool visible) override;
@@ -72,8 +72,7 @@
   // The topmost window (including |last_target_|) under the cursor/touch.
   aura::Window* real_topmost_ = nullptr;
 
-  // The attached root window.
-  aura::Window* root_;
+  aura::Env* env_;
 
   DISALLOW_COPY_AND_ASSIGN(TopmostWindowObserver);
 };
diff --git a/skia/config/SkUserConfig.h b/skia/config/SkUserConfig.h
index 3004114..b8c2e5b 100644
--- a/skia/config/SkUserConfig.h
+++ b/skia/config/SkUserConfig.h
@@ -132,6 +132,8 @@
 // Remove these as we update our sites.
 //
 
+#define SK_LEGACY_APPROX_POWF_SPECIALCASE
+
 // Workaround for poor anisotropic mipmap quality,
 // pending Skia ripmap support.
 // (https://bugs.chromium.org/p/skia/issues/detail?id=4863)
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json
index 9cfe4e1..bd96e6ac 100644
--- a/testing/buildbot/chromium.android.json
+++ b/testing/buildbot/chromium.android.json
@@ -3240,9 +3240,6 @@
         "test": "components_gcm_driver_junit_tests"
       },
       {
-        "test": "components_instance_id_junit_tests"
-      },
-      {
         "test": "components_invalidation_impl_junit_tests"
       },
       {
@@ -20753,9 +20750,6 @@
         "test": "components_gcm_driver_junit_tests"
       },
       {
-        "test": "components_instance_id_junit_tests"
-      },
-      {
         "test": "components_invalidation_impl_junit_tests"
       },
       {
diff --git a/testing/buildbot/chromium.clang.json b/testing/buildbot/chromium.clang.json
index 276b70bf..fafdfd7 100644
--- a/testing/buildbot/chromium.clang.json
+++ b/testing/buildbot/chromium.clang.json
@@ -7341,9 +7341,6 @@
         "test": "components_gcm_driver_junit_tests"
       },
       {
-        "test": "components_instance_id_junit_tests"
-      },
-      {
         "test": "components_invalidation_impl_junit_tests"
       },
       {
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index 9037d1ef..6991e8a 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -392,6 +392,17 @@
       },
       {
         "args": [
+          "--disable-features=VizDisplayCompositor"
+        ],
+        "name": "non_viz_browser_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "shards": 10
+        },
+        "test": "browser_tests"
+      },
+      {
+        "args": [
           "--enable-features=WebUIPolymer2",
           "--test-launcher-filter-file=../../testing/buildbot/filters/webui_polymer2_browser_tests.filter"
         ],
@@ -461,6 +472,17 @@
       },
       {
         "args": [
+          "--disable-features=VizDisplayCompositor"
+        ],
+        "name": "non_viz_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "shards": 10
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--enable-features=TracingPerfettoBackend",
           "--gtest_filter=TracingControllerTest.*"
         ],
@@ -477,6 +499,16 @@
         "test": "content_unittests"
       },
       {
+        "args": [
+          "--disable-features=VizDisplayCompositor"
+        ],
+        "name": "non_viz_content_unittests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_unittests"
+      },
+      {
         "swarming": {
           "can_use_on_swarming_builders": true
         },
@@ -1025,9 +1057,9 @@
     "gtest_tests": [
       {
         "args": [
-          "--enable-features=VizDisplayCompositor"
+          "--disable-features=VizDisplayCompositor"
         ],
-        "name": "viz_browser_tests",
+        "name": "non_viz_browser_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "shards": 10
@@ -1036,9 +1068,9 @@
       },
       {
         "args": [
-          "--enable-features=VizDisplayCompositor"
+          "--disable-features=VizDisplayCompositor"
         ],
-        "name": "viz_content_browsertests",
+        "name": "non_viz_content_browsertests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "shards": 10
@@ -1047,23 +1079,13 @@
       },
       {
         "args": [
-          "--enable-features=VizDisplayCompositor"
+          "--disable-features=VizDisplayCompositor"
         ],
-        "name": "viz_content_unittests",
+        "name": "non_viz_content_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true
         },
         "test": "content_unittests"
-      },
-      {
-        "args": [
-          "--enable-features=VizDisplayCompositor"
-        ],
-        "name": "viz_interactive_ui_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "interactive_ui_tests"
       }
     ]
   },
@@ -1397,6 +1419,53 @@
       },
       {
         "args": [
+          "--disable-features=VizDisplayCompositor",
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "non_viz_content_browsertests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "name": "non_viz_content_browsertests",
+        "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": "MMB29Q",
+              "device_type": "bullhead",
+              "os": "Android"
+            }
+          ],
+          "hard_timeout": 3600,
+          "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": "content_browsertests"
+      },
+      {
+        "args": [
           "--enable-features=NetworkService",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices"
@@ -1750,9 +1819,9 @@
       },
       {
         "args": [
-          "--enable-features=VizDisplayCompositor"
+          "--disable-features=VizDisplayCompositor"
         ],
-        "name": "viz_browser_tests",
+        "name": "non_viz_browser_tests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "shards": 10
@@ -1783,9 +1852,9 @@
       },
       {
         "args": [
-          "--enable-features=VizDisplayCompositor"
+          "--disable-features=VizDisplayCompositor"
         ],
-        "name": "viz_content_browsertests",
+        "name": "non_viz_content_browsertests",
         "swarming": {
           "can_use_on_swarming_builders": true,
           "shards": 10
@@ -1794,9 +1863,9 @@
       },
       {
         "args": [
-          "--enable-features=VizDisplayCompositor"
+          "--disable-features=VizDisplayCompositor"
         ],
-        "name": "viz_content_unittests",
+        "name": "non_viz_content_unittests",
         "swarming": {
           "can_use_on_swarming_builders": true
         },
@@ -1824,16 +1893,6 @@
         "test": "interactive_ui_tests"
       },
       {
-        "args": [
-          "--enable-features=VizDisplayCompositor"
-        ],
-        "name": "viz_interactive_ui_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "interactive_ui_tests"
-      },
-      {
         "swarming": {
           "can_use_on_swarming_builders": true
         },
@@ -2985,6 +3044,52 @@
       },
       {
         "args": [
+          "--disable-features=VizDisplayCompositor",
+          "--gs-results-bucket=chromium-result-details",
+          "--recover-devices"
+        ],
+        "merge": {
+          "args": [
+            "--bucket",
+            "chromium-result-details",
+            "--test-name",
+            "non_viz_content_browsertests"
+          ],
+          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
+        },
+        "name": "non_viz_content_browsertests",
+        "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": "MMB29Q",
+              "device_type": "bullhead",
+              "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": "content_browsertests"
+      },
+      {
+        "args": [
           "--enable-features=NetworkService",
           "--gs-results-bucket=chromium-result-details",
           "--recover-devices"
@@ -5751,9 +5856,9 @@
     "gtest_tests": [
       {
         "isolate_coverage_data": true,
-        "shards": 2,
         "swarming": {
-          "can_use_on_swarming_builders": true
+          "can_use_on_swarming_builders": true,
+          "shards": 2
         },
         "test": "base_unittests"
       }
@@ -6775,6 +6880,24 @@
       },
       {
         "args": [
+          "--disable-features=VizDisplayCompositor"
+        ],
+        "name": "non_viz_browser_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a2e",
+              "os": "Mac-10.14"
+            }
+          ],
+          "expiration": 21600,
+          "shards": 10
+        },
+        "test": "browser_tests"
+      },
+      {
+        "args": [
           "--enable-features=WebUIPolymer2",
           "--test-launcher-filter-file=../../testing/buildbot/filters/webui_polymer2_browser_tests.filter"
         ],
@@ -6950,6 +7073,24 @@
       },
       {
         "args": [
+          "--disable-features=VizDisplayCompositor"
+        ],
+        "name": "non_viz_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a2e",
+              "os": "Mac-10.14"
+            }
+          ],
+          "expiration": 21600,
+          "shards": 10
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--enable-features=TracingPerfettoBackend",
           "--gtest_filter=TracingControllerTest.*"
         ],
@@ -6980,6 +7121,23 @@
         "test": "content_unittests"
       },
       {
+        "args": [
+          "--disable-features=VizDisplayCompositor"
+        ],
+        "name": "non_viz_content_unittests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a2e",
+              "os": "Mac-10.14"
+            }
+          ],
+          "expiration": 21600
+        },
+        "test": "content_unittests"
+      },
+      {
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -8011,6 +8169,18 @@
       },
       {
         "args": [
+          "--disable-features=VizDisplayCompositor",
+          "--enable-features=ViewsBrowserWindows"
+        ],
+        "name": "non_viz_browser_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "shards": 10
+        },
+        "test": "browser_tests"
+      },
+      {
+        "args": [
           "--enable-features=WebUIPolymer2,ViewsBrowserWindows",
           "--test-launcher-filter-file=../../testing/buildbot/filters/webui_polymer2_browser_tests.filter"
         ],
@@ -8105,6 +8275,18 @@
       },
       {
         "args": [
+          "--disable-features=VizDisplayCompositor",
+          "--enable-features=ViewsBrowserWindows"
+        ],
+        "name": "non_viz_content_browsertests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "shards": 10
+        },
+        "test": "content_browsertests"
+      },
+      {
+        "args": [
           "--enable-features=TracingPerfettoBackend,ViewsBrowserWindows",
           "--gtest_filter=TracingControllerTest.*"
         ],
@@ -8125,6 +8307,17 @@
       },
       {
         "args": [
+          "--disable-features=VizDisplayCompositor",
+          "--enable-features=ViewsBrowserWindows"
+        ],
+        "name": "non_viz_content_unittests",
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "content_unittests"
+      },
+      {
+        "args": [
           "--enable-features=ViewsBrowserWindows"
         ],
         "swarming": {
diff --git a/testing/buildbot/chromium.mac.json b/testing/buildbot/chromium.mac.json
index 73033944..86f777b 100644
--- a/testing/buildbot/chromium.mac.json
+++ b/testing/buildbot/chromium.mac.json
@@ -1258,8 +1258,7 @@
           "dimension_sets": [
             {
               "gpu": "none",
-              "os": "Mac-10.11",
-              "pool": "Chrome-quarantine"
+              "os": "Mac-10.11"
             }
           ],
           "shards": 10
@@ -2395,9 +2394,8 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "gpu": "none",
-              "os": "Mac-10.12.6",
-              "pool": "Chrome-quarantine"
+              "gpu": "8086:0a2e",
+              "os": "Mac-10.12.6"
             }
           ],
           "shards": 10
@@ -3619,8 +3617,7 @@
           "dimension_sets": [
             {
               "gpu": "none",
-              "os": "Mac-10.13",
-              "pool": "Chrome-quarantine"
+              "os": "Mac-10.13"
             }
           ],
           "shards": 10
@@ -4745,8 +4742,7 @@
           "dimension_sets": [
             {
               "gpu": "none",
-              "os": "Mac-10.13",
-              "pool": "Chrome-quarantine"
+              "os": "Mac-10.13"
             }
           ],
           "shards": 10
diff --git a/testing/buildbot/filters/chromeos.single_process_mash.interactive_ui_tests.filter b/testing/buildbot/filters/chromeos.single_process_mash.interactive_ui_tests.filter
index d6208876..0be7bd78 100644
--- a/testing/buildbot/filters/chromeos.single_process_mash.interactive_ui_tests.filter
+++ b/testing/buildbot/filters/chromeos.single_process_mash.interactive_ui_tests.filter
@@ -43,9 +43,6 @@
 # TabDragging: crbug.com/890071
 -DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest.CancelDragTabToWindowIn1stDisplay
 -TabDragging/DetachToBrowserInSeparateDisplayTabDragControllerTest.DragBrowserWindowWhenMajorityOfBoundsInSecondDisplay/0
--TabDragging/DetachToBrowserInSeparateDisplayTabDragControllerTest.DragSingleTabToSeparateWindowInSecondDisplay/0
--TabDragging/DetachToBrowserInSeparateDisplayTabDragControllerTest.DragTabToWindowInSeparateDisplay/0
--TabDragging/DetachToBrowserInSeparateDisplayTabDragControllerTest.DragTabToWindowOnSecondDisplay/0
 -TabDragging/DetachToBrowserTabDragControllerTest.DeferredTargetTabStripTest/1
 -TabDragging/DetachToBrowserTabDragControllerTest.DetachToOwnWindowFromMaximizedWindow/1
 -TabDragging/DetachToBrowserTabDragControllerTest.DetachToOwnWindowWhileInImmersiveFullscreenMode/1
diff --git a/testing/buildbot/filters/mojo.fyi.chromeos.network_browser_tests.filter b/testing/buildbot/filters/mojo.fyi.chromeos.network_browser_tests.filter
index f0aa384..d79ad4a 100644
--- a/testing/buildbot/filters/mojo.fyi.chromeos.network_browser_tests.filter
+++ b/testing/buildbot/filters/mojo.fyi.chromeos.network_browser_tests.filter
@@ -45,11 +45,6 @@
 # Flaky with error: `picture_in_picture_window_controller_impl.cc(167)] Check failed: media_player_id_.has_value()`.
 -PictureInPictureWindowControllerBrowserTest.TabIconUpdated
 
-# Relies on net::CertVerifier.
-# https://crbug.com/862043
--PolicyProvidedTrustAnchorsRegularUserTest.AllowedForRegularUser
--PolicyProvidedTrustAnchorsOnUserSessionInitTest.TrustAnchorsAvailableImmediatelyAfterSessionStart
-
 # NOTE: if adding an exclusion for an existing failure (e.g. additional test for
 # feature X that is already not working), please add it beside the existing
 # failures. Otherwise please reach out to network-service-dev@.
diff --git a/testing/buildbot/gn_isolate_map.pyl b/testing/buildbot/gn_isolate_map.pyl
index c40e6409..1a682e1 100644
--- a/testing/buildbot/gn_isolate_map.pyl
+++ b/testing/buildbot/gn_isolate_map.pyl
@@ -393,10 +393,6 @@
     "label": "//components/gcm_driver/android:components_gcm_driver_junit_tests",
     "type": "junit_test",
   },
-  "components_instance_id_junit_tests": {
-    "label": "//components/gcm_driver/instance_id/android:components_instance_id_junit_tests",
-    "type": "junit_test",
-  },
   "components_invalidation_impl_junit_tests": {
     "label": "//components/invalidation/impl:components_invalidation_impl_junit_tests",
     "type": "junit_test",
diff --git a/testing/buildbot/manage.py b/testing/buildbot/manage.py
index d0f9293..3ecec9f 100755
--- a/testing/buildbot/manage.py
+++ b/testing/buildbot/manage.py
@@ -117,7 +117,6 @@
   'chrome_junit_tests',
   'components_background_task_scheduler_junit_tests',
   'components_gcm_driver_junit_tests',
-  'components_instance_id_junit_tests',
   'components_invalidation_impl_junit_tests',
   'components_policy_junit_tests',
   'components_variations_junit_tests',
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl
index 57293ea3..dfdf52c 100644
--- a/testing/buildbot/test_suite_exceptions.pyl
+++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -107,14 +107,6 @@
           '--test-launcher-filter-file=../../testing/buildbot/filters/mac_window_server_killers.browser_tests.filter',
           '--gtest_shuffle',
         ],
-        'swarming': {
-          'dimension_sets': [
-            {
-              'pool': 'Chrome-quarantine',
-              'gpu': 'none',
-            },
-          ],
-        },
       },
       'Mac10.12 Tests': {
         # A subset of tests seem to cause WindowServer deaths on VMs.
@@ -123,14 +115,6 @@
           '--test-launcher-filter-file=../../testing/buildbot/filters/mac_window_server_killers.browser_tests.filter',
           '--gtest_shuffle',
         ],
-        'swarming': {
-          'dimension_sets': [
-            {
-              'pool': 'Chrome-quarantine',
-              'gpu': 'none',
-            },
-          ],
-        },
       },
       'Mac10.13 Tests': {
         # A subset of tests seem to cause WindowServer deaths on VMs.
@@ -139,14 +123,6 @@
           '--test-launcher-filter-file=../../testing/buildbot/filters/mac_window_server_killers.browser_tests.filter',
           '--gtest_shuffle',
         ],
-        'swarming': {
-          'dimension_sets': [
-            {
-              'pool': 'Chrome-quarantine',
-              'gpu': 'none',
-            },
-          ],
-        },
       },
       'Mac10.13 Tests (dbg)': {
         # A subset of tests seem to cause WindowServer deaths on VMs.
@@ -155,14 +131,6 @@
           '--test-launcher-filter-file=../../testing/buildbot/filters/mac_window_server_killers.browser_tests.filter',
           '--gtest_shuffle',
         ],
-        'swarming': {
-          'dimension_sets': [
-            {
-              'pool': 'Chrome-quarantine',
-              'gpu': 'none',
-            },
-          ],
-        },
       },
       # chromium.memory
       'Linux ASan LSan Tests (1)': {
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl
index 74685ec0..3a017468 100644
--- a/testing/buildbot/test_suites.pyl
+++ b/testing/buildbot/test_suites.pyl
@@ -654,7 +654,6 @@
       'chrome_junit_tests': {},
       'components_background_task_scheduler_junit_tests': {},
       'components_gcm_driver_junit_tests': {},
-      'components_instance_id_junit_tests': {},
       'components_invalidation_impl_junit_tests': {},
       'components_policy_junit_tests': {},
       'components_signin_junit_tests': {},
@@ -673,7 +672,9 @@
 
     'chromium_linux_coverage_gtests': {
       'base_unittests': {
-        'shards': 2,
+        'swarming': {
+          'shards': 2,
+        },
       },
     },
 
@@ -2113,6 +2114,36 @@
       'crashpad_tests': {},
     },
 
+    'non_viz_fyi_chromium_gtests': {
+      'non_viz_content_browsertests': {
+        'args': [
+          '--disable-features=VizDisplayCompositor',
+        ],
+        'swarming': {
+          'shards': 10,
+        },
+        'test': 'content_browsertests',
+      },
+    },
+
+    'non_viz_non_android_fyi_chromium_gtests': {
+      'non_viz_browser_tests': {
+        'args': [
+          '--disable-features=VizDisplayCompositor',
+        ],
+        'swarming': {
+          'shards': 10,
+        },
+        'test': 'browser_tests',
+      },
+      'non_viz_content_unittests': {
+        'args': [
+          '--disable-features=VizDisplayCompositor',
+        ],
+        'test': 'content_unittests',
+      },
+    },
+
     'ozone_linux_gtests': {
       'services_unittests': {},
     },
@@ -2549,6 +2580,19 @@
       'telemetry_perf_unittests_isolated_scripts',
     ],
 
+    # chromium_mac_gtests + additional suites.
+    'chromium_mac_fyi_gtests': [
+      'chromium_gtests',
+      'chromium_gtests_for_devices_with_graphical_output',
+      'mac_specific_chromium_gtests',
+      'network_service_gtests',
+      'non_android_chromium_gtests',
+      'non_android_and_cast_and_chromeos_chromium_gtests',
+      'non_linux_chromium_gtests',
+      'non_viz_fyi_chromium_gtests',
+      'non_viz_non_android_fyi_chromium_gtests',
+    ],
+
     'chromium_mac_gtests': [
       'chromium_gtests',
       'chromium_gtests_for_devices_with_graphical_output',
@@ -2859,8 +2903,8 @@
     ],
 
     'linux_viz_gtests': [
-      'viz_gtests',
-      'viz_non_android_fyi_gtests',
+      'non_viz_fyi_chromium_gtests',
+      'non_viz_non_android_fyi_chromium_gtests',
     ],
 
     'marshmallow_isolated_scripts': [
@@ -2871,6 +2915,7 @@
 
     'mojo_android_gtests': [
       'network_service_android_gtests',
+      'non_viz_fyi_chromium_gtests',
     ],
 
     'mojo_chromiumos_fyi_gtests': [
@@ -2885,8 +2930,8 @@
     'mojo_windows_gtests': [
       'mojo_windows_specific_gtests',
       'network_service_gtests',
-      'viz_gtests',
-      'viz_non_android_fyi_gtests',
+      'non_viz_fyi_chromium_gtests',
+      'non_viz_non_android_fyi_chromium_gtests',
     ],
 
     'sandboxed_chromium_memory_linux_gtests': [
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl
index b955549..df716d93 100644
--- a/testing/buildbot/waterfalls.pyl
+++ b/testing/buildbot/waterfalls.pyl
@@ -932,7 +932,7 @@
       },
       'Chromium Mac 10.13': {
         'test_suites': {
-          'gtest_tests': 'chromium_mac_gtests',
+          'gtest_tests': 'chromium_mac_fyi_gtests',
           'isolated_scripts': 'chromium_rel_isolated_scripts',
         },
       },
@@ -1407,13 +1407,13 @@
             'mac_10.14',
         ],
         'test_suites': {
-          'gtest_tests': 'chromium_mac_gtests',
+          'gtest_tests': 'chromium_mac_fyi_gtests',
           'isolated_scripts': 'chromium_rel_isolated_scripts',
         },
       },
       'mac-views-rel': {
         'test_suites': {
-          'gtest_tests': 'chromium_mac_gtests',
+          'gtest_tests': 'chromium_mac_fyi_gtests',
         },
         'args': [
           '--enable-features=ViewsBrowserWindows',
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 94ae74eb..2f4e0cf 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -5019,6 +5019,25 @@
             ]
         }
     ],
+    "V8SiteIsolatedCodeCache": [
+        {
+            "platforms": [
+                "android",
+                "chromeos",
+                "linux",
+                "mac",
+                "windows"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "IsolatedCodeCache"
+                    ]
+                }
+            ]
+        }
+    ],
     "V8WasmTrapHandler": [
         {
             "platforms": [
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
index da35476..099ca536 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
@@ -18,8 +18,8 @@
 crbug.com/450202 fast/multicol/span/overflow-on-multicol.html [ Skip ]
 
 # Wrong quirks mode line height for pattern <div><a><img></a></div>
-crbug.com/854840 fast/table/backgr_border-table-quirks-collapsed-border.html [ Failure ]
-crbug.com/854840 fast/table/backgr_border-table-quirks.html [ Failure ]
+crbug.com/854840 fast/table/backgr_border-table-quirks-collapsed-border.html [ Failure Pass ]
+crbug.com/854840 fast/table/backgr_border-table-quirks.html [ Failure Pass ]
 
 # Superscript text off by 1px
 crbug.com/636993 external/wpt/css/css-text-decor/text-decoration-color.html [ Failure ]
@@ -58,20 +58,23 @@
 crbug.com/591099 fast/dom/nodesFromRect/nodesFromRect-basic.html [ Failure ]
 
 # New failures are appended below by the script.
-crbug.com/591099 accessibility/aom-relation-list-properties.html [ Failure Pass ]
-crbug.com/591099 accessibility/aria-labelledby-stay-within.html [ Failure Pass ]
-crbug.com/591099 accessibility/aria-owns.html [ Failure Pass ]
-crbug.com/591099 accessibility/aria-tab-roles.html [ Failure Pass ]
-crbug.com/591099 accessibility/focusable-div.html [ Failure Pass ]
-crbug.com/591099 accessibility/listitem-presentation-inherited.html [ Failure Pass ]
-crbug.com/591099 accessibility/name-calc-aria-owns.html [ Failure Pass ]
-crbug.com/591099 accessibility/presentation-owned-elements.html [ Failure Pass ]
-crbug.com/591099 accessibility/role-attribute.html [ Failure Pass ]
+crbug.com/591099 accessibility/aom-relation-list-properties.html [ Failure ]
+crbug.com/591099 accessibility/aria-labelledby-stay-within.html [ Failure ]
+crbug.com/591099 accessibility/aria-owns.html [ Failure ]
+crbug.com/591099 accessibility/aria-tab-roles.html [ Failure ]
+crbug.com/591099 accessibility/focusable-div.html [ Failure ]
+crbug.com/591099 accessibility/listitem-presentation-inherited.html [ Failure ]
+crbug.com/591099 accessibility/name-calc-aria-owns.html [ Failure ]
+crbug.com/591099 accessibility/presentation-owned-elements.html [ Failure ]
+crbug.com/591099 accessibility/role-attribute.html [ Failure ]
 crbug.com/728378 compositing/culling/tile-occlusion-boundaries.html [ Failure ]
 crbug.com/864398 compositing/iframes/floating-self-painting-frame.html [ Failure ]
+crbug.com/591099 compositing/masks/mask-with-removed-filters.html [ Pass ]
+crbug.com/591099 compositing/video-frame-size-change.html [ Pass ]
 crbug.com/591099 css3/filters/composited-layer-child-bounds-after-composited-to-sw-shadow-change.html [ Failure ]
 crbug.com/591099 editing/selection/paint-hyphen.html [ Pass ]
 crbug.com/591099 external/wpt/content-security-policy/generic/only-valid-whitespaces-are-allowed.html [ Pass ]
+crbug.com/591099 external/wpt/css/CSS2/abspos/abspos-in-block-in-inline-in-relpos-inline.html [ Failure ]
 crbug.com/591099 external/wpt/css/CSS2/floats/float-nowrap-3.html [ Pass ]
 crbug.com/591099 external/wpt/css/CSS2/floats/floats-line-wrap-shifted-001.html [ Pass ]
 crbug.com/591099 external/wpt/css/CSS2/normal-flow/block-in-inline-empty-001.xht [ Pass ]
@@ -238,11 +241,16 @@
 crbug.com/591099 external/wpt/editing/run/multitest.html [ Pass ]
 crbug.com/591099 external/wpt/editing/run/strikethrough.html [ Pass ]
 crbug.com/591099 external/wpt/encoding/legacy-mb-korean/euc-kr/euckr-decode-ksc_5601.html [ Timeout ]
+crbug.com/591099 external/wpt/feature-policy/picture-in-picture-allowed-by-feature-policy-attribute-redirect-on-load.https.sub.html [ Pass ]
+crbug.com/591099 external/wpt/feature-policy/picture-in-picture-allowed-by-feature-policy-attribute.https.sub.html [ Pass ]
+crbug.com/591099 external/wpt/feature-policy/picture-in-picture-allowed-by-feature-policy.https.sub.html [ Pass ]
+crbug.com/591099 external/wpt/feature-policy/picture-in-picture-default-feature-policy.https.sub.html [ Pass ]
+crbug.com/591099 external/wpt/feature-policy/reporting/picture-in-picture-reporting.html [ Pass ]
 crbug.com/591099 external/wpt/fetch/api/redirect/redirect-count.any.html [ Pass ]
 crbug.com/591099 external/wpt/fetch/api/redirect/redirect-count.any.worker.html [ Pass ]
 crbug.com/591099 external/wpt/fetch/api/request/request-keepalive-quota.html?include=slow-2 [ Pass ]
 crbug.com/591099 external/wpt/fetch/http-cache/basic-auth-cache-test.html [ Timeout ]
-crbug.com/591099 external/wpt/geolocation-API/PositionOptions.https.html [ Failure ]
+crbug.com/591099 external/wpt/geolocation-API/PositionOptions.https.html [ Failure Pass ]
 crbug.com/591099 external/wpt/html/browsers/history/joint-session-history/joint-session-history-remove-iframe.html [ Timeout ]
 crbug.com/591099 external/wpt/html/browsers/the-window-object/window-open-noopener.html?_parent [ Timeout ]
 crbug.com/591099 external/wpt/html/browsers/the-window-object/window-open-noopener.html?_self [ Timeout ]
@@ -257,7 +265,15 @@
 crbug.com/591099 external/wpt/html/semantics/embedded-content/media-elements/interfaces/TextTrackCue/track.html [ Pass ]
 crbug.com/591099 external/wpt/html/semantics/embedded-content/media-elements/track/track-element/cloneNode.html [ Pass ]
 crbug.com/591099 external/wpt/html/semantics/scripting-1/the-script-element/async_010.htm [ Pass ]
-crbug.com/591099 external/wpt/picture-in-picture/request-picture-in-picture-twice.html [ Failure ]
+crbug.com/591099 external/wpt/picture-in-picture/disable-picture-in-picture.html [ Pass ]
+crbug.com/591099 external/wpt/picture-in-picture/enter-picture-in-picture.html [ Pass ]
+crbug.com/591099 external/wpt/picture-in-picture/exit-picture-in-picture.html [ Pass ]
+crbug.com/591099 external/wpt/picture-in-picture/leave-picture-in-picture.html [ Pass ]
+crbug.com/591099 external/wpt/picture-in-picture/picture-in-picture-element.html [ Pass Timeout ]
+crbug.com/591099 external/wpt/picture-in-picture/picture-in-picture-window.html [ Pass ]
+crbug.com/591099 external/wpt/picture-in-picture/request-picture-in-picture-twice.html [ Pass ]
+crbug.com/591099 external/wpt/picture-in-picture/request-picture-in-picture.html [ Pass ]
+crbug.com/591099 external/wpt/picture-in-picture/shadow-dom.html [ Pass ]
 crbug.com/591099 external/wpt/quirks/line-height-calculation.html [ Failure ]
 crbug.com/591099 external/wpt/requestidlecallback/callback-iframe.html [ Pass Timeout ]
 crbug.com/591099 external/wpt/service-workers/service-worker/navigation-preload/broken-chunked-encoding.https.html [ Pass ]
@@ -277,12 +293,16 @@
 crbug.com/591099 external/wpt/workers/constructors/Worker/same-origin.html [ Pass ]
 crbug.com/591099 external/wpt/xhr/send-content-type-string.htm [ Pass ]
 crbug.com/591099 external/wpt/xhr/send-entity-body-document.htm [ Pass ]
+crbug.com/591099 fast/backgrounds/gradient-background-leakage-hidpi.html [ Pass ]
 crbug.com/591099 fast/backgrounds/quirks-mode-line-box-backgrounds.html [ Failure ]
 crbug.com/591099 fast/block/float-avoids-padding-inline-ancestors.html [ Failure ]
 crbug.com/591099 fast/block/positioning/positioned-child-inside-relative-positioned-anonymous-block.html [ Failure ]
 crbug.com/591099 fast/borders/bidi-002.html [ Failure ]
 crbug.com/859497 fast/borders/bidi-009a.html [ Failure ]
+crbug.com/591099 fast/borders/border-radius-mask-canvas-border.html [ Pass ]
+crbug.com/591099 fast/borders/border-radius-mask-canvas-with-mask.html [ Pass ]
 crbug.com/591099 fast/borders/inline-mask-overlay-image-outset-vertical-rl.html [ Failure ]
+crbug.com/591099 fast/canvas/canvas-hidpi-blurry.html [ Pass ]
 crbug.com/591099 fast/css-intrinsic-dimensions/height-positioned.html [ Pass ]
 crbug.com/807708 fast/css-intrinsic-dimensions/width-avoid-floats.html [ Failure ]
 crbug.com/591099 fast/css/absolute-inline-alignment-2.html [ Pass ]
@@ -293,6 +313,14 @@
 crbug.com/591099 fast/events/wheel/mainthread-touchpad-fling-latching.html [ Pass ]
 crbug.com/591099 fast/events/wheel/wheel-scroll-latching-on-scrollbar.html [ Pass ]
 crbug.com/591099 fast/forms/textarea/basic-textareas-quirks.html [ Failure ]
+crbug.com/591099 fast/hidpi/broken-image-icon-hidpi.html [ Pass ]
+crbug.com/591099 fast/hidpi/broken-image-with-size-hidpi.html [ Pass ]
+crbug.com/591099 fast/hidpi/clip-text-in-hidpi.html [ Pass ]
+crbug.com/591099 fast/hidpi/device-scale-factor-paint.html [ Pass ]
+crbug.com/591099 fast/hidpi/focus-rings.html [ Pass ]
+crbug.com/591099 fast/hidpi/gradient-with-scaled-ancestor.html [ Pass ]
+crbug.com/591099 fast/hidpi/resize-corner-hidpi.html [ Pass ]
+crbug.com/591099 fast/hidpi/scrollbar-appearance-increase-device-scale-factor.html [ Pass ]
 crbug.com/889721 fast/inline/continuation-outlines-with-layers.html [ Failure ]
 crbug.com/889721 fast/inline/continuation-outlines.html [ Failure ]
 crbug.com/835484 fast/inline/inline-focus-ring-under-absolute-enclosing-relative-div.html [ Failure ]
@@ -300,6 +328,11 @@
 crbug.com/889721 fast/inline/outline-continuations.html [ Failure ]
 crbug.com/835484 fast/inline/outline-offset.html [ Failure ]
 crbug.com/591099 fast/overflow/overflow-update-transform.html [ Failure ]
+crbug.com/591099 fast/overflow/scrollRevealButton.html [ Pass ]
+crbug.com/591099 fast/replaced/replaced-breaking.html [ Failure Pass ]
+crbug.com/591099 fast/scroll-snap/snaps-after-keyboard-scrolling-rtl.html [ Failure ]
+crbug.com/591099 fast/scrolling/editor-command-scroll-page-scale.html [ Pass ]
+crbug.com/591099 fast/sub-pixel/shadows-hidpi.html [ Pass ]
 crbug.com/591099 fast/sub-pixel/sub-pixel-border-2.html [ Failure ]
 crbug.com/591099 fast/table/border-collapsing/004-vertical.html [ Failure ]
 crbug.com/591099 fast/table/height-percent-test-vertical.html [ Failure ]
@@ -307,15 +340,15 @@
 crbug.com/591099 fast/text/descent-clip-in-scaled-page.html [ Failure ]
 crbug.com/591099 fast/text/ellipsis-in-relative-inline-right.html [ Failure ]
 crbug.com/591099 fast/text/ellipsis-in-relative-inline.html [ Failure ]
-crbug.com/714962 fast/text/emoticons.html [ Failure ]
+crbug.com/714962 fast/text/emoticons.html [ Failure Pass ]
 crbug.com/796943 fast/text/international/shape-across-elements-simple.html [ Pass ]
-crbug.com/591099 fast/text/unicode-fallback-font.html [ Failure ]
+crbug.com/591099 fast/text/unicode-fallback-font.html [ Failure Pass ]
 crbug.com/591099 fast/text/whitespace/018.html [ Failure ]
 crbug.com/591099 fast/writing-mode/auto-sizing-orthogonal-flows.html [ Failure ]
 crbug.com/714962 fast/writing-mode/background-vertical-lr.html [ Failure ]
 crbug.com/591099 fast/writing-mode/basic-vertical-line.html [ Failure ]
-crbug.com/591099 fast/writing-mode/border-radius-clipping-vertical-lr.html [ Failure ]
-crbug.com/714962 fast/writing-mode/border-styles-vertical-lr.html [ Failure ]
+crbug.com/591099 fast/writing-mode/border-radius-clipping-vertical-lr.html [ Failure Pass ]
+crbug.com/714962 fast/writing-mode/border-styles-vertical-lr.html [ Failure Pass ]
 crbug.com/591099 fast/writing-mode/fieldsets.html [ Failure ]
 crbug.com/591099 fast/writing-mode/percentage-height-orthogonal-writing-modes.html [ Failure ]
 crbug.com/591099 fast/writing-mode/table-percent-width-quirk.html [ Pass ]
@@ -339,15 +372,22 @@
 crbug.com/591099 http/tests/security/cors-rfc1918/addressspace-document-appcache.https.html [ Crash Failure ]
 crbug.com/591099 http/tests/security/cors-rfc1918/addressspace-document-csp-appcache.https.html [ Crash Failure Pass ]
 crbug.com/591099 http/tests/security/setDomainRelaxationForbiddenForURLScheme.html [ Crash ]
+crbug.com/591099 http/tests/webaudio/autoplay-crossorigin.html [ Failure ]
 crbug.com/591099 idle-callback/test-runner-run-idle-tasks.html [ Crash Pass ]
-crbug.com/591099 images/color-profile-image-filter-all.html [ Failure ]
-crbug.com/591099 inspector-protocol/accessibility/accessibility-ignoredNodes.js [ Failure Pass ]
-crbug.com/591099 inspector-protocol/accessibility/accessibility-nameSources-labelledby.js [ Failure Pass ]
+crbug.com/591099 images/color-profile-image-filter-all.html [ Failure Pass ]
+crbug.com/591099 inspector-protocol/accessibility/accessibility-ignoredNodes.js [ Failure ]
+crbug.com/591099 inspector-protocol/accessibility/accessibility-nameSources-labelledby.js [ Failure ]
 crbug.com/591099 inspector-protocol/dom-snapshot/dom-snapshot-getSnapshot-pseudo-element.js [ Failure ]
 crbug.com/714962 inspector-protocol/layout-fonts/languages-emoji-rare-glyphs.js [ Failure ]
 crbug.com/591099 inspector-protocol/runtime/runtime-console-log-handle-navigate.js [ Pass ]
 crbug.com/591099 inspector-protocol/timeline/page-frames.js [ Failure ]
 crbug.com/591099 intersection-observer/v2/text-shadow.html [ Failure ]
+crbug.com/591099 media/controls/lazy-loaded-style.html [ Pass ]
+crbug.com/591099 media/picture-in-picture/controls/picture-in-picture-button.html [ Pass ]
+crbug.com/591099 media/picture-in-picture/controls/picture-in-picture-video-with-audio-only-button.html [ Pass ]
+crbug.com/591099 media/picture-in-picture/mediastream.html [ Pass ]
+crbug.com/591099 media/picture-in-picture/picture-in-picture-enabled.html [ Pass ]
+crbug.com/591099 media/picture-in-picture/picture-in-picture-interstitial.html [ Pass ]
 crbug.com/591099 paint/float/float-under-inline-self-painting-change.html [ Failure ]
 crbug.com/835484 paint/inline/focus-ring-under-absolute-with-relative-continuation.html [ Failure ]
 crbug.com/591099 paint/invalidation/clip/control-clip.html [ Failure ]
@@ -375,14 +415,22 @@
 crbug.com/714962 paint/invalidation/position/relative-positioned-movement-repaint.html [ Failure ]
 crbug.com/591099 paint/invalidation/position/relayout-fixed-position-after-scale.html [ Failure ]
 crbug.com/591099 paint/invalidation/scroll/repaint-composited-child-in-scrolled-container.html [ Failure ]
+crbug.com/591099 paint/invalidation/scroll/scrollbar-damage-and-full-viewport-repaint.html [ Pass ]
 crbug.com/591099 paint/invalidation/svg/svg-background-partial-redraw.html [ Failure ]
 crbug.com/591099 paint/invalidation/table/table-extra-bottom-grow.html [ Failure ]
 crbug.com/591099 paint/invalidation/table/table-two-pass-layout-overpaint.html [ Failure ]
+crbug.com/591099 paint/markers/grammar-markers-hidpi.html [ Pass ]
+crbug.com/591099 paint/markers/inline-spelling-markers-hidpi-composited.html [ Pass ]
+crbug.com/591099 paint/markers/inline-spelling-markers-hidpi.html [ Pass ]
 crbug.com/591099 printing/absolute-position-headers-and-footers.html [ Failure ]
 crbug.com/591099 printing/iframe-svg-in-object-print.html [ Failure ]
+crbug.com/591099 rootscroller/rootscroller-during-fullscreen.html [ Pass ]
 crbug.com/591099 scrollbars/auto-scrollbar-fit-content.html [ Failure ]
+crbug.com/591099 scrollbars/resize-scales-with-dpi-150.html [ Pass ]
 crbug.com/591099 storage/indexeddb/mozilla/test_objectStore_openKeyCursor.html [ Pass ]
 crbug.com/591099 storage/indexeddb/objectstore-cursor.html [ Pass ]
+crbug.com/591099 svg/as-image/image-respects-deviceScaleFactor.html [ Pass ]
+crbug.com/591099 svg/custom/masking-clipping-hidpi.svg [ Pass ]
 crbug.com/591099 svg/zoom/page/zoom-img-preserveAspectRatio-support-1.html [ Failure ]
 crbug.com/591099 svg/zoom/page/zoom-svg-float-border-padding.xml [ Failure ]
 crbug.com/591099 svg/zoom/page/zoom-svg-through-object-with-absolute-size-2.xhtml [ Failure ]
@@ -394,24 +442,24 @@
 crbug.com/591099 tables/mozilla/bugs/bug2973.html [ Failure ]
 crbug.com/591099 tables/mozilla/bugs/bug50695-2.html [ Failure ]
 crbug.com/591099 tables/mozilla/bugs/bug55527.html [ Failure ]
-crbug.com/591099 transforms/3d/general/perspective-units.html [ Failure ]
+crbug.com/591099 transforms/3d/general/perspective-units.html [ Failure Pass ]
 crbug.com/870008 virtual/android/rootscroller/position-fixed-in-unscrollable-document-iframe.html [ Failure Pass ]
-crbug.com/870008 virtual/android/rootscroller/position-fixed-in-unscrollable-document.html [ Failure Pass ]
-crbug.com/591099 virtual/android/url-bar/bottom-and-top-fixed-sticks-to-top.html [ Failure Pass ]
+crbug.com/591099 virtual/android/url-bar/bottom-and-top-fixed-sticks-to-top.html [ Failure ]
 crbug.com/591099 virtual/exotic-color-space/ [ Skip ]
 crbug.com/591099 virtual/feature-policy-vibrate/ [ Skip ]
 crbug.com/591099 virtual/fractional_scrolling/fast/scrolling/fractional-scroll-offset-iframe-fixed-position.html [ Pass ]
 crbug.com/591099 virtual/fractional_scrolling_threaded/fast/scrolling/fractional-scroll-offset-iframe-fixed-position.html [ Pass ]
+crbug.com/591099 virtual/fractional_scrolling_threaded/fast/scrolling/overflow-scrollability.html [ Failure Pass ]
 crbug.com/591099 virtual/gpu-rasterization/images/color-profile-image-filter-all.html [ Failure ]
 crbug.com/591099 virtual/gpu/fast/canvas/canvas-blending-color-over-image.html [ Pass ]
 crbug.com/591099 virtual/gpu/fast/canvas/canvas-blending-gradient-over-pattern.html [ Pass Timeout ]
+crbug.com/591099 virtual/gpu/fast/canvas/canvas-hidpi-blurry.html [ Pass ]
 crbug.com/591099 virtual/gpu/fast/canvas/canvas-with-overflowing-object-fit.html [ Pass ]
 crbug.com/591099 virtual/intersection-observer-v2/intersection-observer/v2/text-shadow.html [ Failure ]
 crbug.com/591099 virtual/layout_ng/ [ Skip ]
 crbug.com/824918 virtual/layout_ng_experimental/ [ Skip ]
 crbug.com/591099 virtual/mojo-blob-urls/external/wpt/FileAPI/url/sandboxed-iframe.html [ Pass ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/touch/compositor-touch-hit-rects.html [ Failure ]
-crbug.com/591099 virtual/mouseevent_fractional/fast/events/touch/gesture/touch-gesture-scroll-input-field.html [ Failure Pass ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/wheel/mainthread-touchpad-fling-latching.html [ Pass ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/wheel/wheel-scroll-latching-on-scrollbar.html [ Pass ]
 crbug.com/591099 virtual/new-remote-playback-pipeline/ [ Skip ]
@@ -431,7 +479,7 @@
 crbug.com/591099 virtual/paint-touchaction-rects/fast/events/touch/compositor-touch-hit-rects-continuation.html [ Failure ]
 crbug.com/591099 virtual/paint-touchaction-rects/fast/events/touch/compositor-touch-hit-rects-list-translate.html [ Failure ]
 crbug.com/591099 virtual/paint-touchaction-rects/fast/events/touch/compositor-touch-hit-rects.html [ Failure ]
-crbug.com/591099 virtual/paint-touchaction-rects/fast/events/touch/gesture/touch-gesture-scroll-input-field.html [ Failure Pass ]
+crbug.com/591099 virtual/paint-touchaction-rects/fast/events/touch/gesture/touch-gesture-scroll-input-field.html [ Pass ]
 crbug.com/591099 virtual/prefer_compositing_to_lcd_text/ [ Skip ]
 crbug.com/591099 virtual/reporting-api/external/wpt/content-security-policy/reporting-api/reporting-api-doesnt-send-reports-without-violation.https.sub.html [ Pass ]
 crbug.com/591099 virtual/scroll_customization/ [ Skip ]
@@ -440,8 +488,13 @@
 crbug.com/591099 virtual/spv2/paint/invalidation/box/margin.html [ Failure Pass ]
 crbug.com/591099 virtual/stable/ [ Skip ]
 crbug.com/591099 virtual/threaded/ [ Skip ]
+crbug.com/591099 virtual/unified-autoplay/external/wpt/feature-policy/picture-in-picture-allowed-by-feature-policy-attribute-redirect-on-load.https.sub.html [ Pass ]
+crbug.com/591099 virtual/unified-autoplay/external/wpt/feature-policy/picture-in-picture-allowed-by-feature-policy-attribute.https.sub.html [ Pass ]
+crbug.com/591099 virtual/unified-autoplay/external/wpt/feature-policy/picture-in-picture-allowed-by-feature-policy.https.sub.html [ Pass ]
+crbug.com/591099 virtual/unified-autoplay/external/wpt/feature-policy/picture-in-picture-default-feature-policy.https.sub.html [ Pass ]
+crbug.com/591099 virtual/unified-autoplay/external/wpt/feature-policy/reporting/picture-in-picture-reporting.html [ Pass ]
 crbug.com/591099 virtual/user-activation-v2/fast/events/mouse-cursor.html [ Failure ]
 crbug.com/591099 virtual/user-activation-v2/fast/events/touch/compositor-touch-hit-rects.html [ Failure ]
-crbug.com/591099 virtual/user-activation-v2/fast/events/touch/gesture/touch-gesture-scroll-input-field.html [ Failure Pass ]
+crbug.com/591099 virtual/user-activation-v2/fast/events/touch/gesture/touch-gesture-scroll-input-field.html [ Pass ]
 crbug.com/591099 virtual/video-surface-layer/media/stable/video-object-fit-stable.html [ Pass ]
 crbug.com/591099 virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCDTMFSender-ontonechange.https.html [ Pass ]
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2 b/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2
index bd180b15..15cc802 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2
@@ -835,6 +835,8 @@
 Bug(none) fast/forms/suggestion-picker/week-suggestion-picker-mouse-operations.html [ Failure ]
 
 Bug(none) fast/scroll-snap/snaps-after-scrollbar-scrolling.html [ Failure ]
+Bug(none) fast/scroll-snap/snaps-after-keyboard-scrolling.html [ Failure ]
+Bug(none) fast/scroll-snap/snaps-after-keyboard-scrolling-rtl.html [ Failure ]
 Bug(none) fast/events/remove-child-onscroll.html [ Timeout ]
 
 crbug.com/651292 svg/dynamic-updates/SVGImageElement-dom-x-attr.html [ Pass Failure ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 6006b40..f96b6b9 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -98,12 +98,18 @@
 crbug.com/891427 virtual/fractional_scrolling_threaded/fast/scrolling/editor-command-scroll-page-scale.html [ Pass Failure Timeout Crash ]
 crbug.com/891427 virtual/fractional_scrolling_threaded/fast/scrolling/fractional-scroll-offset-document.html [ Pass Failure Timeout Crash ]
 crbug.com/891427 virtual/fractional_scrolling_threaded/fast/scrolling/scroll-non-composited-scroller.html [ Pass Failure Timeout Crash ]
+crbug.com/891427 virtual/fractional_scrolling_threaded/fast/scrolling/overflow-scrollability.html [ Pass Failure ]
 crbug.com/891427 virtual/threaded/fast/scrolling/fractional-scroll-offset-document.html [ Pass Failure Timeout Crash ]
 crbug.com/891427 virtual/threaded/synthetic_gestures/animated-wheel-tiny-delta.html [ Pass Failure Timeout Crash ]
 crbug.com/891427 virtual/threaded/synthetic_gestures/smooth-scroll-tiny-delta.html [ Pass Failure Timeout Crash ]
 # Next 1 here: https://ci.chromium.org/p/chromium/builders/luci.chromium.try/mac10.12-blink-rel/1427
 crbug.com/891427 virtual/threaded/synthetic_gestures/synthetic-pinch-zoom-gesture-touchpad-zoom-out-slow.html [ Pass Failure Timeout Crash ]
-
+# Adding three more found by findit:
+crbug.com/891427 virtual/threaded/fast/scroll-behavior/smooth-scroll/scroll-during-selection.html [ Pass Failure Timeout Crash ]
+crbug.com/891427 virtual/threaded/fast/scrolling/no-hover-during-scroll.html [ Pass Failure Timeout Crash ]
+crbug.com/891427 virtual/fractional_scrolling_threaded/fast/scrolling/no-hover-during-scroll.html [ Pass Failure Timeout Crash ]
+# More found by Findit:
+crbug.com/891427 virtual/threaded/animations/invisible-composited-animations-prevent-scroll.html [ Pass Failure Timeout Crash ]
 
 # Remove these when --enable-display-compositor-pixel-dump becomes the
 # "default" setting. These will all need to be re-baselined at that point.
@@ -664,6 +670,9 @@
 crbug.com/591099 external/wpt/css/css-writing-modes/inline-box-border-vlr-001.html [ Failure ]
 crbug.com/591099 tables/mozilla/bugs/bug14159-1.html [ Failure ]
 
+### virtual/layout_ng/external/wpt/css/CSS2/abspos
+crbug.com/591099 virtual/layout_ng/external/wpt/css/CSS2/abspos/abspos-in-block-in-inline-in-relpos-inline.html [ Failure ]
+
 ### virtual/layout_ng/external/wpt/css/CSS2/floats
 crbug.com/711704 virtual/layout_ng/external/wpt/css/CSS2/floats/floats-rule3-outside-left-002.xht [ Failure ]
 crbug.com/711704 virtual/layout_ng/external/wpt/css/CSS2/floats/floats-rule3-outside-right-002.xht [ Failure ]
@@ -2171,8 +2180,13 @@
 crbug.com/567837 virtual/scalefactor200/fast/hidpi/static/popup-menu-with-scrollbar-appearance.html [ Skip ]
 crbug.com/567837 virtual/scalefactor200withzoom/fast/hidpi/static/popup-menu-with-scrollbar-appearance.html [ Skip ]
 
+# These tests currently fail but are fixed with PaintTouchActionRects.
 crbug.com/876305 fast/events/touch/compositor-touch-hit-rects-list-translate.html [ Failure ]
 crbug.com/876305 fast/events/touch/compositor-touch-hit-rects.html [ Failure ]
+crbug.com/897186 fast/events/touch/compositor-touch-hit-rects-visibility-hidden.html [ Failure ]
+crbug.com/897186 virtual/scroll_customization/fast/events/touch/compositor-touch-hit-rects-visibility-hidden.html [ Failure ]
+crbug.com/897186 virtual/user-activation-v2/fast/events/touch/compositor-touch-hit-rects-visibility-hidden.html [ Failure ]
+crbug.com/897186 virtual/mouseevent_fractional/fast/events/touch/compositor-touch-hit-rects-visibility-hidden.html [ Failure ]
 
 # TODO(ojan): These tests aren't flaky. See crbug.com/517144.
 # Release trybots run asserts, but the main waterfall ones don't. So, even
@@ -5579,7 +5593,8 @@
 crbug.com/874162 [ Mac ] virtual/mouseevent_fractional/fast/events/middleClickAutoscroll-modal-scrollable-iframe-div.html [ Skip ]
 crbug.com/874162 [ Mac ] virtual/user-activation-v2/fast/events/middleClickAutoscroll-modal-scrollable-iframe-div.html [ Skip ]
 crbug.com/874162 [ Mac ] fast/events/middleClickAutoscroll-nested-divs-forbidden.html [ Skip ]
-crbug.com/874162 [ Mac ] virtual/mouseevent_fractional/fast/events/middleClickAutoscroll-nested-divs-forbidden.html [ Skip ]
+# The next also fails due to crbug.com/891427, thus disabled on all platforms.
+crbug.com/874162 virtual/mouseevent_fractional/fast/events/middleClickAutoscroll-nested-divs-forbidden.html [ Skip ]
 crbug.com/874162 [ Mac ] virtual/user-activation-v2/fast/events/middleClickAutoscroll-nested-divs-forbidden.html [ Skip ]
 crbug.com/874162 [ Mac ] fast/events/middleClickAutoscroll-nested-divs.html [ Skip ]
 crbug.com/874162 [ Mac ] virtual/mouseevent_fractional/fast/events/middleClickAutoscroll-nested-divs.html [ Skip ]
@@ -5674,8 +5689,6 @@
 crbug.com/896765 [ Linux Mac Win ] http/tests/performance-timing/element-timing/observe-child-element.html [ Failure Pass ]
 
 #Sheriff 2018-10-22
-crbug.com/897775 [ Linux Mac Win ] external/wpt/performance-timeline/webtiming-resolution.any.html [ Failure Pass ]
-crbug.com/897775 [ Linux Mac Win ] external/wpt/performance-timeline/webtiming-resolution.any.worker.html [ Failure Pass ]
 crbug.com/897849 [ Mac10.13 Debug ] accessibility/element-role-mapping-normal.html [ Pass Timeout ]
 crbug.com/897849 [ Mac10.13 Debug ] accessibility/table-header-column-row.html [ Pass Timeout ]
 crbug.com/897075 [ Win10 ] inspector-protocol/css/css-coverage-new-stylesheet.js [ Failure Pass ]
@@ -5719,3 +5732,7 @@
 ### See crbug.com/891427 comment near the top of this file:
 ####crbug.com/899087 [ Linux ] virtual/android/fullscreen/full-screen-iframe-allowed-video.html [ Failure Pass ]
 crbug.com/899232 [ Linux ] virtual/user-activation-v2/fast/events/touch/gesture/gesture-scrollbar-touchpad-fling.html [ Failure Pass ]
+
+# Sheriff 2018-10-29
+crbug.com/899710 [ Linux ] virtual/threaded/http/tests/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations.js [ Failure Pass ]
+crbug.com/899715 [ Linux ] virtual/threaded/fast/scroll-behavior/wheel-and-touch-scroll-use-count.html [ Failure Pass ]
diff --git a/third_party/WebKit/LayoutTests/animations/animationworklet/worklet-animation-currentTime.html b/third_party/WebKit/LayoutTests/animations/animationworklet/worklet-animation-currentTime.html
index e32ea76..70157af 100644
--- a/third_party/WebKit/LayoutTests/animations/animationworklet/worklet-animation-currentTime.html
+++ b/third_party/WebKit/LayoutTests/animations/animationworklet/worklet-animation-currentTime.html
@@ -32,8 +32,13 @@
   animation.play();
 
   waitTwoAnimationFrames(t.step_func_done(() => {
-    const second_opacity = getComputedStyle(target).opacity;
-    assert_true(second_opacity < first_opacity);
+    // waitTwoAnimationFrames guarantees a compositor frame that could update
+    // the opacity value in the worklet. Meanwhile, getComputedStyle needs an
+    // extra frame to fetch the updated value.
+    window.requestAnimationFrame( _ => {
+      const second_opacity = getComputedStyle(target).opacity;
+      assert_true(second_opacity < first_opacity);
+    });
   }));
 });
 }, 'Opacity should change as the animation starts.');
diff --git a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST_5.json b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST_5.json
index ce751b31..8752473a 100644
--- a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST_5.json
+++ b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST_5.json
@@ -84191,6 +84191,18 @@
      {}
     ]
    ],
+   "css/css-writing-modes/inline-box-border-vlr-001.html": [
+    [
+     "/css/css-writing-modes/inline-box-border-vlr-001.html",
+     [
+      [
+       "/css/css-writing-modes/reference/inline-box-border-vlr-001.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-writing-modes/inline-replaced-vlr-003.xht": [
     [
      "/css/css-writing-modes/inline-replaced-vlr-003.xht",
@@ -109020,6 +109032,231 @@
      {}
     ]
    ],
+   "2dcontext/wide-gamut-canvas/resources/pattern-semitransparent-p3d65.png": [
+    [
+     {}
+    ]
+   ],
+   "2dcontext/wide-gamut-canvas/resources/pattern-semitransparent-rec2020.png": [
+    [
+     {}
+    ]
+   ],
+   "2dcontext/wide-gamut-canvas/resources/pattern-semitransparent-srgb.png": [
+    [
+     {}
+    ]
+   ],
+   "2dcontext/wide-gamut-canvas/resources/pattern-srgb-fullcolor.ogv": [
+    [
+     {}
+    ]
+   ],
+   "2dcontext/wide-gamut-canvas/resources/pattern-srgb-transparent.bmp": [
+    [
+     {}
+    ]
+   ],
+   "2dcontext/wide-gamut-canvas/resources/pattern-srgb-transparent.ico": [
+    [
+     {}
+    ]
+   ],
+   "2dcontext/wide-gamut-canvas/resources/pattern-srgb-transparent.png": [
+    [
+     {}
+    ]
+   ],
+   "2dcontext/wide-gamut-canvas/resources/pattern-srgb-transparent.webp": [
+    [
+     {}
+    ]
+   ],
+   "2dcontext/wide-gamut-canvas/resources/pattern-srgb.bmp": [
+    [
+     {}
+    ]
+   ],
+   "2dcontext/wide-gamut-canvas/resources/pattern-srgb.gif": [
+    [
+     {}
+    ]
+   ],
+   "2dcontext/wide-gamut-canvas/resources/pattern-srgb.ico": [
+    [
+     {}
+    ]
+   ],
+   "2dcontext/wide-gamut-canvas/resources/pattern-srgb.jpg": [
+    [
+     {}
+    ]
+   ],
+   "2dcontext/wide-gamut-canvas/resources/pattern-srgb.png": [
+    [
+     {}
+    ]
+   ],
+   "2dcontext/wide-gamut-canvas/resources/pattern-srgb.svg": [
+    [
+     {}
+    ]
+   ],
+   "2dcontext/wide-gamut-canvas/resources/pattern-srgb.webp": [
+    [
+     {}
+    ]
+   ],
+   "2dcontext/wide-gamut-canvas/resources/png-16bit/2x2_16bit_AdobeRGB_opaque.png": [
+    [
+     {}
+    ]
+   ],
+   "2dcontext/wide-gamut-canvas/resources/png-16bit/2x2_16bit_AdobeRGB_transparent.png": [
+    [
+     {}
+    ]
+   ],
+   "2dcontext/wide-gamut-canvas/resources/png-16bit/2x2_16bit_DisplayP3_opaque.png": [
+    [
+     {}
+    ]
+   ],
+   "2dcontext/wide-gamut-canvas/resources/png-16bit/2x2_16bit_DisplayP3_transparent.png": [
+    [
+     {}
+    ]
+   ],
+   "2dcontext/wide-gamut-canvas/resources/png-16bit/2x2_16bit_ProPhoto_opaque.png": [
+    [
+     {}
+    ]
+   ],
+   "2dcontext/wide-gamut-canvas/resources/png-16bit/2x2_16bit_ProPhoto_transparent.png": [
+    [
+     {}
+    ]
+   ],
+   "2dcontext/wide-gamut-canvas/resources/png-16bit/2x2_16bit_Rec2020_opaque.png": [
+    [
+     {}
+    ]
+   ],
+   "2dcontext/wide-gamut-canvas/resources/png-16bit/2x2_16bit_Rec2020_transparent.png": [
+    [
+     {}
+    ]
+   ],
+   "2dcontext/wide-gamut-canvas/resources/png-16bit/2x2_16bit_interlaced_AdobeRGB_opaque.png": [
+    [
+     {}
+    ]
+   ],
+   "2dcontext/wide-gamut-canvas/resources/png-16bit/2x2_16bit_interlaced_AdobeRGB_transparent.png": [
+    [
+     {}
+    ]
+   ],
+   "2dcontext/wide-gamut-canvas/resources/png-16bit/2x2_16bit_interlaced_DisplayP3_opaque.png": [
+    [
+     {}
+    ]
+   ],
+   "2dcontext/wide-gamut-canvas/resources/png-16bit/2x2_16bit_interlaced_DisplayP3_transparent.png": [
+    [
+     {}
+    ]
+   ],
+   "2dcontext/wide-gamut-canvas/resources/png-16bit/2x2_16bit_interlaced_ProPhoto_opaque.png": [
+    [
+     {}
+    ]
+   ],
+   "2dcontext/wide-gamut-canvas/resources/png-16bit/2x2_16bit_interlaced_ProPhoto_transparent.png": [
+    [
+     {}
+    ]
+   ],
+   "2dcontext/wide-gamut-canvas/resources/png-16bit/2x2_16bit_interlaced_Rec2020_opaque.png": [
+    [
+     {}
+    ]
+   ],
+   "2dcontext/wide-gamut-canvas/resources/png-16bit/2x2_16bit_interlaced_Rec2020_transparent.png": [
+    [
+     {}
+    ]
+   ],
+   "2dcontext/wide-gamut-canvas/resources/png-16bit/2x2_16bit_interlaced_sRGB_opaque.png": [
+    [
+     {}
+    ]
+   ],
+   "2dcontext/wide-gamut-canvas/resources/png-16bit/2x2_16bit_interlaced_sRGB_transparent.png": [
+    [
+     {}
+    ]
+   ],
+   "2dcontext/wide-gamut-canvas/resources/png-16bit/2x2_16bit_sRGB_opaque.png": [
+    [
+     {}
+    ]
+   ],
+   "2dcontext/wide-gamut-canvas/resources/png-16bit/2x2_16bit_sRGB_transparent.png": [
+    [
+     {}
+    ]
+   ],
+   "2dcontext/wide-gamut-canvas/resources/png-16bit/2x2_8bit_AdobeRGB_opaque.png": [
+    [
+     {}
+    ]
+   ],
+   "2dcontext/wide-gamut-canvas/resources/png-16bit/2x2_8bit_AdobeRGB_transparent.png": [
+    [
+     {}
+    ]
+   ],
+   "2dcontext/wide-gamut-canvas/resources/png-16bit/2x2_8bit_DisplayP3_opaque.png": [
+    [
+     {}
+    ]
+   ],
+   "2dcontext/wide-gamut-canvas/resources/png-16bit/2x2_8bit_DisplayP3_transparent.png": [
+    [
+     {}
+    ]
+   ],
+   "2dcontext/wide-gamut-canvas/resources/png-16bit/2x2_8bit_ProPhoto_opaque.png": [
+    [
+     {}
+    ]
+   ],
+   "2dcontext/wide-gamut-canvas/resources/png-16bit/2x2_8bit_ProPhoto_transparent.png": [
+    [
+     {}
+    ]
+   ],
+   "2dcontext/wide-gamut-canvas/resources/png-16bit/2x2_8bit_Rec2020_opaque.png": [
+    [
+     {}
+    ]
+   ],
+   "2dcontext/wide-gamut-canvas/resources/png-16bit/2x2_8bit_Rec2020_transparent.png": [
+    [
+     {}
+    ]
+   ],
+   "2dcontext/wide-gamut-canvas/resources/png-16bit/2x2_8bit_sRGB_opaque.png": [
+    [
+     {}
+    ]
+   ],
+   "2dcontext/wide-gamut-canvas/resources/png-16bit/2x2_8bit_sRGB_transparent.png": [
+    [
+     {}
+    ]
+   ],
    "BackgroundSync/META.yml": [
     [
      {}
@@ -134800,11 +135037,6 @@
      {}
     ]
    ],
-   "css/css-scroll-snap/inheritance-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "css/css-scrollbars/META.yml": [
     [
      {}
@@ -143410,6 +143642,11 @@
      {}
     ]
    ],
+   "css/css-writing-modes/reference/inline-box-border-vlr-001.html": [
+    [
+     {}
+    ]
+   ],
    "css/css-writing-modes/reference/logical-props-001-ref.html": [
     [
      {}
@@ -175615,6 +175852,16 @@
      {}
     ]
    ],
+   "service-workers/service-worker/resources/imported-classic-script.js": [
+    [
+     {}
+    ]
+   ],
+   "service-workers/service-worker/resources/imported-module-script.js": [
+    [
+     {}
+    ]
+   ],
    "service-workers/service-worker/resources/indexeddb-worker.js": [
     [
      {}
@@ -176240,6 +176487,16 @@
      {}
     ]
    ],
+   "service-workers/service-worker/resources/update-missing-import-scripts-imported-worker.py": [
+    [
+     {}
+    ]
+   ],
+   "service-workers/service-worker/resources/update-missing-import-scripts-main-worker.py": [
+    [
+     {}
+    ]
+   ],
    "service-workers/service-worker/resources/update-nocookie-worker.py": [
     [
      {}
@@ -176250,6 +176507,11 @@
      {}
     ]
    ],
+   "service-workers/service-worker/resources/update-registration-with-type.py": [
+    [
+     {}
+    ]
+   ],
    "service-workers/service-worker/resources/update-worker.py": [
     [
      {}
@@ -179405,7 +179667,7 @@
      {}
     ]
    ],
-   "webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-multi-channels-expected.wav": [
+   "webaudio/the-audio-api/the-audiobuffersourcenode-interface/resources/audiobuffersource-multi-channels-expected.wav": [
     [
      {}
     ]
@@ -183500,7 +183762,7 @@
      {}
     ]
    ],
-   "workers/semantics/interface-objects/002.worker-expected.txt": [
+   "workers/semantics/interface-objects/003-expected.txt": [
     [
      {}
     ]
@@ -189415,6 +189677,90 @@
      {}
     ]
    ],
+   "2dcontext/wide-gamut-canvas/ImageData-fidelity.html": [
+    [
+     "/2dcontext/wide-gamut-canvas/ImageData-fidelity.html",
+     {}
+    ]
+   ],
+   "2dcontext/wide-gamut-canvas/canvas-colorManaged-convertToBlob-roundtrip.html": [
+    [
+     "/2dcontext/wide-gamut-canvas/canvas-colorManaged-convertToBlob-roundtrip.html",
+     {}
+    ]
+   ],
+   "2dcontext/wide-gamut-canvas/canvas-colorManaged-toBlob-toDataURL.html": [
+    [
+     "/2dcontext/wide-gamut-canvas/canvas-colorManaged-toBlob-toDataURL.html",
+     {}
+    ]
+   ],
+   "2dcontext/wide-gamut-canvas/canvas-colorspace-arguments.html": [
+    [
+     "/2dcontext/wide-gamut-canvas/canvas-colorspace-arguments.html",
+     {}
+    ]
+   ],
+   "2dcontext/wide-gamut-canvas/canvas-createImageBitmap-e_srgb.html": [
+    [
+     "/2dcontext/wide-gamut-canvas/canvas-createImageBitmap-e_srgb.html",
+     {}
+    ]
+   ],
+   "2dcontext/wide-gamut-canvas/canvas-createPutGetImageData-colorManaged.html": [
+    [
+     "/2dcontext/wide-gamut-canvas/canvas-createPutGetImageData-colorManaged.html",
+     {}
+    ]
+   ],
+   "2dcontext/wide-gamut-canvas/canvas-draw-high-bit-depth-images.html": [
+    [
+     "/2dcontext/wide-gamut-canvas/canvas-draw-high-bit-depth-images.html",
+     {}
+    ]
+   ],
+   "2dcontext/wide-gamut-canvas/canvas-drawImage-e_srgb.html": [
+    [
+     "/2dcontext/wide-gamut-canvas/canvas-drawImage-e_srgb.html",
+     {}
+    ]
+   ],
+   "2dcontext/wide-gamut-canvas/canvas-drawImage-offscreenCanvas.html": [
+    [
+     "/2dcontext/wide-gamut-canvas/canvas-drawImage-offscreenCanvas.html",
+     {}
+    ]
+   ],
+   "2dcontext/wide-gamut-canvas/canvas-getImageData-e_srgb.html": [
+    [
+     "/2dcontext/wide-gamut-canvas/canvas-getImageData-e_srgb.html",
+     {}
+    ]
+   ],
+   "2dcontext/wide-gamut-canvas/imageData-colorManagedBehavior.html": [
+    [
+     "/2dcontext/wide-gamut-canvas/imageData-colorManagedBehavior.html",
+     {}
+    ]
+   ],
+   "2dcontext/wide-gamut-canvas/imageData-colorSpace.html": [
+    [
+     "/2dcontext/wide-gamut-canvas/imageData-colorSpace.html",
+     {}
+    ]
+   ],
+   "2dcontext/wide-gamut-canvas/imagedata-no-color-settings-crash.html": [
+    [
+     "/2dcontext/wide-gamut-canvas/imagedata-no-color-settings-crash.html",
+     {}
+    ]
+   ],
+   "2dcontext/wide-gamut-canvas/transferFromImageBitmap.html": [
+    [
+     "/2dcontext/wide-gamut-canvas/transferFromImageBitmap.html",
+     {}
+    ]
+   ],
    "BackgroundSync/interfaces.https.any.js": [
     [
      "/BackgroundSync/interfaces.https.any.html",
@@ -193247,9 +193593,9 @@
      {}
     ]
    ],
-   "beacon/beacon-error.window.js": [
+   "beacon/beacon-error.sub.window.js": [
     [
-     "/beacon/beacon-error.window.html",
+     "/beacon/beacon-error.sub.window.html",
      {}
     ]
    ],
@@ -204769,6 +205115,12 @@
      {}
     ]
    ],
+   "css/css-text/inheritance.html": [
+    [
+     "/css/css-text/inheritance.html",
+     {}
+    ]
+   ],
    "css/css-text/overflow-wrap/word-wrap-alias.html": [
     [
      "/css/css-text/overflow-wrap/word-wrap-alias.html",
@@ -207507,6 +207859,12 @@
      {}
     ]
    ],
+   "css/css-ui/inheritance.html": [
+    [
+     "/css/css-ui/inheritance.html",
+     {}
+    ]
+   ],
    "css/css-ui/outline-017.html": [
     [
      "/css/css-ui/outline-017.html",
@@ -212451,6 +212809,12 @@
      {}
     ]
    ],
+   "domparsing/DOMParser-parseFromString-xml-parsererror.html": [
+    [
+     "/domparsing/DOMParser-parseFromString-xml-parsererror.html",
+     {}
+    ]
+   ],
    "domparsing/DOMParser-parseFromString-xml.html": [
     [
      "/domparsing/DOMParser-parseFromString-xml.html",
@@ -263491,6 +263855,12 @@
      {}
     ]
    ],
+   "service-workers/service-worker/update-missing-import-scripts.https.html": [
+    [
+     "/service-workers/service-worker/update-missing-import-scripts.https.html",
+     {}
+    ]
+   ],
    "service-workers/service-worker/update-not-allowed.https.html": [
     [
      "/service-workers/service-worker/update-not-allowed.https.html",
@@ -263503,6 +263873,12 @@
      {}
     ]
    ],
+   "service-workers/service-worker/update-registration-with-type.https.html": [
+    [
+     "/service-workers/service-worker/update-registration-with-type.https.html",
+     {}
+    ]
+   ],
    "service-workers/service-worker/update-result.https.html": [
     [
      "/service-workers/service-worker/update-result.https.html",
@@ -270081,57 +270457,57 @@
      {}
     ]
    ],
-   "webmessaging/with-options/broken-origin.tentative.html": [
+   "webmessaging/with-options/broken-origin.html": [
     [
-     "/webmessaging/with-options/broken-origin.tentative.html",
+     "/webmessaging/with-options/broken-origin.html",
      {}
     ]
    ],
-   "webmessaging/with-options/host-specific-origin.tentative.html": [
+   "webmessaging/with-options/host-specific-origin.html": [
     [
-     "/webmessaging/with-options/host-specific-origin.tentative.html",
+     "/webmessaging/with-options/host-specific-origin.html",
      {}
     ]
    ],
-   "webmessaging/with-options/message-channel-transferable.tentative.html": [
+   "webmessaging/with-options/message-channel-transferable.html": [
     [
-     "/webmessaging/with-options/message-channel-transferable.tentative.html",
+     "/webmessaging/with-options/message-channel-transferable.html",
      {}
     ]
    ],
-   "webmessaging/with-options/no-target-origin.tentative.html": [
+   "webmessaging/with-options/no-target-origin.html": [
     [
-     "/webmessaging/with-options/no-target-origin.tentative.html",
+     "/webmessaging/with-options/no-target-origin.html",
      {}
     ]
    ],
-   "webmessaging/with-options/null-transfer.tentative.html": [
+   "webmessaging/with-options/null-transfer.html": [
     [
-     "/webmessaging/with-options/null-transfer.tentative.html",
+     "/webmessaging/with-options/null-transfer.html",
      {}
     ]
    ],
-   "webmessaging/with-options/one-arg.tentative.html": [
+   "webmessaging/with-options/one-arg.html": [
     [
-     "/webmessaging/with-options/one-arg.tentative.html",
+     "/webmessaging/with-options/one-arg.html",
      {}
     ]
    ],
-   "webmessaging/with-options/slash-origin.tentative.html": [
+   "webmessaging/with-options/slash-origin.html": [
     [
-     "/webmessaging/with-options/slash-origin.tentative.html",
+     "/webmessaging/with-options/slash-origin.html",
      {}
     ]
    ],
-   "webmessaging/with-options/undefined-transferable.tentative.html": [
+   "webmessaging/with-options/undefined-transferable.html": [
     [
-     "/webmessaging/with-options/undefined-transferable.tentative.html",
+     "/webmessaging/with-options/undefined-transferable.html",
      {}
     ]
    ],
-   "webmessaging/with-options/unknown-parameter.tentative.html": [
+   "webmessaging/with-options/unknown-parameter.html": [
     [
-     "/webmessaging/with-options/unknown-parameter.tentative.html",
+     "/webmessaging/with-options/unknown-parameter.html",
      {}
     ]
    ],
@@ -270321,12 +270697,6 @@
      {}
     ]
    ],
-   "webmessaging/without-ports/008.html": [
-    [
-     "/webmessaging/without-ports/008.html",
-     {}
-    ]
-   ],
    "webmessaging/without-ports/009.html": [
     [
      "/webmessaging/without-ports/009.html",
@@ -286607,7 +286977,7 @@
    "support"
   ],
   "2dcontext/imagebitmap/createImageBitmap-invalid-args.html": [
-   "39707e83cb0361a7ab2944a175fe2787e68d9035",
+   "004b3ca6bf39eb7613d2621c8a431df5ab52278b",
    "testharness"
   ],
   "2dcontext/imagebitmap/createImageBitmap-origin.sub.html": [
@@ -288294,6 +288664,242 @@
    "2a166c36ce401cc125e4e8981185d8fa39696207",
    "support"
   ],
+  "2dcontext/wide-gamut-canvas/ImageData-fidelity.html": [
+   "c2d158f893ed8f3fcfe861185197ae0bcd8c7ad6",
+   "testharness"
+  ],
+  "2dcontext/wide-gamut-canvas/canvas-colorManaged-convertToBlob-roundtrip.html": [
+   "72c64b10663866026d35c1daf73714d18f8ea90b",
+   "testharness"
+  ],
+  "2dcontext/wide-gamut-canvas/canvas-colorManaged-toBlob-toDataURL.html": [
+   "ea21d33563ba20187a5424a68885297061fdb10e",
+   "testharness"
+  ],
+  "2dcontext/wide-gamut-canvas/canvas-colorspace-arguments.html": [
+   "f44b3240bcf7f1fca8f0d6058e62f63874f05773",
+   "testharness"
+  ],
+  "2dcontext/wide-gamut-canvas/canvas-createImageBitmap-e_srgb.html": [
+   "1e2e05c2cfc3d0199c65449dda0dc53246e3f276",
+   "testharness"
+  ],
+  "2dcontext/wide-gamut-canvas/canvas-createPutGetImageData-colorManaged.html": [
+   "a6b202e8f2bd671ce5074146d127abf6d2baf910",
+   "testharness"
+  ],
+  "2dcontext/wide-gamut-canvas/canvas-draw-high-bit-depth-images.html": [
+   "7d443817cb67c88abecb989bd30205128961e3aa",
+   "testharness"
+  ],
+  "2dcontext/wide-gamut-canvas/canvas-drawImage-e_srgb.html": [
+   "7620d93d5f11ed9522aa851248e9981d742f7e6d",
+   "testharness"
+  ],
+  "2dcontext/wide-gamut-canvas/canvas-drawImage-offscreenCanvas.html": [
+   "144dca0e7753c420a0a8eb4126c4c8e7cc8a39eb",
+   "testharness"
+  ],
+  "2dcontext/wide-gamut-canvas/canvas-getImageData-e_srgb.html": [
+   "f5f0e629dd19f4d65531b15bf39595e587ded974",
+   "testharness"
+  ],
+  "2dcontext/wide-gamut-canvas/imageData-colorManagedBehavior.html": [
+   "6bc55b7ca70e9cc0fe28e4e0f27a5e094fd725cb",
+   "testharness"
+  ],
+  "2dcontext/wide-gamut-canvas/imageData-colorSpace.html": [
+   "9023cbea3620686b04aeed15120284bdf9a41478",
+   "testharness"
+  ],
+  "2dcontext/wide-gamut-canvas/imagedata-no-color-settings-crash.html": [
+   "d7fe956e4b8d99421181a714648eaf561dbab735",
+   "testharness"
+  ],
+  "2dcontext/wide-gamut-canvas/resources/pattern-semitransparent-p3d65.png": [
+   "5eb3f6a15f01a123cb793e7311b50de30a5af31e",
+   "support"
+  ],
+  "2dcontext/wide-gamut-canvas/resources/pattern-semitransparent-rec2020.png": [
+   "b64db073791ddbf0ea8188247d1160921753a413",
+   "support"
+  ],
+  "2dcontext/wide-gamut-canvas/resources/pattern-semitransparent-srgb.png": [
+   "bfbba8b8e296fe354db953bc9888cd19888ca2d3",
+   "support"
+  ],
+  "2dcontext/wide-gamut-canvas/resources/pattern-srgb-fullcolor.ogv": [
+   "43a72bf271be679a932b69a5c2304d8fe547d22e",
+   "support"
+  ],
+  "2dcontext/wide-gamut-canvas/resources/pattern-srgb-transparent.bmp": [
+   "9c9561c70464eed928e288f27163c47c1a914977",
+   "support"
+  ],
+  "2dcontext/wide-gamut-canvas/resources/pattern-srgb-transparent.ico": [
+   "87e8ff45de76e30bfec9489689830b348ef48903",
+   "support"
+  ],
+  "2dcontext/wide-gamut-canvas/resources/pattern-srgb-transparent.png": [
+   "bfbba8b8e296fe354db953bc9888cd19888ca2d3",
+   "support"
+  ],
+  "2dcontext/wide-gamut-canvas/resources/pattern-srgb-transparent.webp": [
+   "925646067ad079facaaf2d03481e36eadeb25b6f",
+   "support"
+  ],
+  "2dcontext/wide-gamut-canvas/resources/pattern-srgb.bmp": [
+   "465d203d98bf3dcce2fef2f416a1e5b3d2795319",
+   "support"
+  ],
+  "2dcontext/wide-gamut-canvas/resources/pattern-srgb.gif": [
+   "25bcefb2bf4be178ae65d4c8391d8a49328e6a14",
+   "support"
+  ],
+  "2dcontext/wide-gamut-canvas/resources/pattern-srgb.ico": [
+   "e5375826abdf4616b00349946b5892e34fb630dd",
+   "support"
+  ],
+  "2dcontext/wide-gamut-canvas/resources/pattern-srgb.jpg": [
+   "c4579e8f0625719cf61808500c73b3fbe0f95832",
+   "support"
+  ],
+  "2dcontext/wide-gamut-canvas/resources/pattern-srgb.png": [
+   "1b5876b5f39954f7ca0b18fae63e2be46e8ce100",
+   "support"
+  ],
+  "2dcontext/wide-gamut-canvas/resources/pattern-srgb.svg": [
+   "05171308494195082758b4be205b2c297b968efe",
+   "support"
+  ],
+  "2dcontext/wide-gamut-canvas/resources/pattern-srgb.webp": [
+   "b7c0a421dcbc5a4f7ea92306c0f5305d28f04eea",
+   "support"
+  ],
+  "2dcontext/wide-gamut-canvas/resources/png-16bit/2x2_16bit_AdobeRGB_opaque.png": [
+   "c4496db19bf4d0d410256ff7e3ba5add0a65d19e",
+   "support"
+  ],
+  "2dcontext/wide-gamut-canvas/resources/png-16bit/2x2_16bit_AdobeRGB_transparent.png": [
+   "3b4cfda52c506f9aba9aed6d1e96c1eda2a35f71",
+   "support"
+  ],
+  "2dcontext/wide-gamut-canvas/resources/png-16bit/2x2_16bit_DisplayP3_opaque.png": [
+   "e7a142cd2e1481796cebe980b33e8bf9004a5b4d",
+   "support"
+  ],
+  "2dcontext/wide-gamut-canvas/resources/png-16bit/2x2_16bit_DisplayP3_transparent.png": [
+   "0b035317c81c4292336c46067eb4e01239059b48",
+   "support"
+  ],
+  "2dcontext/wide-gamut-canvas/resources/png-16bit/2x2_16bit_ProPhoto_opaque.png": [
+   "a1dc7ddb0de09ff41dc026aaa9e2a3bf998d229a",
+   "support"
+  ],
+  "2dcontext/wide-gamut-canvas/resources/png-16bit/2x2_16bit_ProPhoto_transparent.png": [
+   "be2eb1208e1018d8f293acf71cc6aca51a7cdbc1",
+   "support"
+  ],
+  "2dcontext/wide-gamut-canvas/resources/png-16bit/2x2_16bit_Rec2020_opaque.png": [
+   "e2a2d1445187855e5a704ab286867e92ad10b390",
+   "support"
+  ],
+  "2dcontext/wide-gamut-canvas/resources/png-16bit/2x2_16bit_Rec2020_transparent.png": [
+   "960d7d8e75dc775c8934029a64a4d146c7761c9e",
+   "support"
+  ],
+  "2dcontext/wide-gamut-canvas/resources/png-16bit/2x2_16bit_interlaced_AdobeRGB_opaque.png": [
+   "80cf9785eb0956a2930e19d17ca2347a94b049ff",
+   "support"
+  ],
+  "2dcontext/wide-gamut-canvas/resources/png-16bit/2x2_16bit_interlaced_AdobeRGB_transparent.png": [
+   "3ec565f8c29a8a6745c2410d2160e63af9973776",
+   "support"
+  ],
+  "2dcontext/wide-gamut-canvas/resources/png-16bit/2x2_16bit_interlaced_DisplayP3_opaque.png": [
+   "5f3134b79cf29e53940e98e166b5cc1a0fb2cb37",
+   "support"
+  ],
+  "2dcontext/wide-gamut-canvas/resources/png-16bit/2x2_16bit_interlaced_DisplayP3_transparent.png": [
+   "500a70eff859e7c92f12d08f028cc9dd8c3c884c",
+   "support"
+  ],
+  "2dcontext/wide-gamut-canvas/resources/png-16bit/2x2_16bit_interlaced_ProPhoto_opaque.png": [
+   "b5d0e07a7a44a17f7b70fc3c02baa253747304dc",
+   "support"
+  ],
+  "2dcontext/wide-gamut-canvas/resources/png-16bit/2x2_16bit_interlaced_ProPhoto_transparent.png": [
+   "e4ec3e44549e01db00d80c0148eff2a5f9848994",
+   "support"
+  ],
+  "2dcontext/wide-gamut-canvas/resources/png-16bit/2x2_16bit_interlaced_Rec2020_opaque.png": [
+   "c487d5846f8ef01b80cb16992aa127ff705131bb",
+   "support"
+  ],
+  "2dcontext/wide-gamut-canvas/resources/png-16bit/2x2_16bit_interlaced_Rec2020_transparent.png": [
+   "78fe202c0e49244aba855db499d4ac22d23fe6d6",
+   "support"
+  ],
+  "2dcontext/wide-gamut-canvas/resources/png-16bit/2x2_16bit_interlaced_sRGB_opaque.png": [
+   "babf232a369205380dd3052a52fab6e173fafb29",
+   "support"
+  ],
+  "2dcontext/wide-gamut-canvas/resources/png-16bit/2x2_16bit_interlaced_sRGB_transparent.png": [
+   "30164040096e0f466bba2c742980340ec6f8ddad",
+   "support"
+  ],
+  "2dcontext/wide-gamut-canvas/resources/png-16bit/2x2_16bit_sRGB_opaque.png": [
+   "8a665345e9c27cf4c35eb8621bae7219647c20ce",
+   "support"
+  ],
+  "2dcontext/wide-gamut-canvas/resources/png-16bit/2x2_16bit_sRGB_transparent.png": [
+   "e51cda77c40f63f8913aa53f40c070a055e493b2",
+   "support"
+  ],
+  "2dcontext/wide-gamut-canvas/resources/png-16bit/2x2_8bit_AdobeRGB_opaque.png": [
+   "8b787b5c8729ad2a7a11454aee3ad8195d4c3fc8",
+   "support"
+  ],
+  "2dcontext/wide-gamut-canvas/resources/png-16bit/2x2_8bit_AdobeRGB_transparent.png": [
+   "727028e7656b9b9650716ea1f26560f773bf23b7",
+   "support"
+  ],
+  "2dcontext/wide-gamut-canvas/resources/png-16bit/2x2_8bit_DisplayP3_opaque.png": [
+   "fe8bdd4963712dd87a4e9d541c1765472c452f7d",
+   "support"
+  ],
+  "2dcontext/wide-gamut-canvas/resources/png-16bit/2x2_8bit_DisplayP3_transparent.png": [
+   "b836afebed3208ef181e881e9f3c813f899fbb28",
+   "support"
+  ],
+  "2dcontext/wide-gamut-canvas/resources/png-16bit/2x2_8bit_ProPhoto_opaque.png": [
+   "5ecd8686065930ddfb245a2114986546725b3437",
+   "support"
+  ],
+  "2dcontext/wide-gamut-canvas/resources/png-16bit/2x2_8bit_ProPhoto_transparent.png": [
+   "85a349dc1d169e22bb0b3ef33c8383526ca51c0d",
+   "support"
+  ],
+  "2dcontext/wide-gamut-canvas/resources/png-16bit/2x2_8bit_Rec2020_opaque.png": [
+   "599cd34040e03a0a8a255a9b41f76b8239f2d6ef",
+   "support"
+  ],
+  "2dcontext/wide-gamut-canvas/resources/png-16bit/2x2_8bit_Rec2020_transparent.png": [
+   "ecf65c3d460361a7c5d9bdc7be833f3cf217475e",
+   "support"
+  ],
+  "2dcontext/wide-gamut-canvas/resources/png-16bit/2x2_8bit_sRGB_opaque.png": [
+   "9cab6d12e6e6dd7e9cc52eb47aaae7ee105b4b09",
+   "support"
+  ],
+  "2dcontext/wide-gamut-canvas/resources/png-16bit/2x2_8bit_sRGB_transparent.png": [
+   "5fa01e62c2007b940baace6fe92c34413128f7a9",
+   "support"
+  ],
+  "2dcontext/wide-gamut-canvas/transferFromImageBitmap.html": [
+   "6855dc705b75aff9e609bc01be9ae94079a1ac0d",
+   "testharness"
+  ],
   "BackgroundSync/META.yml": [
    "e5e6a2361f0d0716a27e5e7c5bf63a5527ea5ca8",
    "support"
@@ -290883,7 +291489,7 @@
    "manual"
   ],
   "accelerometer/META.yml": [
-   "cab7007fd2f26525d85e7c76c7033bc89c2b2db4",
+   "6554be89580e7328117fc35880f70cf623ce0ee9",
    "support"
   ],
   "accelerometer/OWNERS": [
@@ -291623,7 +292229,7 @@
    "manual"
   ],
   "ambient-light/META.yml": [
-   "d35c2c53620caa8ed6ec05d1cc2e4eee5c6c75c7",
+   "04fce804971f9050c79960c4f5a344ae1b9fe2bc",
    "support"
   ],
   "ambient-light/OWNERS": [
@@ -291739,7 +292345,7 @@
    "manual"
   ],
   "audio-output/setSinkId.html": [
-   "3fd0d5d6f762b993adb968c994c02ac77b4168f5",
+   "f7cf2c9a0dd5e2436b9e6eadacbfc1f25c1b6a75",
    "testharness"
   ],
   "audio-output/setSinkId.https-expected.txt": [
@@ -291747,7 +292353,7 @@
    "support"
   ],
   "audio-output/setSinkId.https.html": [
-   "b4cf7df71c5f134ecf674663ea208295809c566a",
+   "fa4f48e2bcb60d659f34cdcd2bd95a000e26b68e",
    "testharness"
   ],
   "background-fetch/META.yml": [
@@ -291966,8 +292572,8 @@
    "411cd1c94924127ce95c27707d283e7ca342f367",
    "testharness"
   ],
-  "beacon/beacon-error.window.js": [
-   "b53353abc1ea29679216488ef17c9c9a010a434d",
+  "beacon/beacon-error.sub.window.js": [
+   "f2c5e95a276c257387e1cd85c2bcb70090d1132c",
    "testharness"
   ],
   "beacon/beacon-navigate-expected.txt": [
@@ -312775,7 +313381,7 @@
    "support"
   ],
   "css/build-css-testsuites.sh": [
-   "4aad0bbbb19e79d97a9d4c46dc239bec8c311108",
+   "5cb26179b8dbe4423885bcc7c8d687bab224df91",
    "support"
   ],
   "css/css-align/META.yml": [
@@ -337938,12 +338544,8 @@
    "df776353a31f1cef3abe9bc9d195da9be5da2510",
    "support"
   ],
-  "css/css-scroll-snap/inheritance-expected.txt": [
-   "150868971a33aac5981da2194e25e790c4752879",
-   "support"
-  ],
   "css/css-scroll-snap/inheritance.html": [
-   "40600d460c4f6a05f6df0a1d8ddb7ad3c3fee53d",
+   "b380cb400f2c291832fdfeeab72e9b5561b3c847",
    "testharness"
   ],
   "css/css-scroll-snap/overflowing-snap-areas.html": [
@@ -342694,6 +343296,10 @@
    "ec44c093a32decdc7bd39b77d7409fff36b62f4b",
    "testharness"
   ],
+  "css/css-text/inheritance.html": [
+   "ef3270651c3df4ae6112fdfeec0e7fea4b9d6ccf",
+   "testharness"
+  ],
   "css/css-text/letter-spacing/letter-spacing-control-chars-001.html": [
    "87d071a1ed3d1f738986271be530460833e495ec",
    "reftest"
@@ -353646,6 +354252,10 @@
    "cb3b7ae9df1998eb125182d21e6d27d79f408e81",
    "manual"
   ],
+  "css/css-ui/inheritance.html": [
+   "912e9f3228f5be96542f8052a13fca9acb718f83",
+   "testharness"
+  ],
   "css/css-ui/nav-dir-001.html": [
    "98250a1d5cffa25db13425d32ae3edb9f56ac07f",
    "manual"
@@ -358778,6 +359388,10 @@
    "ce87900ddc949a3a536df66b26a3268ee343207d",
    "reftest"
   ],
+  "css/css-writing-modes/inline-box-border-vlr-001.html": [
+   "453a8a51c3bf17bbf035b16abfedb1d6c09349d4",
+   "reftest"
+  ],
   "css/css-writing-modes/inline-replaced-vlr-003.xht": [
    "1c33d6eb0262441f88428753cc3642fc6105f71a",
    "reftest"
@@ -359874,6 +360488,10 @@
    "99c61207a488f7da2af9cf9b81b3f3414e536b88",
    "support"
   ],
+  "css/css-writing-modes/reference/inline-box-border-vlr-001.html": [
+   "5b57e460caecc93fea4dc39981ba563b283ce4b9",
+   "support"
+  ],
   "css/css-writing-modes/reference/logical-props-001-ref.html": [
    "2154a8d3f773c80e62c28ec7f789b3cbe677e125",
    "support"
@@ -372842,6 +373460,10 @@
    "26b5fa99f17568bbb9fd831f274e6c1f8d8b98f1",
    "testharness"
   ],
+  "domparsing/DOMParser-parseFromString-xml-parsererror.html": [
+   "9ecd0edd1e7d3244940c2d9b0dc3f7b4bcf478a4",
+   "testharness"
+  ],
   "domparsing/DOMParser-parseFromString-xml.html": [
    "c639c239dd432cfe029dc0414601ac921cca8892",
    "testharness"
@@ -379263,7 +379885,7 @@
    "testharness"
   ],
   "generic-sensor/META.yml": [
-   "056de5c1cd6a69301e742e817a3706254ec81d89",
+   "1cfe809776ba04c66560bc9ef6cce0aa476b7082",
    "support"
   ],
   "generic-sensor/OWNERS": [
@@ -379571,7 +380193,7 @@
    "manual"
   ],
   "gyroscope/META.yml": [
-   "3c10460607dfc778103a9432a4d271ba416b8407",
+   "67f22d5374b0385db98fc885918d3b2f23a2f66b",
    "support"
   ],
   "gyroscope/OWNERS": [
@@ -382043,7 +382665,7 @@
    "support"
   ],
   "html/browsers/the-window-object/window-properties.https.html": [
-   "603f98326c2f779fd3e623c7d3edc5390cc6a225",
+   "3a5d49460f5448ba7c20eadc62fa1ff00746390a",
    "testharness"
   ],
   "html/browsers/the-window-object/window-prototype-chain-expected.txt": [
@@ -399223,7 +399845,7 @@
    "support"
   ],
   "interfaces/SVG.idl": [
-   "4c1c4855f27af4a330565703277f7081c2860c86",
+   "9588ad0d608d48b0279a71fda7b2233be8db0bbf",
    "support"
   ],
   "interfaces/WebCryptoAPI.idl": [
@@ -399355,7 +399977,7 @@
    "support"
   ],
   "interfaces/cssom-view.idl": [
-   "2b5b381dfa4af736d96a3c2e0bb0db372846f3dd",
+   "9567b134cf9b4b183c75c63666eb48e2dd20b5ca",
    "support"
   ],
   "interfaces/cssom.idl": [
@@ -400067,7 +400689,7 @@
    "support"
   ],
   "magnetometer/META.yml": [
-   "46d83d3f08fa71d38b52d3fac67a4394f75495f5",
+   "88b900c569340a167ac2a8aa967099bfdfff388b",
    "support"
   ],
   "magnetometer/Magnetometer-disabled-by-feature-policy.https-expected.txt": [
@@ -410951,7 +411573,7 @@
    "testharness"
   ],
   "orientation-sensor/META.yml": [
-   "5f2d45bfb3cdd2c6bdf417ec6000c33494006f22",
+   "99d6166664ca11196582e9bd058d225df833a4e2",
    "support"
   ],
   "orientation-sensor/OWNERS": [
@@ -421131,7 +421753,7 @@
    "support"
   ],
   "resource-timing/resource_TAO_cross_origin_redirect_chain.html": [
-   "af3d31eabd17dcbfbd3900c5d4009ff723987fd1",
+   "522188279c3ab81ec27cd7e83f014ecf747b21a8",
    "testharness"
   ],
   "resource-timing/resource_TAO_match_origin.htm": [
@@ -421251,7 +421873,7 @@
    "testharness"
   ],
   "resource-timing/resource_timing_cross_origin_redirect_chain.html": [
-   "2a7b2f7ce64152f932a3ee7dea9781acac92efe6",
+   "5675f20f1dd78c90c87313ccdbbf4c9a5b7f38dc",
    "testharness"
   ],
   "resource-timing/resource_timing_same_origin_redirect.html": [
@@ -421691,11 +422313,11 @@
    "support"
   ],
   "screen-capture/getdisplaymedia.https-expected.txt": [
-   "0f2d8d8d6f60f0d6f4f8e90fc02cbf52b836687b",
+   "d73ca7830695ce5f3e8e6e668dab757f6c959e38",
    "support"
   ],
   "screen-capture/getdisplaymedia.https.html": [
-   "f5edab5b7adfb70c15efbdea5014c631277484d4",
+   "06ab72d20bf2668dfc91096afb28c88bd100d2a0",
    "testharness"
   ],
   "screen-capture/idlharness.window.js": [
@@ -424558,6 +425180,14 @@
    "91caa1a41ed2f76f23425bc7978b6056e42d3c2f",
    "support"
   ],
+  "service-workers/service-worker/resources/imported-classic-script.js": [
+   "5fc520405135e215290ebfee008f9f71960955a8",
+   "support"
+  ],
+  "service-workers/service-worker/resources/imported-module-script.js": [
+   "56d196df040f9adb999c944329e6f1569ac876fd",
+   "support"
+  ],
   "service-workers/service-worker/resources/indexeddb-worker.js": [
    "9add47683884c04fc22c34337714fd2a356dcac7",
    "support"
@@ -425058,6 +425688,14 @@
    "9bdaee795eb7ee20342f2cfabeb62078ff0adc0e",
    "support"
   ],
+  "service-workers/service-worker/resources/update-missing-import-scripts-imported-worker.py": [
+   "2d95387fc9233ed12fa26b36f06a99f9775ed08b",
+   "support"
+  ],
+  "service-workers/service-worker/resources/update-missing-import-scripts-main-worker.py": [
+   "b1d2f6fcb78271bf533ec8ec4aa415c21c8d15c2",
+   "support"
+  ],
   "service-workers/service-worker/resources/update-nocookie-worker.py": [
    "0f09b7e32c03c3724cbb55e88f19c0b9b4d78db7",
    "support"
@@ -425066,6 +425704,10 @@
    "8aaa5ca934457714ee0e529ad4b2b1740d9758dd",
    "support"
   ],
+  "service-workers/service-worker/resources/update-registration-with-type.py": [
+   "4f6d5ae28200e09cba0e25c2769168bc1622a360",
+   "support"
+  ],
   "service-workers/service-worker/resources/update-worker.py": [
    "bc9b32ad3e68870d9f540524e70cd7947346e5c8",
    "support"
@@ -425254,6 +425896,10 @@
    "ec3d15abec09ca5f5e3db9e2c8ac2e9040ffe7fe",
    "testharness"
   ],
+  "service-workers/service-worker/update-missing-import-scripts.https.html": [
+   "66e8bfac751e835af8e543fc5289697c15ac118d",
+   "testharness"
+  ],
   "service-workers/service-worker/update-not-allowed.https.html": [
    "71fe1730e0d68e4e7e0949cfa408d3c2d4ed9d39",
    "testharness"
@@ -425266,6 +425912,10 @@
    "17608d2ef790e2ea97a43f56b86a28ef0e647604",
    "testharness"
   ],
+  "service-workers/service-worker/update-registration-with-type.https.html": [
+   "00c8a3345bb3d837c7f0004ce7436065b655476c",
+   "testharness"
+  ],
   "service-workers/service-worker/update-result.https.html": [
    "d8ed94f776650c8a40ba82df9ca5e909b460bb79",
    "testharness"
@@ -431155,7 +431805,7 @@
    "testharness"
   ],
   "web-nfc/META.yml": [
-   "ffc54cf33550e3e57a00da6a1e52d72e5f124772",
+   "32c24570db165422a60a18b767c828dab10c5b9c",
    "support"
   ],
   "web-nfc/OWNERS": [
@@ -431546,12 +432196,8 @@
    "f554304a21eedff3af541c68bea6530b502bc22c",
    "testharness"
   ],
-  "webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-multi-channels-expected.wav": [
-   "ab9d5fe5a9dbd736a079f0cfd7966d5e064ed7ef",
-   "support"
-  ],
   "webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-multi-channels.html": [
-   "b7e6b93ac42f6dc8b9435447b2b4f78e70c2b597",
+   "4e0de21e96fa8470f5305d9405bdccf8f937e660",
    "testharness"
   ],
   "webaudio/the-audio-api/the-audiobuffersourcenode-interface/audiobuffersource-one-sample-loop.html": [
@@ -431590,6 +432236,10 @@
    "0db297b42cca3de45cdd212af1373fdc553729a5",
    "testharness"
   ],
+  "webaudio/the-audio-api/the-audiobuffersourcenode-interface/resources/audiobuffersource-multi-channels-expected.wav": [
+   "ab9d5fe5a9dbd736a079f0cfd7966d5e064ed7ef",
+   "support"
+  ],
   "webaudio/the-audio-api/the-audiobuffersourcenode-interface/sample-accurate-scheduling.html": [
    "5fafd024eef9b476f4d97b2ebaa2190a4ca520d5",
    "testharness"
@@ -432694,39 +433344,39 @@
    "5341b374381ffeb44fcd7b8bc92c33cdc9826bd4",
    "support"
   ],
-  "webmessaging/with-options/broken-origin.tentative.html": [
+  "webmessaging/with-options/broken-origin.html": [
    "d6901a15a34a166a9db7a999dc99f4f43c60bcb8",
    "testharness"
   ],
-  "webmessaging/with-options/host-specific-origin.tentative.html": [
+  "webmessaging/with-options/host-specific-origin.html": [
    "5003bcc807c94404c42297a2ceb964eb38d5a1b9",
    "testharness"
   ],
-  "webmessaging/with-options/message-channel-transferable.tentative.html": [
+  "webmessaging/with-options/message-channel-transferable.html": [
    "d42db10695af68ca0d3f8264d7f703352783ff9b",
    "testharness"
   ],
-  "webmessaging/with-options/no-target-origin.tentative.html": [
+  "webmessaging/with-options/no-target-origin.html": [
    "517466cc4c3ee96ba82d2a27b38050bd2e0fbf53",
    "testharness"
   ],
-  "webmessaging/with-options/null-transfer.tentative.html": [
+  "webmessaging/with-options/null-transfer.html": [
    "72bebd1e38e8c5538ebaf24fe608048bed61d18d",
    "testharness"
   ],
-  "webmessaging/with-options/one-arg.tentative.html": [
+  "webmessaging/with-options/one-arg.html": [
    "2595134b54478306adebe687af86bcdf949fd043",
    "testharness"
   ],
-  "webmessaging/with-options/slash-origin.tentative.html": [
+  "webmessaging/with-options/slash-origin.html": [
    "8bfde73774d3974d893272df117643d48f01039e",
    "testharness"
   ],
-  "webmessaging/with-options/undefined-transferable.tentative.html": [
+  "webmessaging/with-options/undefined-transferable.html": [
    "a123b7d9bd843f61f6dcf09e4fcab77d80a27200",
    "testharness"
   ],
-  "webmessaging/with-options/unknown-parameter.tentative.html": [
+  "webmessaging/with-options/unknown-parameter.html": [
    "de050e74f5e2b5c4a102a3b0be1a43c4c2219117",
    "testharness"
   ],
@@ -432854,10 +433504,6 @@
    "eb2b5c52e56f3ed1d3aa20c16e5ec099213efac0",
    "testharness"
   ],
-  "webmessaging/without-ports/008.html": [
-   "30bf607f3577e6b4220893c436a7f8bfd8f60fa6",
-   "testharness"
-  ],
   "webmessaging/without-ports/009.html": [
    "779383da203902aa5c34e1e3085e43467dc9c4a0",
    "testharness"
@@ -433575,7 +434221,7 @@
    "support"
   ],
   "webrtc/RTCRtpTransceiver.https.html": [
-   "c638e64b8ba3983dd9a12a5c5e2d240bef270b23",
+   "860f5de2d2aca4b3cbcc6e201c8dc774f154346f",
    "testharness"
   ],
   "webrtc/RTCSctpTransport-constructor-expected.txt": [
@@ -439411,27 +440057,27 @@
    "testharness"
   ],
   "workers/semantics/interface-objects/001.worker-expected.txt": [
-   "ca574aaab5cbceb73f40ce9d07719fb17eade62c",
+   "842154f827110f28609e0073d9aba63a4b50c97b",
    "support"
   ],
   "workers/semantics/interface-objects/001.worker.js": [
-   "23df420368abcbdd49dadeeb7847c8a4c046febe",
+   "a2b09fd1a16994494d3b0764cb694933efcb0249",
    "testharness"
   ],
-  "workers/semantics/interface-objects/002.worker-expected.txt": [
-   "ec73f22a81eac6a3b38d3bb7c1bd794f3cb07090",
-   "support"
-  ],
   "workers/semantics/interface-objects/002.worker.js": [
-   "2c5f5a5f44aaa8fd41491a45a928c533da96cffd",
+   "27be44396f57837bd2950f0c5e231e6e5f1b288a",
    "testharness"
   ],
+  "workers/semantics/interface-objects/003-expected.txt": [
+   "b2b1f993012a6044c3661ea694f1985f20175e99",
+   "support"
+  ],
   "workers/semantics/interface-objects/003.html": [
-   "5277825dbc1dc24c669e08d04f182680dfb035a0",
+   "1ed257ff880c5cfdd080537bd3290b1b4b8f088b",
    "testharness"
   ],
   "workers/semantics/interface-objects/004.html": [
-   "2e4387ede3c5bf1e2f1fdc76a40a84d81fada85c",
+   "0c3a3d824c93da03aa28ab54781e8bb78f43dabe",
    "testharness"
   ],
   "workers/semantics/multiple-workers/001.html": [
diff --git a/third_party/WebKit/LayoutTests/external/wpt/2dcontext/imagebitmap/createImageBitmap-invalid-args-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/2dcontext/imagebitmap/createImageBitmap-invalid-args-expected.txt
index 149fbe0..9824e58e 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/2dcontext/imagebitmap/createImageBitmap-invalid-args-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/2dcontext/imagebitmap/createImageBitmap-invalid-args-expected.txt
@@ -13,13 +13,13 @@
 PASS createImageBitmap with a bitmap HTMLImageElement source and oversized (unallocatable) crop region
 PASS createImageBitmap with a vector HTMLImageElement source and sw set to 0
 PASS createImageBitmap with a vector HTMLImageElement source and sh set to 0
-FAIL createImageBitmap with a vector HTMLImageElement source and oversized (unallocatable) crop region assert_throws: InvalidStateError function "function() { throw e }" threw null, not an object
+FAIL createImageBitmap with a vector HTMLImageElement source and oversized (unallocatable) crop region assert_throws: function "() => { throw e }" threw null, not an object
 PASS createImageBitmap with a bitmap SVGImageElement source and sw set to 0
 PASS createImageBitmap with a bitmap SVGImageElement source and sh set to 0
 PASS createImageBitmap with a bitmap SVGImageElement source and oversized (unallocatable) crop region
 PASS createImageBitmap with a vector SVGImageElement source and sw set to 0
 PASS createImageBitmap with a vector SVGImageElement source and sh set to 0
-FAIL createImageBitmap with a vector SVGImageElement source and oversized (unallocatable) crop region assert_throws: InvalidStateError function "function() { throw e }" threw null, not an object
+FAIL createImageBitmap with a vector SVGImageElement source and oversized (unallocatable) crop region assert_throws: function "() => { throw e }" threw null, not an object
 PASS createImageBitmap with an OffscreenCanvas source and sw set to 0
 PASS createImageBitmap with an OffscreenCanvas source and sh set to 0
 PASS createImageBitmap with an OffscreenCanvas source and oversized (unallocatable) crop region
diff --git a/third_party/WebKit/LayoutTests/external/wpt/2dcontext/imagebitmap/createImageBitmap-invalid-args.html b/third_party/WebKit/LayoutTests/external/wpt/2dcontext/imagebitmap/createImageBitmap-invalid-args.html
index 39707e8..004b3ca6 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/2dcontext/imagebitmap/createImageBitmap-invalid-args.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/2dcontext/imagebitmap/createImageBitmap-invalid-args.html
@@ -80,7 +80,7 @@
             // cause InvalidStateError.
             //
             // Note: https://bugs.chromium.org/p/chromium/issues/detail?id=799025
-            assert_throws(e, function() { throw e }, new DOMException('', 'InvalidStateError'));
+            assert_throws("InvalidStateError", () => { throw e });
           });
       }
   },
diff --git a/third_party/WebKit/LayoutTests/external/wpt/accelerometer/META.yml b/third_party/WebKit/LayoutTests/external/wpt/accelerometer/META.yml
index cab7007f..6554be8 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/accelerometer/META.yml
+++ b/third_party/WebKit/LayoutTests/external/wpt/accelerometer/META.yml
@@ -4,5 +4,4 @@
   - dontcallmedom
   - riju
   - Honry
-  - alexshalamov
   - rakuco
diff --git a/third_party/WebKit/LayoutTests/external/wpt/ambient-light/META.yml b/third_party/WebKit/LayoutTests/external/wpt/ambient-light/META.yml
index d35c2c53..04fce804 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/ambient-light/META.yml
+++ b/third_party/WebKit/LayoutTests/external/wpt/ambient-light/META.yml
@@ -3,6 +3,5 @@
   - zqzhang
   - dontcallmedom
   - riju
-  - alexshalamov
   - rakuco
   - Honry
diff --git a/third_party/WebKit/LayoutTests/external/wpt/audio-output/setSinkId-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/audio-output/setSinkId-expected.txt
index cdf1a9f..81cdb58c 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/audio-output/setSinkId-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/audio-output/setSinkId-expected.txt
@@ -1,6 +1,6 @@
 This is a testharness.js-based test.
 PASS setSinkId on default audio output should always work
 PASS setSinkId fails with NotFoundError on made up deviceid
-FAIL List device, setSinkId should on the default, the rest of the devices will get a NotAlowedError assert_equals: Non-default devices are failing with NotAllowed error expected "NotAllowedError" but got "NotFoundError"
+FAIL List device, setSinkId should be allowed on the default, the rest of the devices will get a NotAllowedError assert_equals: Non-default devices are failing with NotAllowed error expected "NotAllowedError" but got "NotFoundError"
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/audio-output/setSinkId.html b/third_party/WebKit/LayoutTests/external/wpt/audio-output/setSinkId.html
index 3fd0d5d..f7cf2c9 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/audio-output/setSinkId.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/audio-output/setSinkId.html
@@ -39,6 +39,6 @@
       assert_equals(e.name, "NotAllowedError", "Non-default devices are failing with NotAllowed error");
     }
   }
-}, "List device, setSinkId should on the default, the rest of the devices will get a NotAlowedError");
+}, "List device, setSinkId should be allowed on the default, the rest of the devices will get a NotAllowedError");
 
 </script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/audio-output/setSinkId.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/audio-output/setSinkId.https-expected.txt
index cdf1a9f..81cdb58c 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/audio-output/setSinkId.https-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/audio-output/setSinkId.https-expected.txt
@@ -1,6 +1,6 @@
 This is a testharness.js-based test.
 PASS setSinkId on default audio output should always work
 PASS setSinkId fails with NotFoundError on made up deviceid
-FAIL List device, setSinkId should on the default, the rest of the devices will get a NotAlowedError assert_equals: Non-default devices are failing with NotAllowed error expected "NotAllowedError" but got "NotFoundError"
+FAIL List device, setSinkId should be allowed on the default, the rest of the devices will get a NotAllowedError assert_equals: Non-default devices are failing with NotAllowed error expected "NotAllowedError" but got "NotFoundError"
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/audio-output/setSinkId.https.html b/third_party/WebKit/LayoutTests/external/wpt/audio-output/setSinkId.https.html
index b4cf7df..fa4f48e2 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/audio-output/setSinkId.https.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/audio-output/setSinkId.https.html
@@ -41,6 +41,6 @@
       assert_equals(e.name, "NotAllowedError", "Non-default devices are failing with NotAllowed error");
     }
   }
-}, "List device, setSinkId should on the default, the rest of the devices will get a NotAlowedError");
+}, "List device, setSinkId should be allowed on the default, the rest of the devices will get a NotAllowedError");
 
 </script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/beacon/beacon-error.window.js b/third_party/WebKit/LayoutTests/external/wpt/beacon/beacon-error.sub.window.js
similarity index 95%
rename from third_party/WebKit/LayoutTests/external/wpt/beacon/beacon-error.window.js
rename to third_party/WebKit/LayoutTests/external/wpt/beacon/beacon-error.sub.window.js
index b53353ab..f2c5e95a 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/beacon/beacon-error.window.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/beacon/beacon-error.sub.window.js
@@ -7,7 +7,7 @@
     // Payload that should cause sendBeacon to return false because it exceeds the maximum payload size.
     var exceedPayload = Array(maxPayloadSize + 1).fill('z').join("");
 
-    var success = navigator.sendBeacon("http://doesnotmatter", exceedPayload);
+    var success = navigator.sendBeacon("http://{{hosts[][nonexistent]}}", exceedPayload);
     assert_false(success, "calling 'navigator.sendBeacon()' with payload size exceeding the maximum size must fail");
 }, "Verify calling 'navigator.sendBeacon()' with a large payload returns 'false'.");
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/CSS2/abspos/abspos-in-block-in-inline-in-relpos-inline.html b/third_party/WebKit/LayoutTests/external/wpt/css/CSS2/abspos/abspos-in-block-in-inline-in-relpos-inline.html
new file mode 100644
index 0000000..4b1baff
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/CSS2/abspos/abspos-in-block-in-inline-in-relpos-inline.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<link rel="author" title="Morten Stenshorne" href="mstensho@chromium.org">
+<link rel="help" href="https://www.w3.org/TR/CSS22/visudet.html#containing-block-details">
+<link rel="help" href="https://www.w3.org/TR/CSS22/visuren.html#anonymous-block-level">
+<style>
+  .rel { position:relative; }
+  .inline-block { display:inline-block; width:100px; height:1px; }
+  .inline-block.large { width:200px; }
+  #target { position:absolute; width:100%; height:100px; background:green; }
+</style>
+<p>There should be a green square below.</p>
+<div style="height:200px;">
+  <span class="rel" id="notContainingBlockOfTarget">
+    <div class="large inline-block"></div>
+    <br>
+    <span id="containingBlockOfTarget" class="rel">
+      <div class="inline-block"></div>
+      <span>
+        <div>
+          <div id="target"></div>
+        </div>
+      </span>
+      <div class="inline-block"></div></span><br>
+    <div class="large inline-block"></div>
+  </span>
+</div>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+  test(()=> {
+      assert_equals(document.getElementById("target").offsetWidth, 100);
+  }, "Make sure that we're sized by the right ancestor");
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/build-css-testsuites.sh b/third_party/WebKit/LayoutTests/external/wpt/css/build-css-testsuites.sh
index 4aad0bb..5cb2617 100755
--- a/third_party/WebKit/LayoutTests/external/wpt/css/build-css-testsuites.sh
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/build-css-testsuites.sh
@@ -1,8 +1,8 @@
 #!/usr/bin/env sh
 set -ex
 
-SCRIPT_DIR=$(dirname $(readlink -f "$0"))
-WPT_ROOT=$(readlink -f $SCRIPT_DIR/..)
+SCRIPT_DIR=$(cd $(dirname "$0") && pwd -P)
+WPT_ROOT=$SCRIPT_DIR/..
 cd $WPT_ROOT
 
 main() {
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-text/inheritance-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css/css-text/inheritance-expected.txt
new file mode 100644
index 0000000..42a075a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-text/inheritance-expected.txt
@@ -0,0 +1,33 @@
+This is a testharness.js-based test.
+PASS Property hanging-punctuation has initial value none
+PASS Property hanging-punctuation inherits
+PASS Property hyphens has initial value manual
+PASS Property hyphens inherits
+PASS Property letter-spacing has initial value normal
+PASS Property letter-spacing inherits
+PASS Property line-break has initial value auto
+PASS Property line-break inherits
+PASS Property overflow-wrap has initial value normal
+PASS Property overflow-wrap inherits
+PASS Property tab-size has initial value 8
+PASS Property tab-size inherits
+PASS Property text-align-all has initial value start
+PASS Property text-align-all inherits
+PASS Property text-align-last has initial value auto
+PASS Property text-align-last inherits
+PASS Property text-indent has initial value 0px
+PASS Property text-indent inherits
+PASS Property text-justify has initial value auto
+FAIL Property text-justify inherits assert_equals: expected "inter-character" but got "auto"
+PASS Property text-transform has initial value none
+PASS Property text-transform inherits
+PASS Property white-space has initial value normal
+PASS Property white-space inherits
+PASS Property word-break has initial value normal
+PASS Property word-break inherits
+PASS Property word-spacing has initial value 0px
+PASS Property word-spacing inherits
+PASS Property word-wrap has initial value normal
+PASS Property word-wrap inherits
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-text/inheritance.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-text/inheritance.html
new file mode 100644
index 0000000..ef32706
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-text/inheritance.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Inheritance of CSS Text properties</title>
+<link rel="help" href="https://drafts.csswg.org/css-text/#property-index">
+<meta name="assert" content="Properties inherit according to the spec.">
+<meta name="assert" content="Properties have initial values according to the spec.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/inheritance-testcommon.js"></script>
+</head>
+<body>
+<div id="container">
+  <div id="target"></div>
+</div>
+<script>
+assert_inherited('hanging-punctuation', 'none', 'first last');
+assert_inherited('hyphens', 'manual', 'none');
+assert_inherited('letter-spacing', 'normal', '10px');
+assert_inherited('line-break', 'auto', 'strict');
+assert_inherited('overflow-wrap', 'normal', 'break-word');
+assert_inherited('tab-size', '8', '10px');
+assert_inherited('text-align-all', 'start', 'right');
+assert_inherited('text-align-last', 'auto', 'right');
+assert_inherited('text-indent', '0px', '10px');
+assert_inherited('text-justify', 'auto', 'inter-character');
+assert_inherited('text-transform', 'none', 'uppercase');
+assert_inherited('white-space', 'normal', 'pre-wrap');
+assert_inherited('word-break', 'normal', 'break-all');
+assert_inherited('word-spacing', '0px', '10px');
+assert_inherited('word-wrap', 'normal', 'break-word');
+</script>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-ui/inheritance-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css/css-ui/inheritance-expected.txt
new file mode 100644
index 0000000..848321d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-ui/inheritance-expected.txt
@@ -0,0 +1,31 @@
+This is a testharness.js-based test.
+PASS Property appearance has initial value auto
+PASS Property appearance does not inherit
+FAIL Property caret-color has initial value auto assert_equals: expected "auto" but got "rgb(0, 0, 0)"
+PASS Property caret-color inherits
+PASS Property caret-shape has initial value auto
+PASS Property caret-shape inherits
+PASS Property cursor has initial value auto
+PASS Property cursor inherits
+PASS Property nav-down has initial value auto
+PASS Property nav-down does not inherit
+PASS Property nav-left has initial value auto
+PASS Property nav-left does not inherit
+PASS Property nav-right has initial value auto
+PASS Property nav-right does not inherit
+PASS Property nav-up has initial value auto
+PASS Property nav-up does not inherit
+FAIL Property outline-color has initial value invert assert_equals: expected "invert" but got "rgb(0, 0, 0)"
+PASS Property outline-color does not inherit
+PASS Property outline-offset has initial value 0px
+PASS Property outline-offset does not inherit
+PASS Property outline-style has initial value none
+PASS Property outline-style does not inherit
+PASS Property outline-width has initial value 3px
+PASS Property outline-width does not inherit
+PASS Property resize has initial value none
+PASS Property resize does not inherit
+PASS Property user-select has initial value auto
+FAIL Property user-select does not inherit assert_not_equals: got disallowed value "none"
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-ui/inheritance.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-ui/inheritance.html
new file mode 100644
index 0000000..912e9f3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-ui/inheritance.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Inheritance of CSS Basic User Interface properties</title>
+<link rel="help" href="https://drafts.csswg.org/css-ui/#property-index">
+<meta name="assert" content="Properties inherit or not according to the spec.">
+<meta name="assert" content="Properties have initial values according to the spec.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/inheritance-testcommon.js"></script>
+</head>
+<body>
+<div id="reference"></div>
+<div id="container">
+  <div id="target"></div>
+</div>
+<style>
+#reference {
+  border-style: dotted; /* Avoid border-top-width computed style 0 */
+  border-top-width: medium;
+}
+
+#container, #target {
+  outline-style: dotted; /* Avoid outline-width computed style 0 */
+}
+</style>
+<script>
+const mediumWidth = getComputedStyle(reference).borderTopWidth; // e.g. 3px
+
+assert_not_inherited('appearance', 'auto', 'none');
+assert_inherited('caret-color', 'auto', 'rgba(42, 53, 64, 0.75)');
+assert_inherited('caret-shape', 'auto', 'bar');
+assert_inherited('cursor', 'auto', 'pointer');
+assert_not_inherited('nav-down', 'auto', '#foo');
+assert_not_inherited('nav-left', 'auto', '#foo');
+assert_not_inherited('nav-right', 'auto', '#foo');
+assert_not_inherited('nav-up', 'auto', '#foo');
+assert_not_inherited('outline-color', 'invert', 'rgba(42, 53, 64, 0.75)');
+assert_not_inherited('outline-offset', '0px', '10px');
+assert_not_inherited('outline-style', 'none', 'auto');
+assert_not_inherited('outline-width', mediumWidth, '10px');
+assert_not_inherited('resize', 'none', 'vertical');
+assert_not_inherited('user-select', 'auto', 'none');
+</script>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/cssom-view/interfaces-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/css/cssom-view/interfaces-expected.txt
index eb20004..97749137 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/cssom-view/interfaces-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/cssom-view/interfaces-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 322 tests; 243 PASS, 79 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 326 tests; 247 PASS, 79 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS idl_test setup
 PASS Partial interface Window: original interface defined
 PASS Partial interface Document: original interface defined
@@ -191,7 +191,9 @@
 FAIL Window interface: operation scrollBy(ScrollToOptions) assert_equals: property has wrong .length expected 0 but got 2
 FAIL Window interface: operation scrollBy(unrestricted double, unrestricted double) assert_equals: property has wrong .length expected 0 but got 2
 PASS Window interface: attribute screenX
+PASS Window interface: attribute screenLeft
 PASS Window interface: attribute screenY
+PASS Window interface: attribute screenTop
 PASS Window interface: attribute outerWidth
 PASS Window interface: attribute outerHeight
 PASS Window interface: attribute devicePixelRatio
@@ -225,7 +227,9 @@
 PASS Window interface: window must inherit property "scrollBy(unrestricted double, unrestricted double)" with the proper type
 PASS Window interface: calling scrollBy(unrestricted double, unrestricted double) on window with too few arguments must throw TypeError
 PASS Window interface: window must inherit property "screenX" with the proper type
+PASS Window interface: window must inherit property "screenLeft" with the proper type
 PASS Window interface: window must inherit property "screenY" with the proper type
+PASS Window interface: window must inherit property "screenTop" with the proper type
 PASS Window interface: window must inherit property "outerWidth" with the proper type
 PASS Window interface: window must inherit property "outerHeight" with the proper type
 PASS Window interface: window must inherit property "devicePixelRatio" with the proper type
diff --git a/third_party/WebKit/LayoutTests/fast/css/invalidation/where.html b/third_party/WebKit/LayoutTests/external/wpt/css/selectors/invalidation/where.html
similarity index 92%
rename from third_party/WebKit/LayoutTests/fast/css/invalidation/where.html
rename to third_party/WebKit/LayoutTests/external/wpt/css/selectors/invalidation/where.html
index f25cfcd..1c6432f 100644
--- a/third_party/WebKit/LayoutTests/fast/css/invalidation/where.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/selectors/invalidation/where.html
@@ -1,14 +1,16 @@
 <!DOCTYPE html>
 <html>
   <head>
-    <!-- Move to external/wpt/css/selectors/invalidation once the selector name is resolved. -->
     <title>CSS Selectors Invalidation: :where()</title>
     <link rel="author" title="Victoria Su" href="mailto:victoriaytsu@google.com">
     <link rel="help" href="https://drafts.csswg.org/selectors-4/#zero-matches">
     <meta name="assert" content="This tests that the :where() selector is effective">
-    <script src="../../../resources/testharness.js"></script>
-    <script src="../../../resources/testharnessreport.js"></script>
+    <script src="/resources/testharness.js"></script>
+    <script src="/resources/testharnessreport.js"></script>
     <style>
+      * {
+        color: black;
+      }
       .b {
         color: yellow;
       }
diff --git a/third_party/WebKit/LayoutTests/external/wpt/generic-sensor/META.yml b/third_party/WebKit/LayoutTests/external/wpt/generic-sensor/META.yml
index 056de5c..1cfe809 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/generic-sensor/META.yml
+++ b/third_party/WebKit/LayoutTests/external/wpt/generic-sensor/META.yml
@@ -3,6 +3,5 @@
   - zqzhang
   - dontcallmedom
   - riju
-  - alexshalamov
   - rakuco
   - Honry
diff --git a/third_party/WebKit/LayoutTests/external/wpt/gyroscope/META.yml b/third_party/WebKit/LayoutTests/external/wpt/gyroscope/META.yml
index 3c10460..67f22d53 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/gyroscope/META.yml
+++ b/third_party/WebKit/LayoutTests/external/wpt/gyroscope/META.yml
@@ -4,5 +4,4 @@
   - dontcallmedom
   - riju
   - Honry
-  - alexshalamov
   - rakuco
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/browsers/the-window-object/window-properties.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/browsers/the-window-object/window-properties.https-expected.txt
index 706f4d5..bc228dee1 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/browsers/the-window-object/window-properties.https-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/browsers/the-window-object/window-properties.https-expected.txt
@@ -54,9 +54,15 @@
 PASS Window method: clearTimeout
 PASS Window method: setInterval
 PASS Window method: clearInterval
+PASS Window method: queueMicrotask
+PASS Window method: createImageBitmap
 PASS Window method: getSelection
 PASS Window method: getComputedStyle
 PASS Window method: matchMedia
+PASS Window method: moveBy
+PASS Window method: moveTo
+PASS Window method: resizeBy
+PASS Window method: resizeTo
 PASS Window method: scroll
 PASS Window method: scrollTo
 PASS Window method: scrollBy
@@ -151,6 +157,7 @@
 FAIL Window replaceable attribute: parent assert_equals: expected "function" but got "undefined"
 PASS Window replaceable attribute: external
 FAIL Window replaceable attribute: length assert_equals: expected "function" but got "undefined"
+PASS Window replaceable attribute: origin
 PASS Window replaceable attribute: screen
 PASS Window replaceable attribute: scrollX
 PASS Window replaceable attribute: scrollY
@@ -158,6 +165,8 @@
 PASS Window replaceable attribute: pageYOffset
 PASS Window replaceable attribute: innerWidth
 PASS Window replaceable attribute: innerHeight
+PASS Window replaceable attribute: screenLeft
+PASS Window replaceable attribute: screenTop
 PASS Window replaceable attribute: screenX
 PASS Window replaceable attribute: screenY
 PASS Window replaceable attribute: outerWidth
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/browsers/the-window-object/window-properties.https.html b/third_party/WebKit/LayoutTests/external/wpt/html/browsers/the-window-object/window-properties.https.html
index 603f9832..3a5d494 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/browsers/the-window-object/window-properties.https.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/browsers/the-window-object/window-properties.https.html
@@ -54,6 +54,7 @@
   "parent",
   "external",
   "length",
+  "origin",
 
   // CSSOM-View
   "screen",
@@ -63,6 +64,8 @@
   "pageYOffset",
   "innerWidth",
   "innerHeight",
+  "screenLeft",
+  "screenTop",
   "screenX",
   "screenY",
   "outerWidth",
@@ -92,6 +95,12 @@
   "setInterval",
   "clearInterval",
 
+  // Microtask queuing
+  "queueMicrotask",
+
+  // ImageBitmap
+  "createImageBitmap",
+
   // HTML Editing APIs
   "getSelection",
 
@@ -100,6 +109,10 @@
 
   // CSSOM-View
   "matchMedia",
+  "moveBy",
+  "moveTo",
+  "resizeBy",
+  "resizeTo",
   "scroll",
   "scrollTo",
   "scrollBy"
diff --git a/third_party/WebKit/LayoutTests/external/wpt/interfaces/SVG.idl b/third_party/WebKit/LayoutTests/external/wpt/interfaces/SVG.idl
index 4c1c4855..9588ad0d 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/interfaces/SVG.idl
+++ b/third_party/WebKit/LayoutTests/external/wpt/interfaces/SVG.idl
@@ -676,7 +676,7 @@
   attribute DOMString download;
   attribute USVString ping;
   attribute DOMString rel;
-  [SameObject, PutsForward=value] readonly attribute DOMTokenList relList;
+  [SameObject, PutForwards=value] readonly attribute DOMTokenList relList;
   attribute DOMString hreflang;
   attribute DOMString type;
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/interfaces/cssom-view.idl b/third_party/WebKit/LayoutTests/external/wpt/interfaces/cssom-view.idl
index 2b5b381d..9567b13 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/interfaces/cssom-view.idl
+++ b/third_party/WebKit/LayoutTests/external/wpt/interfaces/cssom-view.idl
@@ -41,7 +41,9 @@
 
     // client
     [Replaceable] readonly attribute long screenX;
+    [Replaceable] readonly attribute long screenLeft;
     [Replaceable] readonly attribute long screenY;
+    [Replaceable] readonly attribute long screenTop;
     [Replaceable] readonly attribute long outerWidth;
     [Replaceable] readonly attribute long outerHeight;
     [Replaceable] readonly attribute double devicePixelRatio;
diff --git a/third_party/WebKit/LayoutTests/external/wpt/magnetometer/META.yml b/third_party/WebKit/LayoutTests/external/wpt/magnetometer/META.yml
index 46d83d3f..88b900c 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/magnetometer/META.yml
+++ b/third_party/WebKit/LayoutTests/external/wpt/magnetometer/META.yml
@@ -4,5 +4,4 @@
   - dontcallmedom
   - riju
   - Honry
-  - alexshalamov
   - rakuco
diff --git a/third_party/WebKit/LayoutTests/external/wpt/orientation-sensor/META.yml b/third_party/WebKit/LayoutTests/external/wpt/orientation-sensor/META.yml
index 5f2d45b..99d61666 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/orientation-sensor/META.yml
+++ b/third_party/WebKit/LayoutTests/external/wpt/orientation-sensor/META.yml
@@ -4,5 +4,4 @@
   - dontcallmedom
   - riju
   - Honry
-  - alexshalamov
   - rakuco
diff --git a/third_party/WebKit/LayoutTests/external/wpt/performance-timeline/webtiming-resolution.any.js b/third_party/WebKit/LayoutTests/external/wpt/performance-timeline/webtiming-resolution.any.js
index 4031388a3..46e0489 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/performance-timeline/webtiming-resolution.any.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/performance-timeline/webtiming-resolution.any.js
@@ -5,8 +5,9 @@
         while (t0 == t1) {
             t1 = highResTimeFunc();
         }
-        assert_greater_than_equal(t1 - t0, 0.02, 'The second ' + funcString + ' should be much greater than the first');
-    }, 'Verifies the resolution of ' + funcString + ' is at least 20 microseconds.');
+        const epsilon = 1e-5;
+        assert_greater_than_equal(t1 - t0, 0.005 - epsilon, 'The second ' + funcString + ' should be much greater than the first');
+    }, 'Verifies the resolution of ' + funcString + ' is at least 5 microseconds.');
 }
 
 function timeByPerformanceNow() {
@@ -21,4 +22,4 @@
 }
 
 testTimeResolution(timeByPerformanceNow, 'performance.now()');
-testTimeResolution(timeByUserTiming, 'entry.startTime');
+testTimeResolution(timeByUserTiming, 'entry.startTime');
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/resource-timing/resource_TAO_cross_origin_redirect_chain.html b/third_party/WebKit/LayoutTests/external/wpt/resource-timing/resource_TAO_cross_origin_redirect_chain.html
index af3d31e..52218827 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/resource-timing/resource_TAO_cross_origin_redirect_chain.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/resource-timing/resource_TAO_cross_origin_redirect_chain.html
@@ -7,14 +7,13 @@
 <link rel="help" href="http://www.w3.org/TR/resource-timing/#performanceresourcetiming"/>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
+<script src=/common/get-host-info.sub.js></script>
 <script src="resources/webperftestharness.js"></script>
 <script src="resources/webperftestharnessextension.js"></script>
 
 <script>
     setup({explicit_done: true});
     test_namespace('getEntriesByName');
-    const pageOrigin = document.location.host;
-    const crossOrigin = 'www.' + pageOrigin;
 
     function onload_test()
     {
@@ -35,9 +34,9 @@
 <body>
 <iframe id="frameContext" src="" style="width: 250px; height: 250px;"></iframe>
 <script>
-    let destUrl = 'http://' + crossOrigin + '/resource-timing/resources/multi_redirect.py?';
-    destUrl += 'page_origin=' + 'http://' + pageOrigin;
-    destUrl += '&cross_origin=' + 'http://' + crossOrigin;
+    let destUrl = get_host_info().HTTP_REMOTE_ORIGIN + '/resource-timing/resources/multi_redirect.py?';
+    destUrl += 'page_origin=' + 'http://' + document.location.host;
+    destUrl += '&cross_origin=' + get_host_info().HTTP_REMOTE_ORIGIN;
     destUrl += '&timing_allow=1';
     const frameContext = document.getElementById('frameContext');
     frameContext.onload = onload_test;
diff --git a/third_party/WebKit/LayoutTests/external/wpt/resource-timing/resource_timing_cross_origin_redirect_chain.html b/third_party/WebKit/LayoutTests/external/wpt/resource-timing/resource_timing_cross_origin_redirect_chain.html
index 2a7b2f7..5675f20 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/resource-timing/resource_timing_cross_origin_redirect_chain.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/resource-timing/resource_timing_cross_origin_redirect_chain.html
@@ -7,14 +7,13 @@
 <link rel="help" href="http://www.w3.org/TR/resource-timing/#performanceresourcetiming"/>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
+<script src=/common/get-host-info.sub.js></script>
 <script src="resources/webperftestharness.js"></script>
 <script src="resources/webperftestharnessextension.js"></script>
 
 <script>
     setup({explicit_done: true});
     test_namespace('getEntriesByName');
-    const pageOrigin = document.location.host;
-    const crossOrigin = 'www.' + pageOrigin;
 
     function onload_test()
     {
@@ -35,9 +34,9 @@
 <body>
 <iframe id="frameContext" src="" style="width: 250px; height: 250px;"></iframe>
 <script>
-    let destUrl = 'http://' + crossOrigin + '/resource-timing/resources/multi_redirect.py?';
-    destUrl += 'page_origin=' + 'http://' + pageOrigin;
-    destUrl += '&cross_origin=' + 'http://' + crossOrigin;
+    let destUrl = get_host_info().HTTP_REMOTE_ORIGIN + '/resource-timing/resources/multi_redirect.py?';
+    destUrl += 'page_origin=' + 'http://' + document.location.host;
+    destUrl += '&cross_origin=' + get_host_info().HTTP_REMOTE_ORIGIN;
     const frameContext = document.getElementById('frameContext');
     frameContext.onload = onload_test;
     frameContext.src = destUrl;
diff --git a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/update-missing-import-scripts-imported-worker.py b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/update-missing-import-scripts-imported-worker.py
new file mode 100644
index 0000000..2d95387f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/update-missing-import-scripts-imported-worker.py
@@ -0,0 +1,9 @@
+def main(request, response):
+    key = request.GET['key']
+    already_requested = request.server.stash.take(key)
+
+    if already_requested is None:
+        request.server.stash.put(key, True)
+        return [('Content-Type', 'application/javascript')], '// initial script'
+
+    response.status = (404, 'Not found: should not have been able to import this script twice!')
diff --git a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/update-missing-import-scripts-main-worker.py b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/update-missing-import-scripts-main-worker.py
new file mode 100644
index 0000000..b1d2f6fc
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/resources/update-missing-import-scripts-main-worker.py
@@ -0,0 +1,13 @@
+def main(request, response):
+    key = request.GET['key']
+    already_requested = request.server.stash.take(key)
+
+    header = [('Content-Type', 'application/javascript')]
+    initial_script = 'importScripts("./update-missing-import-scripts-imported-worker.py?key={0}")'.format(key)
+    updated_script = '// removed importScripts()'
+
+    if already_requested is None:
+        request.server.stash.put(key, True)
+        return header, initial_script
+
+    return header, updated_script
diff --git a/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/update-missing-import-scripts.https.html b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/update-missing-import-scripts.https.html
new file mode 100644
index 0000000..66e8bfac
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/service-workers/service-worker/update-missing-import-scripts.https.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<title>Service Worker: update with missing importScripts</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/test-helpers.sub.js"></script>
+<script src="/common/utils.js"></script>
+<body>
+<script>
+/**
+ * Test ServiceWorkerRegistration.update() when importScripts in a service worker
+ * script is no longer available (but was initially).
+ */
+let registration = null;
+
+promise_test(async (test) => {
+  const script = `resources/update-missing-import-scripts-main-worker.py?key=${token()}`;
+  const scope = 'resources/update-missing-import-scripts';
+
+  registration = await service_worker_unregister_and_register(test, script, scope);
+
+  add_completion_callback(() => { registration.unregister(); });
+
+  await wait_for_state(test, registration.installing, 'activated');
+}, 'Initialize global state');
+
+promise_test(test => {
+  return new Promise(resolve => {
+    registration.addEventListener('updatefound', resolve);
+    registration.update();
+  });
+}, 'Update service worker with new script that\'s missing importScripts()');
+</script>
+</body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/render/reftests/filter-effects-on-pattern-ref.html b/third_party/WebKit/LayoutTests/external/wpt/svg/render/reftests/filter-effects-on-pattern-ref.html
new file mode 100644
index 0000000..a61f17bf
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/svg/render/reftests/filter-effects-on-pattern-ref.html
@@ -0,0 +1,3 @@
+<!DOCTYPE html>
+<div>Expected: a solid green square.</div>
+<svg style="width: 200px; height: 200px; background: green;"></svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/render/reftests/filter-effects-on-pattern.html b/third_party/WebKit/LayoutTests/external/wpt/svg/render/reftests/filter-effects-on-pattern.html
new file mode 100644
index 0000000..1894bf8
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/svg/render/reftests/filter-effects-on-pattern.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<title>'mix-blend-mode' for &lt;svg:pattern&gt;</title>
+<link rel="help" href="https://www.w3.org/TR/SVG2/render.html#PaintersModel">
+<link rel="help" href="https://github.com/w3c/fxtf-drafts/issues/309">
+<link rel="match"  href="filter-effects-on-pattern-ref.html">
+<div>Expected: a solid green square.</div>
+<svg style="width: 200px; height: 200px; background: green;">
+  <defs>
+    <pattern id="pattern" x="0" y="0" width=".25" height=".25" style="mix-blend-mode: difference;">
+      <rect x="0" y="0" width="25" height="25" fill="green"/>
+    </pattern>
+  </defs>
+  <rect fill="url(#pattern)" width="200" height="200"/>
+</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/web-nfc/META.yml b/third_party/WebKit/LayoutTests/external/wpt/web-nfc/META.yml
index ffc54cf..32c2457 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/web-nfc/META.yml
+++ b/third_party/WebKit/LayoutTests/external/wpt/web-nfc/META.yml
@@ -2,4 +2,3 @@
 suggested_reviewers:
   - Honry
   - kenchris
-  - alexshalamov
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCRtpTransceiver.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCRtpTransceiver.https-expected.txt
index 429c3ca..09b20d2 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCRtpTransceiver.https-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCRtpTransceiver.https-expected.txt
@@ -35,6 +35,7 @@
 FAIL checkStopAfterSetLocalAnswer promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'receiver' of undefined"
 FAIL checkStopAfterClose assert_equals: Stopping a transceiver on a closed PC should throw. throws InvalidStateError expected "InvalidStateError" but got "TypeError"
 FAIL checkLocalRollback assert_equals: expected "[{currentDirection:null,direction:\"sendrecv\",receiver:{track:{kind:\"audio\"}},sender:{track:{}},stopped:false}]" but got "[]"
+FAIL checkRollbackAndSetRemoteOfferWithDifferentType promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'setLocalDescription' on 'RTCPeerConnection': The provided value 'rollback' is not a valid enum value of type RTCSdpType."
 FAIL checkRemoteRollback promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'setRemoteDescription' on 'RTCPeerConnection': The provided value 'rollback' is not a valid enum value of type RTCSdpType."
 FAIL checkMsectionReuse promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'mid' of undefined"
 Harness: the test ran to completion.
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCRtpTransceiver.https.html b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCRtpTransceiver.https.html
index c638e64..860f5de 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCRtpTransceiver.https.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/webrtc/RTCRtpTransceiver.https.html
@@ -1798,6 +1798,85 @@
     hasProps(pc.getTransceivers(), [{ stopped: true }]);
   };
 
+  const checkRollbackAndSetRemoteOfferWithDifferentType = async t => {
+    const pc1 = new RTCPeerConnection();
+    t.add_cleanup(() => pc1.close());
+
+    const audioStream = await navigator.mediaDevices.getUserMedia({audio: true});
+    t.add_cleanup(() => stopTracks(audioStream));
+    const audioTrack = audioStream.getAudioTracks()[0];
+    pc1.addTrack(audioTrack, audioStream);
+
+    const pc2 = new RTCPeerConnection();
+    t.add_cleanup(() => pc2.close());
+
+    const videoStream = await navigator.mediaDevices.getUserMedia({video: true});
+    t.add_cleanup(() => stopTracks(videoStream));
+    const videoTrack = videoStream.getVideoTracks()[0];
+    pc2.addTrack(videoTrack, videoStream);
+
+    await pc1.setLocalDescription(await pc1.createOffer());
+    await pc1.setLocalDescription({type: "rollback"});
+
+    hasProps(pc1.getTransceivers(),
+      [
+        {
+          receiver: {track: {kind: "audio"}},
+          sender: {track: audioTrack},
+          direction: "sendrecv",
+          mid: null,
+          currentDirection: null,
+          stopped: false
+        }
+      ]);
+
+    hasProps(pc2.getTransceivers(),
+      [
+        {
+          receiver: {track: {kind: "video"}},
+          sender: {track: videoTrack},
+          direction: "sendrecv",
+          mid: null,
+          currentDirection: null,
+          stopped: false
+        }
+      ]);
+
+    await offerAnswer(pc2, pc1);
+
+    hasPropsAndUniqueMids(pc1.getTransceivers(),
+      [
+        {
+          receiver: {track: {kind: "audio"}},
+          sender: {track: audioTrack},
+          direction: "sendrecv",
+          mid: null,
+          currentDirection: null,
+          stopped: false
+        },
+        {
+          receiver: {track: {kind: "video"}},
+          sender: {track: null},
+          direction: "recvonly",
+          currentDirection: "recvonly",
+          stopped: false
+        }
+      ]);
+
+    hasPropsAndUniqueMids(pc2.getTransceivers(),
+      [
+        {
+          receiver: {track: {kind: "video"}},
+          sender: {track: videoTrack},
+          direction: "sendrecv",
+          currentDirection: "sendonly",
+          stopped: false
+        }
+      ]);
+
+    await offerAnswer(pc1, pc2);
+  };
+
   const checkRemoteRollback = async t => {
     const pc1 = new RTCPeerConnection();
     t.add_cleanup(() => pc1.close());
@@ -2270,6 +2349,7 @@
   checkStopAfterSetLocalAnswer,
   checkStopAfterClose,
   checkLocalRollback,
+  checkRollbackAndSetRemoteOfferWithDifferentType,
   checkRemoteRollback,
   checkMsectionReuse
 ].forEach(test => promise_test(test, test.name));
diff --git a/third_party/WebKit/LayoutTests/fast/events/touch/compositor-touch-hit-rects-visibility-hidden-expected.txt b/third_party/WebKit/LayoutTests/fast/events/touch/compositor-touch-hit-rects-visibility-hidden-expected.txt
new file mode 100644
index 0000000..158ef6c7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/events/touch/compositor-touch-hit-rects-visibility-hidden-expected.txt
@@ -0,0 +1,25 @@
+: no rects
+
+: no rects
+
+: #document scrolling (13, 220, 42, 42)
+
+: #document scrolling (13, 325, 102, 102)
+
+: no rects
+
+: #document scrolling (8, 532, 100, 100)
+
+: no rects
+
+: #document scrolling (8, 738, 100, 100)
+
+: no rects
+
+: #document scrolling (120, 840, 102, 102)
+
+: no rects
+
+: #document scrolling (118, 944, 100, 100)
+
+
diff --git a/third_party/WebKit/LayoutTests/fast/events/touch/compositor-touch-hit-rects-visibility-hidden.html b/third_party/WebKit/LayoutTests/fast/events/touch/compositor-touch-hit-rects-visibility-hidden.html
new file mode 100644
index 0000000..4911eef
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/events/touch/compositor-touch-hit-rects-visibility-hidden.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<link rel="stylesheet" href="resources/compositor-touch-hit-rects.css">
+<!-- This tests verifies that visibility:hidden objects do not create touch
+action rects, but visibility:visible objects do. -->
+<div id="tests">
+  <div class="testcase" style="width: 100px; height: 100px; background: red; visibility: hidden;"></div>
+  <div style="width: 100px; height: 100px; background: red; visibility: hidden;">
+    <!-- This div should inherit the hidden visibility of the parent and be hidden. -->
+    <div class="testcase" style="width: 30px; height: 30px; background: red;"></div>
+  </div>
+  <div style="width: 100px; height: 100px; background: red; visibility: hidden;">
+    <!-- This div should override the hidden visibility of the parent and be visible. -->
+    <div class="testcase" style="width: 40px; height: 40px; background: green; visibility: visible;"></div>
+  </div>
+  <div class="testcase" style="width: 100px; height: 100px; background: green; visibility: visible;"></div>
+
+  <table class="testcase" style="width: 100px; height: 100px; background: red; visibility: hidden;"></table>
+  <table class="testcase" style="width: 100px; height: 100px; background: green; visibility: visible;"></table>
+
+  <table style="width: 100px; height: 100px;">
+    <tr class="testcase" style="width: 100px; height: 100px; background: red; visibility: hidden;"><td></td></tr>
+  </table>
+  <table style="width: 100px; height: 100px;">
+    <tr class="testcase" style="width: 100px; height: 100px; background: green; visibility: visible;"><td></td></tr>
+  </table>
+
+  <img class="testcase" style="width: 100px; height: 100px; background: red; visibility: hidden;"></img>
+  <img class="testcase" style="width: 100px; height: 100px; background: green; visibility: visible;"></img>
+
+  <svg width="100" height="100">
+    <rect class="testcase" width="100" height="100" fill="red" style="visibility: hidden;"></rect>
+  </svg>
+  <svg width="100" height="100">
+    <rect class="testcase" width="100" height="100" fill="green" style="visibility: visible;"></rect>
+  </svg>
+</div>
+<div id="console"></div>
+<script src="resources/compositor-touch-hit-rects.js"></script>
diff --git a/third_party/WebKit/LayoutTests/fast/scroll-snap/resources/simple-snap.css b/third_party/WebKit/LayoutTests/fast/scroll-snap/resources/simple-snap.css
new file mode 100644
index 0000000..ac71423d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/scroll-snap/resources/simple-snap.css
@@ -0,0 +1,35 @@
+body {
+  margin: 0px;
+}
+#scroller {
+  position: absolute;
+  width: 400px;
+  height: 400px;
+  overflow: scroll;
+  scroll-snap-type: both mandatory;
+  padding: 0px;
+}
+.snap {
+  position: absolute;
+  width: 200px;
+  height: 200px;
+  background-color: blue;
+  scroll-snap-align: start;
+}
+#space {
+  position: absolute;
+  width: 1000px;
+  height: 1000px;
+}
+.left {
+  left: 0px;
+}
+.top {
+  top: 0px;
+}
+.right {
+  left: 400px;
+}
+.bottom {
+  top: 400px;
+}
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/fast/scroll-snap/snaps-after-keyboard-scrolling-rtl.html b/third_party/WebKit/LayoutTests/fast/scroll-snap/snaps-after-keyboard-scrolling-rtl.html
new file mode 100644
index 0000000..7a78820
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/scroll-snap/snaps-after-keyboard-scrolling-rtl.html
@@ -0,0 +1,85 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-scroll-snap-1" />
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../../resources/gesture-util.js"></script>
+<style>
+div {
+  position: absolute;
+}
+#scroller {
+  writing-mode: vertical-rl;
+  width: 400px;
+  height: 400px;
+  overflow: scroll;
+  scroll-snap-type: both mandatory;
+  padding: 0px;
+}
+.snap {
+  width: 200px;
+  height: 200px;
+  background-color: blue;
+  scroll-snap-align: start;
+}
+#space {
+  width: 1000px;
+  height: 1000px;
+}
+.left {
+  left: -400px;
+  top: 0px;
+}
+.right {
+  left: 0px;
+  top: 0px;
+}
+</style>
+
+<div id='scroller'>
+  <div id="space"></div>
+  <div class="snap left" id="left"></div>
+  <div class="snap right" id="right"></div>
+</div>
+
+<script>
+var scroller = document.getElementById("scroller");
+var width = scroller.clientWidth;
+
+function scrollLeft() {
+  return scroller.scrollLeft;
+}
+
+function keyPress(key) {
+  return new Promise((resolve, reject) => {
+    if (window.eventSender) {
+      eventSender.keyDown(key);
+      resolve();
+    }
+    else {
+      reject('This test requires window.eventSender');
+    }
+  })
+}
+
+promise_test (async () => {
+  await mouseClickOn(510, 10);
+  scroller.scrollTo(0, 0);
+  await keyPress("ArrowRight");
+  await waitForAnimationEnd(scrollLeft, 500, 15);
+  // The left border of #right is at 1000 - width.
+  // The right border of #right is thus 1200 - width.
+  // When right-aligned, the scroll position should be 1200 - 2 * width.
+  assert_equals(scroller.scrollLeft, 1200 - 2 * width);
+}, "Snaps to #right after pressing ArrowRight");
+
+promise_test (async () => {
+  await mouseClickOn(510, 10);
+  scroller.scrollTo(400, 0);
+  await keyPress("ArrowLeft");
+  await waitForAnimationEnd(scrollLeft, 500, 15);
+  // The left border of #left is at 600 - width.
+  // The right border of #left is thus 800 - width.
+  // When right-aligned, the scroll position should be 800 - 2 * width.
+  assert_equals(scroller.scrollLeft, 800 - 2 * width);
+}, "Snaps to #left after pressing ArrowLeft");
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/scroll-snap/snaps-after-keyboard-scrolling.html b/third_party/WebKit/LayoutTests/fast/scroll-snap/snaps-after-keyboard-scrolling.html
new file mode 100644
index 0000000..5890394
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/scroll-snap/snaps-after-keyboard-scrolling.html
@@ -0,0 +1,126 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-scroll-snap-1" />
+<link rel="stylesheet" href="resources/simple-snap.css">
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../../resources/gesture-util.js"></script>
+
+<div id='scroller'>
+  <div id="space"></div>
+  <div class="snap left top" id="top-left"></div>
+  <div class="snap right top" id="top-right"></div>
+  <div class="snap left bottom" id="bottom-left"></div>
+</div>
+
+<script>
+var scroller = document.getElementById("scroller");
+var topLeft = document.getElementById("top-left");
+var topRight = document.getElementById("top-right");
+
+function scrollLeft() {
+  return scroller.scrollLeft;
+}
+
+function scrollTop() {
+  return scroller.scrollTop;
+}
+
+function keyPress(key) {
+  return new Promise((resolve, reject) => {
+    if (window.eventSender) {
+      eventSender.keyDown(key);
+      resolve();
+    }
+    else {
+      reject('This test requires window.eventSender');
+    }
+  })
+}
+
+promise_test (async () => {
+  await mouseClickOn(10, 10);
+  scroller.scrollTo(0, 0);
+  await keyPress("ArrowDown");
+  await waitForAnimationEnd(scrollTop, 500, 15);
+  assert_equals(scroller.scrollTop, 400);
+}, "Snaps to bottom-left after pressing ArrowDown");
+
+promise_test (async () => {
+  await mouseClickOn(10, 10);
+  scroller.scrollTo(0, 400);
+  await keyPress("ArrowUp");
+  await waitForAnimationEnd(scrollTop, 500, 15);
+  assert_equals(scroller.scrollTop, 0);
+}, "Snaps to top-left after pressing ArrowUp");
+
+promise_test (async () => {
+  await mouseClickOn(10, 10);
+  scroller.scrollTo(0, 0);
+  await keyPress("ArrowRight");
+  await waitForAnimationEnd(scrollLeft, 500, 15);
+  assert_equals(scroller.scrollLeft, 400);
+}, "Snaps to top-right after pressing ArrowRight");
+
+promise_test (async () => {
+  await mouseClickOn(10, 10);
+  scroller.scrollTo(400, 0);
+  await keyPress("ArrowLeft");
+  await waitForAnimationEnd(scrollLeft, 500, 15);
+  assert_equals(scroller.scrollLeft, 0);
+}, "Snaps to top-left after pressing ArrowLeft");
+
+promise_test (async () => {
+  // Make the snap area covers the snapport.
+  topLeft.style.width = "800px";
+  // Make the distance between the previous and the next snap position larger
+  // than snapport.
+  topRight.style.left = "500px";
+  await mouseClickOn(10, 10);
+  scroller.scrollTo(0, 0);
+  await keyPress("ArrowRight");
+  await waitForAnimationEnd(scrollLeft, 500, 15);
+  assert_between_exclusive(scroller.scrollLeft, 0, 500);
+  topLeft.style.width = "";
+  topRight.style.left = "400px";
+}, "If the original intended offset is valid as making a snap area cover the"
++ "snapport, and there's no other snap offset in between, use the original"
++ "intended offset");
+
+promise_test (async () => {
+  // Make the snap area covers the snapport.
+  topLeft.style.width = "800px";
+  // Make the next snap offset closer than the original intended offset.
+  topRight.style.left = "20px";
+  await mouseClickOn(10, 10);
+  scroller.scrollTo(0, 0);
+  await keyPress("ArrowRight");
+  await waitForAnimationEnd(scrollLeft, 500, 15);
+  assert_equals(scroller.scrollLeft, 20);
+  topLeft.style.width = "";
+  topRight.style.left = "400px";
+}, "If the original intended offset is valid as making a snap area cover the "
++ "snapport, but there's a defined snap offset in between, use the defined snap"
++ " offset.");
+
+promise_test (async () => {
+  await mouseClickOn(10, 10);
+  scroller.scrollTo(400, 0);
+  await keyPress("ArrowRight");
+  await waitForAnimationEnd(scrollLeft, 500, 15);
+  assert_equals(scroller.scrollLeft, 400);
+}, "If there is no valid snap offset on the arrow key's direction other than "
++ "the current offset, and the scroll-snap-type is mandatory, stay at the "
++ "current offset.");
+
+promise_test (async () => {
+  scroller.style.scrollSnapType = "both proximity";
+  await mouseClickOn(10, 10);
+  scroller.scrollTo(400, 0);
+  await keyPress("ArrowRight");
+  await waitForAnimationEnd(scrollLeft, 500, 15);
+  assert_greater_than(scroller.scrollLeft, 400);
+  scroller.style.scrollSnapType = "both mandatory";
+}, "If there is no valid snap offset on the arrow key's direction other than "
++ "the current offset, and the scroll-snap-type is proximity, go to the "
++ "original intended offset");
+</script>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/fast/scroll-snap/snaps-after-scrollbar-scrolling.html b/third_party/WebKit/LayoutTests/fast/scroll-snap/snaps-after-scrollbar-scrolling.html
index dc42e00..9bc46e47d 100644
--- a/third_party/WebKit/LayoutTests/fast/scroll-snap/snaps-after-scrollbar-scrolling.html
+++ b/third_party/WebKit/LayoutTests/fast/scroll-snap/snaps-after-scrollbar-scrolling.html
@@ -1,52 +1,15 @@
 <!DOCTYPE html>
 <link rel="help" href="https://drafts.csswg.org/css-scroll-snap-1" />
+<link rel="stylesheet" href="resources/simple-snap.css">
 <script src="../../resources/testharness.js"></script>
 <script src="../../resources/testharnessreport.js"></script>
 <script src="../../resources/gesture-util.js"></script>
-<style>
-body {
-  margin: 0px;
-}
-div {
-  position: absolute;
-}
-#scroller {
-  width: 400px;
-  height: 400px;
-  overflow: scroll;
-  scroll-snap-type: both mandatory;
-  padding: 0px;
-}
-.snap {
-  width: 200px;
-  height: 200px;
-  background-color: blue;
-  scroll-snap-align: start;
-}
-#space {
-  width: 1000px;
-  height: 1000px;
-}
-#left-top {
-  left: 0px;
-  top: 0px;
-}
-#right-top {
-  left: 400px;
-  top: 0px;
-}
-#left-bottom {
-  left: 0px;
-  top: 400px;
-}
-
-</style>
 
 <div id='scroller'>
   <div id="space"></div>
-  <div class="snap" id="left-top"></div>
-  <div class="snap" id="right-top"></div>
-  <div class="snap" id="left-bottom"></div>
+  <div class="snap left top"></div>
+  <div class="snap right top"></div>
+  <div class="snap left bottom"></div>
 </div>
 
 <script>
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-quirks-collapsed-border-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-quirks-collapsed-border-expected.png
index 3bbac58..c2ac289 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-quirks-collapsed-border-expected.png
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-quirks-collapsed-border-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-quirks-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-quirks-expected.png
index f7a81d3..5182b3c 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-quirks-expected.png
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_border-table-quirks-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/text/emoticons-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/text/emoticons-expected.png
new file mode 100644
index 0000000..6df201276
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/text/emoticons-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/text/unicode-fallback-font-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/text/unicode-fallback-font-expected.png
new file mode 100644
index 0000000..df1db80
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/text/unicode-fallback-font-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/writing-mode/border-radius-clipping-vertical-lr-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/writing-mode/border-radius-clipping-vertical-lr-expected.png
new file mode 100644
index 0000000..57a9c64
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/writing-mode/border-radius-clipping-vertical-lr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/writing-mode/border-styles-vertical-lr-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/writing-mode/border-styles-vertical-lr-expected.png
new file mode 100644
index 0000000..de3911c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/fast/writing-mode/border-styles-vertical-lr-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/images/color-profile-image-filter-all-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/images/color-profile-image-filter-all-expected.png
index eaff314c..616c2182 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/images/color-profile-image-filter-all-expected.png
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/images/color-profile-image-filter-all-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/transforms/3d/general/perspective-units-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/transforms/3d/general/perspective-units-expected.png
index beedef9..73d373a 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/transforms/3d/general/perspective-units-expected.png
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/transforms/3d/general/perspective-units-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/paint/subpixel/subpixel-composited-iframe-expected.html b/third_party/WebKit/LayoutTests/paint/subpixel/subpixel-composited-iframe-expected.html
new file mode 100644
index 0000000..48d6c2a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/paint/subpixel/subpixel-composited-iframe-expected.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<iframe id="iframe"
+  style="position: absolute; top: 6px; left: 6px; border: none; width: 200px; height: 200px"
+  srcdoc="
+      <div id='target' style='width: 100px; height: 100px; background: black'>
+      </div>
+  ">
+</iframe>
diff --git a/third_party/WebKit/LayoutTests/paint/subpixel/subpixel-composited-iframe.html b/third_party/WebKit/LayoutTests/paint/subpixel/subpixel-composited-iframe.html
new file mode 100644
index 0000000..1e23a62
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/paint/subpixel/subpixel-composited-iframe.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<iframe id="iframe"
+  style="position: absolute; top: 5.5px; left: 5.5px; border: none; width: 200px; height: 200px"
+  srcdoc="
+      <div id='target' style='width: 100px; height: 100px; background: black; will-change: transform'>
+      </div>
+  ">
+</iframe>
diff --git a/third_party/blink/common/font_unique_name_lookup/icu_fold_case_util.cc b/third_party/blink/common/font_unique_name_lookup/icu_fold_case_util.cc
index 048679c..7fd0f09e 100644
--- a/third_party/blink/common/font_unique_name_lookup/icu_fold_case_util.cc
+++ b/third_party/blink/common/font_unique_name_lookup/icu_fold_case_util.cc
@@ -8,8 +8,8 @@
 namespace blink {
 
 std::string IcuFoldCase(const std::string& name_request) {
-  icu_62::UnicodeString name_request_unicode =
-      icu_62::UnicodeString::fromUTF8(name_request);
+  icu::UnicodeString name_request_unicode =
+      icu::UnicodeString::fromUTF8(name_request);
   name_request_unicode.foldCase();
   std::string name_request_lower;
   name_request_unicode.toUTF8String(name_request_lower);
diff --git a/third_party/blink/public/platform/platform.h b/third_party/blink/public/platform/platform.h
index 2906462..6225f1f 100644
--- a/third_party/blink/public/platform/platform.h
+++ b/third_party/blink/public/platform/platform.h
@@ -64,12 +64,15 @@
 #include "third_party/blink/public/platform/web_url_error.h"
 #include "third_party/blink/public/platform/web_url_loader.h"
 #include "third_party/blink/public/platform/web_url_loader_factory.h"
-#include "third_party/webrtc/p2p/base/portallocator.h"
 
 namespace base {
 class SingleThreadTaskRunner;
 }
 
+namespace cricket {
+class PortAllocator;
+}
+
 namespace gpu {
 class GpuMemoryBufferManager;
 }
@@ -651,9 +654,7 @@
 
   // May return null if WebRTC functionality is not implemented.
   virtual std::unique_ptr<cricket::PortAllocator> CreateWebRtcPortAllocator(
-      WebLocalFrame* frame) {
-    return nullptr;
-  }
+      WebLocalFrame* frame);
 
   // Creates a WebCanvasCaptureHandler to capture Canvas output.
   virtual std::unique_ptr<WebCanvasCaptureHandler>
diff --git a/third_party/blink/public/platform/scheduler/test/mock_renderer_scheduler.h b/third_party/blink/public/platform/scheduler/test/mock_renderer_scheduler.h
index b90d717..cbf0189 100644
--- a/third_party/blink/public/platform/scheduler/test/mock_renderer_scheduler.h
+++ b/third_party/blink/public/platform/scheduler/test/mock_renderer_scheduler.h
@@ -12,7 +12,6 @@
 #include "components/viz/common/frame_sinks/begin_frame_args.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "third_party/blink/public/platform/scheduler/web_thread_scheduler.h"
-#include "third_party/blink/renderer/platform/scheduler/public/thread.h"
 
 namespace blink {
 namespace scheduler {
@@ -22,7 +21,6 @@
   MockRendererScheduler() = default;
   ~MockRendererScheduler() override = default;
 
-  MOCK_METHOD0(CreateMainThread, std::unique_ptr<Thread>());
   MOCK_METHOD0(DefaultTaskRunner,
                scoped_refptr<base::SingleThreadTaskRunner>());
   MOCK_METHOD0(CompositorTaskRunner,
diff --git a/third_party/blink/public/platform/web_canonical_cookie.h b/third_party/blink/public/platform/web_canonical_cookie.h
index 8fb3ea5..a19d999 100644
--- a/third_party/blink/public/platform/web_canonical_cookie.h
+++ b/third_party/blink/public/platform/web_canonical_cookie.h
@@ -10,8 +10,7 @@
 #include "services/network/public/mojom/restricted_cookie_manager.mojom-shared.h"
 #include "third_party/blink/public/platform/web_string.h"
 #include "third_party/blink/public/platform/web_url.h"
-#include "third_party/blink/renderer/platform/platform_export.h"
-#include "third_party/blink/renderer/platform/wtf/forward.h"
+#include "third_party/blink/renderer/platform/platform_export.h"  // nogncheck
 
 namespace blink {
 
@@ -60,9 +59,6 @@
                                                    const WebString& cookie_line,
                                                    base::Time creation_time);
 
-  // Serializing, for the document.cookie API.
-  static String BuildCookieLine(const Vector<WebCanonicalCookie>& cookies);
-
   static constexpr const network::mojom::CookieSameSite kDefaultSameSiteMode =
       network::mojom::CookieSameSite::NO_RESTRICTION;
   static constexpr const network::mojom::CookiePriority kDefaultPriority =
diff --git a/third_party/blink/public/platform/web_feature.mojom b/third_party/blink/public/platform/web_feature.mojom
index 2f0499c..112cc3e 100644
--- a/third_party/blink/public/platform/web_feature.mojom
+++ b/third_party/blink/public/platform/web_feature.mojom
@@ -2063,6 +2063,7 @@
   kV8AttemptOverrideReadOnlyOnPrototypeStrict = 2610,
   kHTMLCanvasElementLowLatency = 2611,
   kV8OptimizedFunctionWithOneShotBytecode = 2612,
+  kSVGGeometryPropertyHasNonZeroUnitlessValue = 2613,
   // Add new features immediately above this line. Don't change assigned
   // numbers of any item, and don't reuse removed slots.
   // Also, run update_use_counter_feature_enum.py in
diff --git a/third_party/blink/renderer/bindings/core/v8/v0_custom_element_constructor_builder.cc b/third_party/blink/renderer/bindings/core/v8/v0_custom_element_constructor_builder.cc
index 2ea911a..e98f28ae 100644
--- a/third_party/blink/renderer/bindings/core/v8/v0_custom_element_constructor_builder.cc
+++ b/third_party/blink/renderer/bindings/core/v8/v0_custom_element_constructor_builder.cc
@@ -104,7 +104,7 @@
 
   AtomicString namespace_uri = HTMLNames::xhtmlNamespaceURI;
   if (HasValidPrototypeChainFor(&V8SVGElement::wrapperTypeInfo))
-    namespace_uri = SVGNames::svgNamespaceURI;
+    namespace_uri = svg_names::kNamespaceURI;
 
   DCHECK(!try_catch.HasCaught());
 
@@ -128,7 +128,7 @@
       return false;
     }
   } else {
-    if (namespace_uri == SVGNames::svgNamespaceURI) {
+    if (namespace_uri == svg_names::kNamespaceURI) {
       V0CustomElementException::ThrowException(
           V0CustomElementException::kExtendsIsInvalidName, type,
           exception_state);
diff --git a/third_party/blink/renderer/bindings/scripts/v8_attributes.py b/third_party/blink/renderer/bindings/scripts/v8_attributes.py
index eefe480..930e8af3 100644
--- a/third_party/blink/renderer/bindings/scripts/v8_attributes.py
+++ b/third_party/blink/renderer/bindings/scripts/v8_attributes.py
@@ -35,6 +35,12 @@
 Design doc: http://www.chromium.org/developers/design-documents/idl-compiler
 """
 
+import os
+import sys
+
+sys.path.append(os.path.join(os.path.dirname(__file__),
+                             '..', '..', 'build', 'scripts'))
+from blinkbuild.name_style_converter import NameStyleConverter
 import idl_types
 from idl_types import inherits_interface
 from v8_globals import includes
@@ -535,13 +541,15 @@
 
 def scoped_content_attribute_name(interface, attribute):
     content_attribute_name = attribute.extended_attributes['Reflect'] or attribute.name.lower()
+    symbol_name = 'k' + NameStyleConverter(content_attribute_name).to_upper_camel_case()
     if interface.name.startswith('SVG'):
-        namespace = 'SVGNames'
+        namespace = 'svg_names'
         includes.add('core/svg_names.h')
     else:
         namespace = 'HTMLNames'
         includes.add('core/html_names.h')
-    return '%s::%sAttr' % (namespace, content_attribute_name)
+        symbol_name = content_attribute_name
+    return '%s::%sAttr' % (namespace, symbol_name)
 
 
 ################################################################################
diff --git a/third_party/blink/renderer/bindings/tests/results/core/v8_svg_test_interface.cc b/third_party/blink/renderer/bindings/tests/results/core/v8_svg_test_interface.cc
index f4458f3..fd80699 100644
--- a/third_party/blink/renderer/bindings/tests/results/core/v8_svg_test_interface.cc
+++ b/third_party/blink/renderer/bindings/tests/results/core/v8_svg_test_interface.cc
@@ -70,7 +70,7 @@
 
   SVGTestInterface* impl = V8SVGTestInterface::ToImpl(holder);
 
-  V8SetReturnValueString(info, impl->FastGetAttribute(SVGNames::typeAttr), info.GetIsolate());
+  V8SetReturnValueString(info, impl->FastGetAttribute(svg_names::kTypeAttr), info.GetIsolate());
 }
 
 static void typeAttributeSetter(v8::Local<v8::Value> v8Value, const v8::FunctionCallbackInfo<v8::Value>& info) {
@@ -89,7 +89,7 @@
   if (!cppValue.Prepare())
     return;
 
-  impl->setAttribute(SVGNames::typeAttr, cppValue);
+  impl->setAttribute(svg_names::kTypeAttr, cppValue);
 }
 
 }  // namespace svg_test_interface_v8_internal
diff --git a/third_party/blink/renderer/build/scripts/core/css/make_media_features.py b/third_party/blink/renderer/build/scripts/core/css/make_media_features.py
index 6582bda..fcf89d7d 100755
--- a/third_party/blink/renderer/build/scripts/core/css/make_media_features.py
+++ b/third_party/blink/renderer/build/scripts/core/css/make_media_features.py
@@ -21,7 +21,8 @@
     }
     filters = {
         'symbol': media_feature_symbol.getMediaFeatureSymbolWithSuffix(''),
-        'to_function_name': lambda symbol: NameStyleConverter(symbol).to_function_name(),
+        # symbol[1:] removes the leading 'k' produced by the above function.
+        'to_function_name': lambda symbol: NameStyleConverter(symbol[1:]).to_function_name(),
     }
 
     def __init__(self, json5_file_path, output_dir):
diff --git a/third_party/blink/renderer/build/scripts/make_element_type_helpers.py b/third_party/blink/renderer/build/scripts/make_element_type_helpers.py
index 0c8561e..d7972da 100755
--- a/third_party/blink/renderer/build/scripts/make_element_type_helpers.py
+++ b/third_party/blink/renderer/build/scripts/make_element_type_helpers.py
@@ -12,10 +12,14 @@
 import template_expander
 
 
-def _symbol(tag):
+def _legacy_symbol(tag):
     return name_utilities.cpp_name(tag).replace('-', '_')
 
 
+def _symbol(tag):
+    return 'k' + tag['name'].to_upper_camel_case()
+
+
 class MakeElementTypeHelpersWriter(json5_generator.Writer):
     default_parameters = {
         'Conditional': {},
@@ -49,6 +53,11 @@
         self.fallback_interface = self.json5_file.metadata['fallbackInterfaceName'].strip('"')
 
         assert self.namespace, 'A namespace is required.'
+        cpp_namespace = self.namespace.lower() + '_names'
+        # TODO(tkent): Remove the following branch.  crbug.com/889726
+        if self.namespace == 'HTML':
+            cpp_namespace = self.namespace + 'Names'
+            MakeElementTypeHelpersWriter.filters['symbol'] = _legacy_symbol
 
         basename = self.namespace.lower() + '_element_type_helpers'
         self._outputs = {
@@ -60,6 +69,7 @@
                               '{0}/{0}_element.h'.format(self.namespace.lower())
         self._template_context = {
             'base_element_header': base_element_header,
+            'cpp_namespace': cpp_namespace,
             'input_files': self._input_files,
             'namespace': self.namespace,
             'tags': self.json5_file.name_dictionaries,
diff --git a/third_party/blink/renderer/build/scripts/make_qualified_names.py b/third_party/blink/renderer/build/scripts/make_qualified_names.py
index ec075ec..3450583 100755
--- a/third_party/blink/renderer/build/scripts/make_qualified_names.py
+++ b/third_party/blink/renderer/build/scripts/make_qualified_names.py
@@ -92,7 +92,7 @@
         cpp_namespace = self.namespace.lower() + '_names'
         namespace_prefix = self._metadata('namespacePrefix') or 'k'
         # TODO(tkent): Remove the following branch.  crbug.com/889726
-        if self.namespace in ('HTML', 'SVG'):
+        if self.namespace == 'HTML':
             cpp_namespace = self.namespace + 'Names'
             MakeQualifiedNamesWriter.filters['symbol'] = _legacy_symbol
             namespace_prefix = self._metadata('namespacePrefix') or self.namespace.lower()
diff --git a/third_party/blink/renderer/build/scripts/media_feature_symbol.py b/third_party/blink/renderer/build/scripts/media_feature_symbol.py
index f9d51e9..10d8a10f 100644
--- a/third_party/blink/renderer/build/scripts/media_feature_symbol.py
+++ b/third_party/blink/renderer/build/scripts/media_feature_symbol.py
@@ -3,23 +3,14 @@
 # found in the LICENSE file.
 
 
+from blinkbuild.name_style_converter import NameStyleConverter
+
+
 def mediaFeatureSymbol(entry, suffix):
     name = entry['name'].original
     if name.startswith('-webkit-'):
         name = name[8:]
-
-    foundDash = False
-    newName = ""
-    for chr in name:
-        if chr == '-':
-            foundDash = True
-            continue
-        if foundDash:
-            chr = chr.upper()
-            foundDash = False
-        newName = newName + chr
-    newName = newName + suffix
-    return newName
+    return 'k' + NameStyleConverter(name).to_upper_camel_case() + suffix
 
 
 def getMediaFeatureSymbolWithSuffix(suffix):
diff --git a/third_party/blink/renderer/build/scripts/templates/element_type_helpers.h.tmpl b/third_party/blink/renderer/build/scripts/templates/element_type_helpers.h.tmpl
index d0f65a3..7b4a4578 100644
--- a/third_party/blink/renderer/build/scripts/templates/element_type_helpers.h.tmpl
+++ b/third_party/blink/renderer/build/scripts/templates/element_type_helpers.h.tmpl
@@ -23,7 +23,7 @@
   if (!RuntimeEnabledFeatures::{{tag.runtimeEnabled}}Enabled())
     return false;
   {% endif %}
-  return element.HasTagName({{namespace}}Names::{{tag|symbol}}Tag);
+  return element.HasTagName({{cpp_namespace}}::{{tag|symbol}}Tag);
 }
 inline bool Is{{tag.interface}}(const {{namespace}}Element* element) {
   return element && Is{{tag.interface}}(*element);
diff --git a/third_party/blink/renderer/core/BUILD.gn b/third_party/blink/renderer/core/BUILD.gn
index 1db1a55..c048c382 100644
--- a/third_party/blink/renderer/core/BUILD.gn
+++ b/third_party/blink/renderer/core/BUILD.gn
@@ -1160,6 +1160,8 @@
 code_generator("make_core_generated_media_features") {
   script = "../build/scripts/core/css/make_media_features.py"
   json_inputs = [ "css/media_feature_names.json5" ]
+  other_inputs =
+      scripts_for_json5_files + [ "../build/scripts/media_feature_symbol.py" ]
   templates = [ "../build/scripts/core/css/templates/media_features.h.tmpl" ]
   outputs = [
     "$blink_core_output_dir/css/media_features.h",
@@ -1286,7 +1288,8 @@
     "../build/scripts/templates/make_names.cc.tmpl",
     "../build/scripts/templates/make_names.h.tmpl",
   ]
-  other_inputs = make_names_files
+  other_inputs =
+      make_names_files + [ "../build/scripts/media_feature_symbol.py" ]
   outputs = [
     "$blink_core_output_dir/css/media_feature_names.cc",
     "$blink_core_output_dir/css/media_feature_names.h",
diff --git a/third_party/blink/renderer/core/animation/animation_input_helpers.cc b/third_party/blink/renderer/core/animation/animation_input_helpers.cc
index 1aa84f6..14119ca7 100644
--- a/third_party/blink/renderer/core/animation/animation_input_helpers.cc
+++ b/third_party/blink/renderer/core/animation/animation_input_helpers.cc
@@ -105,100 +105,100 @@
     // Animatable attributes from http://www.w3.org/TR/SVG/attindex.html
     const QualifiedName* attributes[] = {
         &HTMLNames::classAttr,
-        &SVGNames::amplitudeAttr,
-        &SVGNames::azimuthAttr,
-        &SVGNames::baseFrequencyAttr,
-        &SVGNames::biasAttr,
-        &SVGNames::clipPathUnitsAttr,
-        &SVGNames::cxAttr,
-        &SVGNames::cyAttr,
-        &SVGNames::dAttr,
-        &SVGNames::diffuseConstantAttr,
-        &SVGNames::divisorAttr,
-        &SVGNames::dxAttr,
-        &SVGNames::dyAttr,
-        &SVGNames::edgeModeAttr,
-        &SVGNames::elevationAttr,
-        &SVGNames::exponentAttr,
-        &SVGNames::filterUnitsAttr,
-        &SVGNames::fxAttr,
-        &SVGNames::fyAttr,
-        &SVGNames::gradientTransformAttr,
-        &SVGNames::gradientUnitsAttr,
-        &SVGNames::heightAttr,
-        &SVGNames::hrefAttr,
-        &SVGNames::in2Attr,
-        &SVGNames::inAttr,
-        &SVGNames::interceptAttr,
-        &SVGNames::k1Attr,
-        &SVGNames::k2Attr,
-        &SVGNames::k3Attr,
-        &SVGNames::k4Attr,
-        &SVGNames::kernelMatrixAttr,
-        &SVGNames::kernelUnitLengthAttr,
-        &SVGNames::lengthAdjustAttr,
-        &SVGNames::limitingConeAngleAttr,
-        &SVGNames::markerHeightAttr,
-        &SVGNames::markerUnitsAttr,
-        &SVGNames::markerWidthAttr,
-        &SVGNames::maskContentUnitsAttr,
-        &SVGNames::maskUnitsAttr,
-        &SVGNames::methodAttr,
-        &SVGNames::modeAttr,
-        &SVGNames::numOctavesAttr,
-        &SVGNames::offsetAttr,
-        &SVGNames::operatorAttr,
-        &SVGNames::orderAttr,
-        &SVGNames::orientAttr,
-        &SVGNames::pathLengthAttr,
-        &SVGNames::patternContentUnitsAttr,
-        &SVGNames::patternTransformAttr,
-        &SVGNames::patternUnitsAttr,
-        &SVGNames::pointsAtXAttr,
-        &SVGNames::pointsAtYAttr,
-        &SVGNames::pointsAtZAttr,
-        &SVGNames::pointsAttr,
-        &SVGNames::preserveAlphaAttr,
-        &SVGNames::preserveAspectRatioAttr,
-        &SVGNames::primitiveUnitsAttr,
-        &SVGNames::rAttr,
-        &SVGNames::radiusAttr,
-        &SVGNames::refXAttr,
-        &SVGNames::refYAttr,
-        &SVGNames::resultAttr,
-        &SVGNames::rotateAttr,
-        &SVGNames::rxAttr,
-        &SVGNames::ryAttr,
-        &SVGNames::scaleAttr,
-        &SVGNames::seedAttr,
-        &SVGNames::slopeAttr,
-        &SVGNames::spacingAttr,
-        &SVGNames::specularConstantAttr,
-        &SVGNames::specularExponentAttr,
-        &SVGNames::spreadMethodAttr,
-        &SVGNames::startOffsetAttr,
-        &SVGNames::stdDeviationAttr,
-        &SVGNames::stitchTilesAttr,
-        &SVGNames::surfaceScaleAttr,
-        &SVGNames::tableValuesAttr,
-        &SVGNames::targetAttr,
-        &SVGNames::targetXAttr,
-        &SVGNames::targetYAttr,
-        &SVGNames::textLengthAttr,
-        &SVGNames::transformAttr,
-        &SVGNames::typeAttr,
-        &SVGNames::valuesAttr,
-        &SVGNames::viewBoxAttr,
-        &SVGNames::widthAttr,
-        &SVGNames::x1Attr,
-        &SVGNames::x2Attr,
-        &SVGNames::xAttr,
-        &SVGNames::xChannelSelectorAttr,
-        &SVGNames::y1Attr,
-        &SVGNames::y2Attr,
-        &SVGNames::yAttr,
-        &SVGNames::yChannelSelectorAttr,
-        &SVGNames::zAttr,
+        &svg_names::kAmplitudeAttr,
+        &svg_names::kAzimuthAttr,
+        &svg_names::kBaseFrequencyAttr,
+        &svg_names::kBiasAttr,
+        &svg_names::kClipPathUnitsAttr,
+        &svg_names::kCxAttr,
+        &svg_names::kCyAttr,
+        &svg_names::kDAttr,
+        &svg_names::kDiffuseConstantAttr,
+        &svg_names::kDivisorAttr,
+        &svg_names::kDxAttr,
+        &svg_names::kDyAttr,
+        &svg_names::kEdgeModeAttr,
+        &svg_names::kElevationAttr,
+        &svg_names::kExponentAttr,
+        &svg_names::kFilterUnitsAttr,
+        &svg_names::kFxAttr,
+        &svg_names::kFyAttr,
+        &svg_names::kGradientTransformAttr,
+        &svg_names::kGradientUnitsAttr,
+        &svg_names::kHeightAttr,
+        &svg_names::kHrefAttr,
+        &svg_names::kIn2Attr,
+        &svg_names::kInAttr,
+        &svg_names::kInterceptAttr,
+        &svg_names::kK1Attr,
+        &svg_names::kK2Attr,
+        &svg_names::kK3Attr,
+        &svg_names::kK4Attr,
+        &svg_names::kKernelMatrixAttr,
+        &svg_names::kKernelUnitLengthAttr,
+        &svg_names::kLengthAdjustAttr,
+        &svg_names::kLimitingConeAngleAttr,
+        &svg_names::kMarkerHeightAttr,
+        &svg_names::kMarkerUnitsAttr,
+        &svg_names::kMarkerWidthAttr,
+        &svg_names::kMaskContentUnitsAttr,
+        &svg_names::kMaskUnitsAttr,
+        &svg_names::kMethodAttr,
+        &svg_names::kModeAttr,
+        &svg_names::kNumOctavesAttr,
+        &svg_names::kOffsetAttr,
+        &svg_names::kOperatorAttr,
+        &svg_names::kOrderAttr,
+        &svg_names::kOrientAttr,
+        &svg_names::kPathLengthAttr,
+        &svg_names::kPatternContentUnitsAttr,
+        &svg_names::kPatternTransformAttr,
+        &svg_names::kPatternUnitsAttr,
+        &svg_names::kPointsAtXAttr,
+        &svg_names::kPointsAtYAttr,
+        &svg_names::kPointsAtZAttr,
+        &svg_names::kPointsAttr,
+        &svg_names::kPreserveAlphaAttr,
+        &svg_names::kPreserveAspectRatioAttr,
+        &svg_names::kPrimitiveUnitsAttr,
+        &svg_names::kRAttr,
+        &svg_names::kRadiusAttr,
+        &svg_names::kRefXAttr,
+        &svg_names::kRefYAttr,
+        &svg_names::kResultAttr,
+        &svg_names::kRotateAttr,
+        &svg_names::kRxAttr,
+        &svg_names::kRyAttr,
+        &svg_names::kScaleAttr,
+        &svg_names::kSeedAttr,
+        &svg_names::kSlopeAttr,
+        &svg_names::kSpacingAttr,
+        &svg_names::kSpecularConstantAttr,
+        &svg_names::kSpecularExponentAttr,
+        &svg_names::kSpreadMethodAttr,
+        &svg_names::kStartOffsetAttr,
+        &svg_names::kStdDeviationAttr,
+        &svg_names::kStitchTilesAttr,
+        &svg_names::kSurfaceScaleAttr,
+        &svg_names::kTableValuesAttr,
+        &svg_names::kTargetAttr,
+        &svg_names::kTargetXAttr,
+        &svg_names::kTargetYAttr,
+        &svg_names::kTextLengthAttr,
+        &svg_names::kTransformAttr,
+        &svg_names::kTypeAttr,
+        &svg_names::kValuesAttr,
+        &svg_names::kViewBoxAttr,
+        &svg_names::kWidthAttr,
+        &svg_names::kX1Attr,
+        &svg_names::kX2Attr,
+        &svg_names::kXAttr,
+        &svg_names::kXChannelSelectorAttr,
+        &svg_names::kY1Attr,
+        &svg_names::kY2Attr,
+        &svg_names::kYAttr,
+        &svg_names::kYChannelSelectorAttr,
+        &svg_names::kZAttr,
     };
     for (size_t i = 0; i < arraysize(attributes); i++) {
       DCHECK(!SVGElement::IsAnimatableCSSProperty(*attributes[i]));
diff --git a/third_party/blink/renderer/core/animation/path_interpolation_functions.cc b/third_party/blink/renderer/core/animation/path_interpolation_functions.cc
index 1b8bace..1a70078 100644
--- a/third_party/blink/renderer/core/animation/path_interpolation_functions.cc
+++ b/third_party/blink/renderer/core/animation/path_interpolation_functions.cc
@@ -203,7 +203,7 @@
           *ToInterpolableList(interpolable_value).Get(kPathArgsIndex)),
       ToSVGPathNonInterpolableValue(non_interpolable_value)->PathSegTypes());
   SVGPathByteStreamBuilder builder(*path_byte_stream);
-  SVGPathParser::ParsePath(source, builder);
+  svg_path_parser::ParsePath(source, builder);
   return path_byte_stream;
 }
 
diff --git a/third_party/blink/renderer/core/animation/property_handle_test.cc b/third_party/blink/renderer/core/animation/property_handle_test.cc
index f30eb08..50dc32c 100644
--- a/third_party/blink/renderer/core/animation/property_handle_test.cc
+++ b/third_party/blink/renderer/core/animation/property_handle_test.cc
@@ -9,8 +9,8 @@
 
 namespace blink {
 
-using SVGNames::amplitudeAttr;
-using SVGNames::exponentAttr;
+using svg_names::kAmplitudeAttr;
+using svg_names::kExponentAttr;
 
 class PropertyHandleTest : public testing::Test {};
 
@@ -31,9 +31,9 @@
   EXPECT_TRUE(PropertyHandle(GetCSSPropertyOpacity()) !=
               PropertyHandle(name_a));
   EXPECT_FALSE(PropertyHandle(GetCSSPropertyOpacity()) ==
-               PropertyHandle(amplitudeAttr));
+               PropertyHandle(kAmplitudeAttr));
   EXPECT_TRUE(PropertyHandle(GetCSSPropertyOpacity()) !=
-              PropertyHandle(amplitudeAttr));
+              PropertyHandle(kAmplitudeAttr));
 
   EXPECT_FALSE(PropertyHandle(name_a) ==
                PropertyHandle(GetCSSPropertyOpacity()));
@@ -47,19 +47,20 @@
   EXPECT_FALSE(PropertyHandle(name_a) != PropertyHandle(name_a));
   EXPECT_FALSE(PropertyHandle(name_a) == PropertyHandle(name_b));
   EXPECT_TRUE(PropertyHandle(name_a) != PropertyHandle(name_b));
-  EXPECT_FALSE(PropertyHandle(name_a) == PropertyHandle(amplitudeAttr));
-  EXPECT_TRUE(PropertyHandle(name_a) != PropertyHandle(amplitudeAttr));
+  EXPECT_FALSE(PropertyHandle(name_a) == PropertyHandle(kAmplitudeAttr));
+  EXPECT_TRUE(PropertyHandle(name_a) != PropertyHandle(kAmplitudeAttr));
 
-  EXPECT_FALSE(PropertyHandle(amplitudeAttr) ==
+  EXPECT_FALSE(PropertyHandle(kAmplitudeAttr) ==
                PropertyHandle(GetCSSPropertyOpacity()));
-  EXPECT_TRUE(PropertyHandle(amplitudeAttr) !=
+  EXPECT_TRUE(PropertyHandle(kAmplitudeAttr) !=
               PropertyHandle(GetCSSPropertyOpacity()));
-  EXPECT_FALSE(PropertyHandle(amplitudeAttr) == PropertyHandle(name_a));
-  EXPECT_TRUE(PropertyHandle(amplitudeAttr) != PropertyHandle(name_a));
-  EXPECT_TRUE(PropertyHandle(amplitudeAttr) == PropertyHandle(amplitudeAttr));
-  EXPECT_FALSE(PropertyHandle(amplitudeAttr) != PropertyHandle(amplitudeAttr));
-  EXPECT_FALSE(PropertyHandle(amplitudeAttr) == PropertyHandle(exponentAttr));
-  EXPECT_TRUE(PropertyHandle(amplitudeAttr) != PropertyHandle(exponentAttr));
+  EXPECT_FALSE(PropertyHandle(kAmplitudeAttr) == PropertyHandle(name_a));
+  EXPECT_TRUE(PropertyHandle(kAmplitudeAttr) != PropertyHandle(name_a));
+  EXPECT_TRUE(PropertyHandle(kAmplitudeAttr) == PropertyHandle(kAmplitudeAttr));
+  EXPECT_FALSE(PropertyHandle(kAmplitudeAttr) !=
+               PropertyHandle(kAmplitudeAttr));
+  EXPECT_FALSE(PropertyHandle(kAmplitudeAttr) == PropertyHandle(kExponentAttr));
+  EXPECT_TRUE(PropertyHandle(kAmplitudeAttr) != PropertyHandle(kExponentAttr));
 }
 
 TEST_F(PropertyHandleTest, Hash) {
@@ -73,7 +74,7 @@
   EXPECT_FALSE(PropertyHandle(GetCSSPropertyOpacity()).GetHash() ==
                PropertyHandle(GetCSSPropertyTransform()).GetHash());
   EXPECT_FALSE(PropertyHandle(GetCSSPropertyOpacity()).GetHash() ==
-               PropertyHandle(amplitudeAttr).GetHash());
+               PropertyHandle(kAmplitudeAttr).GetHash());
 
   EXPECT_FALSE(PropertyHandle(name_a).GetHash() ==
                PropertyHandle(GetCSSPropertyOpacity()).GetHash());
@@ -82,16 +83,16 @@
   EXPECT_FALSE(PropertyHandle(name_a).GetHash() ==
                PropertyHandle(name_b).GetHash());
   EXPECT_FALSE(PropertyHandle(name_a).GetHash() ==
-               PropertyHandle(exponentAttr).GetHash());
+               PropertyHandle(kExponentAttr).GetHash());
 
-  EXPECT_FALSE(PropertyHandle(amplitudeAttr).GetHash() ==
+  EXPECT_FALSE(PropertyHandle(kAmplitudeAttr).GetHash() ==
                PropertyHandle(GetCSSPropertyOpacity()).GetHash());
-  EXPECT_FALSE(PropertyHandle(amplitudeAttr).GetHash() ==
+  EXPECT_FALSE(PropertyHandle(kAmplitudeAttr).GetHash() ==
                PropertyHandle(name_a).GetHash());
-  EXPECT_TRUE(PropertyHandle(amplitudeAttr).GetHash() ==
-              PropertyHandle(amplitudeAttr).GetHash());
-  EXPECT_FALSE(PropertyHandle(amplitudeAttr).GetHash() ==
-               PropertyHandle(exponentAttr).GetHash());
+  EXPECT_TRUE(PropertyHandle(kAmplitudeAttr).GetHash() ==
+              PropertyHandle(kAmplitudeAttr).GetHash());
+  EXPECT_FALSE(PropertyHandle(kAmplitudeAttr).GetHash() ==
+               PropertyHandle(kExponentAttr).GetHash());
 }
 
 TEST_F(PropertyHandleTest, Accessors) {
@@ -99,15 +100,15 @@
 
   EXPECT_TRUE(PropertyHandle(GetCSSPropertyOpacity()).IsCSSProperty());
   EXPECT_TRUE(PropertyHandle(name).IsCSSProperty());
-  EXPECT_FALSE(PropertyHandle(amplitudeAttr).IsCSSProperty());
+  EXPECT_FALSE(PropertyHandle(kAmplitudeAttr).IsCSSProperty());
 
   EXPECT_FALSE(PropertyHandle(GetCSSPropertyOpacity()).IsSVGAttribute());
   EXPECT_FALSE(PropertyHandle(name).IsSVGAttribute());
-  EXPECT_TRUE(PropertyHandle(amplitudeAttr).IsSVGAttribute());
+  EXPECT_TRUE(PropertyHandle(kAmplitudeAttr).IsSVGAttribute());
 
   EXPECT_FALSE(PropertyHandle(GetCSSPropertyOpacity()).IsCSSCustomProperty());
   EXPECT_TRUE(PropertyHandle(name).IsCSSCustomProperty());
-  EXPECT_FALSE(PropertyHandle(amplitudeAttr).IsCSSCustomProperty());
+  EXPECT_FALSE(PropertyHandle(kAmplitudeAttr).IsCSSCustomProperty());
 
   EXPECT_EQ(
       PropertyHandle(GetCSSPropertyOpacity()).GetCSSProperty().PropertyID(),
@@ -115,7 +116,7 @@
   EXPECT_EQ(PropertyHandle(name).GetCSSProperty().PropertyID(),
             CSSPropertyVariable);
   EXPECT_EQ(PropertyHandle(name).CustomPropertyName(), name);
-  EXPECT_EQ(PropertyHandle(amplitudeAttr).SvgAttribute(), amplitudeAttr);
+  EXPECT_EQ(PropertyHandle(kAmplitudeAttr).SvgAttribute(), kAmplitudeAttr);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/animation/svg_interpolation_types_map.cc b/third_party/blink/renderer/core/animation/svg_interpolation_types_map.cc
index 9e3b73d..a81333a 100644
--- a/third_party/blink/renderer/core/animation/svg_interpolation_types_map.cc
+++ b/third_party/blink/renderer/core/animation/svg_interpolation_types_map.cc
@@ -37,121 +37,131 @@
       std::make_unique<InterpolationTypes>();
 
   const QualifiedName& attribute = property.SvgAttribute();
-  if (attribute == SVGNames::orientAttr) {
+  if (attribute == svg_names::kOrientAttr) {
     applicable_types->push_back(
         std::make_unique<SVGAngleInterpolationType>(attribute));
-  } else if (attribute == SVGNames::numOctavesAttr ||
-             attribute == SVGNames::targetXAttr ||
-             attribute == SVGNames::targetYAttr) {
+  } else if (attribute == svg_names::kNumOctavesAttr ||
+             attribute == svg_names::kTargetXAttr ||
+             attribute == svg_names::kTargetYAttr) {
     applicable_types->push_back(
         std::make_unique<SVGIntegerInterpolationType>(attribute));
-  } else if (attribute == SVGNames::orderAttr) {
+  } else if (attribute == svg_names::kOrderAttr) {
     applicable_types->push_back(
         std::make_unique<SVGIntegerOptionalIntegerInterpolationType>(
             attribute));
-  } else if (attribute == SVGNames::cxAttr || attribute == SVGNames::cyAttr ||
-             attribute == SVGNames::fxAttr || attribute == SVGNames::fyAttr ||
-             attribute == SVGNames::heightAttr ||
-             attribute == SVGNames::markerHeightAttr ||
-             attribute == SVGNames::markerWidthAttr ||
-             attribute == SVGNames::rAttr || attribute == SVGNames::refXAttr ||
-             attribute == SVGNames::refYAttr || attribute == SVGNames::rxAttr ||
-             attribute == SVGNames::ryAttr ||
-             attribute == SVGNames::startOffsetAttr ||
-             attribute == SVGNames::textLengthAttr ||
-             attribute == SVGNames::widthAttr ||
-             attribute == SVGNames::x1Attr || attribute == SVGNames::x2Attr ||
-             attribute == SVGNames::y1Attr || attribute == SVGNames::y2Attr) {
+  } else if (attribute == svg_names::kCxAttr ||
+             attribute == svg_names::kCyAttr ||
+             attribute == svg_names::kFxAttr ||
+             attribute == svg_names::kFyAttr ||
+             attribute == svg_names::kHeightAttr ||
+             attribute == svg_names::kMarkerHeightAttr ||
+             attribute == svg_names::kMarkerWidthAttr ||
+             attribute == svg_names::kRAttr ||
+             attribute == svg_names::kRefXAttr ||
+             attribute == svg_names::kRefYAttr ||
+             attribute == svg_names::kRxAttr ||
+             attribute == svg_names::kRyAttr ||
+             attribute == svg_names::kStartOffsetAttr ||
+             attribute == svg_names::kTextLengthAttr ||
+             attribute == svg_names::kWidthAttr ||
+             attribute == svg_names::kX1Attr ||
+             attribute == svg_names::kX2Attr ||
+             attribute == svg_names::kY1Attr ||
+             attribute == svg_names::kY2Attr) {
     applicable_types->push_back(
         std::make_unique<SVGLengthInterpolationType>(attribute));
-  } else if (attribute == SVGNames::dxAttr || attribute == SVGNames::dyAttr) {
+  } else if (attribute == svg_names::kDxAttr ||
+             attribute == svg_names::kDyAttr) {
     applicable_types->push_back(
         std::make_unique<SVGNumberInterpolationType>(attribute));
     applicable_types->push_back(
         std::make_unique<SVGLengthListInterpolationType>(attribute));
-  } else if (attribute == SVGNames::xAttr || attribute == SVGNames::yAttr) {
+  } else if (attribute == svg_names::kXAttr || attribute == svg_names::kYAttr) {
     applicable_types->push_back(
         std::make_unique<SVGLengthInterpolationType>(attribute));
     applicable_types->push_back(
         std::make_unique<SVGLengthListInterpolationType>(attribute));
-  } else if (attribute == SVGNames::amplitudeAttr ||
-             attribute == SVGNames::azimuthAttr ||
-             attribute == SVGNames::biasAttr ||
-             attribute == SVGNames::diffuseConstantAttr ||
-             attribute == SVGNames::divisorAttr ||
-             attribute == SVGNames::elevationAttr ||
-             attribute == SVGNames::exponentAttr ||
-             attribute == SVGNames::interceptAttr ||
-             attribute == SVGNames::k1Attr || attribute == SVGNames::k2Attr ||
-             attribute == SVGNames::k3Attr || attribute == SVGNames::k4Attr ||
-             attribute == SVGNames::limitingConeAngleAttr ||
-             attribute == SVGNames::offsetAttr ||
-             attribute == SVGNames::pathLengthAttr ||
-             attribute == SVGNames::pointsAtXAttr ||
-             attribute == SVGNames::pointsAtYAttr ||
-             attribute == SVGNames::pointsAtZAttr ||
-             attribute == SVGNames::scaleAttr ||
-             attribute == SVGNames::seedAttr ||
-             attribute == SVGNames::slopeAttr ||
-             attribute == SVGNames::specularConstantAttr ||
-             attribute == SVGNames::specularExponentAttr ||
-             attribute == SVGNames::surfaceScaleAttr ||
-             attribute == SVGNames::zAttr) {
+  } else if (attribute == svg_names::kAmplitudeAttr ||
+             attribute == svg_names::kAzimuthAttr ||
+             attribute == svg_names::kBiasAttr ||
+             attribute == svg_names::kDiffuseConstantAttr ||
+             attribute == svg_names::kDivisorAttr ||
+             attribute == svg_names::kElevationAttr ||
+             attribute == svg_names::kExponentAttr ||
+             attribute == svg_names::kInterceptAttr ||
+             attribute == svg_names::kK1Attr ||
+             attribute == svg_names::kK2Attr ||
+             attribute == svg_names::kK3Attr ||
+             attribute == svg_names::kK4Attr ||
+             attribute == svg_names::kLimitingConeAngleAttr ||
+             attribute == svg_names::kOffsetAttr ||
+             attribute == svg_names::kPathLengthAttr ||
+             attribute == svg_names::kPointsAtXAttr ||
+             attribute == svg_names::kPointsAtYAttr ||
+             attribute == svg_names::kPointsAtZAttr ||
+             attribute == svg_names::kScaleAttr ||
+             attribute == svg_names::kSeedAttr ||
+             attribute == svg_names::kSlopeAttr ||
+             attribute == svg_names::kSpecularConstantAttr ||
+             attribute == svg_names::kSpecularExponentAttr ||
+             attribute == svg_names::kSurfaceScaleAttr ||
+             attribute == svg_names::kZAttr) {
     applicable_types->push_back(
         std::make_unique<SVGNumberInterpolationType>(attribute));
-  } else if (attribute == SVGNames::kernelMatrixAttr ||
-             attribute == SVGNames::rotateAttr ||
-             attribute == SVGNames::tableValuesAttr ||
-             attribute == SVGNames::valuesAttr) {
+  } else if (attribute == svg_names::kKernelMatrixAttr ||
+             attribute == svg_names::kRotateAttr ||
+             attribute == svg_names::kTableValuesAttr ||
+             attribute == svg_names::kValuesAttr) {
     applicable_types->push_back(
         std::make_unique<SVGNumberListInterpolationType>(attribute));
-  } else if (attribute == SVGNames::baseFrequencyAttr ||
-             attribute == SVGNames::kernelUnitLengthAttr ||
-             attribute == SVGNames::radiusAttr ||
-             attribute == SVGNames::stdDeviationAttr) {
+  } else if (attribute == svg_names::kBaseFrequencyAttr ||
+             attribute == svg_names::kKernelUnitLengthAttr ||
+             attribute == svg_names::kRadiusAttr ||
+             attribute == svg_names::kStdDeviationAttr) {
     applicable_types->push_back(
         std::make_unique<SVGNumberOptionalNumberInterpolationType>(attribute));
-  } else if (attribute == SVGNames::dAttr) {
+  } else if (attribute == svg_names::kDAttr) {
     applicable_types->push_back(
         std::make_unique<SVGPathInterpolationType>(attribute));
-  } else if (attribute == SVGNames::pointsAttr) {
+  } else if (attribute == svg_names::kPointsAttr) {
     applicable_types->push_back(
         std::make_unique<SVGPointListInterpolationType>(attribute));
-  } else if (attribute == SVGNames::viewBoxAttr) {
+  } else if (attribute == svg_names::kViewBoxAttr) {
     applicable_types->push_back(
         std::make_unique<SVGRectInterpolationType>(attribute));
-  } else if (attribute == SVGNames::gradientTransformAttr ||
-             attribute == SVGNames::patternTransformAttr ||
-             attribute == SVGNames::transformAttr) {
+  } else if (attribute == svg_names::kGradientTransformAttr ||
+             attribute == svg_names::kPatternTransformAttr ||
+             attribute == svg_names::kTransformAttr) {
     applicable_types->push_back(
         std::make_unique<SVGTransformListInterpolationType>(attribute));
   } else if (attribute == HTMLNames::classAttr ||
-             attribute == SVGNames::clipPathUnitsAttr ||
-             attribute == SVGNames::edgeModeAttr ||
-             attribute == SVGNames::filterUnitsAttr ||
-             attribute == SVGNames::gradientUnitsAttr ||
-             attribute == SVGNames::hrefAttr || attribute == SVGNames::inAttr ||
-             attribute == SVGNames::in2Attr ||
-             attribute == SVGNames::lengthAdjustAttr ||
-             attribute == SVGNames::markerUnitsAttr ||
-             attribute == SVGNames::maskContentUnitsAttr ||
-             attribute == SVGNames::maskUnitsAttr ||
-             attribute == SVGNames::methodAttr ||
-             attribute == SVGNames::modeAttr ||
-             attribute == SVGNames::operatorAttr ||
-             attribute == SVGNames::patternContentUnitsAttr ||
-             attribute == SVGNames::patternUnitsAttr ||
-             attribute == SVGNames::preserveAlphaAttr ||
-             attribute == SVGNames::preserveAspectRatioAttr ||
-             attribute == SVGNames::primitiveUnitsAttr ||
-             attribute == SVGNames::resultAttr ||
-             attribute == SVGNames::spacingAttr ||
-             attribute == SVGNames::spreadMethodAttr ||
-             attribute == SVGNames::stitchTilesAttr ||
-             attribute == SVGNames::targetAttr ||
-             attribute == SVGNames::typeAttr ||
-             attribute == SVGNames::xChannelSelectorAttr ||
-             attribute == SVGNames::yChannelSelectorAttr) {
+             attribute == svg_names::kClipPathUnitsAttr ||
+             attribute == svg_names::kEdgeModeAttr ||
+             attribute == svg_names::kFilterUnitsAttr ||
+             attribute == svg_names::kGradientUnitsAttr ||
+             attribute == svg_names::kHrefAttr ||
+             attribute == svg_names::kInAttr ||
+             attribute == svg_names::kIn2Attr ||
+             attribute == svg_names::kLengthAdjustAttr ||
+             attribute == svg_names::kMarkerUnitsAttr ||
+             attribute == svg_names::kMaskContentUnitsAttr ||
+             attribute == svg_names::kMaskUnitsAttr ||
+             attribute == svg_names::kMethodAttr ||
+             attribute == svg_names::kModeAttr ||
+             attribute == svg_names::kOperatorAttr ||
+             attribute == svg_names::kPatternContentUnitsAttr ||
+             attribute == svg_names::kPatternUnitsAttr ||
+             attribute == svg_names::kPreserveAlphaAttr ||
+             attribute == svg_names::kPreserveAspectRatioAttr ||
+             attribute == svg_names::kPrimitiveUnitsAttr ||
+             attribute == svg_names::kResultAttr ||
+             attribute == svg_names::kSpacingAttr ||
+             attribute == svg_names::kSpreadMethodAttr ||
+             attribute == svg_names::kStitchTilesAttr ||
+             attribute == svg_names::kTargetAttr ||
+             attribute == svg_names::kTypeAttr ||
+             attribute == svg_names::kXChannelSelectorAttr ||
+             attribute == svg_names::kYChannelSelectorAttr) {
     // Use default SVGValueInterpolationType.
   } else {
     NOTREACHED();
diff --git a/third_party/blink/renderer/core/animation/svg_number_interpolation_type.h b/third_party/blink/renderer/core/animation/svg_number_interpolation_type.h
index 02a01fb..9afe9be 100644
--- a/third_party/blink/renderer/core/animation/svg_number_interpolation_type.h
+++ b/third_party/blink/renderer/core/animation/svg_number_interpolation_type.h
@@ -14,7 +14,7 @@
  public:
   SVGNumberInterpolationType(const QualifiedName& attribute)
       : SVGInterpolationType(attribute),
-        is_non_negative_(attribute == SVGNames::pathLengthAttr) {}
+        is_non_negative_(attribute == svg_names::kPathLengthAttr) {}
 
  private:
   InterpolationValue MaybeConvertNeutral(const InterpolationValue& underlying,
diff --git a/third_party/blink/renderer/core/core_initializer.cc b/third_party/blink/renderer/core/core_initializer.cc
index 7183ea41..cdfd7c9 100644
--- a/third_party/blink/renderer/core/core_initializer.cc
+++ b/third_party/blink/renderer/core/core_initializer.cc
@@ -91,8 +91,9 @@
   const unsigned kQualifiedNamesCount =
       HTMLNames::kTagsCount + HTMLNames::kAttrsCount +
       mathml_names::kTagsCount + mathml_names::kAttrsCount +
-      SVGNames::kTagsCount + SVGNames::kAttrsCount + xlink_names::kAttrsCount +
-      xml_names::kAttrsCount + xmlns_names::kAttrsCount;
+      svg_names::kTagsCount + svg_names::kAttrsCount +
+      xlink_names::kAttrsCount + xml_names::kAttrsCount +
+      xmlns_names::kAttrsCount;
 
   const unsigned kCoreStaticStringsCount =
       kQualifiedNamesCount + EventNames::kNamesCount +
@@ -100,7 +101,7 @@
       FetchInitiatorTypeNames::kNamesCount + FontFamilyNames::kNamesCount +
       HTMLTokenizerNames::kNamesCount + HTTPNames::kNamesCount +
       InputModeNames::kNamesCount + InputTypeNames::kNamesCount +
-      MediaFeatureNames::kNamesCount + media_type_names::kNamesCount +
+      media_feature_names::kNamesCount + media_type_names::kNamesCount +
       performance_entry_names::kNamesCount;
 
   StringImpl::ReserveStaticStringsCapacityForSize(
@@ -110,8 +111,8 @@
   AtomicStringTable::Instance().ReserveCapacity(kCoreStaticStringsCount);
 
   HTMLNames::init();
-  SVGNames::init();
   mathml_names::init();
+  svg_names::init();
   xlink_names::init();
   xml_names::init();
   xmlns_names::init();
@@ -125,7 +126,7 @@
   HTTPNames::init();
   InputModeNames::init();
   InputTypeNames::init();
-  MediaFeatureNames::init();
+  media_feature_names::init();
   media_type_names::init();
   performance_entry_names::init();
 
diff --git a/third_party/blink/renderer/core/css/media_feature_names.json5 b/third_party/blink/renderer/core/css/media_feature_names.json5
index c36a0f83..4640d1a 100644
--- a/third_party/blink/renderer/core/css/media_feature_names.json5
+++ b/third_party/blink/renderer/core/css/media_feature_names.json5
@@ -1,6 +1,6 @@
 {
   metadata: {
-    namespace: "MediaFeature",
+    namespace: "media_feature_names",
     export: "",
   },
 
diff --git a/third_party/blink/renderer/core/css/media_query_evaluator.cc b/third_party/blink/renderer/core/css/media_query_evaluator.cc
index 328dbfe..e0e5ca2 100644
--- a/third_party/blink/renderer/core/css/media_query_evaluator.cc
+++ b/third_party/blink/renderer/core/css/media_query_evaluator.cc
@@ -55,7 +55,7 @@
 
 namespace blink {
 
-using namespace MediaFeatureNames;
+using namespace media_feature_names;
 
 enum MediaFeaturePrefix { kMinPrefix, kMaxPrefix, kNoPrefix };
 
diff --git a/third_party/blink/renderer/core/css/media_query_exp.cc b/third_party/blink/renderer/core/css/media_query_exp.cc
index b61a883..13b35b03 100644
--- a/third_party/blink/renderer/core/css/media_query_exp.cc
+++ b/third_party/blink/renderer/core/css/media_query_exp.cc
@@ -39,35 +39,35 @@
 
 namespace blink {
 
-using namespace MediaFeatureNames;
+using namespace media_feature_names;
 
 static inline bool FeatureWithValidIdent(const String& media_feature,
                                          CSSValueID ident) {
-  if (media_feature == displayModeMediaFeature)
+  if (media_feature == kDisplayModeMediaFeature)
     return ident == CSSValueFullscreen || ident == CSSValueStandalone ||
            ident == CSSValueMinimalUi || ident == CSSValueBrowser;
 
-  if (media_feature == orientationMediaFeature)
+  if (media_feature == kOrientationMediaFeature)
     return ident == CSSValuePortrait || ident == CSSValueLandscape;
 
-  if (media_feature == pointerMediaFeature ||
-      media_feature == anyPointerMediaFeature)
+  if (media_feature == kPointerMediaFeature ||
+      media_feature == kAnyPointerMediaFeature)
     return ident == CSSValueNone || ident == CSSValueCoarse ||
            ident == CSSValueFine;
 
-  if (media_feature == hoverMediaFeature ||
-      media_feature == anyHoverMediaFeature)
+  if (media_feature == kHoverMediaFeature ||
+      media_feature == kAnyHoverMediaFeature)
     return ident == CSSValueNone || ident == CSSValueHover;
 
-  if (media_feature == scanMediaFeature)
+  if (media_feature == kScanMediaFeature)
     return ident == CSSValueInterlace || ident == CSSValueProgressive;
 
   if (RuntimeEnabledFeatures::MediaQueryShapeEnabled()) {
-    if (media_feature == shapeMediaFeature)
+    if (media_feature == kShapeMediaFeature)
       return ident == CSSValueRect || ident == CSSValueRound;
   }
 
-  if (media_feature == colorGamutMediaFeature) {
+  if (media_feature == kColorGamutMediaFeature) {
     return ident == CSSValueSRGB || ident == CSSValueP3 ||
            ident == CSSValueRec2020;
   }
@@ -82,18 +82,18 @@
         (value->IsNumber() && value->GetDoubleValue() == 0)))
     return false;
 
-  return media_feature == heightMediaFeature ||
-         media_feature == maxHeightMediaFeature ||
-         media_feature == minHeightMediaFeature ||
-         media_feature == widthMediaFeature ||
-         media_feature == maxWidthMediaFeature ||
-         media_feature == minWidthMediaFeature ||
-         media_feature == deviceHeightMediaFeature ||
-         media_feature == maxDeviceHeightMediaFeature ||
-         media_feature == minDeviceHeightMediaFeature ||
-         media_feature == deviceWidthMediaFeature ||
-         media_feature == minDeviceWidthMediaFeature ||
-         media_feature == maxDeviceWidthMediaFeature;
+  return media_feature == kHeightMediaFeature ||
+         media_feature == kMaxHeightMediaFeature ||
+         media_feature == kMinHeightMediaFeature ||
+         media_feature == kWidthMediaFeature ||
+         media_feature == kMaxWidthMediaFeature ||
+         media_feature == kMinWidthMediaFeature ||
+         media_feature == kDeviceHeightMediaFeature ||
+         media_feature == kMaxDeviceHeightMediaFeature ||
+         media_feature == kMinDeviceHeightMediaFeature ||
+         media_feature == kDeviceWidthMediaFeature ||
+         media_feature == kMinDeviceWidthMediaFeature ||
+         media_feature == kMaxDeviceWidthMediaFeature;
 }
 
 static inline bool FeatureWithValidDensity(const String& media_feature,
@@ -107,23 +107,23 @@
       value->GetDoubleValue() <= 0)
     return false;
 
-  return media_feature == resolutionMediaFeature ||
-         media_feature == minResolutionMediaFeature ||
-         media_feature == maxResolutionMediaFeature;
+  return media_feature == kResolutionMediaFeature ||
+         media_feature == kMinResolutionMediaFeature ||
+         media_feature == kMaxResolutionMediaFeature;
 }
 
 static inline bool FeatureExpectingPositiveInteger(
     const String& media_feature) {
-  return media_feature == colorMediaFeature ||
-         media_feature == maxColorMediaFeature ||
-         media_feature == minColorMediaFeature ||
-         media_feature == colorIndexMediaFeature ||
-         media_feature == maxColorIndexMediaFeature ||
-         media_feature == minColorIndexMediaFeature ||
-         media_feature == monochromeMediaFeature ||
-         media_feature == maxMonochromeMediaFeature ||
-         media_feature == minMonochromeMediaFeature ||
-         media_feature == immersiveMediaFeature;
+  return media_feature == kColorMediaFeature ||
+         media_feature == kMaxColorMediaFeature ||
+         media_feature == kMinColorMediaFeature ||
+         media_feature == kColorIndexMediaFeature ||
+         media_feature == kMaxColorIndexMediaFeature ||
+         media_feature == kMinColorIndexMediaFeature ||
+         media_feature == kMonochromeMediaFeature ||
+         media_feature == kMaxMonochromeMediaFeature ||
+         media_feature == kMinMonochromeMediaFeature ||
+         media_feature == kImmersiveMediaFeature;
 }
 
 static inline bool FeatureWithPositiveInteger(const String& media_feature,
@@ -138,10 +138,10 @@
   if (!value->IsNumber())
     return false;
 
-  return media_feature == transform3dMediaFeature ||
-         media_feature == devicePixelRatioMediaFeature ||
-         media_feature == maxDevicePixelRatioMediaFeature ||
-         media_feature == minDevicePixelRatioMediaFeature;
+  return media_feature == kTransform3dMediaFeature ||
+         media_feature == kDevicePixelRatioMediaFeature ||
+         media_feature == kMaxDevicePixelRatioMediaFeature ||
+         media_feature == kMinDevicePixelRatioMediaFeature;
 }
 
 static inline bool FeatureWithZeroOrOne(const String& media_feature,
@@ -150,73 +150,73 @@
       !(value->GetDoubleValue() == 1 || !value->GetDoubleValue()))
     return false;
 
-  return media_feature == gridMediaFeature;
+  return media_feature == kGridMediaFeature;
 }
 
 static inline bool FeatureWithAspectRatio(const String& media_feature) {
-  return media_feature == aspectRatioMediaFeature ||
-         media_feature == deviceAspectRatioMediaFeature ||
-         media_feature == minAspectRatioMediaFeature ||
-         media_feature == maxAspectRatioMediaFeature ||
-         media_feature == minDeviceAspectRatioMediaFeature ||
-         media_feature == maxDeviceAspectRatioMediaFeature;
+  return media_feature == kAspectRatioMediaFeature ||
+         media_feature == kDeviceAspectRatioMediaFeature ||
+         media_feature == kMinAspectRatioMediaFeature ||
+         media_feature == kMaxAspectRatioMediaFeature ||
+         media_feature == kMinDeviceAspectRatioMediaFeature ||
+         media_feature == kMaxDeviceAspectRatioMediaFeature;
 }
 
 static inline bool FeatureWithoutValue(const String& media_feature) {
   // Media features that are prefixed by min/max cannot be used without a value.
-  return media_feature == monochromeMediaFeature ||
-         media_feature == colorMediaFeature ||
-         media_feature == colorIndexMediaFeature ||
-         media_feature == gridMediaFeature ||
-         media_feature == heightMediaFeature ||
-         media_feature == widthMediaFeature ||
-         media_feature == deviceHeightMediaFeature ||
-         media_feature == deviceWidthMediaFeature ||
-         media_feature == orientationMediaFeature ||
-         media_feature == aspectRatioMediaFeature ||
-         media_feature == deviceAspectRatioMediaFeature ||
-         media_feature == hoverMediaFeature ||
-         media_feature == anyHoverMediaFeature ||
-         media_feature == transform3dMediaFeature ||
-         media_feature == pointerMediaFeature ||
-         media_feature == anyPointerMediaFeature ||
-         media_feature == devicePixelRatioMediaFeature ||
-         media_feature == resolutionMediaFeature ||
-         media_feature == displayModeMediaFeature ||
-         media_feature == scanMediaFeature ||
-         media_feature == shapeMediaFeature ||
-         media_feature == colorGamutMediaFeature ||
-         media_feature == immersiveMediaFeature;
+  return media_feature == kMonochromeMediaFeature ||
+         media_feature == kColorMediaFeature ||
+         media_feature == kColorIndexMediaFeature ||
+         media_feature == kGridMediaFeature ||
+         media_feature == kHeightMediaFeature ||
+         media_feature == kWidthMediaFeature ||
+         media_feature == kDeviceHeightMediaFeature ||
+         media_feature == kDeviceWidthMediaFeature ||
+         media_feature == kOrientationMediaFeature ||
+         media_feature == kAspectRatioMediaFeature ||
+         media_feature == kDeviceAspectRatioMediaFeature ||
+         media_feature == kHoverMediaFeature ||
+         media_feature == kAnyHoverMediaFeature ||
+         media_feature == kTransform3dMediaFeature ||
+         media_feature == kPointerMediaFeature ||
+         media_feature == kAnyPointerMediaFeature ||
+         media_feature == kDevicePixelRatioMediaFeature ||
+         media_feature == kResolutionMediaFeature ||
+         media_feature == kDisplayModeMediaFeature ||
+         media_feature == kScanMediaFeature ||
+         media_feature == kShapeMediaFeature ||
+         media_feature == kColorGamutMediaFeature ||
+         media_feature == kImmersiveMediaFeature;
 }
 
 bool MediaQueryExp::IsViewportDependent() const {
-  return media_feature_ == widthMediaFeature ||
-         media_feature_ == heightMediaFeature ||
-         media_feature_ == minWidthMediaFeature ||
-         media_feature_ == minHeightMediaFeature ||
-         media_feature_ == maxWidthMediaFeature ||
-         media_feature_ == maxHeightMediaFeature ||
-         media_feature_ == orientationMediaFeature ||
-         media_feature_ == aspectRatioMediaFeature ||
-         media_feature_ == minAspectRatioMediaFeature ||
-         media_feature_ == devicePixelRatioMediaFeature ||
-         media_feature_ == resolutionMediaFeature ||
-         media_feature_ == maxAspectRatioMediaFeature ||
-         media_feature_ == maxDevicePixelRatioMediaFeature ||
-         media_feature_ == minDevicePixelRatioMediaFeature;
+  return media_feature_ == kWidthMediaFeature ||
+         media_feature_ == kHeightMediaFeature ||
+         media_feature_ == kMinWidthMediaFeature ||
+         media_feature_ == kMinHeightMediaFeature ||
+         media_feature_ == kMaxWidthMediaFeature ||
+         media_feature_ == kMaxHeightMediaFeature ||
+         media_feature_ == kOrientationMediaFeature ||
+         media_feature_ == kAspectRatioMediaFeature ||
+         media_feature_ == kMinAspectRatioMediaFeature ||
+         media_feature_ == kDevicePixelRatioMediaFeature ||
+         media_feature_ == kResolutionMediaFeature ||
+         media_feature_ == kMaxAspectRatioMediaFeature ||
+         media_feature_ == kMaxDevicePixelRatioMediaFeature ||
+         media_feature_ == kMinDevicePixelRatioMediaFeature;
 }
 
 bool MediaQueryExp::IsDeviceDependent() const {
-  return media_feature_ == deviceAspectRatioMediaFeature ||
-         media_feature_ == deviceWidthMediaFeature ||
-         media_feature_ == deviceHeightMediaFeature ||
-         media_feature_ == minDeviceAspectRatioMediaFeature ||
-         media_feature_ == minDeviceWidthMediaFeature ||
-         media_feature_ == minDeviceHeightMediaFeature ||
-         media_feature_ == maxDeviceAspectRatioMediaFeature ||
-         media_feature_ == maxDeviceWidthMediaFeature ||
-         media_feature_ == maxDeviceHeightMediaFeature ||
-         media_feature_ == shapeMediaFeature;
+  return media_feature_ == kDeviceAspectRatioMediaFeature ||
+         media_feature_ == kDeviceWidthMediaFeature ||
+         media_feature_ == kDeviceHeightMediaFeature ||
+         media_feature_ == kMinDeviceAspectRatioMediaFeature ||
+         media_feature_ == kMinDeviceWidthMediaFeature ||
+         media_feature_ == kMinDeviceHeightMediaFeature ||
+         media_feature_ == kMaxDeviceAspectRatioMediaFeature ||
+         media_feature_ == kMaxDeviceWidthMediaFeature ||
+         media_feature_ == kMaxDeviceHeightMediaFeature ||
+         media_feature_ == kShapeMediaFeature;
 }
 
 MediaQueryExp::MediaQueryExp(const MediaQueryExp& other)
diff --git a/third_party/blink/renderer/core/css/parser/css_property_parser_helpers.cc b/third_party/blink/renderer/core/css/parser/css_property_parser_helpers.cc
index 590bfa4a..d055e28a 100644
--- a/third_party/blink/renderer/core/css/parser/css_property_parser_helpers.cc
+++ b/third_party/blink/renderer/core/css/parser/css_property_parser_helpers.cc
@@ -419,6 +419,28 @@
   return nullptr;
 }
 
+namespace {
+
+bool IsNonZeroUserUnitsValue(const CSSPrimitiveValue* value) {
+  return value &&
+         value->TypeWithCalcResolved() ==
+             CSSPrimitiveValue::UnitType::kUserUnits &&
+         value->GetDoubleValue() != 0;
+}
+
+}  // namespace
+
+CSSPrimitiveValue* ConsumeSVGGeometryPropertyLength(
+    CSSParserTokenRange& range,
+    const CSSParserContext& context) {
+  // TODO(fs): Not all callers should be using kValueRangeAll.
+  CSSPrimitiveValue* value = ConsumeLengthOrPercent(
+      range, kSVGAttributeMode, kValueRangeAll, UnitlessQuirk::kForbid);
+  if (IsNonZeroUserUnitsValue(value))
+    context.Count(WebFeature::kSVGGeometryPropertyHasNonZeroUnitlessValue);
+  return value;
+}
+
 CSSPrimitiveValue* ConsumeGradientLengthOrPercent(
     CSSParserTokenRange& range,
     const CSSParserContext& context,
diff --git a/third_party/blink/renderer/core/css/parser/css_property_parser_helpers.h b/third_party/blink/renderer/core/css/parser/css_property_parser_helpers.h
index fa046f17..ca925eda 100644
--- a/third_party/blink/renderer/core/css/parser/css_property_parser_helpers.h
+++ b/third_party/blink/renderer/core/css/parser/css_property_parser_helpers.h
@@ -59,6 +59,8 @@
     CSSParserMode,
     ValueRange,
     UnitlessQuirk = UnitlessQuirk::kForbid);
+CSSPrimitiveValue* ConsumeSVGGeometryPropertyLength(CSSParserTokenRange&,
+                                                    const CSSParserContext&);
 
 CSSPrimitiveValue* ConsumeAngle(
     CSSParserTokenRange&,
diff --git a/third_party/blink/renderer/core/css/parser/css_property_parser_test.cc b/third_party/blink/renderer/core/css/parser/css_property_parser_test.cc
index 89b0b1b..20911b6 100644
--- a/third_party/blink/renderer/core/css/parser/css_property_parser_test.cc
+++ b/third_party/blink/renderer/core/css/parser/css_property_parser_test.cc
@@ -457,4 +457,101 @@
       IsValidPropertyValueForStyleRule(CSSPropertySrc, "var(--dummy)"));
 }
 
+class CSSPropertyUseCounterTest : public ::testing::Test {
+ public:
+  void SetUp() override {
+    dummy_page_holder_ = DummyPageHolder::Create(IntSize(800, 600));
+    Page::InsertOrdinaryPageForTesting(&dummy_page_holder_->GetPage());
+    // Use strict mode.
+    GetDocument().SetCompatibilityMode(Document::kNoQuirksMode);
+  }
+  void TearDown() override { dummy_page_holder_ = nullptr; }
+
+  void ParseProperty(CSSPropertyID property, const char* value_string) {
+    const CSSValue* value =
+        CSSParser::ParseSingleValue(property, String(value_string),
+                                    CSSParserContext::Create(GetDocument()));
+    DCHECK(value);
+  }
+
+  bool IsCounted(WebFeature feature) {
+    return UseCounter::IsCounted(GetDocument(), feature);
+  }
+
+ private:
+  Document& GetDocument() { return dummy_page_holder_->GetDocument(); }
+
+  std::unique_ptr<DummyPageHolder> dummy_page_holder_;
+};
+
+TEST_F(CSSPropertyUseCounterTest, CSSPropertyXUnitlessUseCount) {
+  WebFeature feature = WebFeature::kSVGGeometryPropertyHasNonZeroUnitlessValue;
+  EXPECT_FALSE(IsCounted(feature));
+  ParseProperty(CSSPropertyX, "0");
+  // Unitless zero should not register.
+  EXPECT_FALSE(IsCounted(feature));
+  ParseProperty(CSSPropertyX, "42");
+  EXPECT_TRUE(IsCounted(feature));
+}
+
+TEST_F(CSSPropertyUseCounterTest, CSSPropertyYUnitlessUseCount) {
+  WebFeature feature = WebFeature::kSVGGeometryPropertyHasNonZeroUnitlessValue;
+  EXPECT_FALSE(IsCounted(feature));
+  ParseProperty(CSSPropertyY, "0");
+  // Unitless zero should not register.
+  EXPECT_FALSE(IsCounted(feature));
+  ParseProperty(CSSPropertyY, "42");
+  EXPECT_TRUE(IsCounted(feature));
+}
+
+TEST_F(CSSPropertyUseCounterTest, CSSPropertyRUnitlessUseCount) {
+  WebFeature feature = WebFeature::kSVGGeometryPropertyHasNonZeroUnitlessValue;
+  EXPECT_FALSE(IsCounted(feature));
+  ParseProperty(CSSPropertyR, "0");
+  // Unitless zero should not register.
+  EXPECT_FALSE(IsCounted(feature));
+  ParseProperty(CSSPropertyR, "42");
+  EXPECT_TRUE(IsCounted(feature));
+}
+
+TEST_F(CSSPropertyUseCounterTest, CSSPropertyRxUnitlessUseCount) {
+  WebFeature feature = WebFeature::kSVGGeometryPropertyHasNonZeroUnitlessValue;
+  EXPECT_FALSE(IsCounted(feature));
+  ParseProperty(CSSPropertyRx, "0");
+  // Unitless zero should not register.
+  EXPECT_FALSE(IsCounted(feature));
+  ParseProperty(CSSPropertyRx, "42");
+  EXPECT_TRUE(IsCounted(feature));
+}
+
+TEST_F(CSSPropertyUseCounterTest, CSSPropertyRyUnitlessUseCount) {
+  WebFeature feature = WebFeature::kSVGGeometryPropertyHasNonZeroUnitlessValue;
+  EXPECT_FALSE(IsCounted(feature));
+  ParseProperty(CSSPropertyRy, "0");
+  // Unitless zero should not register.
+  EXPECT_FALSE(IsCounted(feature));
+  ParseProperty(CSSPropertyRy, "42");
+  EXPECT_TRUE(IsCounted(feature));
+}
+
+TEST_F(CSSPropertyUseCounterTest, CSSPropertyCxUnitlessUseCount) {
+  WebFeature feature = WebFeature::kSVGGeometryPropertyHasNonZeroUnitlessValue;
+  EXPECT_FALSE(IsCounted(feature));
+  ParseProperty(CSSPropertyCx, "0");
+  // Unitless zero should not register.
+  EXPECT_FALSE(IsCounted(feature));
+  ParseProperty(CSSPropertyCx, "42");
+  EXPECT_TRUE(IsCounted(feature));
+}
+
+TEST_F(CSSPropertyUseCounterTest, CSSPropertyCyUnitlessUseCount) {
+  WebFeature feature = WebFeature::kSVGGeometryPropertyHasNonZeroUnitlessValue;
+  EXPECT_FALSE(IsCounted(feature));
+  ParseProperty(CSSPropertyCy, "0");
+  // Unitless zero should not register.
+  EXPECT_FALSE(IsCounted(feature));
+  ParseProperty(CSSPropertyCy, "42");
+  EXPECT_TRUE(IsCounted(feature));
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/css/parser/media_query_parser.cc b/third_party/blink/renderer/core/css/parser/media_query_parser.cc
index 29235af..0dcf599e 100644
--- a/third_party/blink/renderer/core/css/parser/media_query_parser.cc
+++ b/third_party/blink/renderer/core/css/parser/media_query_parser.cc
@@ -283,7 +283,7 @@
 bool MediaQueryParser::IsMediaFeatureAllowedInMode(
     const String& media_feature) const {
   return mode_ == kUASheetMode ||
-         media_feature != MediaFeatureNames::immersiveMediaFeature;
+         media_feature != media_feature_names::kImmersiveMediaFeature;
 }
 
 MediaQueryData::MediaQueryData()
diff --git a/third_party/blink/renderer/core/css/properties/longhands/cx_custom.cc b/third_party/blink/renderer/core/css/properties/longhands/cx_custom.cc
index 2acdba9..cc143319 100644
--- a/third_party/blink/renderer/core/css/properties/longhands/cx_custom.cc
+++ b/third_party/blink/renderer/core/css/properties/longhands/cx_custom.cc
@@ -11,11 +11,10 @@
 namespace CSSLonghand {
 
 const CSSValue* Cx::ParseSingleValue(CSSParserTokenRange& range,
-                                     const CSSParserContext&,
+                                     const CSSParserContext& context,
                                      const CSSParserLocalContext&) const {
-  return CSSPropertyParserHelpers::ConsumeLengthOrPercent(
-      range, kSVGAttributeMode, kValueRangeAll,
-      CSSPropertyParserHelpers::UnitlessQuirk::kForbid);
+  return CSSPropertyParserHelpers::ConsumeSVGGeometryPropertyLength(range,
+                                                                    context);
 }
 
 const CSSValue* Cx::CSSValueFromComputedStyleInternal(
diff --git a/third_party/blink/renderer/core/css/properties/longhands/cy_custom.cc b/third_party/blink/renderer/core/css/properties/longhands/cy_custom.cc
index e3bc5b1d..638d9f9f 100644
--- a/third_party/blink/renderer/core/css/properties/longhands/cy_custom.cc
+++ b/third_party/blink/renderer/core/css/properties/longhands/cy_custom.cc
@@ -11,11 +11,10 @@
 namespace CSSLonghand {
 
 const CSSValue* Cy::ParseSingleValue(CSSParserTokenRange& range,
-                                     const CSSParserContext&,
+                                     const CSSParserContext& context,
                                      const CSSParserLocalContext&) const {
-  return CSSPropertyParserHelpers::ConsumeLengthOrPercent(
-      range, kSVGAttributeMode, kValueRangeAll,
-      CSSPropertyParserHelpers::UnitlessQuirk::kForbid);
+  return CSSPropertyParserHelpers::ConsumeSVGGeometryPropertyLength(range,
+                                                                    context);
 }
 
 const CSSValue* Cy::CSSValueFromComputedStyleInternal(
diff --git a/third_party/blink/renderer/core/css/properties/longhands/r_custom.cc b/third_party/blink/renderer/core/css/properties/longhands/r_custom.cc
index fb272fc..abd14fd 100644
--- a/third_party/blink/renderer/core/css/properties/longhands/r_custom.cc
+++ b/third_party/blink/renderer/core/css/properties/longhands/r_custom.cc
@@ -11,11 +11,10 @@
 namespace CSSLonghand {
 
 const CSSValue* R::ParseSingleValue(CSSParserTokenRange& range,
-                                    const CSSParserContext&,
+                                    const CSSParserContext& context,
                                     const CSSParserLocalContext&) const {
-  return CSSPropertyParserHelpers::ConsumeLengthOrPercent(
-      range, kSVGAttributeMode, kValueRangeAll,
-      CSSPropertyParserHelpers::UnitlessQuirk::kForbid);
+  return CSSPropertyParserHelpers::ConsumeSVGGeometryPropertyLength(range,
+                                                                    context);
 }
 
 const CSSValue* R::CSSValueFromComputedStyleInternal(
diff --git a/third_party/blink/renderer/core/css/properties/longhands/rx_custom.cc b/third_party/blink/renderer/core/css/properties/longhands/rx_custom.cc
index 1df2543f1..50d1f6c 100644
--- a/third_party/blink/renderer/core/css/properties/longhands/rx_custom.cc
+++ b/third_party/blink/renderer/core/css/properties/longhands/rx_custom.cc
@@ -15,9 +15,8 @@
                                      const CSSParserLocalContext&) const {
   if (range.Peek().Id() == CSSValueAuto)
     return CSSPropertyParserHelpers::ConsumeIdent(range);
-  return CSSPropertyParserHelpers::ConsumeLengthOrPercent(
-      range, kSVGAttributeMode, kValueRangeAll,
-      CSSPropertyParserHelpers::UnitlessQuirk::kForbid);
+  return CSSPropertyParserHelpers::ConsumeSVGGeometryPropertyLength(range,
+                                                                    context);
 }
 
 const CSSValue* Rx::CSSValueFromComputedStyleInternal(
diff --git a/third_party/blink/renderer/core/css/properties/longhands/ry_custom.cc b/third_party/blink/renderer/core/css/properties/longhands/ry_custom.cc
index 88d773f..223f1e69 100644
--- a/third_party/blink/renderer/core/css/properties/longhands/ry_custom.cc
+++ b/third_party/blink/renderer/core/css/properties/longhands/ry_custom.cc
@@ -15,9 +15,8 @@
                                      const CSSParserLocalContext&) const {
   if (range.Peek().Id() == CSSValueAuto)
     return CSSPropertyParserHelpers::ConsumeIdent(range);
-  return CSSPropertyParserHelpers::ConsumeLengthOrPercent(
-      range, kSVGAttributeMode, kValueRangeAll,
-      CSSPropertyParserHelpers::UnitlessQuirk::kForbid);
+  return CSSPropertyParserHelpers::ConsumeSVGGeometryPropertyLength(range,
+                                                                    context);
 }
 
 const CSSValue* Ry::CSSValueFromComputedStyleInternal(
diff --git a/third_party/blink/renderer/core/css/properties/longhands/x_custom.cc b/third_party/blink/renderer/core/css/properties/longhands/x_custom.cc
index 1d40a1a..e20bdd7 100644
--- a/third_party/blink/renderer/core/css/properties/longhands/x_custom.cc
+++ b/third_party/blink/renderer/core/css/properties/longhands/x_custom.cc
@@ -11,11 +11,10 @@
 namespace CSSLonghand {
 
 const CSSValue* X::ParseSingleValue(CSSParserTokenRange& range,
-                                    const CSSParserContext&,
+                                    const CSSParserContext& context,
                                     const CSSParserLocalContext&) const {
-  return CSSPropertyParserHelpers::ConsumeLengthOrPercent(
-      range, kSVGAttributeMode, kValueRangeAll,
-      CSSPropertyParserHelpers::UnitlessQuirk::kForbid);
+  return CSSPropertyParserHelpers::ConsumeSVGGeometryPropertyLength(range,
+                                                                    context);
 }
 
 const CSSValue* X::CSSValueFromComputedStyleInternal(
diff --git a/third_party/blink/renderer/core/css/properties/longhands/y_custom.cc b/third_party/blink/renderer/core/css/properties/longhands/y_custom.cc
index 3f11b32..e85cef0e 100644
--- a/third_party/blink/renderer/core/css/properties/longhands/y_custom.cc
+++ b/third_party/blink/renderer/core/css/properties/longhands/y_custom.cc
@@ -11,11 +11,10 @@
 namespace CSSLonghand {
 
 const CSSValue* Y::ParseSingleValue(CSSParserTokenRange& range,
-                                    const CSSParserContext&,
+                                    const CSSParserContext& context,
                                     const CSSParserLocalContext&) const {
-  return CSSPropertyParserHelpers::ConsumeLengthOrPercent(
-      range, kSVGAttributeMode, kValueRangeAll,
-      CSSPropertyParserHelpers::UnitlessQuirk::kForbid);
+  return CSSPropertyParserHelpers::ConsumeSVGGeometryPropertyLength(range,
+                                                                    context);
 }
 
 const CSSValue* Y::CSSValueFromComputedStyleInternal(
diff --git a/third_party/blink/renderer/core/dom/context_features_client_impl.cc b/third_party/blink/renderer/core/dom/context_features_client_impl.cc
index bde295e4..69f26b60 100644
--- a/third_party/blink/renderer/core/dom/context_features_client_impl.cc
+++ b/third_party/blink/renderer/core/dom/context_features_client_impl.cc
@@ -30,8 +30,8 @@
 
 #include "third_party/blink/renderer/core/dom/context_features_client_impl.h"
 
+#include "third_party/blink/public/platform/web_content_settings_client.h"
 #include "third_party/blink/renderer/core/dom/document.h"
-#include "third_party/blink/renderer/core/frame/content_settings_client.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/platform/weborigin/security_origin.h"
 
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc
index 511d80a..f79c16c 100644
--- a/third_party/blink/renderer/core/dom/document.cc
+++ b/third_party/blink/renderer/core/dom/document.cc
@@ -46,6 +46,7 @@
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/public/platform/task_type.h"
 #include "third_party/blink/public/platform/ukm.mojom-blink.h"
+#include "third_party/blink/public/platform/web_content_settings_client.h"
 #include "third_party/blink/public/platform/web_prerendering_support.h"
 #include "third_party/blink/renderer/bindings/core/v8/html_script_element_or_svg_script_element.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_controller.h"
@@ -136,7 +137,6 @@
 #include "third_party/blink/renderer/core/events/visual_viewport_resize_event.h"
 #include "third_party/blink/renderer/core/events/visual_viewport_scroll_event.h"
 #include "third_party/blink/renderer/core/feature_policy/document_policy.h"
-#include "third_party/blink/renderer/core/frame/content_settings_client.h"
 #include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
 #include "third_party/blink/renderer/core/frame/dom_timer.h"
 #include "third_party/blink/renderer/core/frame/dom_visual_viewport.h"
@@ -909,7 +909,7 @@
         element = HTMLUnknownElement::Create(qname, *this);
     }
     saw_elements_in_known_namespaces_ = true;
-  } else if (qname.NamespaceURI() == SVGNames::svgNamespaceURI) {
+  } else if (qname.NamespaceURI() == svg_names::kNamespaceURI) {
     element = SVGElementFactory::Create(qname.LocalName(), *this, flags);
     if (!element)
       element = SVGUnknownElement::Create(qname, *this);
@@ -956,31 +956,27 @@
   return Element::Create(QualifiedName(g_null_atom, name, g_null_atom), this);
 }
 
-String GetTypeExtension(Document* document,
-                        const StringOrDictionary& string_or_options,
-                        ExceptionState& exception_state) {
+AtomicString GetTypeExtension(Document* document,
+                              const StringOrDictionary& string_or_options,
+                              ExceptionState& exception_state) {
   if (string_or_options.IsNull())
-    return String();
+    return AtomicString();
 
   if (string_or_options.IsString()) {
     UseCounter::Count(document,
                       WebFeature::kDocumentCreateElement2ndArgStringHandling);
-    return string_or_options.GetAsString();
+    return AtomicString(string_or_options.GetAsString());
   }
 
   if (string_or_options.IsDictionary()) {
     Dictionary dict = string_or_options.GetAsDictionary();
-    ElementCreationOptions impl;
-    V8ElementCreationOptions::ToImpl(dict.GetIsolate(), dict.V8Value(), impl,
-                                     exception_state);
-    if (exception_state.HadException())
-      return String();
-
-    if (impl.hasIs())
-      return impl.is();
+    v8::Local<v8::Value> value;
+    if (dict.HasProperty("is", exception_state) && dict.Get("is", value)) {
+      return ToCoreAtomicString(v8::Local<v8::String>::Cast(value));
+    }
   }
 
-  return String();
+  return AtomicString();
 }
 
 // https://dom.spec.whatwg.org/#dom-document-createelement
@@ -1014,7 +1010,7 @@
 
   // 3.
   const AtomicString& is =
-      AtomicString(GetTypeExtension(this, string_or_options, exception_state));
+      GetTypeExtension(this, string_or_options, exception_state);
 
   // 5. Let element be the result of creating an element given ...
   Element* element =
@@ -1089,7 +1085,7 @@
 
   // 2.
   const AtomicString& is =
-      AtomicString(GetTypeExtension(this, string_or_options, exception_state));
+      GetTypeExtension(this, string_or_options, exception_state);
 
   if (!IsValidElementName(this, qualified_name)) {
     exception_state.ThrowDOMException(DOMExceptionCode::kInvalidCharacterError,
@@ -6556,20 +6552,20 @@
     return false;
   }
 
-  ContentSettingsClient* settings_client =
-      GetFrame()->GetContentSettingsClient();
-  if (!settings_client)
+  // No scripting on a detached frame.
+  if (!GetFrame()->Client())
     return false;
 
+  WebContentSettingsClient* settings_client =
+      GetFrame()->GetContentSettingsClient();
+
   Settings* settings = GetFrame()->GetSettings();
-  if (!settings_client->AllowScript(settings && settings->GetScriptEnabled())) {
-    if (reason == kAboutToExecuteScript)
-      settings_client->DidNotAllowScript();
-
-    return false;
-  }
-
-  return true;
+  bool script_enabled = settings && settings->GetScriptEnabled();
+  if (settings_client)
+    script_enabled = settings_client->AllowScript(script_enabled);
+  if (!script_enabled && reason == kAboutToExecuteScript && settings_client)
+    settings_client->DidNotAllowScript();
+  return script_enabled;
 }
 
 bool Document::IsRenderingReady() const {
diff --git a/third_party/blink/renderer/core/dom/dom_implementation.cc b/third_party/blink/renderer/core/dom/dom_implementation.cc
index c360933..7f90997 100644
--- a/third_party/blink/renderer/core/dom/dom_implementation.cc
+++ b/third_party/blink/renderer/core/dom/dom_implementation.cc
@@ -84,7 +84,7 @@
   XMLDocument* doc = nullptr;
   DocumentInit init =
       DocumentInit::Create().WithContextDocument(document_->ContextDocument());
-  if (namespace_uri == SVGNames::svgNamespaceURI) {
+  if (namespace_uri == svg_names::kNamespaceURI) {
     doc = XMLDocument::CreateSVG(init);
   } else if (namespace_uri == HTMLNames::xhtmlNamespaceURI) {
     doc = XMLDocument::CreateXHTML(
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc
index 052b5e0..93268fb 100644
--- a/third_party/blink/renderer/core/dom/element.cc
+++ b/third_party/blink/renderer/core/dom/element.cc
@@ -764,9 +764,12 @@
     FloatPoint end_point(new_left * box->Style()->EffectiveZoom(),
                          box->ScrollTop().ToFloat());
     if (RuntimeEnabledFeatures::CSSScrollSnapPointsEnabled()) {
+      std::unique_ptr<SnapSelectionStrategy> strategy =
+          SnapSelectionStrategy::CreateForEndPosition(
+              gfx::ScrollOffset(end_point), true, false);
       end_point = GetDocument()
                       .GetSnapCoordinator()
-                      ->GetSnapPositionForPoint(*box, end_point, true, false)
+                      ->GetSnapPosition(*box, *strategy)
                       .value_or(end_point);
     }
     box->SetScrollLeft(LayoutUnit::FromFloatRound(end_point.X()));
@@ -795,9 +798,12 @@
     FloatPoint end_point(box->ScrollLeft().ToFloat(),
                          new_top * box->Style()->EffectiveZoom());
     if (RuntimeEnabledFeatures::CSSScrollSnapPointsEnabled()) {
+      std::unique_ptr<SnapSelectionStrategy> strategy =
+          SnapSelectionStrategy::CreateForEndPosition(
+              gfx::ScrollOffset(end_point), false, true);
       end_point = GetDocument()
                       .GetSnapCoordinator()
-                      ->GetSnapPositionForPoint(*box, end_point, false, true)
+                      ->GetSnapPosition(*box, *strategy)
                       .value_or(end_point);
     }
     box->SetScrollTop(LayoutUnit::FromFloatRound(end_point.Y()));
@@ -893,38 +899,37 @@
 }
 
 void Element::ScrollLayoutBoxBy(const ScrollToOptions& scroll_to_options) {
-  double left =
-      scroll_to_options.hasLeft()
-          ? ScrollableArea::NormalizeNonFiniteScroll(scroll_to_options.left())
-          : 0.0;
-  double top =
-      scroll_to_options.hasTop()
-          ? ScrollableArea::NormalizeNonFiniteScroll(scroll_to_options.top())
-          : 0.0;
+  gfx::ScrollOffset displacement;
+  if (scroll_to_options.hasLeft()) {
+    displacement.set_x(
+        ScrollableArea::NormalizeNonFiniteScroll(scroll_to_options.left()));
+  }
+  if (scroll_to_options.hasTop()) {
+    displacement.set_y(
+        ScrollableArea::NormalizeNonFiniteScroll(scroll_to_options.top()));
+  }
 
   ScrollBehavior scroll_behavior = kScrollBehaviorAuto;
   ScrollableArea::ScrollBehaviorFromString(scroll_to_options.behavior(),
                                            scroll_behavior);
   LayoutBox* box = GetLayoutBox();
   if (box) {
-    float current_scaled_left = box->ScrollLeft().ToFloat();
-    float current_scaled_top = box->ScrollTop().ToFloat();
-    float new_scaled_left =
-        left * box->Style()->EffectiveZoom() + current_scaled_left;
-    float new_scaled_top =
-        top * box->Style()->EffectiveZoom() + current_scaled_top;
+    gfx::ScrollOffset current_position(box->ScrollLeft().ToFloat(),
+                                       box->ScrollTop().ToFloat());
+    displacement.Scale(box->Style()->EffectiveZoom());
+    gfx::ScrollOffset new_offset(current_position + displacement);
+    FloatPoint new_position(new_offset.x(), new_offset.y());
 
-    FloatPoint new_scaled_position(new_scaled_left, new_scaled_top);
     if (RuntimeEnabledFeatures::CSSScrollSnapPointsEnabled()) {
-      new_scaled_position =
-          GetDocument()
-              .GetSnapCoordinator()
-              ->GetSnapPositionForPoint(*box, new_scaled_position,
-                                        scroll_to_options.hasLeft(),
-                                        scroll_to_options.hasTop())
-              .value_or(new_scaled_position);
+      std::unique_ptr<SnapSelectionStrategy> strategy =
+          SnapSelectionStrategy::CreateForEndAndDirection(current_position,
+                                                          displacement);
+      new_position = GetDocument()
+                         .GetSnapCoordinator()
+                         ->GetSnapPosition(*box, *strategy)
+                         .value_or(new_position);
     }
-    box->ScrollToPosition(new_scaled_position, scroll_behavior);
+    box->ScrollToPosition(new_position, scroll_behavior);
   }
 }
 
@@ -935,40 +940,43 @@
 
   LayoutBox* box = GetLayoutBox();
   if (box) {
-    float scaled_left = box->ScrollLeft().ToFloat();
-    float scaled_top = box->ScrollTop().ToFloat();
-    if (scroll_to_options.hasLeft())
-      scaled_left =
+    FloatPoint new_position(box->ScrollLeft().ToFloat(),
+                            box->ScrollTop().ToFloat());
+    if (scroll_to_options.hasLeft()) {
+      new_position.SetX(
           ScrollableArea::NormalizeNonFiniteScroll(scroll_to_options.left()) *
-          box->Style()->EffectiveZoom();
-    if (scroll_to_options.hasTop())
-      scaled_top =
-          ScrollableArea::NormalizeNonFiniteScroll(scroll_to_options.top()) *
-          box->Style()->EffectiveZoom();
-
-    FloatPoint new_scaled_position(scaled_left, scaled_top);
-    if (RuntimeEnabledFeatures::CSSScrollSnapPointsEnabled()) {
-      new_scaled_position =
-          GetDocument()
-              .GetSnapCoordinator()
-              ->GetSnapPositionForPoint(*box, new_scaled_position,
-                                        scroll_to_options.hasLeft(),
-                                        scroll_to_options.hasTop())
-              .value_or(new_scaled_position);
+          box->Style()->EffectiveZoom());
     }
-    box->ScrollToPosition(new_scaled_position, scroll_behavior);
+    if (scroll_to_options.hasTop()) {
+      new_position.SetY(
+          ScrollableArea::NormalizeNonFiniteScroll(scroll_to_options.top()) *
+          box->Style()->EffectiveZoom());
+    }
+
+    if (RuntimeEnabledFeatures::CSSScrollSnapPointsEnabled()) {
+      std::unique_ptr<SnapSelectionStrategy> strategy =
+          SnapSelectionStrategy::CreateForEndPosition(
+              gfx::ScrollOffset(new_position), scroll_to_options.hasLeft(),
+              scroll_to_options.hasTop());
+      new_position = GetDocument()
+                         .GetSnapCoordinator()
+                         ->GetSnapPosition(*box, *strategy)
+                         .value_or(new_position);
+    }
+    box->ScrollToPosition(new_position, scroll_behavior);
   }
 }
 
 void Element::ScrollFrameBy(const ScrollToOptions& scroll_to_options) {
-  double left =
-      scroll_to_options.hasLeft()
-          ? ScrollableArea::NormalizeNonFiniteScroll(scroll_to_options.left())
-          : 0.0;
-  double top =
-      scroll_to_options.hasTop()
-          ? ScrollableArea::NormalizeNonFiniteScroll(scroll_to_options.top())
-          : 0.0;
+  gfx::ScrollOffset displacement;
+  if (scroll_to_options.hasLeft()) {
+    displacement.set_x(
+        ScrollableArea::NormalizeNonFiniteScroll(scroll_to_options.left()));
+  }
+  if (scroll_to_options.hasTop()) {
+    displacement.set_y(
+        ScrollableArea::NormalizeNonFiniteScroll(scroll_to_options.top()));
+  }
 
   ScrollBehavior scroll_behavior = kScrollBehaviorAuto;
   ScrollableArea::ScrollBehaviorFromString(scroll_to_options.behavior(),
@@ -981,25 +989,23 @@
   if (!viewport)
     return;
 
-  float new_scaled_left =
-      left * frame->PageZoomFactor() + viewport->GetScrollOffset().Width();
-  float new_scaled_top =
-      top * frame->PageZoomFactor() + viewport->GetScrollOffset().Height();
+  displacement.Scale(frame->PageZoomFactor());
+  FloatPoint new_position = viewport->ScrollPosition() +
+                            FloatPoint(displacement.x(), displacement.y());
 
-  FloatPoint new_scaled_position = viewport->ScrollOffsetToPosition(
-      ScrollOffset(new_scaled_left, new_scaled_top));
   if (RuntimeEnabledFeatures::CSSScrollSnapPointsEnabled()) {
-    new_scaled_position =
+    gfx::ScrollOffset current_position(viewport->ScrollPosition());
+    std::unique_ptr<SnapSelectionStrategy> strategy =
+        SnapSelectionStrategy::CreateForEndAndDirection(current_position,
+                                                        displacement);
+    new_position =
         GetDocument()
             .GetSnapCoordinator()
-            ->GetSnapPositionForPoint(
-                *GetDocument().GetLayoutView(), new_scaled_position,
-                scroll_to_options.hasLeft(), scroll_to_options.hasTop())
-            .value_or(new_scaled_position);
+            ->GetSnapPosition(*GetDocument().GetLayoutView(), *strategy)
+            .value_or(new_position);
   }
-  viewport->SetScrollOffset(
-      viewport->ScrollPositionToOffset(new_scaled_position),
-      kProgrammaticScroll, scroll_behavior);
+  viewport->SetScrollOffset(viewport->ScrollPositionToOffset(new_position),
+                            kProgrammaticScroll, scroll_behavior);
 }
 
 void Element::ScrollFrameTo(const ScrollToOptions& scroll_to_options) {
@@ -1014,31 +1020,32 @@
   if (!viewport)
     return;
 
-  float scaled_left = viewport->GetScrollOffset().Width();
-  float scaled_top = viewport->GetScrollOffset().Height();
-  if (scroll_to_options.hasLeft())
-    scaled_left =
+  ScrollOffset new_offset = viewport->GetScrollOffset();
+  if (scroll_to_options.hasLeft()) {
+    new_offset.SetWidth(
         ScrollableArea::NormalizeNonFiniteScroll(scroll_to_options.left()) *
-        frame->PageZoomFactor();
-  if (scroll_to_options.hasTop())
-    scaled_top =
+        frame->PageZoomFactor());
+  }
+  if (scroll_to_options.hasTop()) {
+    new_offset.SetHeight(
         ScrollableArea::NormalizeNonFiniteScroll(scroll_to_options.top()) *
-        frame->PageZoomFactor();
+        frame->PageZoomFactor());
+  }
 
-  FloatPoint new_scaled_position =
-      viewport->ScrollOffsetToPosition(ScrollOffset(scaled_left, scaled_top));
   if (RuntimeEnabledFeatures::CSSScrollSnapPointsEnabled()) {
-    new_scaled_position =
+    FloatPoint new_position = viewport->ScrollOffsetToPosition(new_offset);
+    std::unique_ptr<SnapSelectionStrategy> strategy =
+        SnapSelectionStrategy::CreateForEndPosition(
+            gfx::ScrollOffset(new_position), scroll_to_options.hasLeft(),
+            scroll_to_options.hasTop());
+    new_position =
         GetDocument()
             .GetSnapCoordinator()
-            ->GetSnapPositionForPoint(
-                *GetDocument().GetLayoutView(), new_scaled_position,
-                scroll_to_options.hasLeft(), scroll_to_options.hasTop())
-            .value_or(new_scaled_position);
+            ->GetSnapPosition(*GetDocument().GetLayoutView(), *strategy)
+            .value_or(new_position);
+    new_offset = viewport->ScrollPositionToOffset(new_position);
   }
-  viewport->SetScrollOffset(
-      viewport->ScrollPositionToOffset(new_scaled_position),
-      kProgrammaticScroll, scroll_behavior);
+  viewport->SetScrollOffset(new_offset, kProgrammaticScroll, scroll_behavior);
 }
 
 bool Element::HasNonEmptyLayoutSize() const {
diff --git a/third_party/blink/renderer/core/editing/commands/clipboard_commands.cc b/third_party/blink/renderer/core/editing/commands/clipboard_commands.cc
index ea1691d..9f41051 100644
--- a/third_party/blink/renderer/core/editing/commands/clipboard_commands.cc
+++ b/third_party/blink/renderer/core/editing/commands/clipboard_commands.cc
@@ -31,6 +31,7 @@
 
 #include "third_party/blink/renderer/core/editing/commands/clipboard_commands.h"
 
+#include "third_party/blink/public/platform/web_content_settings_client.h"
 #include "third_party/blink/renderer/core/clipboard/data_transfer_access_policy.h"
 #include "third_party/blink/renderer/core/clipboard/paste_mode.h"
 #include "third_party/blink/renderer/core/clipboard/system_clipboard.h"
@@ -43,7 +44,6 @@
 #include "third_party/blink/renderer/core/editing/serializers/serialization.h"
 #include "third_party/blink/renderer/core/events/clipboard_event.h"
 #include "third_party/blink/renderer/core/events/text_event.h"
-#include "third_party/blink/renderer/core/frame/content_settings_client.h"
 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/frame/settings.h"
diff --git a/third_party/blink/renderer/core/exported/local_frame_client_impl.cc b/third_party/blink/renderer/core/exported/local_frame_client_impl.cc
index 3978a58..010a748f 100644
--- a/third_party/blink/renderer/core/exported/local_frame_client_impl.cc
+++ b/third_party/blink/renderer/core/exported/local_frame_client_impl.cc
@@ -933,7 +933,7 @@
   return web_frame_->Client()->CreateServiceWorkerProvider();
 }
 
-ContentSettingsClient& LocalFrameClientImpl::GetContentSettingsClient() {
+WebContentSettingsClient* LocalFrameClientImpl::GetContentSettingsClient() {
   return web_frame_->GetContentSettingsClient();
 }
 
diff --git a/third_party/blink/renderer/core/exported/local_frame_client_impl.h b/third_party/blink/renderer/core/exported/local_frame_client_impl.h
index 0d1c9a9..48232bc 100644
--- a/third_party/blink/renderer/core/exported/local_frame_client_impl.h
+++ b/third_party/blink/renderer/core/exported/local_frame_client_impl.h
@@ -218,7 +218,7 @@
 
   std::unique_ptr<WebServiceWorkerProvider> CreateServiceWorkerProvider()
       override;
-  ContentSettingsClient& GetContentSettingsClient() override;
+  WebContentSettingsClient* GetContentSettingsClient() override;
 
   SharedWorkerRepositoryClient* GetSharedWorkerRepositoryClient() override;
 
diff --git a/third_party/blink/renderer/core/exported/web_view_impl.cc b/third_party/blink/renderer/core/exported/web_view_impl.cc
index 5cb0fd2..124825f 100644
--- a/third_party/blink/renderer/core/exported/web_view_impl.cc
+++ b/third_party/blink/renderer/core/exported/web_view_impl.cc
@@ -3172,12 +3172,6 @@
     // We register viewport layers here since there may not be a layer
     // tree view prior to this point.
     RegisterViewportLayersWithCompositor();
-
-    // TODO(enne): Work around page visibility changes not being
-    // propagated to the WebView in some circumstances.  This needs to
-    // be refreshed here when setting a new root layer to avoid being
-    // stuck in a presumed incorrectly invisible state.
-    layer_tree_view_->SetVisible(GetPage()->IsPageVisible());
   } else {
     root_graphics_layer_ = nullptr;
     visual_viewport_container_layer_ = nullptr;
@@ -3198,7 +3192,6 @@
   if (layer) {
     root_layer_ = layer;
     layer_tree_view_->SetRootLayer(root_layer_);
-    layer_tree_view_->SetVisible(GetPage()->IsPageVisible());
   } else {
     root_layer_ = nullptr;
     // This means that we're transitioning to a new page. Suppress
diff --git a/third_party/blink/renderer/core/frame/BUILD.gn b/third_party/blink/renderer/core/frame/BUILD.gn
index 3bd04766..1fce3b6b 100644
--- a/third_party/blink/renderer/core/frame/BUILD.gn
+++ b/third_party/blink/renderer/core/frame/BUILD.gn
@@ -12,8 +12,6 @@
     "bar_prop.h",
     "browser_controls.cc",
     "browser_controls.h",
-    "content_settings_client.cc",
-    "content_settings_client.h",
     "csp/content_security_policy.cc",
     "csp/content_security_policy.h",
     "csp/csp_directive.h",
diff --git a/third_party/blink/renderer/core/frame/content_settings_client.cc b/third_party/blink/renderer/core/frame/content_settings_client.cc
deleted file mode 100644
index 388d808..0000000
--- a/third_party/blink/renderer/core/frame/content_settings_client.cc
+++ /dev/null
@@ -1,147 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/core/frame/content_settings_client.h"
-
-#include "third_party/blink/public/platform/web_content_setting_callbacks.h"
-#include "third_party/blink/public/platform/web_content_settings_client.h"
-#include "third_party/blink/public/platform/web_security_origin.h"
-#include "third_party/blink/public/platform/web_url.h"
-#include "third_party/blink/renderer/platform/content_setting_callbacks.h"
-#include "third_party/blink/renderer/platform/weborigin/kurl.h"
-#include "third_party/blink/renderer/platform/weborigin/security_origin.h"
-
-namespace blink {
-
-ContentSettingsClient::ContentSettingsClient() = default;
-
-bool ContentSettingsClient::AllowDatabase(const String& name,
-                                          const String& display_name,
-                                          unsigned estimated_size) {
-  if (client_)
-    return client_->AllowDatabase(name, display_name, estimated_size);
-  return true;
-}
-
-bool ContentSettingsClient::AllowIndexedDB(
-    const String& name,
-    const SecurityOrigin* security_origin) {
-  if (client_)
-    return client_->AllowIndexedDB(name, WebSecurityOrigin(security_origin));
-  return true;
-}
-
-bool ContentSettingsClient::RequestFileSystemAccessSync() {
-  if (client_)
-    return client_->RequestFileSystemAccessSync();
-  return true;
-}
-
-void ContentSettingsClient::RequestFileSystemAccessAsync(
-    std::unique_ptr<ContentSettingCallbacks> callbacks) {
-  if (client_)
-    client_->RequestFileSystemAccessAsync(std::move(callbacks));
-  else
-    callbacks->OnAllowed();
-}
-
-bool ContentSettingsClient::AllowScript(bool enabled_per_settings) {
-  if (client_)
-    return client_->AllowScript(enabled_per_settings);
-  return enabled_per_settings;
-}
-
-bool ContentSettingsClient::AllowScriptFromSource(bool enabled_per_settings,
-                                                  const KURL& script_url) {
-  if (client_)
-    return client_->AllowScriptFromSource(enabled_per_settings, script_url);
-  return enabled_per_settings;
-}
-
-void ContentSettingsClient::GetAllowedClientHintsFromSource(
-    const KURL& url,
-    WebEnabledClientHints* client_hints) {
-  if (client_)
-    client_->GetAllowedClientHintsFromSource(url, client_hints);
-}
-
-bool ContentSettingsClient::AllowImage(bool enabled_per_settings,
-                                       const KURL& image_url) {
-  if (client_)
-    return client_->AllowImage(enabled_per_settings, image_url);
-  return enabled_per_settings;
-}
-
-bool ContentSettingsClient::AllowReadFromClipboard(bool default_value) {
-  if (client_)
-    return client_->AllowReadFromClipboard(default_value);
-  return default_value;
-}
-
-bool ContentSettingsClient::AllowWriteToClipboard(bool default_value) {
-  if (client_)
-    return client_->AllowWriteToClipboard(default_value);
-  return default_value;
-}
-
-bool ContentSettingsClient::AllowStorage(StorageType type) {
-  if (client_)
-    return client_->AllowStorage(type == StorageType::kLocal);
-  return true;
-}
-
-bool ContentSettingsClient::AllowRunningInsecureContent(
-    bool enabled_per_settings,
-    const SecurityOrigin* origin,
-    const KURL& url) {
-  if (client_) {
-    return client_->AllowRunningInsecureContent(enabled_per_settings,
-                                                WebSecurityOrigin(origin), url);
-  }
-  return enabled_per_settings;
-}
-
-bool ContentSettingsClient::AllowMutationEvents(bool default_value) {
-  if (client_)
-    return client_->AllowMutationEvents(default_value);
-  return default_value;
-}
-
-bool ContentSettingsClient::AllowAutoplay(bool default_value) {
-  if (client_)
-    return client_->AllowAutoplay(default_value);
-  return default_value;
-}
-
-bool ContentSettingsClient::AllowPopupsAndRedirects(bool default_value) {
-  if (client_)
-    return client_->AllowPopupsAndRedirects(default_value);
-  return default_value;
-}
-
-void ContentSettingsClient::PassiveInsecureContentFound(const KURL& url) {
-  if (client_)
-    return client_->PassiveInsecureContentFound(url);
-}
-
-void ContentSettingsClient::DidNotAllowScript() {
-  if (client_)
-    client_->DidNotAllowScript();
-}
-
-void ContentSettingsClient::DidNotAllowPlugins() {
-  if (client_)
-    client_->DidNotAllowPlugins();
-}
-
-void ContentSettingsClient::PersistClientHints(
-    const WebEnabledClientHints& enabled_client_hints,
-    TimeDelta duration,
-    const KURL& url) {
-  if (client_) {
-    return client_->PersistClientHints(enabled_client_hints, duration, url);
-  }
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/core/frame/content_settings_client.h b/third_party/blink/renderer/core/frame/content_settings_client.h
deleted file mode 100644
index 8fce92fe..0000000
--- a/third_party/blink/renderer/core/frame/content_settings_client.h
+++ /dev/null
@@ -1,115 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_CONTENT_SETTINGS_CLIENT_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_CONTENT_SETTINGS_CLIENT_H_
-
-#include <memory>
-
-#include "third_party/blink/public/platform/web_client_hints_type.h"
-#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/platform/heap/heap.h"
-#include "third_party/blink/renderer/platform/wtf/forward.h"
-#include "third_party/blink/renderer/platform/wtf/time.h"
-
-namespace blink {
-
-class ContentSettingCallbacks;
-class KURL;
-class SecurityOrigin;
-class WebContentSettingsClient;
-struct WebEnabledClientHints;
-
-// This class provides the content settings information which tells
-// whether each feature is allowed. Most of the methods return the
-// given default values if embedder doesn't provide their own
-// content settings client implementation (via m_client).
-class CORE_EXPORT ContentSettingsClient {
- public:
-  ContentSettingsClient();
-
-  void SetClient(WebContentSettingsClient* client) { client_ = client; }
-
-  // Controls whether access to Web Databases is allowed.
-  bool AllowDatabase(const String& name,
-                     const String& display_name,
-                     unsigned estimated_size);
-
-  // Controls whether access to File System is allowed for this frame.
-  bool RequestFileSystemAccessSync();
-
-  // Controls whether access to File System is allowed for this frame.
-  void RequestFileSystemAccessAsync(std::unique_ptr<ContentSettingCallbacks>);
-
-  // Controls whether access to File System is allowed.
-  bool AllowIndexedDB(const String& name, const SecurityOrigin*);
-
-  // Controls whether scripts are allowed to execute.
-  bool AllowScript(bool enabled_per_settings);
-
-  // Controls whether scripts loaded from the given URL are allowed to execute.
-  bool AllowScriptFromSource(bool enabled_per_settings, const KURL&);
-
-  // Retrieves the client hints that should be attached to the request for the
-  // given URL.
-  void GetAllowedClientHintsFromSource(const KURL&, WebEnabledClientHints*);
-  // Controls whether images are allowed.
-  bool AllowImage(bool enabled_per_settings, const KURL&);
-
-  // Controls whether insecure scripts are allowed to execute for this frame.
-  bool AllowRunningInsecureContent(bool enabled_per_settings,
-                                   const SecurityOrigin*,
-                                   const KURL&);
-
-  // Controls whether HTML5 Web Storage is allowed for this frame.
-  enum class StorageType { kLocal, kSession };
-  bool AllowStorage(StorageType);
-
-  // Controls whether access to read the clipboard is allowed for this frame.
-  bool AllowReadFromClipboard(bool default_value);
-
-  // Controls whether access to write the clipboard is allowed for this frame.
-  bool AllowWriteToClipboard(bool default_value);
-
-  // Controls whether to enable MutationEvents for this frame.
-  // The common use case of this method is actually to selectively disable
-  // MutationEvents, but it's been named for consistency with the rest of the
-  // interface.
-  bool AllowMutationEvents(bool default_value);
-
-  // Controls whether autoplay is allowed for this frame.
-  bool AllowAutoplay(bool default_value);
-
-  // Controls whether popups and abusive redirects (e.g. framebusting) are
-  // allowed for this frame.
-  bool AllowPopupsAndRedirects(bool default_value);
-
-  // Reports that passive mixed content was found at the provided URL. It may or
-  // may not be actually displayed later, what would be flagged by
-  // didDisplayInsecureContent.
-  void PassiveInsecureContentFound(const KURL&);
-
-  // This callback notifies the client that the frame was about to run
-  // JavaScript but did not because allowScript returned false. We have a
-  // separate callback here because there are a number of places that need to
-  // know if JavaScript is enabled but are not necessarily preparing to execute
-  // script.
-  void DidNotAllowScript();
-
-  // This callback is similar, but for plugins.
-  void DidNotAllowPlugins();
-
-  // Called to persist the client hint preferences received when |url| was
-  // fetched. The preferences should be persisted for |duration|.
-  void PersistClientHints(const WebEnabledClientHints&,
-                          TimeDelta duration,
-                          const KURL&);
-
- private:
-  WebContentSettingsClient* client_ = nullptr;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_CONTENT_SETTINGS_CLIENT_H_
diff --git a/third_party/blink/renderer/core/frame/deprecation.cc b/third_party/blink/renderer/core/frame/deprecation.cc
index 9c7cffd..013bedb 100644
--- a/third_party/blink/renderer/core/frame/deprecation.cc
+++ b/third_party/blink/renderer/core/frame/deprecation.cc
@@ -515,9 +515,9 @@
     case WebFeature::kPresentationRequestStartInsecureOrigin:
     case WebFeature::kPresentationReceiverInsecureOrigin:
       return {
-          "PresentationInsecureOrigin", kM71,
+          "PresentationInsecureOrigin", kM72,
           String("Using the Presentation API on insecure origins is "
-                 "deprecated and will be removed in M71. You should consider "
+                 "deprecated and will be removed in M72. You should consider "
                  "switching your application to a secure origin, such as "
                  "HTTPS. See "
                  "https://goo.gl/rStTGz for more details.")};
diff --git a/third_party/blink/renderer/core/frame/local_dom_window.cc b/third_party/blink/renderer/core/frame/local_dom_window.cc
index b4b1e22..70824a1 100644
--- a/third_party/blink/renderer/core/frame/local_dom_window.cc
+++ b/third_party/blink/renderer/core/frame/local_dom_window.cc
@@ -1088,18 +1088,20 @@
     y = ScrollableArea::NormalizeNonFiniteScroll(scroll_to_options.top());
 
   PaintLayerScrollableArea* viewport = view->LayoutViewport();
-  ScrollOffset current_offset = viewport->GetScrollOffset();
-  ScrollOffset scaled_delta(x * GetFrame()->PageZoomFactor(),
-                            y * GetFrame()->PageZoomFactor());
-  FloatPoint new_scaled_position =
-      viewport->ScrollOffsetToPosition(scaled_delta + current_offset);
+  FloatPoint current_position = viewport->ScrollPosition();
+  FloatPoint scaled_delta(x * GetFrame()->PageZoomFactor(),
+                          y * GetFrame()->PageZoomFactor());
+  FloatPoint new_scaled_position = current_position + scaled_delta;
+
   if (RuntimeEnabledFeatures::CSSScrollSnapPointsEnabled()) {
+    std::unique_ptr<SnapSelectionStrategy> strategy =
+        SnapSelectionStrategy::CreateForEndAndDirection(
+            gfx::ScrollOffset(current_position),
+            gfx::ScrollOffset(scaled_delta));
     new_scaled_position =
         document()
             ->GetSnapCoordinator()
-            ->GetSnapPositionForPoint(
-                *document()->GetLayoutView(), new_scaled_position,
-                scroll_to_options.hasLeft(), scroll_to_options.hasTop())
+            ->GetSnapPosition(*document()->GetLayoutView(), *strategy)
             .value_or(new_scaled_position);
   }
 
@@ -1157,20 +1159,21 @@
 
   FloatPoint new_scaled_position =
       viewport->ScrollOffsetToPosition(ScrollOffset(scaled_x, scaled_y));
+
   if (RuntimeEnabledFeatures::CSSScrollSnapPointsEnabled()) {
+    std::unique_ptr<SnapSelectionStrategy> strategy =
+        SnapSelectionStrategy::CreateForEndPosition(
+            gfx::ScrollOffset(new_scaled_position), scroll_to_options.hasLeft(),
+            scroll_to_options.hasTop());
     new_scaled_position =
         document()
             ->GetSnapCoordinator()
-            ->GetSnapPositionForPoint(
-                *document()->GetLayoutView(), new_scaled_position,
-                scroll_to_options.hasLeft(), scroll_to_options.hasTop())
+            ->GetSnapPosition(*document()->GetLayoutView(), *strategy)
             .value_or(new_scaled_position);
   }
-
   ScrollBehavior scroll_behavior = kScrollBehaviorAuto;
   ScrollableArea::ScrollBehaviorFromString(scroll_to_options.behavior(),
                                            scroll_behavior);
-
   viewport->SetScrollOffset(
       viewport->ScrollPositionToOffset(new_scaled_position),
       kProgrammaticScroll, scroll_behavior);
diff --git a/third_party/blink/renderer/core/frame/local_frame.cc b/third_party/blink/renderer/core/frame/local_frame.cc
index 5a1134e9..c3cc252 100644
--- a/third_party/blink/renderer/core/frame/local_frame.cc
+++ b/third_party/blink/renderer/core/frame/local_frame.cc
@@ -38,6 +38,7 @@
 #include "third_party/blink/public/platform/interface_provider.h"
 #include "third_party/blink/public/platform/interface_registry.h"
 #include "third_party/blink/public/platform/scheduler/web_resource_loading_task_runner_handle.h"
+#include "third_party/blink/public/platform/web_content_settings_client.h"
 #include "third_party/blink/public/platform/web_url_request.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_controller.h"
 #include "third_party/blink/renderer/bindings/core/v8/source_location.h"
@@ -61,7 +62,6 @@
 #include "third_party/blink/renderer/core/events/current_input_event.h"
 #include "third_party/blink/renderer/core/exported/web_plugin_container_impl.h"
 #include "third_party/blink/renderer/core/frame/ad_tracker.h"
-#include "third_party/blink/renderer/core/frame/content_settings_client.h"
 #include "third_party/blink/renderer/core/frame/event_handler_registry.h"
 #include "third_party/blink/renderer/core/frame/frame_console.h"
 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
@@ -1017,10 +1017,14 @@
     //
     // TODO(csharrison,japhet): Consider not logging an error message if the
     // user has allowed popups/redirects.
+    bool allow_popups_and_redirects = false;
+    if (auto* settings_client = Client()->GetContentSettingsClient()) {
+      allow_popups_and_redirects =
+          settings_client->AllowPopupsAndRedirects(allow_popups_and_redirects);
+    }
     if (!RuntimeEnabledFeatures::
             FramebustingNeedsSameOriginOrUserGestureEnabled() ||
-        Client()->GetContentSettingsClient().AllowPopupsAndRedirects(
-            false /* default_value */)) {
+        allow_popups_and_redirects) {
       String target_frame_description =
           target_frame.IsLocalFrame() ? "with URL '" +
                                             ToLocalFrame(target_frame)
@@ -1220,8 +1224,8 @@
   return static_cast<LocalFrameClient*>(Frame::Client());
 }
 
-ContentSettingsClient* LocalFrame::GetContentSettingsClient() {
-  return Client() ? &Client()->GetContentSettingsClient() : nullptr;
+WebContentSettingsClient* LocalFrame::GetContentSettingsClient() {
+  return Client() ? Client()->GetContentSettingsClient() : nullptr;
 }
 
 FrameResourceCoordinator* LocalFrame::GetFrameResourceCoordinator() {
diff --git a/third_party/blink/renderer/core/frame/local_frame.h b/third_party/blink/renderer/core/frame/local_frame.h
index b0a066e..78ba350c 100644
--- a/third_party/blink/renderer/core/frame/local_frame.h
+++ b/third_party/blink/renderer/core/frame/local_frame.h
@@ -68,7 +68,6 @@
 class Color;
 class ComputedAccessibleNode;
 class ContentSecurityPolicy;
-class ContentSettingsClient;
 class Document;
 class Editor;
 class Element;
@@ -102,6 +101,7 @@
 class SpellChecker;
 class TextSuggestionController;
 class WebComputedAXTree;
+class WebContentSettingsClient;
 class WebPluginContainerImpl;
 class WebURLLoaderFactory;
 
@@ -307,7 +307,7 @@
 
   LocalFrameClient* Client() const;
 
-  ContentSettingsClient* GetContentSettingsClient();
+  WebContentSettingsClient* GetContentSettingsClient();
 
   // GetFrameResourceCoordinator may return nullptr when it can not hook up to
   // services/resource_coordinator.
diff --git a/third_party/blink/renderer/core/frame/local_frame_client.h b/third_party/blink/renderer/core/frame/local_frame_client.h
index cc9c517..16180589 100644
--- a/third_party/blink/renderer/core/frame/local_frame_client.h
+++ b/third_party/blink/renderer/core/frame/local_frame_client.h
@@ -335,7 +335,7 @@
   virtual std::unique_ptr<WebServiceWorkerProvider>
   CreateServiceWorkerProvider() = 0;
 
-  virtual ContentSettingsClient& GetContentSettingsClient() = 0;
+  virtual WebContentSettingsClient* GetContentSettingsClient() = 0;
 
   virtual SharedWorkerRepositoryClient* GetSharedWorkerRepositoryClient() {
     return nullptr;
diff --git a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
index 0b5eabba6..5cc7ff7 100644
--- a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
+++ b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
@@ -574,7 +574,7 @@
 
 void WebLocalFrameImpl::SetContentSettingsClient(
     WebContentSettingsClient* client) {
-  content_settings_client_.SetClient(client);
+  content_settings_client_ = client;
 }
 
 void WebLocalFrameImpl::SetSharedWorkerRepositoryClient(
diff --git a/third_party/blink/renderer/core/frame/web_local_frame_impl.h b/third_party/blink/renderer/core/frame/web_local_frame_impl.h
index df8df74..80fa1cf 100644
--- a/third_party/blink/renderer/core/frame/web_local_frame_impl.h
+++ b/third_party/blink/renderer/core/frame/web_local_frame_impl.h
@@ -44,7 +44,6 @@
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/editing/forward.h"
 #include "third_party/blink/renderer/core/exported/web_input_method_controller_impl.h"
-#include "third_party/blink/renderer/core/frame/content_settings_client.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/platform/geometry/float_rect.h"
 #include "third_party/blink/renderer/platform/heap/self_keep_alive.h"
@@ -63,6 +62,7 @@
 class WebAssociatedURLLoader;
 struct WebAssociatedURLLoaderOptions;
 class WebAutofillClient;
+class WebContentSettingsClient;
 class WebDevToolsAgentImpl;
 class WebLocalFrameClient;
 class WebFrameWidgetBase;
@@ -399,7 +399,7 @@
 
   WebFrameWidgetBase* FrameWidgetImpl() { return frame_widget_; }
 
-  ContentSettingsClient& GetContentSettingsClient() {
+  WebContentSettingsClient* GetContentSettingsClient() {
     return content_settings_client_;
   }
 
@@ -485,7 +485,7 @@
   Member<WebDevToolsAgentImpl> dev_tools_agent_;
 
   WebAutofillClient* autofill_client_;
-  ContentSettingsClient content_settings_client_;
+  WebContentSettingsClient* content_settings_client_ = nullptr;
   std::unique_ptr<SharedWorkerRepositoryClientImpl>
       shared_worker_repository_client_;
 
diff --git a/third_party/blink/renderer/core/html/custom/custom_element_test.cc b/third_party/blink/renderer/core/html/custom/custom_element_test.cc
index 97f0af7..b6140c8 100644
--- a/third_party/blink/renderer/core/html/custom/custom_element_test.cc
+++ b/third_party/blink/renderer/core/html/custom/custom_element_test.cc
@@ -204,7 +204,7 @@
     EXPECT_EQ(data.state, element->GetCustomElementState()) << data.name;
     EXPECT_EQ(data.v0state, element->GetV0CustomElementState()) << data.name;
 
-    element = document.createElementNS(SVGNames::svgNamespaceURI, data.name,
+    element = document.createElementNS(svg_names::kNamespaceURI, data.name,
                                        ASSERT_NO_EXCEPTION);
     EXPECT_EQ(CustomElementState::kUncustomized,
               element->GetCustomElementState())
diff --git a/third_party/blink/renderer/core/html/custom/v0_custom_element_registration_context.cc b/third_party/blink/renderer/core/html/custom/v0_custom_element_registration_context.cc
index 9fa081e..517684d 100644
--- a/third_party/blink/renderer/core/html/custom/v0_custom_element_registration_context.cc
+++ b/third_party/blink/renderer/core/html/custom/v0_custom_element_registration_context.cc
@@ -78,7 +78,7 @@
 
   if (HTMLNames::xhtmlNamespaceURI == tag_name.NamespaceURI()) {
     element = HTMLElement::Create(tag_name, document);
-  } else if (SVGNames::svgNamespaceURI == tag_name.NamespaceURI()) {
+  } else if (svg_names::kNamespaceURI == tag_name.NamespaceURI()) {
     element = SVGUnknownElement::Create(tag_name, document);
   } else {
     // XML elements are not custom elements, so return early.
diff --git a/third_party/blink/renderer/core/html/custom/v0_custom_element_registry.cc b/third_party/blink/renderer/core/html/custom/v0_custom_element_registry.cc
index 40de265c..bdbd7ad 100644
--- a/third_party/blink/renderer/core/html/custom/v0_custom_element_registry.cc
+++ b/third_party/blink/renderer/core/html/custom/v0_custom_element_registry.cc
@@ -74,7 +74,7 @@
     return nullptr;
 
   DCHECK(tag_name.NamespaceURI() == HTMLNames::xhtmlNamespaceURI ||
-         tag_name.NamespaceURI() == SVGNames::svgNamespaceURI);
+         tag_name.NamespaceURI() == svg_names::kNamespaceURI);
 
   DCHECK(!document_was_detached_);
 
@@ -109,7 +109,7 @@
     return nullptr;
   }
 
-  if (tag_name.NamespaceURI() == SVGNames::svgNamespaceURI) {
+  if (tag_name.NamespaceURI() == svg_names::kNamespaceURI) {
     UseCounter::Count(document,
                       WebFeature::kV0CustomElementsRegisterSVGElement);
   } else {
diff --git a/third_party/blink/renderer/core/html/image_document.cc b/third_party/blink/renderer/core/html/image_document.cc
index 06eec5f..7aecfe5c 100644
--- a/third_party/blink/renderer/core/html/image_document.cc
+++ b/third_party/blink/renderer/core/html/image_document.cc
@@ -25,11 +25,11 @@
 #include "third_party/blink/renderer/core/html/image_document.h"
 
 #include <limits>
+#include "third_party/blink/public/platform/web_content_settings_client.h"
 #include "third_party/blink/renderer/core/dom/events/event_listener.h"
 #include "third_party/blink/renderer/core/dom/raw_data_document_parser.h"
 #include "third_party/blink/renderer/core/dom/shadow_root.h"
 #include "third_party/blink/renderer/core/events/mouse_event.h"
-#include "third_party/blink/renderer/core/frame/content_settings_client.h"
 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/frame/local_frame_client.h"
@@ -128,8 +128,10 @@
 
   LocalFrame* frame = GetDocument()->GetFrame();
   Settings* settings = frame->GetSettings();
-  if (!frame->GetContentSettingsClient()->AllowImage(
-          !settings || settings->GetImagesEnabled(), GetDocument()->Url()))
+  bool allow_image = !settings || settings->GetImagesEnabled();
+  if (auto* client = frame->GetContentSettingsClient())
+    allow_image = client->AllowImage(allow_image, GetDocument()->Url());
+  if (!allow_image)
     return;
 
   if (GetDocument()->CachedImageResourceDeprecated()) {
diff --git a/third_party/blink/renderer/core/html/media/autoplay_policy.cc b/third_party/blink/renderer/core/html/media/autoplay_policy.cc
index 67e0b0d..c915cc3 100644
--- a/third_party/blink/renderer/core/html/media/autoplay_policy.cc
+++ b/third_party/blink/renderer/core/html/media/autoplay_policy.cc
@@ -7,6 +7,7 @@
 #include "build/build_config.h"
 #include "third_party/blink/public/mojom/feature_policy/feature_policy.mojom-blink.h"
 #include "third_party/blink/public/platform/autoplay.mojom-blink.h"
+#include "third_party/blink/public/platform/web_content_settings_client.h"
 #include "third_party/blink/public/platform/web_media_player.h"
 #include "third_party/blink/public/web/web_local_frame.h"
 #include "third_party/blink/public/web/web_local_frame_client.h"
@@ -14,7 +15,6 @@
 #include "third_party/blink/public/web/web_user_media_client.h"
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/dom/element_visibility_observer.h"
-#include "third_party/blink/renderer/core/frame/content_settings_client.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/frame/settings.h"
 #include "third_party/blink/renderer/core/html/media/autoplay_uma_helper.h"
@@ -172,7 +172,7 @@
   WebFrame* web_frame = WebFrame::FromFrame(document.GetFrame());
   if (!web_frame)
     return false;
-  
+
   WebLocalFrame* frame = web_frame->ToWebLocalFrame();
   if (!frame || !frame->Client())
     return false;
@@ -470,7 +470,9 @@
   LocalFrame* frame = element_->GetDocument().GetFrame();
   if (!frame)
     return false;
-  return frame->GetContentSettingsClient()->AllowAutoplay(true);
+  if (auto* settings_client = frame->GetContentSettingsClient())
+    return settings_client->AllowAutoplay(true /* default_value */);
+  return true;
 }
 
 bool AutoplayPolicy::ShouldAutoplay() {
diff --git a/third_party/blink/renderer/core/html/parser/html_element_stack.cc b/third_party/blink/renderer/core/html/parser/html_element_stack.cc
index 878a97d..ed87e39 100644
--- a/third_party/blink/renderer/core/html/parser/html_element_stack.cc
+++ b/third_party/blink/renderer/core/html/parser/html_element_stack.cc
@@ -54,9 +54,9 @@
          item->HasTagName(mathml_names::kMsTag) ||
          item->HasTagName(mathml_names::kMtextTag) ||
          item->HasTagName(mathml_names::kAnnotationXmlTag) ||
-         item->HasTagName(SVGNames::foreignObjectTag) ||
-         item->HasTagName(SVGNames::descTag) ||
-         item->HasTagName(SVGNames::titleTag) ||
+         item->HasTagName(svg_names::kForeignObjectTag) ||
+         item->HasTagName(svg_names::kDescTag) ||
+         item->HasTagName(svg_names::kTitleTag) ||
          item->HasTagName(templateTag) || IsRootNode(item);
 }
 
@@ -250,9 +250,9 @@
     }
     return false;
   }
-  return item->HasTagName(SVGNames::foreignObjectTag) ||
-         item->HasTagName(SVGNames::descTag) ||
-         item->HasTagName(SVGNames::titleTag);
+  return item->HasTagName(svg_names::kForeignObjectTag) ||
+         item->HasTagName(svg_names::kDescTag) ||
+         item->HasTagName(svg_names::kTitleTag);
 }
 
 void HTMLElementStack::PopUntilForeignContentScopeMarker() {
diff --git a/third_party/blink/renderer/core/html/parser/html_stack_item.h b/third_party/blink/renderer/core/html/parser/html_stack_item.h
index 05c3bb97..d92c673 100644
--- a/third_party/blink/renderer/core/html/parser/html_stack_item.h
+++ b/third_party/blink/renderer/core/html/parser/html_stack_item.h
@@ -120,8 +120,8 @@
         HasTagName(mathml_names::kMnTag) || HasTagName(mathml_names::kMsTag) ||
         HasTagName(mathml_names::kMtextTag) ||
         HasTagName(mathml_names::kAnnotationXmlTag) ||
-        HasTagName(SVGNames::foreignObjectTag) ||
-        HasTagName(SVGNames::descTag) || HasTagName(SVGNames::titleTag))
+        HasTagName(svg_names::kForeignObjectTag) ||
+        HasTagName(svg_names::kDescTag) || HasTagName(svg_names::kTitleTag))
       return true;
     if (IsDocumentFragmentNode())
       return true;
diff --git a/third_party/blink/renderer/core/html/parser/html_tree_builder.cc b/third_party/blink/renderer/core/html/parser/html_tree_builder.cc
index 0af2338..157195f 100644
--- a/third_party/blink/renderer/core/html/parser/html_tree_builder.cc
+++ b/third_party/blink/renderer/core/html/parser/html_tree_builder.cc
@@ -463,8 +463,8 @@
   static PrefixedNameToQualifiedNameMap* case_map = nullptr;
   if (!case_map) {
     case_map = new PrefixedNameToQualifiedNameMap;
-    std::unique_ptr<const SVGQualifiedName* []> svg_tags = SVGNames::GetTags();
-    MapLoweredLocalNameToName(case_map, svg_tags.get(), SVGNames::kTagsCount);
+    std::unique_ptr<const SVGQualifiedName* []> svg_tags = svg_names::GetTags();
+    MapLoweredLocalNameToName(case_map, svg_tags.get(), svg_names::kTagsCount);
   }
 
   const QualifiedName& cased_name = case_map->at(token->GetName());
@@ -491,7 +491,7 @@
 
 // https://html.spec.whatwg.org/multipage/parsing.html#adjust-svg-attributes
 static void AdjustSVGAttributes(AtomicHTMLToken* token) {
-  AdjustAttributes<SVGNames::GetAttrs, SVGNames::kAttrsCount>(token);
+  AdjustAttributes<svg_names::GetAttrs, svg_names::kAttrsCount>(token);
 }
 
 // https://html.spec.whatwg.org/multipage/parsing.html#adjust-mathml-attributes
@@ -830,11 +830,11 @@
     tree_.InsertForeignElement(token, mathml_names::kNamespaceURI);
     return;
   }
-  if (token->GetName() == SVGNames::svgTag.LocalName()) {
+  if (token->GetName() == svg_names::kSVGTag.LocalName()) {
     tree_.ReconstructTheActiveFormattingElements();
     AdjustSVGAttributes(token);
     AdjustForeignAttributes(token);
-    tree_.InsertForeignElement(token, SVGNames::svgNamespaceURI);
+    tree_.InsertForeignElement(token, svg_names::kNamespaceURI);
     return;
   }
   if (IsCaptionColOrColgroupTag(token->GetName()) ||
@@ -2599,7 +2599,7 @@
   }
   if (adjusted_current_node->HasTagName(mathml_names::kAnnotationXmlTag) &&
       token->GetType() == HTMLToken::kStartTag &&
-      token->GetName() == SVGNames::svgTag)
+      token->GetName() == svg_names::kSVGTag)
     return false;
   if (HTMLElementStack::IsHTMLIntegrationPoint(adjusted_current_node)) {
     if (token->GetType() == HTMLToken::kStartTag)
@@ -2668,7 +2668,7 @@
           adjusted_current_node->NamespaceURI();
       if (current_namespace == mathml_names::kNamespaceURI)
         AdjustMathMLAttributes(token);
-      if (current_namespace == SVGNames::svgNamespaceURI) {
+      if (current_namespace == svg_names::kNamespaceURI) {
         AdjustSVGTagNameCase(token);
         AdjustSVGAttributes(token);
       }
@@ -2677,11 +2677,11 @@
       break;
     }
     case HTMLToken::kEndTag: {
-      if (adjusted_current_node->NamespaceURI() == SVGNames::svgNamespaceURI)
+      if (adjusted_current_node->NamespaceURI() == svg_names::kNamespaceURI)
         AdjustSVGTagNameCase(token);
 
-      if (token->GetName() == SVGNames::scriptTag &&
-          tree_.CurrentStackItem()->HasTagName(SVGNames::scriptTag)) {
+      if (token->GetName() == svg_names::kScriptTag &&
+          tree_.CurrentStackItem()->HasTagName(svg_names::kScriptTag)) {
         if (ScriptingContentIsAllowed(tree_.GetParserContentPolicy()))
           script_to_process_ = tree_.CurrentElement();
         tree_.OpenElements()->Pop();
diff --git a/third_party/blink/renderer/core/html/parser/html_tree_builder_simulator.cc b/third_party/blink/renderer/core/html/parser/html_tree_builder_simulator.cc
index 44c1e1a..b99fee5 100644
--- a/third_party/blink/renderer/core/html/parser/html_tree_builder_simulator.cc
+++ b/third_party/blink/renderer/core/html/parser/html_tree_builder_simulator.cc
@@ -116,7 +116,7 @@
            tree_builder->OpenElements()->TopRecord();
        record; record = record->Next()) {
     Namespace current_namespace = HTML;
-    if (record->NamespaceURI() == SVGNames::svgNamespaceURI)
+    if (record->NamespaceURI() == svg_names::kNamespaceURI)
       current_namespace = SVG;
     else if (record->NamespaceURI() == mathml_names::kNamespaceURI)
       current_namespace = kMathML;
@@ -136,7 +136,7 @@
 
   if (token.GetType() == HTMLToken::kStartTag) {
     const String& tag_name = token.Data();
-    if (ThreadSafeMatch(tag_name, SVGNames::svgTag))
+    if (ThreadSafeMatch(tag_name, svg_names::kSVGTag))
       namespace_stack_.push_back(SVG);
     if (ThreadSafeMatch(tag_name, mathml_names::kMathTag))
       namespace_stack_.push_back(kMathML);
@@ -210,7 +210,7 @@
        InForeignContent())) {
     const String& tag_name = token.Data();
     if ((namespace_stack_.back() == SVG &&
-         ThreadSafeMatch(tag_name, SVGNames::svgTag)) ||
+         ThreadSafeMatch(tag_name, svg_names::kSVGTag)) ||
         (namespace_stack_.back() == kMathML &&
          ThreadSafeMatch(tag_name, mathml_names::kMathTag)) ||
         IsHTMLIntegrationPointForEndTag(token) ||
@@ -253,10 +253,10 @@
     // FIXME: It's very fragile that we special case foreignObject here to be
     // case-insensitive.
     if (DeprecatedEqualIgnoringCase(tag_name,
-                                    SVGNames::foreignObjectTag.LocalName()))
+                                    svg_names::kForeignObjectTag.LocalName()))
       return true;
-    return ThreadSafeMatch(tag_name, SVGNames::descTag) ||
-           ThreadSafeMatch(tag_name, SVGNames::titleTag);
+    return ThreadSafeMatch(tag_name, svg_names::kDescTag) ||
+           ThreadSafeMatch(tag_name, svg_names::kTitleTag);
   }
   return false;
 }
@@ -282,10 +282,10 @@
     // FIXME: It's very fragile that we special case foreignObject here to be
     // case-insensitive.
     if (DeprecatedEqualIgnoringCase(tag_name,
-                                    SVGNames::foreignObjectTag.LocalName()))
+                                    svg_names::kForeignObjectTag.LocalName()))
       return true;
-    return ThreadSafeMatch(tag_name, SVGNames::descTag) ||
-           ThreadSafeMatch(tag_name, SVGNames::titleTag);
+    return ThreadSafeMatch(tag_name, svg_names::kDescTag) ||
+           ThreadSafeMatch(tag_name, svg_names::kTitleTag);
   }
   return false;
 }
diff --git a/third_party/blink/renderer/core/html/parser/xss_auditor.cc b/third_party/blink/renderer/core/html/parser/xss_auditor.cc
index 58afc8a..b0b92b01 100644
--- a/third_party/blink/renderer/core/html/parser/xss_auditor.cc
+++ b/third_party/blink/renderer/core/html/parser/xss_auditor.cc
@@ -325,7 +325,7 @@
 
 static bool IsSemicolonSeparatedAttribute(
     const HTMLToken::Attribute& attribute) {
-  return ThreadSafeMatch(attribute.NameAsVector(), SVGNames::valuesAttr);
+  return ThreadSafeMatch(attribute.NameAsVector(), svg_names::kValuesAttr);
 }
 
 static bool IsSemicolonSeparatedValueContainingJavaScriptURL(
@@ -590,7 +590,7 @@
   if (script_tag_found_in_request_) {
     did_block_script |= EraseAttributeIfInjected(
         request, srcAttr, BlankURL().GetString(), kSrcLikeAttributeTruncation);
-    did_block_script |= EraseAttributeIfInjected(request, SVGNames::hrefAttr,
+    did_block_script |= EraseAttributeIfInjected(request, svg_names::kHrefAttr,
                                                  BlankURL().GetString(),
                                                  kSrcLikeAttributeTruncation);
     did_block_script |= EraseAttributeIfInjected(
diff --git a/third_party/blink/renderer/core/imagebitmap/image_bitmap.cc b/third_party/blink/renderer/core/imagebitmap/image_bitmap.cc
index 94eb622..daa6c5b 100644
--- a/third_party/blink/renderer/core/imagebitmap/image_bitmap.cc
+++ b/third_party/blink/renderer/core/imagebitmap/image_bitmap.cc
@@ -348,7 +348,7 @@
           sk_image.get(),
           SkRect::MakeWH(parsed_options.resize_width,
                          parsed_options.resize_height),
-          &paint, SkCanvas::SrcRectConstraint::kStrict_SrcRectConstraint);
+          &paint);
       resized_sk_image = surface->makeImageSnapshot();
     }
   }
diff --git a/third_party/blink/renderer/core/input/scroll_manager.cc b/third_party/blink/renderer/core/input/scroll_manager.cc
index 57eb815..d4798092 100644
--- a/third_party/blink/renderer/core/input/scroll_manager.cc
+++ b/third_party/blink/renderer/core/input/scroll_manager.cc
@@ -275,6 +275,15 @@
     }
 
     DCHECK(scrollable_area);
+
+    SnapCoordinator* snap_coordinator =
+        frame_->GetDocument()->GetSnapCoordinator();
+    ScrollOffset delta = ToScrollDelta(physical_direction, 1);
+    delta.Scale(scrollable_area->ScrollStep(granularity, kHorizontalScrollbar),
+                scrollable_area->ScrollStep(granularity, kVerticalScrollbar));
+    if (snap_coordinator->SnapForDirection(*box, delta))
+      return true;
+
     ScrollResult result = scrollable_area->UserScroll(
         granularity, ToScrollDelta(physical_direction, 1));
 
@@ -618,24 +627,34 @@
   if (!snap_coordinator || !layout_box)
     return;
 
-  snap_coordinator->PerformSnapping(*layout_box,
-                                    did_scroll_x_for_scroll_gesture_,
-                                    did_scroll_y_for_scroll_gesture_);
+  snap_coordinator->SnapForEndPosition(*layout_box,
+                                       did_scroll_x_for_scroll_gesture_,
+                                       did_scroll_y_for_scroll_gesture_);
 }
 
-bool ScrollManager::GetSnapFlingInfo(const gfx::Vector2dF& natural_displacement,
-                                     gfx::Vector2dF* out_initial_offset,
-                                     gfx::Vector2dF* out_target_offset) const {
-  if (!previous_gesture_scrolled_node_)
-    return false;
-
+bool ScrollManager::GetSnapFlingInfo(
+    const gfx::Vector2dF& natural_displacement,
+    gfx::Vector2dF* out_initial_position,
+    gfx::Vector2dF* out_target_position) const {
   SnapCoordinator* snap_coordinator =
       frame_->GetDocument()->GetSnapCoordinator();
   LayoutBox* layout_box = LayoutBoxForSnapping();
-  if (!snap_coordinator || !layout_box || !layout_box->GetScrollableArea())
+  ScrollableArea* scrollable_area = ScrollableAreaForSnapping(layout_box);
+  if (!snap_coordinator || !layout_box || !scrollable_area)
     return false;
-  return snap_coordinator->GetSnapFlingInfo(
-      *layout_box, natural_displacement, out_initial_offset, out_target_offset);
+
+  FloatPoint current_position = scrollable_area->ScrollPosition();
+  *out_initial_position = gfx::Vector2dF(current_position);
+  std::unique_ptr<SnapSelectionStrategy> strategy =
+      SnapSelectionStrategy::CreateForEndAndDirection(
+          gfx::ScrollOffset(*out_initial_position),
+          gfx::ScrollOffset(natural_displacement));
+  base::Optional<FloatPoint> snap_end =
+      snap_coordinator->GetSnapPosition(*layout_box, *strategy);
+  if (!snap_end.has_value())
+    return false;
+  *out_target_position = gfx::Vector2dF(snap_end.value());
+  return true;
 }
 
 gfx::Vector2dF ScrollManager::ScrollByForSnapFling(
diff --git a/third_party/blink/renderer/core/input/scroll_manager.h b/third_party/blink/renderer/core/input/scroll_manager.h
index 5dbece07..c76f8eb 100644
--- a/third_party/blink/renderer/core/input/scroll_manager.h
+++ b/third_party/blink/renderer/core/input/scroll_manager.h
@@ -96,8 +96,8 @@
 
   // SnapFlingClient implementation.
   bool GetSnapFlingInfo(const gfx::Vector2dF& natural_displacement,
-                        gfx::Vector2dF* out_initial_offset,
-                        gfx::Vector2dF* out_target_offset) const override;
+                        gfx::Vector2dF* out_initial_position,
+                        gfx::Vector2dF* out_target_position) const override;
   gfx::Vector2dF ScrollByForSnapFling(const gfx::Vector2dF& delta) override;
   void ScrollEndForSnapFling() override;
   void RequestAnimationForSnapFling() override;
diff --git a/third_party/blink/renderer/core/inspector/browser_protocol.pdl b/third_party/blink/renderer/core/inspector/browser_protocol.pdl
index 5925db8..df61e497 100644
--- a/third_party/blink/renderer/core/inspector/browser_protocol.pdl
+++ b/third_party/blink/renderer/core/inspector/browser_protocol.pdl
@@ -4054,7 +4054,7 @@
       optional ErrorReason errorReason
       # If set the requests completes using with the provided base64 encoded raw response, including
       # HTTP status line and headers etc... Must not be set in response to an authChallenge.
-      optional string rawResponse
+      optional binary rawResponse
       # If set the request url will be modified in a way that's not observable by page. Must not be
       # set in response to an authChallenge.
       optional string url
diff --git a/third_party/blink/renderer/core/inspector/inspector_emulation_agent.cc b/third_party/blink/renderer/core/inspector/inspector_emulation_agent.cc
index e0f3c33..ea592b5 100644
--- a/third_party/blink/renderer/core/inspector/inspector_emulation_agent.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_emulation_agent.cc
@@ -21,7 +21,7 @@
 #include "third_party/blink/renderer/platform/loader/fetch/resource_request.h"
 #include "third_party/blink/renderer/platform/network/network_utils.h"
 #include "third_party/blink/renderer/platform/scheduler/public/thread.h"
-#include "third_party/blink/renderer/platform/scheduler/util/thread_cpu_throttler.h"
+#include "third_party/blink/renderer/platform/scheduler/public/thread_cpu_throttler.h"
 #include "third_party/blink/renderer/platform/wtf/time.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/inspector/v8_inspector_string.cc b/third_party/blink/renderer/core/inspector/v8_inspector_string.cc
index c405cab..f1d6ef8 100644
--- a/third_party/blink/renderer/core/inspector/v8_inspector_string.cc
+++ b/third_party/blink/renderer/core/inspector/v8_inspector_string.cc
@@ -139,16 +139,11 @@
 }
 
 // static
-Binary Binary::fromVector(Vector<uint8_t>&& in) {
+Binary Binary::fromVector(Vector<uint8_t> in) {
   return Binary(base::AdoptRef(new BinaryBasedOnVector(std::move(in))));
 }
 
 // static
-Binary Binary::fromVector(const Vector<uint8_t>& in) {
-  return Binary(base::AdoptRef(new BinaryBasedOnVector(in)));
-}
-
-// static
 Binary Binary::fromCachedData(
     std::unique_ptr<v8::ScriptCompiler::CachedData> data) {
   CHECK_EQ(data->buffer_policy, v8::ScriptCompiler::CachedData::BufferOwned);
diff --git a/third_party/blink/renderer/core/inspector/v8_inspector_string.h b/third_party/blink/renderer/core/inspector/v8_inspector_string.h
index a982716..ec28817 100644
--- a/third_party/blink/renderer/core/inspector/v8_inspector_string.h
+++ b/third_party/blink/renderer/core/inspector/v8_inspector_string.h
@@ -97,8 +97,7 @@
   String toBase64() const;
   static Binary fromBase64(const String& base64, bool* success);
   static Binary fromSharedBuffer(scoped_refptr<SharedBuffer> buffer);
-  static Binary fromVector(Vector<uint8_t>&& in);
-  static Binary fromVector(const Vector<uint8_t>& in);
+  static Binary fromVector(Vector<uint8_t> in);
 
   // Note: |data.buffer_policy| must be
   // ScriptCompiler::ScriptCompiler::CachedData::BufferOwned.
diff --git a/third_party/blink/renderer/core/layout/layout_box.cc b/third_party/blink/renderer/core/layout/layout_box.cc
index 96151c6..1707ab9 100644
--- a/third_party/blink/renderer/core/layout/layout_box.cc
+++ b/third_party/blink/renderer/core/layout/layout_box.cc
@@ -3963,12 +3963,20 @@
   if (HasOverrideContainingBlockContentLogicalWidth())
     return OverrideContainingBlockContentLogicalWidth();
 
-  // Ensure we compute our width based on the width of our rel-pos inline
-  // container rather than any anonymous block created to manage a block-flow
-  // ancestor of ours in the rel-pos inline's inline flow.
   if (containing_block->IsAnonymousBlock() &&
       containing_block->IsRelPositioned()) {
+    // Ensure we compute our width based on the width of our rel-pos inline
+    // container rather than any anonymous block created to manage a block-flow
+    // ancestor of ours in the rel-pos inline's inline flow.
     containing_block = ToLayoutBox(containing_block)->Continuation();
+    // There may be nested parallel inline continuations. We have now found the
+    // innermost inline (which may not be relatively positioned). Locate the
+    // inline that serves as the containing block of this box.
+    while (!containing_block->CanContainOutOfFlowPositionedElement(
+        StyleRef().GetPosition())) {
+      containing_block = ToLayoutBoxModelObject(containing_block->Container());
+      DCHECK(containing_block->IsLayoutInline());
+    }
   } else if (containing_block->IsBox()) {
     return std::max(LayoutUnit(),
                     ToLayoutBox(containing_block)->ClientLogicalWidth());
diff --git a/third_party/blink/renderer/core/layout/layout_object.h b/third_party/blink/renderer/core/layout/layout_object.h
index 0cc77b7..2511f3e 100644
--- a/third_party/blink/renderer/core/layout/layout_object.h
+++ b/third_party/blink/renderer/core/layout/layout_object.h
@@ -749,8 +749,8 @@
   bool IsBlendingAllowed() const {
     return !IsSVG() || IsSVGShape() || IsSVGImage() || IsSVGText() ||
            IsSVGInline() || IsSVGRoot() || IsSVGForeignObject() ||
-           // TODO(pdr): According to the current spec, blending should apply to
-           // hidden containers (e.g. pattern).
+           // Blending does not apply to non-renderable elements such as
+           // patterns (see: https://github.com/w3c/fxtf-drafts/issues/309).
            (IsSVGContainer() && !IsSVGHiddenContainer());
   }
   virtual bool HasNonIsolatedBlendingDescendants() const {
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.cc
index 95b9dd1..8e370a1 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.cc
@@ -84,17 +84,9 @@
     break_token_ = NGInlineBreakToken::Create(node_);
 
   scoped_refptr<const NGPhysicalLineBoxFragment> fragment =
-      base::AdoptRef(new NGPhysicalLineBoxFragment(this));
+      NGPhysicalLineBoxFragment::Create(this);
 
-  return base::AdoptRef(new NGLayoutResult(
-      std::move(fragment), std::move(oof_positioned_descendants_),
-      std::move(positioned_floats_), unpositioned_list_marker_,
-      std::move(exclusion_space_), bfc_line_offset_, bfc_block_offset_,
-      end_margin_strut_,
-      /* intrinsic_block_size */ LayoutUnit(),
-      /* minimal_space_shortage */ LayoutUnit::Max(), EBreakBetween::kAuto,
-      EBreakBetween::kAuto, /* has_forced_break */ false, is_pushed_by_floats_,
-      adjoining_floats_, NGLayoutResult::kSuccess));
+  return base::AdoptRef(new NGLayoutResult(std::move(fragment), this));
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.h b/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.h
index aedfbb8..b09a19e 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.h
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.h
@@ -200,6 +200,7 @@
 
   TextDirection base_direction_;
 
+  friend class NGLayoutResult;
   friend class NGPhysicalLineBoxFragment;
 
   DISALLOW_COPY_AND_ASSIGN(NGLineBoxFragmentBuilder);
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.cc
index bf97083..f0bc6f3 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.cc
@@ -11,10 +11,26 @@
 
 namespace blink {
 
+scoped_refptr<const NGPhysicalLineBoxFragment>
+NGPhysicalLineBoxFragment::Create(NGLineBoxFragmentBuilder* builder) {
+  // We store the children list inline in the fragment as a flexible
+  // array. Therefore, we need to make sure to allocate enough space for
+  // that array here, which requires a manual allocation + placement new.
+  // The initialization of the array is done by NGPhysicalContainerFragment;
+  // we pass the buffer as a constructor argument.
+  void* data = ::WTF::Partitions::FastMalloc(
+      sizeof(NGPhysicalLineBoxFragment) +
+          builder->children_.size() * sizeof(NGLinkStorage),
+      ::WTF::GetStringWithTypeName<NGPhysicalLineBoxFragment>());
+  new (data) NGPhysicalLineBoxFragment(builder);
+  return base::AdoptRef(static_cast<NGPhysicalLineBoxFragment*>(data));
+}
+
 NGPhysicalLineBoxFragment::NGPhysicalLineBoxFragment(
     NGLineBoxFragmentBuilder* builder)
     : NGPhysicalContainerFragment(builder,
                                   builder->GetWritingMode(),
+                                  children_,
                                   kFragmentLineBox,
                                   0),
       metrics_(builder->metrics_) {
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h b/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h
index d843e28..e873f0e 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h
@@ -17,7 +17,17 @@
 class CORE_EXPORT NGPhysicalLineBoxFragment final
     : public NGPhysicalContainerFragment {
  public:
-  NGPhysicalLineBoxFragment(NGLineBoxFragmentBuilder* builder);
+  static scoped_refptr<const NGPhysicalLineBoxFragment> Create(
+      NGLineBoxFragmentBuilder* builder);
+
+  ~NGPhysicalLineBoxFragment() {
+    for (const NGLinkStorage& child : Children())
+      child.fragment->Release();
+  }
+
+  ChildLinkList Children() const final {
+    return ChildLinkList(num_children_, &children_[0]);
+  }
 
   const NGLineHeightMetrics& Metrics() const { return metrics_; }
 
@@ -54,7 +64,10 @@
   bool HasSoftWrapToNextLine() const;
 
  private:
+  NGPhysicalLineBoxFragment(NGLineBoxFragmentBuilder* builder);
+
   NGLineHeightMetrics metrics_;
+  NGLinkStorage children_[];
 };
 
 DEFINE_TYPE_CASTS(NGPhysicalLineBoxFragment,
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc b/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc
index 68530841..7858c06 100644
--- a/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc
+++ b/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc
@@ -240,7 +240,7 @@
   // TODO(layout-ng): Come up with a better solution for this
   if (cached_result_->OutOfFlowPositionedDescendants().size())
     return nullptr;
-  return cached_result_->CloneWithoutOffset();
+  return base::AdoptRef(new NGLayoutResult(*cached_result_));
 }
 
 template <typename Base>
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
index 7b6ccdd..40ba43b0 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
@@ -774,9 +774,9 @@
   const TextDirection direction = ConstraintSpace().Direction();
   bool has_clearance_past_adjoining_floats = HasClearancePastAdjoiningFloats(
       container_builder_.AdjoiningFloatTypes(), child_style);
-  NGInflowChildData child_data =
-      ComputeChildData(*previous_inflow_position, child, child_break_token,
-                       has_clearance_past_adjoining_floats);
+  NGInflowChildData child_data = ComputeChildData(
+      *previous_inflow_position, child, child_break_token,
+      has_clearance_past_adjoining_floats, /* is_new_fc */ true);
 
   LayoutUnit child_origin_line_offset =
       ConstraintSpace().BfcOffset().line_offset +
@@ -1109,9 +1109,9 @@
   }
 
   // Perform layout on the child.
-  NGInflowChildData child_data =
-      ComputeChildData(*previous_inflow_position, child, child_break_token,
-                       has_clearance_past_adjoining_floats);
+  NGInflowChildData child_data = ComputeChildData(
+      *previous_inflow_position, child, child_break_token,
+      has_clearance_past_adjoining_floats, /* is_new_fc */ false);
   NGConstraintSpace child_space =
       CreateConstraintSpaceForChild(child, child_data, child_available_size_);
   scoped_refptr<NGLayoutResult> layout_result = child.Layout(
@@ -1350,14 +1350,16 @@
     const NGPreviousInflowPosition& previous_inflow_position,
     NGLayoutInputNode child,
     const NGBreakToken* child_break_token,
-    bool force_clearance) {
+    bool force_clearance,
+    bool is_new_fc) {
   DCHECK(child);
   DCHECK(!child.IsFloating());
+  DCHECK_EQ(is_new_fc, child.CreatesNewFormattingContext());
 
   // Calculate margins in parent's writing mode.
   bool margins_fully_resolved;
-  NGBoxStrut margins =
-      CalculateMargins(child, child_break_token, &margins_fully_resolved);
+  NGBoxStrut margins = CalculateMargins(child, is_new_fc, child_break_token,
+                                        &margins_fully_resolved);
 
   // Append the current margin strut with child's block start margin.
   // Non empty border/padding, and new FC use cases are handled inside of the
@@ -1383,8 +1385,8 @@
           margins.LineLeft(ConstraintSpace().Direction()),
       BfcBlockOffset() + logical_block_offset};
 
-  return {child_bfc_offset, margin_strut, margins, margins_fully_resolved,
-          force_clearance};
+  return {child_bfc_offset,       margin_strut,    margins,
+          margins_fully_resolved, force_clearance, is_new_fc};
 }
 
 NGPreviousInflowPosition NGBlockLayoutAlgorithm::ComputeInflowPosition(
@@ -1399,8 +1401,7 @@
   // Determine the child's end logical offset, for the next child to use.
   LayoutUnit logical_block_offset;
 
-  bool is_empty_block =
-      IsEmptyBlock(child.CreatesNewFormattingContext(), layout_result);
+  bool is_empty_block = IsEmptyBlock(child_data.is_new_fc, layout_result);
   if (is_empty_block) {
     // The default behaviour for empty blocks is they just pass through the
     // previous inflow position.
@@ -1815,6 +1816,7 @@
 
 NGBoxStrut NGBlockLayoutAlgorithm::CalculateMargins(
     NGLayoutInputNode child,
+    bool is_new_fc,
     const NGBreakToken* child_break_token,
     bool* margins_fully_resolved) {
   // We need to at least partially resolve margins before creating a constraint
@@ -1847,7 +1849,7 @@
   // floats correctly. If we need to resolve auto margins or other alignment
   // properties to calculate the line-left offset, we also need to calculate its
   // inline size first.
-  if (!child.CreatesNewFormattingContext() && needs_inline_size) {
+  if (!is_new_fc && needs_inline_size) {
     NGConstraintSpace space =
         NGConstraintSpaceBuilder(ConstraintSpace())
             .SetAvailableSize(child_available_size_)
@@ -1889,8 +1891,7 @@
   if (NGBaseline::ShouldPropagateBaselines(child))
     space_builder.AddBaselineRequests(ConstraintSpace().BaselineRequests());
 
-  bool is_new_fc = child.CreatesNewFormattingContext();
-  space_builder.SetIsNewFormattingContext(is_new_fc)
+  space_builder.SetIsNewFormattingContext(child_data.is_new_fc)
       .SetBfcOffset(child_data.bfc_offset_estimate)
       .SetMarginStrut(child_data.margin_strut);
 
@@ -1928,7 +1929,7 @@
   if (child_data.force_clearance)
     space_builder.SetShouldForceClearance(true);
 
-  if (!is_new_fc) {
+  if (!child_data.is_new_fc) {
     space_builder.SetExclusionSpace(exclusion_space_);
     space_builder.SetAdjoiningFloatTypes(
         container_builder_.AdjoiningFloatTypes());
@@ -1940,7 +1941,7 @@
     // If a block establishes a new formatting context we must know our
     // position in the formatting context, and are able to adjust the
     // fragmentation line.
-    if (is_new_fc) {
+    if (child_data.is_new_fc) {
       space_available -= child_data.bfc_offset_estimate.block_offset;
     }
     // The policy regarding collapsing block-start margin with the fragmentainer
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.h b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.h
index 3aba29b..e7811f0 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.h
@@ -41,6 +41,7 @@
   NGBoxStrut margins;
   bool margins_fully_resolved;
   bool force_clearance;
+  bool is_new_fc;
 };
 
 // A class for general block layout (e.g. a <div> with no special style).
@@ -87,6 +88,7 @@
   }
 
   NGBoxStrut CalculateMargins(NGLayoutInputNode child,
+                              bool is_new_fc,
                               const NGBreakToken* child_break_token,
                               bool* margins_fully_resolved);
 
@@ -101,7 +103,8 @@
   NGInflowChildData ComputeChildData(const NGPreviousInflowPosition&,
                                      NGLayoutInputNode,
                                      const NGBreakToken* child_break_token,
-                                     bool force_clearance);
+                                     bool force_clearance,
+                                     bool is_new_fc);
 
   NGPreviousInflowPosition ComputeInflowPosition(
       const NGPreviousInflowPosition&,
diff --git a/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc b/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc
index dd04b8ec..1377d7bb 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc
@@ -226,30 +226,15 @@
     }
   }
 
-  scoped_refptr<const NGPhysicalBoxFragment> fragment = base::AdoptRef(
-      new NGPhysicalBoxFragment(this, block_or_line_writing_mode));
+  scoped_refptr<const NGPhysicalBoxFragment> fragment =
+      NGPhysicalBoxFragment::Create(this, block_or_line_writing_mode);
 
-  Vector<NGPositionedFloat> positioned_floats;
-
-  return base::AdoptRef(new NGLayoutResult(
-      std::move(fragment), std::move(oof_positioned_descendants_),
-      std::move(positioned_floats), unpositioned_list_marker_,
-      std::move(exclusion_space_), bfc_line_offset_, bfc_block_offset_,
-      end_margin_strut_, intrinsic_block_size_, minimal_space_shortage_,
-      initial_break_before_, previous_break_after_, has_forced_break_,
-      is_pushed_by_floats_, adjoining_floats_, NGLayoutResult::kSuccess));
+  return base::AdoptRef(new NGLayoutResult(std::move(fragment), this));
 }
 
 scoped_refptr<NGLayoutResult> NGBoxFragmentBuilder::Abort(
     NGLayoutResult::NGLayoutResultStatus status) {
-  Vector<NGOutOfFlowPositionedDescendant> oof_positioned_descendants;
-  Vector<NGPositionedFloat> positioned_floats;
-  return base::AdoptRef(new NGLayoutResult(
-      nullptr, std::move(oof_positioned_descendants),
-      std::move(positioned_floats), NGUnpositionedListMarker(),
-      NGExclusionSpace(), bfc_line_offset_, bfc_block_offset_,
-      end_margin_strut_, LayoutUnit(), LayoutUnit(), EBreakBetween::kAuto,
-      EBreakBetween::kAuto, false, false, kFloatTypeNone, status));
+  return base::AdoptRef(new NGLayoutResult(status, this));
 }
 
 // Finds FragmentPairs that define inline containing blocks.
diff --git a/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h b/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h
index 0fb54f2c..40a00010 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h
@@ -265,6 +265,7 @@
   NGBorderEdges border_edges_;
 
   friend class NGPhysicalBoxFragment;
+  friend class NGLayoutResult;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/ng_layout_result.cc b/third_party/blink/renderer/core/layout/ng/ng_layout_result.cc
index 7c47dcb..872fdef 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_layout_result.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_layout_result.cc
@@ -8,60 +8,89 @@
 #include <utility>
 
 #include "third_party/blink/renderer/core/layout/ng/exclusions/ng_exclusion_space.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_positioned_float.h"
 
 namespace blink {
 
 NGLayoutResult::NGLayoutResult(
     scoped_refptr<const NGPhysicalFragment> physical_fragment,
-    Vector<NGOutOfFlowPositionedDescendant>&& oof_positioned_descendants,
-    Vector<NGPositionedFloat>&& positioned_floats,
-    const NGUnpositionedListMarker& unpositioned_list_marker,
-    NGExclusionSpace&& exclusion_space,
-    LayoutUnit bfc_line_offset,
-    const base::Optional<LayoutUnit> bfc_block_offset,
-    const NGMarginStrut end_margin_strut,
-    const LayoutUnit intrinsic_block_size,
-    LayoutUnit minimal_space_shortage,
-    EBreakBetween initial_break_before,
-    EBreakBetween final_break_after,
-    bool has_forced_break,
-    bool is_pushed_by_floats,
-    NGFloatTypes adjoining_floats,
-    NGLayoutResultStatus status)
-    : unpositioned_list_marker_(unpositioned_list_marker),
-      exclusion_space_(std::move(exclusion_space)),
-      bfc_line_offset_(bfc_line_offset),
-      bfc_block_offset_(bfc_block_offset),
-      end_margin_strut_(end_margin_strut),
-      intrinsic_block_size_(intrinsic_block_size),
-      minimal_space_shortage_(minimal_space_shortage),
-      initial_break_before_(initial_break_before),
-      final_break_after_(final_break_after),
-      has_forced_break_(has_forced_break),
-      is_pushed_by_floats_(is_pushed_by_floats),
-      adjoining_floats_(adjoining_floats),
-      status_(status) {
+    NGBoxFragmentBuilder* builder)
+    : unpositioned_list_marker_(builder->unpositioned_list_marker_),
+      exclusion_space_(std::move(builder->exclusion_space_)),
+      bfc_line_offset_(builder->bfc_line_offset_),
+      bfc_block_offset_(builder->bfc_block_offset_),
+      end_margin_strut_(builder->end_margin_strut_),
+      intrinsic_block_size_(builder->intrinsic_block_size_),
+      minimal_space_shortage_(builder->minimal_space_shortage_),
+      initial_break_before_(builder->initial_break_before_),
+      final_break_after_(builder->previous_break_after_),
+      has_forced_break_(builder->has_forced_break_),
+      is_pushed_by_floats_(builder->is_pushed_by_floats_),
+      adjoining_floats_(builder->adjoining_floats_),
+      status_(kSuccess) {
+  DCHECK(physical_fragment) << "Use the other constructor for aborting layout";
   root_fragment_.fragment_ = std::move(physical_fragment);
-  oof_positioned_descendants_.swap(oof_positioned_descendants);
-  positioned_floats_.swap(positioned_floats);
+  oof_positioned_descendants_ = std::move(builder->oof_positioned_descendants_);
 }
 
+NGLayoutResult::NGLayoutResult(NGLayoutResultStatus status,
+                               NGBoxFragmentBuilder* builder)
+    : bfc_line_offset_(builder->bfc_line_offset_),
+      bfc_block_offset_(builder->bfc_block_offset_),
+      end_margin_strut_(builder->end_margin_strut_),
+      initial_break_before_(EBreakBetween::kAuto),
+      final_break_after_(EBreakBetween::kAuto),
+      has_forced_break_(false),
+      is_pushed_by_floats_(false),
+      adjoining_floats_(kFloatTypeNone),
+      status_(status) {
+  DCHECK_NE(status, kSuccess)
+      << "Use the other constructor for successful layout";
+}
+
+NGLayoutResult::NGLayoutResult(
+    scoped_refptr<const NGPhysicalFragment> physical_fragment,
+    NGLineBoxFragmentBuilder* builder)
+    : unpositioned_list_marker_(builder->unpositioned_list_marker_),
+      exclusion_space_(std::move(builder->exclusion_space_)),
+      bfc_line_offset_(builder->bfc_line_offset_),
+      bfc_block_offset_(builder->bfc_block_offset_),
+      end_margin_strut_(builder->end_margin_strut_),
+      minimal_space_shortage_(LayoutUnit::Max()),
+      initial_break_before_(EBreakBetween::kAuto),
+      final_break_after_(EBreakBetween::kAuto),
+      has_forced_break_(false),
+      is_pushed_by_floats_(builder->is_pushed_by_floats_),
+      adjoining_floats_(builder->adjoining_floats_),
+      status_(kSuccess) {
+  root_fragment_.fragment_ = std::move(physical_fragment);
+  oof_positioned_descendants_ = std::move(builder->oof_positioned_descendants_);
+  positioned_floats_ = std::move(builder->positioned_floats_);
+}
+
+// We can't use =default here because RefCounted can't be copied.
+NGLayoutResult::NGLayoutResult(const NGLayoutResult& other)
+    : root_fragment_(other.root_fragment_),
+      oof_positioned_descendants_(other.oof_positioned_descendants_),
+      positioned_floats_(other.positioned_floats_),
+      unpositioned_list_marker_(other.unpositioned_list_marker_),
+      exclusion_space_(other.exclusion_space_),
+      bfc_line_offset_(other.bfc_line_offset_),
+      bfc_block_offset_(other.bfc_block_offset_),
+      end_margin_strut_(other.end_margin_strut_),
+      intrinsic_block_size_(other.intrinsic_block_size_),
+      minimal_space_shortage_(other.minimal_space_shortage_),
+      initial_break_before_(other.initial_break_before_),
+      final_break_after_(other.final_break_after_),
+      has_forced_break_(other.has_forced_break_),
+      is_pushed_by_floats_(other.is_pushed_by_floats_),
+      adjoining_floats_(other.adjoining_floats_),
+      status_(other.status_) {}
+
 // Define the destructor here, so that we can forward-declare more in the
 // header.
 NGLayoutResult::~NGLayoutResult() = default;
 
-scoped_refptr<NGLayoutResult> NGLayoutResult::CloneWithoutOffset() const {
-  Vector<NGOutOfFlowPositionedDescendant> oof_positioned_descendants(
-      oof_positioned_descendants_);
-  Vector<NGPositionedFloat> positioned_floats(positioned_floats_);
-  return base::AdoptRef(new NGLayoutResult(
-      root_fragment_.fragment_, std::move(oof_positioned_descendants),
-      std::move(positioned_floats), unpositioned_list_marker_,
-      NGExclusionSpace(exclusion_space_), bfc_line_offset_, bfc_block_offset_,
-      end_margin_strut_, intrinsic_block_size_, minimal_space_shortage_,
-      initial_break_before_, final_break_after_, has_forced_break_,
-      is_pushed_by_floats_, adjoining_floats_, Status()));
-}
-
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/ng_layout_result.h b/third_party/blink/renderer/core/layout/ng/ng_layout_result.h
index 10ac807..e16c675 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_layout_result.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_layout_result.h
@@ -20,7 +20,9 @@
 
 namespace blink {
 
+class NGBoxFragmentBuilder;
 class NGExclusionSpace;
+class NGLineBoxFragmentBuilder;
 struct NGPositionedFloat;
 
 // The NGLayoutResult stores the resulting data from layout. This includes
@@ -38,6 +40,7 @@
     // enough to store.
   };
 
+  NGLayoutResult(const NGLayoutResult&);
   ~NGLayoutResult();
 
   scoped_refptr<const NGPhysicalFragment> PhysicalFragment() const {
@@ -110,29 +113,17 @@
   // the block, and the block will fail to clear).
   NGFloatTypes AdjoiningFloatTypes() const { return adjoining_floats_; }
 
-  scoped_refptr<NGLayoutResult> CloneWithoutOffset() const;
-
  private:
   friend class NGBoxFragmentBuilder;
   friend class NGLineBoxFragmentBuilder;
 
+  // This constructor requires a non-null fragment and sets a success status.
   NGLayoutResult(scoped_refptr<const NGPhysicalFragment> physical_fragment,
-                 Vector<NGOutOfFlowPositionedDescendant>&&
-                     out_of_flow_positioned_descendants,
-                 Vector<NGPositionedFloat>&& positioned_floats,
-                 const NGUnpositionedListMarker& unpositioned_list_marker,
-                 NGExclusionSpace&& exclusion_space,
-                 LayoutUnit bfc_line_offset,
-                 const base::Optional<LayoutUnit> bfc_block_offset,
-                 const NGMarginStrut end_margin_strut,
-                 const LayoutUnit intrinsic_block_size,
-                 LayoutUnit minimal_space_shortage,
-                 EBreakBetween initial_break_before,
-                 EBreakBetween final_break_after,
-                 bool has_forced_break,
-                 bool is_pushed_by_floats,
-                 NGFloatTypes adjoining_floats,
-                 NGLayoutResultStatus status);
+                 NGBoxFragmentBuilder*);
+  // This constructor is for a non-success status.
+  NGLayoutResult(NGLayoutResultStatus, NGBoxFragmentBuilder*);
+  NGLayoutResult(scoped_refptr<const NGPhysicalFragment> physical_fragment,
+                 NGLineBoxFragmentBuilder*);
 
   NGLink root_fragment_;
   Vector<NGOutOfFlowPositionedDescendant> oof_positioned_descendants_;
diff --git a/third_party/blink/renderer/core/layout/ng/ng_length_utils.cc b/third_party/blink/renderer/core/layout/ng/ng_length_utils.cc
index 068a1f7..07d5ead 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_length_utils.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_length_utils.cc
@@ -53,20 +53,6 @@
 
 }  // anonymous namespace
 
-bool NeedMinMaxSize(const NGConstraintSpace& constraint_space,
-                    const ComputedStyle& style) {
-  // This check is technically too broad (fill-available does not need intrinsic
-  // size computation) but that's a rare case and only affects performance, not
-  // correctness.
-  return constraint_space.IsShrinkToFit() || NeedMinMaxSize(style);
-}
-
-bool NeedMinMaxSize(const ComputedStyle& style) {
-  return style.LogicalWidth().IsIntrinsic() ||
-         style.LogicalMinWidth().IsIntrinsic() ||
-         style.LogicalMaxWidth().IsIntrinsic();
-}
-
 bool NeedMinMaxSizeForContentContribution(WritingMode mode,
                                           const ComputedStyle& style) {
   // During the intrinsic sizes pass percentages/calc() are defined to behave
@@ -297,13 +283,6 @@
   }
 }
 
-LayoutUnit ResolveMarginPaddingLength(const NGConstraintSpace& constraint_space,
-                                      const Length& length) {
-  LayoutUnit percentage_resolution_size =
-      constraint_space.PercentageResolutionInlineSizeForParentWritingMode();
-  return ResolveMarginPaddingLength(percentage_resolution_size, length);
-}
-
 LayoutUnit ResolveMarginPaddingLength(LayoutUnit percentage_resolution_size,
                                       const Length& length) {
   DCHECK_GE(percentage_resolution_size, LayoutUnit());
@@ -700,14 +679,6 @@
 }
 
 NGPhysicalBoxStrut ComputePhysicalMargins(
-    const NGConstraintSpace& constraint_space,
-    const ComputedStyle& style) {
-  LayoutUnit percentage_resolution_size =
-      constraint_space.PercentageResolutionInlineSizeForParentWritingMode();
-  return ComputePhysicalMargins(style, percentage_resolution_size);
-}
-
-NGPhysicalBoxStrut ComputePhysicalMargins(
     const ComputedStyle& style,
     LayoutUnit percentage_resolution_size) {
   if (!style.HasMargin())
@@ -736,39 +707,6 @@
       .ConvertToLogical(compute_for.GetWritingMode(), compute_for.Direction());
 }
 
-NGLineBoxStrut ComputeLineMarginsForVisualContainer(
-    const NGConstraintSpace& constraint_space,
-    const ComputedStyle& style) {
-  if (constraint_space.IsAnonymous())
-    return NGLineBoxStrut();
-  LayoutUnit percentage_resolution_size =
-      constraint_space.PercentageResolutionInlineSizeForParentWritingMode();
-  return ComputePhysicalMargins(style, percentage_resolution_size)
-      .ConvertToLineLogical(constraint_space.GetWritingMode(),
-                            TextDirection::kLtr);
-}
-
-NGBoxStrut ComputeMarginsForSelf(const NGConstraintSpace& constraint_space,
-                                 const ComputedStyle& style) {
-  if (constraint_space.IsAnonymous())
-    return NGBoxStrut();
-  LayoutUnit percentage_resolution_size =
-      constraint_space.PercentageResolutionInlineSizeForParentWritingMode();
-  return ComputePhysicalMargins(style, percentage_resolution_size)
-      .ConvertToLogical(style.GetWritingMode(), style.Direction());
-}
-
-NGLineBoxStrut ComputeLineMarginsForSelf(
-    const NGConstraintSpace& constraint_space,
-    const ComputedStyle& style) {
-  if (constraint_space.IsAnonymous())
-    return NGLineBoxStrut();
-  LayoutUnit percentage_resolution_size =
-      constraint_space.PercentageResolutionInlineSizeForParentWritingMode();
-  return ComputePhysicalMargins(style, percentage_resolution_size)
-      .ConvertToLineLogical(style.GetWritingMode(), style.Direction());
-}
-
 NGBoxStrut ComputeMinMaxMargins(const ComputedStyle& parent_style,
                                 NGLayoutInputNode child) {
   // An inline child just produces line-boxes which don't have any margins.
@@ -822,12 +760,6 @@
   return ComputeBorders(constraint_space, node.Style());
 }
 
-NGLineBoxStrut ComputeLineBorders(const NGConstraintSpace& constraint_space,
-                                  const ComputedStyle& style) {
-  return NGLineBoxStrut(ComputeBorders(constraint_space, style),
-                        style.IsFlippedLinesWritingMode());
-}
-
 NGBoxStrut ComputeIntrinsicPadding(const NGConstraintSpace& constraint_space,
                                    const NGLayoutInputNode node) {
   if (constraint_space.IsAnonymous() || !node.IsTableCell())
@@ -864,11 +796,6 @@
   return padding;
 }
 
-NGLineBoxStrut ComputeLinePadding(const NGConstraintSpace& constraint_space,
-                                  const ComputedStyle& style) {
-  return NGLineBoxStrut(ComputePadding(constraint_space, style),
-                        style.IsFlippedLinesWritingMode());
-}
 
 bool NeedsInlineSizeToResolveLineLeft(const ComputedStyle& style,
                                       const ComputedStyle& container_style) {
@@ -955,12 +882,6 @@
   return IsLtr(direction) ? line_offset : space_left - line_offset;
 }
 
-LayoutUnit ConstrainByMinMax(LayoutUnit length,
-                             LayoutUnit min,
-                             LayoutUnit max) {
-  return std::max(min, std::min(length, max));
-}
-
 bool ClampScrollbarToContentBox(NGBoxStrut* scrollbars,
                                 LayoutUnit content_box_inline_size) {
   DCHECK(scrollbars->InlineSum());
diff --git a/third_party/blink/renderer/core/layout/ng/ng_length_utils.h b/third_party/blink/renderer/core/layout/ng/ng_length_utils.h
index 09c730f..0ad5af7d1 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_length_utils.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_length_utils.h
@@ -11,6 +11,8 @@
 #include "third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.h"
 #include "third_party/blink/renderer/core/layout/ng/geometry/ng_logical_size.h"
 #include "third_party/blink/renderer/core/layout/ng/geometry/ng_physical_size.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space.h"
+#include "third_party/blink/renderer/core/style/computed_style.h"
 #include "third_party/blink/renderer/core/style/computed_style_constants.h"
 #include "third_party/blink/renderer/platform/text/text_direction.h"
 #include "third_party/blink/renderer/platform/text/writing_mode.h"
@@ -35,13 +37,24 @@
 // kContentSize - width / height
 enum class LengthResolveType { kMinSize, kMaxSize, kContentSize };
 
+CORE_EXPORT inline bool NeedMinMaxSize(const ComputedStyle& style) {
+  // This check is technically too broad (fill-available does not need intrinsic
+  // size computation) but that's a rare case and only affects performance, not
+  // correctness.
+  return style.LogicalWidth().IsIntrinsic() ||
+         style.LogicalMinWidth().IsIntrinsic() ||
+         style.LogicalMaxWidth().IsIntrinsic();
+}
+
 // Whether the caller needs to compute min-content and max-content sizes to
 // pass them to ResolveInlineLength / ComputeInlineSizeForFragment.
 // If this function returns false, it is safe to pass an empty
 // MinMaxSize struct to those functions.
-CORE_EXPORT bool NeedMinMaxSize(const NGConstraintSpace&, const ComputedStyle&);
-
-CORE_EXPORT bool NeedMinMaxSize(const ComputedStyle&);
+CORE_EXPORT inline bool NeedMinMaxSize(
+    const NGConstraintSpace& constraint_space,
+    const ComputedStyle& style) {
+  return constraint_space.IsShrinkToFit() || NeedMinMaxSize(style);
+}
 
 // Like NeedMinMaxSize, but for use when calling
 // ComputeMinAndMaxContentContribution.
@@ -80,10 +93,15 @@
 
 // Convert margin/border/padding length to a layout unit using the
 // given constraint space.
-CORE_EXPORT LayoutUnit ResolveMarginPaddingLength(const NGConstraintSpace&,
-                                                  const Length&);
 LayoutUnit ResolveMarginPaddingLength(LayoutUnit percentage_resolution_size,
                                       const Length&);
+CORE_EXPORT inline LayoutUnit ResolveMarginPaddingLength(
+    const NGConstraintSpace& constraint_space,
+    const Length& length) {
+  LayoutUnit percentage_resolution_size =
+      constraint_space.PercentageResolutionInlineSizeForParentWritingMode();
+  return ResolveMarginPaddingLength(percentage_resolution_size, length);
+}
 
 // For the given style and min/max content sizes, computes the min and max
 // content contribution (https://drafts.csswg.org/css-sizing/#contributions).
@@ -162,12 +180,18 @@
                                             const ComputedStyle&);
 
 // Compute physical margins.
-CORE_EXPORT NGPhysicalBoxStrut ComputePhysicalMargins(const NGConstraintSpace&,
-                                                      const ComputedStyle&);
 CORE_EXPORT NGPhysicalBoxStrut
 ComputePhysicalMargins(const ComputedStyle&,
                        LayoutUnit percentage_resolution_size);
 
+CORE_EXPORT inline NGPhysicalBoxStrut ComputePhysicalMargins(
+    const NGConstraintSpace& constraint_space,
+    const ComputedStyle& style) {
+  LayoutUnit percentage_resolution_size =
+      constraint_space.PercentageResolutionInlineSizeForParentWritingMode();
+  return ComputePhysicalMargins(style, percentage_resolution_size);
+}
+
 // Compute margins for the specified NGConstraintSpace.
 CORE_EXPORT NGBoxStrut ComputeMarginsFor(const NGConstraintSpace&,
                                          const ComputedStyle&,
@@ -182,21 +206,45 @@
 }
 
 // Compute margins for the style owner.
-CORE_EXPORT NGBoxStrut ComputeMarginsForSelf(const NGConstraintSpace&,
-                                             const ComputedStyle&);
+CORE_EXPORT inline NGBoxStrut ComputeMarginsForSelf(
+    const NGConstraintSpace& constraint_space,
+    const ComputedStyle& style) {
+  if (constraint_space.IsAnonymous())
+    return NGBoxStrut();
+  LayoutUnit percentage_resolution_size =
+      constraint_space.PercentageResolutionInlineSizeForParentWritingMode();
+  return ComputePhysicalMargins(style, percentage_resolution_size)
+      .ConvertToLogical(style.GetWritingMode(), style.Direction());
+}
 
 // Compute line logical margins for the style owner.
 //
 // The "line" versions compute line-relative logical values. See NGLineBoxStrut
 // for more details.
-CORE_EXPORT NGLineBoxStrut ComputeLineMarginsForSelf(const NGConstraintSpace&,
-                                                     const ComputedStyle&);
+CORE_EXPORT inline NGLineBoxStrut ComputeLineMarginsForSelf(
+    const NGConstraintSpace& constraint_space,
+    const ComputedStyle& style) {
+  if (constraint_space.IsAnonymous())
+    return NGLineBoxStrut();
+  LayoutUnit percentage_resolution_size =
+      constraint_space.PercentageResolutionInlineSizeForParentWritingMode();
+  return ComputePhysicalMargins(style, percentage_resolution_size)
+      .ConvertToLineLogical(style.GetWritingMode(), style.Direction());
+}
 
 // Compute line logical margins for the constraint space, in the visual order
 // (always assumes LTR, ignoring the direction) for inline layout algorithm.
-CORE_EXPORT NGLineBoxStrut
-ComputeLineMarginsForVisualContainer(const NGConstraintSpace&,
-                                     const ComputedStyle&);
+CORE_EXPORT inline NGLineBoxStrut ComputeLineMarginsForVisualContainer(
+    const NGConstraintSpace& constraint_space,
+    const ComputedStyle& style) {
+  if (constraint_space.IsAnonymous())
+    return NGLineBoxStrut();
+  LayoutUnit percentage_resolution_size =
+      constraint_space.PercentageResolutionInlineSizeForParentWritingMode();
+  return ComputePhysicalMargins(style, percentage_resolution_size)
+      .ConvertToLineLogical(constraint_space.GetWritingMode(),
+                            TextDirection::kLtr);
+}
 
 // Compute margins for a child during the min-max size calculation.
 CORE_EXPORT NGBoxStrut ComputeMinMaxMargins(const ComputedStyle& parent_style,
@@ -208,8 +256,12 @@
 CORE_EXPORT NGBoxStrut ComputeBorders(const NGConstraintSpace&,
                                       const NGLayoutInputNode);
 
-CORE_EXPORT NGLineBoxStrut ComputeLineBorders(const NGConstraintSpace&,
-                                              const ComputedStyle&);
+CORE_EXPORT inline NGLineBoxStrut ComputeLineBorders(
+    const NGConstraintSpace& constraint_space,
+    const ComputedStyle& style) {
+  return NGLineBoxStrut(ComputeBorders(constraint_space, style),
+                        style.IsFlippedLinesWritingMode());
+}
 
 CORE_EXPORT NGBoxStrut ComputeIntrinsicPadding(const NGConstraintSpace&,
                                                const NGLayoutInputNode);
@@ -217,8 +269,12 @@
 CORE_EXPORT NGBoxStrut ComputePadding(const NGConstraintSpace&,
                                       const ComputedStyle&);
 
-CORE_EXPORT NGLineBoxStrut ComputeLinePadding(const NGConstraintSpace&,
-                                              const ComputedStyle&);
+CORE_EXPORT inline NGLineBoxStrut ComputeLinePadding(
+    const NGConstraintSpace& constraint_space,
+    const ComputedStyle& style) {
+  return NGLineBoxStrut(ComputePadding(constraint_space, style),
+                        style.IsFlippedLinesWritingMode());
+}
 
 // Return true if we need to know the inline size of the fragment in order to
 // calculate its line-left offset. This is the case when we have auto margins,
@@ -253,9 +309,11 @@
 CORE_EXPORT LayoutUnit InlineOffsetForTextAlign(const ComputedStyle&,
                                                 LayoutUnit space_left);
 
-CORE_EXPORT LayoutUnit ConstrainByMinMax(LayoutUnit length,
-                                         LayoutUnit min,
-                                         LayoutUnit max);
+CORE_EXPORT inline LayoutUnit ConstrainByMinMax(LayoutUnit length,
+                                                LayoutUnit min,
+                                                LayoutUnit max) {
+  return std::max(min, std::min(length, max));
+}
 
 // Clamp the inline size of the scrollbar, unless it's larger than the inline
 // size of the content box, in which case we'll return that instead. Scrollbar
diff --git a/third_party/blink/renderer/core/layout/ng/ng_link.h b/third_party/blink/renderer/core/layout/ng/ng_link.h
index a501c373..089992d 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_link.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_link.h
@@ -12,6 +12,21 @@
 
 namespace blink {
 
+// We use this struct to store NGLinks in a flexible array in fragments. We have
+// to use this struct instead of using NGLink because flexible array members
+// cannot have destructors, so we need to do manual refcounting.
+struct NGLinkStorage {
+  NGPhysicalOffset Offset() const { return offset; }
+  const NGPhysicalFragment* get() const { return fragment; }
+
+  operator bool() const { return fragment; }
+  const NGPhysicalFragment& operator*() const { return *fragment; }
+  const NGPhysicalFragment* operator->() const { return fragment; }
+
+  const NGPhysicalFragment* fragment;
+  NGPhysicalOffset offset;
+};
+
 // Class representing the offset of a child fragment relative to the
 // parent fragment. Fragments themselves have no position information
 // allowing entire fragment subtrees to be reused and cached regardless
@@ -26,6 +41,8 @@
       : fragment_(std::move(fragment)), offset_(offset) {}
   NGLink(NGLink&& o) noexcept
       : fragment_(std::move(o.fragment_)), offset_(o.offset_) {}
+  NGLink(const NGLinkStorage& storage)
+      : fragment_(storage.fragment), offset_(storage.offset) {}
   ~NGLink() = default;
   NGLink(const NGLink&) = default;
   NGLink& operator=(const NGLink&) = default;
@@ -46,8 +63,6 @@
   // The builder classes needs to set the offset_ field during
   // fragment construciton to allow the child vector to be moved
   // instead of reconstructed during fragment construction.
-  friend class NGBoxFragmentBuilder;
-  friend class NGLineBoxFragmentBuilder;
   friend class NGLayoutResult;
 };
 
diff --git a/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc b/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc
index fc7e3d7..ef01c9b 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc
@@ -17,12 +17,29 @@
 
 namespace blink {
 
+scoped_refptr<const NGPhysicalBoxFragment> NGPhysicalBoxFragment::Create(
+    NGBoxFragmentBuilder* builder,
+    WritingMode block_or_line_writing_mode) {
+  // We store the children list inline in the fragment as a flexible
+  // array. Therefore, we need to make sure to allocate enough space for
+  // that array here, which requires a manual allocation + placement new.
+  // The initialization of the array is done by NGPhysicalContainerFragment;
+  // we pass the buffer as a constructor argument.
+  void* data = ::WTF::Partitions::FastMalloc(
+      sizeof(NGPhysicalBoxFragment) +
+          builder->children_.size() * sizeof(NGLinkStorage),
+      ::WTF::GetStringWithTypeName<NGPhysicalBoxFragment>());
+  new (data) NGPhysicalBoxFragment(builder, block_or_line_writing_mode);
+  return base::AdoptRef(static_cast<NGPhysicalBoxFragment*>(data));
+}
+
 NGPhysicalBoxFragment::NGPhysicalBoxFragment(
     NGBoxFragmentBuilder* builder,
     WritingMode block_or_line_writing_mode)
     : NGPhysicalContainerFragment(
           builder,
           block_or_line_writing_mode,
+          children_,
           (builder->node_ && builder->node_.IsRenderedLegend())
               ? kFragmentRenderedLegend
               : kFragmentBox,
diff --git a/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h b/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h
index a337031..fb56147 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h
@@ -19,8 +19,18 @@
 class CORE_EXPORT NGPhysicalBoxFragment final
     : public NGPhysicalContainerFragment {
  public:
-  NGPhysicalBoxFragment(NGBoxFragmentBuilder* builder,
-                        WritingMode block_or_line_writing_mode);
+  static scoped_refptr<const NGPhysicalBoxFragment> Create(
+      NGBoxFragmentBuilder* builder,
+      WritingMode block_or_line_writing_mode);
+
+  ~NGPhysicalBoxFragment() {
+    for (const NGLinkStorage& child : Children())
+      child.fragment->Release();
+  }
+
+  ChildLinkList Children() const final {
+    return ChildLinkList(num_children_, &children_[0]);
+  }
 
   const NGBaseline* Baseline(const NGBaselineRequest&) const;
 
@@ -75,10 +85,14 @@
   scoped_refptr<const NGPhysicalFragment> CloneWithoutOffset() const;
 
  private:
+  NGPhysicalBoxFragment(NGBoxFragmentBuilder* builder,
+                        WritingMode block_or_line_writing_mode);
+
   Vector<NGBaseline> baselines_;
   NGPhysicalBoxStrut borders_;
   NGPhysicalBoxStrut padding_;
   NGPhysicalOffsetRect descendant_outlines_;
+  NGLinkStorage children_[];
 };
 
 DEFINE_TYPE_CASTS(
diff --git a/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.cc b/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.cc
index ca46a4c..bb9f199 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.cc
@@ -17,18 +17,22 @@
 NGPhysicalContainerFragment::NGPhysicalContainerFragment(
     NGContainerFragmentBuilder* builder,
     WritingMode block_or_line_writing_mode,
+    NGLinkStorage* buffer,
     NGFragmentType type,
     unsigned sub_type)
-    : NGPhysicalFragment(builder, type, sub_type) {
-  children_.ReserveInitialCapacity(children_.size());
-
+    : NGPhysicalFragment(builder, type, sub_type),
+      num_children_(builder->children_.size()) {
   DCHECK_EQ(builder->children_.size(), builder->offsets_.size());
+  // Because flexible arrays need to be the last member in a class, we need to
+  // have the buffer passed as a constructor argument and have the actual
+  // storage be part of the subclass.
   wtf_size_t i = 0;
   for (auto& child : builder->children_) {
-    children_.emplace_back(std::move(child),
-                           builder->offsets_[i].ConvertToPhysical(
-                               block_or_line_writing_mode, builder->Direction(),
-                               Size(), child->Size()));
+    buffer[i].fragment = child.get();
+    buffer[i].fragment->AddRef();
+    buffer[i].offset = builder->offsets_[i].ConvertToPhysical(
+        block_or_line_writing_mode, builder->Direction(), Size(),
+        child->Size());
     ++i;
   }
 }
diff --git a/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.h b/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.h
index a997951..9ef9a35 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.h
@@ -18,7 +18,29 @@
 
 class CORE_EXPORT NGPhysicalContainerFragment : public NGPhysicalFragment {
  public:
-  const Vector<NGLink>& Children() const { return children_; }
+  class ChildLinkList {
+   public:
+    ChildLinkList(wtf_size_t count, const NGLinkStorage* buffer)
+        : count_(count), buffer_(buffer) {}
+
+    wtf_size_t size() const { return count_; }
+    const NGLinkStorage& operator[](wtf_size_t idx) const {
+      return buffer_[idx];
+    }
+    const NGLinkStorage& front() const { return buffer_[0]; }
+    const NGLinkStorage& back() const { return buffer_[count_ - 1]; }
+
+    const NGLinkStorage* begin() const { return buffer_; }
+    const NGLinkStorage* end() const { return begin() + count_; }
+
+    bool IsEmpty() const { return count_ == 0; }
+
+   private:
+    wtf_size_t count_;
+    const NGLinkStorage* buffer_;
+  };
+
+  virtual ChildLinkList Children() const = 0;
 
   void AddOutlineRectsForNormalChildren(Vector<LayoutRect>* outline_rects,
                                         const LayoutPoint& additional_offset,
@@ -32,10 +54,11 @@
   // block_or_line_writing_mode is used for converting the child offsets.
   NGPhysicalContainerFragment(NGContainerFragmentBuilder*,
                               WritingMode block_or_line_writing_mode,
+                              NGLinkStorage* buffer,
                               NGFragmentType,
                               unsigned sub_type);
 
-  Vector<NGLink> children_;
+  wtf_size_t num_children_;
 };
 
 DEFINE_TYPE_CASTS(NGPhysicalContainerFragment,
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_resource_filter_primitive.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_resource_filter_primitive.cc
index 014b405..b76d248 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_resource_filter_primitive.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_resource_filter_primitive.cc
@@ -49,19 +49,19 @@
   if (IsSVGFEFloodElement(element) || IsSVGFEDropShadowElement(element)) {
     if (new_style.FloodColor() != old_style->SvgStyle().FloodColor() ||
         CurrentColorChanged(diff, new_style.FloodColor()))
-      element.PrimitiveAttributeChanged(SVGNames::flood_colorAttr);
+      element.PrimitiveAttributeChanged(svg_names::kFloodColorAttr);
     if (new_style.FloodOpacity() != old_style->SvgStyle().FloodOpacity())
-      element.PrimitiveAttributeChanged(SVGNames::flood_opacityAttr);
+      element.PrimitiveAttributeChanged(svg_names::kFloodOpacityAttr);
   } else if (IsSVGFEDiffuseLightingElement(element) ||
              IsSVGFESpecularLightingElement(element)) {
     if (new_style.LightingColor() != old_style->SvgStyle().LightingColor() ||
         CurrentColorChanged(diff, new_style.LightingColor()))
-      element.PrimitiveAttributeChanged(SVGNames::lighting_colorAttr);
+      element.PrimitiveAttributeChanged(svg_names::kLightingColorAttr);
   }
   if (new_style.ColorInterpolationFilters() !=
       old_style->SvgStyle().ColorInterpolationFilters()) {
     element.PrimitiveAttributeChanged(
-        SVGNames::color_interpolation_filtersAttr);
+        svg_names::kColorInterpolationFiltersAttr);
   }
 }
 
diff --git a/third_party/blink/renderer/core/layout/svg/svg_resources.cc b/third_party/blink/renderer/core/layout/svg/svg_resources.cc
index 5728ea3e..a24b06dc 100644
--- a/third_party/blink/renderer/core/layout/svg/svg_resources.cc
+++ b/third_party/blink/renderer/core/layout/svg/svg_resources.cc
@@ -43,7 +43,7 @@
 
 namespace blink {
 
-using namespace SVGNames;
+using namespace svg_names;
 
 SVGResources::SVGResources() : linked_resource_(nullptr) {}
 
@@ -59,25 +59,26 @@
           // http://www.w3.org/TR/SVG11/intro.html#TermContainerElement
           // "graphics elements" :
           // http://www.w3.org/TR/SVG11/intro.html#TermGraphicsElement
-          aTag.LocalName(), circleTag.LocalName(), ellipseTag.LocalName(),
-          gTag.LocalName(), imageTag.LocalName(), lineTag.LocalName(),
-          markerTag.LocalName(), maskTag.LocalName(), pathTag.LocalName(),
-          polygonTag.LocalName(), polylineTag.LocalName(), rectTag.LocalName(),
-          svgTag.LocalName(), textTag.LocalName(), useTag.LocalName(),
+          kATag.LocalName(), kCircleTag.LocalName(), kEllipseTag.LocalName(),
+          kGTag.LocalName(), kImageTag.LocalName(), kLineTag.LocalName(),
+          kMarkerTag.LocalName(), kMaskTag.LocalName(), kPathTag.LocalName(),
+          kPolygonTag.LocalName(), kPolylineTag.LocalName(),
+          kRectTag.LocalName(), kSVGTag.LocalName(), kTextTag.LocalName(),
+          kUseTag.LocalName(),
           // Not listed in the definitions is the clipPath element, the SVG spec
           // says though:
           // The "clipPath" element or any of its children can specify property
           // "clip-path".
-          // So we have to add clipPathTag here, otherwhise clip-path on
+          // So we have to add kClipPathTag here, otherwhise clip-path on
           // clipPath will fail. (Already mailed SVG WG, waiting for a solution)
-          clipPathTag.LocalName(),
+          kClipPathTag.LocalName(),
           // Not listed in the definitions are the text content elements, though
           // filter/clipper/masker on tspan/text/.. is allowed.
           // (Already mailed SVG WG, waiting for a solution)
-          textPathTag.LocalName(), tspanTag.LocalName(),
+          kTextPathTag.LocalName(), kTSpanTag.LocalName(),
           // Not listed in the definitions is the foreignObject element, but
           // clip-path is a supported attribute.
-          foreignObjectTag.LocalName(),
+          kForeignObjectTag.LocalName(),
           // Elements that we ignore, as it doesn't make any sense.
           // defs, pattern, switch (FIXME: Mail SVG WG about these)
           // symbol (is converted to a svg element, when referenced by use, we
@@ -89,8 +90,8 @@
 bool SVGResources::SupportsMarkers(const SVGElement& element) {
   DEFINE_STATIC_LOCAL(HashSet<AtomicString>, tag_list,
                       ({
-                          lineTag.LocalName(), pathTag.LocalName(),
-                          polygonTag.LocalName(), polylineTag.LocalName(),
+                          kLineTag.LocalName(), kPathTag.LocalName(),
+                          kPolygonTag.LocalName(), kPolylineTag.LocalName(),
                       }));
   return tag_list.Contains(element.localName());
 }
@@ -99,10 +100,10 @@
   DEFINE_STATIC_LOCAL(
       HashSet<AtomicString>, tag_list,
       ({
-          circleTag.LocalName(), ellipseTag.LocalName(), lineTag.LocalName(),
-          pathTag.LocalName(), polygonTag.LocalName(), polylineTag.LocalName(),
-          rectTag.LocalName(), textTag.LocalName(), textPathTag.LocalName(),
-          tspanTag.LocalName(),
+          kCircleTag.LocalName(), kEllipseTag.LocalName(), kLineTag.LocalName(),
+          kPathTag.LocalName(), kPolygonTag.LocalName(),
+          kPolylineTag.LocalName(), kRectTag.LocalName(), kTextTag.LocalName(),
+          kTextPathTag.LocalName(), kTSpanTag.LocalName(),
       }));
   return tag_list;
 }
diff --git a/third_party/blink/renderer/core/loader/base_fetch_context.cc b/third_party/blink/renderer/core/loader/base_fetch_context.cc
index 7a7dd29..b783fd6 100644
--- a/third_party/blink/renderer/core/loader/base_fetch_context.cc
+++ b/third_party/blink/renderer/core/loader/base_fetch_context.cc
@@ -5,8 +5,8 @@
 #include "third_party/blink/renderer/core/loader/base_fetch_context.h"
 
 #include "services/network/public/mojom/request_context_frame_type.mojom-blink.h"
+#include "third_party/blink/public/platform/web_content_settings_client.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
-#include "third_party/blink/renderer/core/frame/content_settings_client.h"
 #include "third_party/blink/renderer/core/frame/settings.h"
 #include "third_party/blink/renderer/core/frame/web_feature.h"
 #include "third_party/blink/renderer/core/inspector/console_message.h"
diff --git a/third_party/blink/renderer/core/loader/empty_clients.cc b/third_party/blink/renderer/core/loader/empty_clients.cc
index 38ef71e6..dd09f337 100644
--- a/third_party/blink/renderer/core/loader/empty_clients.cc
+++ b/third_party/blink/renderer/core/loader/empty_clients.cc
@@ -34,7 +34,6 @@
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/public/platform/web_application_cache_host.h"
 #include "third_party/blink/public/platform/web_media_player.h"
-#include "third_party/blink/renderer/core/frame/content_settings_client.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/frame/visual_viewport.h"
 #include "third_party/blink/renderer/core/html/forms/color_chooser.h"
@@ -178,10 +177,6 @@
   return nullptr;
 }
 
-ContentSettingsClient& EmptyLocalFrameClient::GetContentSettingsClient() {
-  return content_settings_client_;
-}
-
 std::unique_ptr<WebApplicationCacheHost>
 EmptyLocalFrameClient::CreateApplicationCacheHost(
     WebApplicationCacheHostClient*) {
diff --git a/third_party/blink/renderer/core/loader/empty_clients.h b/third_party/blink/renderer/core/loader/empty_clients.h
index 6034ab8..5de9c45 100644
--- a/third_party/blink/renderer/core/loader/empty_clients.h
+++ b/third_party/blink/renderer/core/loader/empty_clients.h
@@ -41,7 +41,6 @@
 #include "third_party/blink/public/platform/web_spell_check_panel_host_client.h"
 #include "third_party/blink/public/platform/web_url_loader.h"
 #include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/frame/content_settings_client.h"
 #include "third_party/blink/renderer/core/frame/local_frame_client.h"
 #include "third_party/blink/renderer/core/frame/remote_frame_client.h"
 #include "third_party/blink/renderer/core/page/chrome_client.h"
@@ -363,7 +362,9 @@
 
   std::unique_ptr<WebServiceWorkerProvider> CreateServiceWorkerProvider()
       override;
-  ContentSettingsClient& GetContentSettingsClient() override;
+  WebContentSettingsClient* GetContentSettingsClient() override {
+    return nullptr;
+  }
   std::unique_ptr<WebApplicationCacheHost> CreateApplicationCacheHost(
       WebApplicationCacheHostClient*) override;
 
@@ -394,7 +395,6 @@
   // Not owned
   WebTextCheckClient* text_check_client_;
 
-  ContentSettingsClient content_settings_client_;
   service_manager::InterfaceProvider interface_provider_;
 
   DISALLOW_COPY_AND_ASSIGN(EmptyLocalFrameClient);
diff --git a/third_party/blink/renderer/core/loader/frame_fetch_context.cc b/third_party/blink/renderer/core/loader/frame_fetch_context.cc
index bf485a3..5a74886 100644
--- a/third_party/blink/renderer/core/loader/frame_fetch_context.cc
+++ b/third_party/blink/renderer/core/loader/frame_fetch_context.cc
@@ -44,6 +44,7 @@
 #include "third_party/blink/public/platform/modules/service_worker/web_service_worker_network_provider.h"
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/public/platform/web_application_cache_host.h"
+#include "third_party/blink/public/platform/web_content_settings_client.h"
 #include "third_party/blink/public/platform/web_effective_connection_type.h"
 #include "third_party/blink/public/platform/web_insecure_request_policy.h"
 #include "third_party/blink/public/platform/websocket_handshake_throttle.h"
@@ -54,7 +55,6 @@
 #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/fileapi/public_url_manager.h"
-#include "third_party/blink/renderer/core/frame/content_settings_client.h"
 #include "third_party/blink/renderer/core/frame/deprecation.h"
 #include "third_party/blink/renderer/core/frame/frame_console.h"
 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
@@ -842,8 +842,9 @@
 bool FrameFetchContext::AllowImage(bool images_enabled, const KURL& url) const {
   if (IsDetached())
     return true;
-
-  return GetContentSettingsClient()->AllowImage(images_enabled, url);
+  if (auto* settings_client = GetContentSettingsClient())
+    images_enabled = settings_client->AllowImage(images_enabled, url);
+  return images_enabled;
 }
 
 blink::mojom::ControllerServiceWorkerMode
@@ -1093,7 +1094,7 @@
 bool FrameFetchContext::AllowScriptFromSource(const KURL& url) const {
   if (AllowScriptFromSourceWithoutNotifying(url))
     return true;
-  ContentSettingsClient* settings_client = GetContentSettingsClient();
+  WebContentSettingsClient* settings_client = GetContentSettingsClient();
   if (settings_client)
     settings_client->DidNotAllowScript();
   return false;
@@ -1101,13 +1102,11 @@
 
 bool FrameFetchContext::AllowScriptFromSourceWithoutNotifying(
     const KURL& url) const {
-  ContentSettingsClient* settings_client = GetContentSettingsClient();
   Settings* settings = GetSettings();
-  if (settings_client && !settings_client->AllowScriptFromSource(
-                             !settings || settings->GetScriptEnabled(), url)) {
-    return false;
-  }
-  return true;
+  bool allow_script = !settings || settings->GetScriptEnabled();
+  if (auto* settings_client = GetContentSettingsClient())
+    allow_script = settings_client->AllowScriptFromSource(allow_script, url);
+  return allow_script;
 }
 
 bool FrameFetchContext::IsFirstPartyOrigin(const KURL& url) const {
@@ -1291,7 +1290,7 @@
     GetFrame()->Console().AddMessage(message);
 }
 
-ContentSettingsClient* FrameFetchContext::GetContentSettingsClient() const {
+WebContentSettingsClient* FrameFetchContext::GetContentSettingsClient() const {
   if (IsDetached())
     return nullptr;
   return GetFrame()->GetContentSettingsClient();
@@ -1369,8 +1368,10 @@
     return;
   }
 
-  GetContentSettingsClient()->PersistClientHints(
-      enabled_client_hints, persist_duration, response.Url());
+  if (auto* settings_client = GetContentSettingsClient()) {
+    settings_client->PersistClientHints(enabled_client_hints, persist_duration,
+                                        response.Url());
+  }
 }
 
 std::unique_ptr<WebURLLoader> FrameFetchContext::CreateURLLoader(
diff --git a/third_party/blink/renderer/core/loader/frame_fetch_context.h b/third_party/blink/renderer/core/loader/frame_fetch_context.h
index 3192f284..5ea56a66 100644
--- a/third_party/blink/renderer/core/loader/frame_fetch_context.h
+++ b/third_party/blink/renderer/core/loader/frame_fetch_context.h
@@ -50,7 +50,6 @@
 namespace blink {
 
 class ClientHintsPreferences;
-class ContentSettingsClient;
 class Document;
 class DocumentLoader;
 class LocalFrame;
@@ -58,6 +57,7 @@
 class ResourceError;
 class ResourceResponse;
 class Settings;
+class WebContentSettingsClient;
 struct WebEnabledClientHints;
 
 class CORE_EXPORT FrameFetchContext final : public BaseFetchContext {
@@ -243,7 +243,7 @@
   const ContentSecurityPolicy* GetContentSecurityPolicy() const override;
   void AddConsoleMessage(ConsoleMessage*) const override;
 
-  ContentSettingsClient* GetContentSettingsClient() const;
+  WebContentSettingsClient* GetContentSettingsClient() const;
   Settings* GetSettings() const;
   String GetUserAgent() const;
   const ClientHintsPreferences GetClientHintsPreferences() const;
@@ -252,14 +252,14 @@
                             const ClientHintsPreferences&,
                             const WebEnabledClientHints&) const;
   // Checks if the origin requested persisting the client hints, and notifies
-  // the |ContentSettingsClient| with the list of client hints and the
+  // the |WebContentSettingsClient| with the list of client hints and the
   // persistence duration.
   void ParseAndPersistClientHints(const ResourceResponse&);
   void SetFirstPartyCookie(ResourceRequest&);
 
   // Returns true if execution of scripts from the url are allowed. Compared to
   // AllowScriptFromSource(), this method does not generate any
-  // notification to the |ContentSettingsClient| that the execution of the
+  // notification to the |WebContentSettingsClient| that the execution of the
   // script was blocked. This method should be called only when there is a need
   // to check the settings, and where blocked setting doesn't really imply that
   // JavaScript was blocked from being executed.
diff --git a/third_party/blink/renderer/core/loader/frame_loader.cc b/third_party/blink/renderer/core/loader/frame_loader.cc
index 23400759..ede5700d 100644
--- a/third_party/blink/renderer/core/loader/frame_loader.cc
+++ b/third_party/blink/renderer/core/loader/frame_loader.cc
@@ -46,6 +46,7 @@
 #include "third_party/blink/public/platform/modules/fetch/fetch_api_request.mojom-shared.h"
 #include "third_party/blink/public/platform/modules/service_worker/web_service_worker_network_provider.h"
 #include "third_party/blink/public/platform/task_type.h"
+#include "third_party/blink/public/platform/web_content_settings_client.h"
 #include "third_party/blink/public/platform/web_mixed_content.h"
 #include "third_party/blink/public/platform/web_mixed_content_context_type.h"
 #include "third_party/blink/public/platform/web_url_request.h"
@@ -59,7 +60,6 @@
 #include "third_party/blink/renderer/core/dom/element.h"
 #include "third_party/blink/renderer/core/dom/ignore_opens_during_unload_count_incrementer.h"
 #include "third_party/blink/renderer/core/events/page_transition_event.h"
-#include "third_party/blink/renderer/core/frame/content_settings_client.h"
 #include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
@@ -487,8 +487,10 @@
     return false;
   Settings* settings = frame_->GetSettings();
   bool allowed = settings && settings->GetPluginsEnabled();
-  if (!allowed && reason == kAboutToInstantiatePlugin)
-    frame_->GetContentSettingsClient()->DidNotAllowPlugins();
+  if (!allowed && reason == kAboutToInstantiatePlugin) {
+    if (auto* settings_client = frame_->GetContentSettingsClient())
+      settings_client->DidNotAllowPlugins();
+  }
   return allowed;
 }
 
diff --git a/third_party/blink/renderer/core/loader/http_equiv.cc b/third_party/blink/renderer/core/loader/http_equiv.cc
index befb7ae..f78e8ca 100644
--- a/third_party/blink/renderer/core/loader/http_equiv.cc
+++ b/third_party/blink/renderer/core/loader/http_equiv.cc
@@ -4,10 +4,10 @@
 
 #include "third_party/blink/renderer/core/loader/http_equiv.h"
 
+#include "third_party/blink/public/platform/web_content_settings_client.h"
 #include "third_party/blink/renderer/core/css/style_engine.h"
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/dom/scriptable_document_parser.h"
-#include "third_party/blink/renderer/core/frame/content_settings_client.h"
 #include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
 #include "third_party/blink/renderer/core/frame/deprecation.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
@@ -47,13 +47,12 @@
 // JavaScript was blocked from being executed.
 bool AllowScriptFromSourceWithoutNotifying(
     const KURL& url,
-    ContentSettingsClient* settings_client,
+    WebContentSettingsClient* settings_client,
     Settings* settings) {
-  if (settings_client && !settings_client->AllowScriptFromSource(
-                             !settings || settings->GetScriptEnabled(), url)) {
-    return false;
-  }
-  return true;
+  bool allow_script = !settings || settings->GetScriptEnabled();
+  if (settings_client)
+    allow_script = settings_client->AllowScriptFromSource(allow_script, url);
+  return allow_script;
 }
 
 // Notifies content settings client of persistent client hint headers.
@@ -78,8 +77,10 @@
     return;
   }
 
-  document.GetFrame()->GetContentSettingsClient()->PersistClientHints(
-      enabled_client_hints, persist_duration, document.Url());
+  if (auto* settings_client = document.GetFrame()->GetContentSettingsClient()) {
+    settings_client->PersistClientHints(enabled_client_hints, persist_duration,
+                                        document.Url());
+  }
 }
 
 }  // namespace
diff --git a/third_party/blink/renderer/core/loader/mixed_content_checker.cc b/third_party/blink/renderer/core/loader/mixed_content_checker.cc
index b4359f71..9e09546b 100644
--- a/third_party/blink/renderer/core/loader/mixed_content_checker.cc
+++ b/third_party/blink/renderer/core/loader/mixed_content_checker.cc
@@ -33,12 +33,12 @@
 #include "services/network/public/mojom/request_context_frame_type.mojom-blink.h"
 #include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/mojom/net/ip_address_space.mojom-blink.h"
+#include "third_party/blink/public/platform/web_content_settings_client.h"
 #include "third_party/blink/public/platform/web_insecure_request_policy.h"
 #include "third_party/blink/public/platform/web_mixed_content.h"
 #include "third_party/blink/public/platform/web_security_origin.h"
 #include "third_party/blink/public/platform/web_worker_fetch_context.h"
 #include "third_party/blink/renderer/core/dom/document.h"
-#include "third_party/blink/renderer/core/frame/content_settings_client.h"
 #include "third_party/blink/renderer/core/frame/frame.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/frame/local_frame_client.h"
@@ -148,15 +148,12 @@
   return "resource";
 }
 
-// TODO(nhiroki): Consider adding interfaces for Settings/WorkerSettings and
-// ContentSettingsClient/WorkerContentSettingsClient to avoid using C++
-// template.
-template <typename SettingsType, typename SettingsClientType>
+// TODO(nhiroki): Consider adding interfaces for Settings/WorkerSettings
+// to avoid using C++ template.
+template <typename SettingsType>
 bool IsWebSocketAllowedImpl(const BaseFetchContext& fetch_context,
                             SecurityContext* security_context,
-                            const SecurityOrigin* security_origin,
                             SettingsType* settings,
-                            SettingsClientType* settings_client,
                             const KURL& url) {
   fetch_context.CountUsage(WebFeature::kMixedContentPresent);
   fetch_context.CountUsage(WebFeature::kMixedContentWebSocket);
@@ -174,10 +171,7 @@
       settings->GetStrictMixedContentChecking();
   if (strict_mode)
     return false;
-  bool allowed_per_settings =
-      settings && settings->GetAllowRunningOfInsecureContent();
-  return settings_client->AllowRunningInsecureContent(allowed_per_settings,
-                                                      security_origin, url);
+  return settings && settings->GetAllowRunningOfInsecureContent();
 }
 
 }  // namespace
@@ -378,7 +372,7 @@
   // Use the current local frame's client; the embedder doesn't distinguish
   // mixed content signals from different frames on the same page.
   LocalFrameClient* client = frame->Client();
-  ContentSettingsClient* content_settings_client =
+  WebContentSettingsClient* content_settings_client =
       frame->GetContentSettingsClient();
   const SecurityOrigin* security_origin =
       mixed_frame->GetSecurityContext()->GetSecurityOrigin();
@@ -412,7 +406,8 @@
     case WebMixedContentContextType::kOptionallyBlockable:
       allowed = !strict_mode;
       if (allowed) {
-        content_settings_client->PassiveInsecureContentFound(url);
+        if (content_settings_client)
+          content_settings_client->PassiveInsecureContentFound(url);
         client->DidDisplayInsecureContent();
       }
       break;
@@ -439,10 +434,13 @@
           !strict_mode && settings &&
           (!settings->GetStrictlyBlockBlockableMixedContent() ||
            settings->GetAllowRunningOfInsecureContent());
-      allowed = should_ask_embedder &&
-                content_settings_client->AllowRunningInsecureContent(
-                    settings && settings->GetAllowRunningOfInsecureContent(),
-                    security_origin, url);
+      if (should_ask_embedder) {
+        allowed = settings && settings->GetAllowRunningOfInsecureContent();
+        if (content_settings_client) {
+          allowed = content_settings_client->AllowRunningInsecureContent(
+              allowed, WebSecurityOrigin(security_origin), url);
+        }
+      }
       if (allowed) {
         client->DidRunInsecureContent(security_origin, url);
         UseCounter::Count(frame, WebFeature::kMixedContentBlockableAllowed);
@@ -561,14 +559,18 @@
   Settings* settings = mixed_frame->GetSettings();
   // Use the current local frame's client; the embedder doesn't distinguish
   // mixed content signals from different frames on the same page.
-  ContentSettingsClient* content_settings_client =
+  WebContentSettingsClient* content_settings_client =
       frame->GetContentSettingsClient();
   SecurityContext* security_context = mixed_frame->GetSecurityContext();
   const SecurityOrigin* security_origin = security_context->GetSecurityOrigin();
 
   bool allowed = IsWebSocketAllowedImpl(frame_fetch_context, security_context,
-                                        security_origin, settings,
-                                        content_settings_client, url);
+                                        settings, url);
+  if (content_settings_client) {
+    allowed = content_settings_client->AllowRunningInsecureContent(
+        allowed, WebSecurityOrigin(security_origin), url);
+  }
+
   if (allowed)
     frame->Client()->DidRunInsecureContent(security_origin, url);
 
@@ -596,8 +598,12 @@
       worker_fetch_context.GetSecurityOrigin();
 
   bool allowed = IsWebSocketAllowedImpl(worker_fetch_context, security_context,
-                                        security_origin, settings,
-                                        content_settings_client, url);
+                                        settings, url);
+  if (content_settings_client) {
+    allowed = content_settings_client->AllowRunningInsecureContent(
+        allowed, security_origin, url);
+  }
+
   if (allowed) {
     worker_fetch_context.GetWebWorkerFetchContext()->DidRunInsecureContent(
         WebSecurityOrigin(security_origin), url);
diff --git a/third_party/blink/renderer/core/page/scrolling/snap_coordinator.cc b/third_party/blink/renderer/core/page/scrolling/snap_coordinator.cc
index b2197103..bd1be07 100644
--- a/third_party/blink/renderer/core/page/scrolling/snap_coordinator.cc
+++ b/third_party/blink/renderer/core/page/scrolling/snap_coordinator.cc
@@ -18,7 +18,7 @@
 namespace {
 // This is experimentally determined and corresponds to the UA decided
 // parameter as mentioned in spec.
-constexpr float kProximityRaio = 1.0 / 3.0;
+constexpr float kProximityRatio = 1.0 / 3.0;
 }  // namespace
 // TODO(sunyunjia): Move the static functions to an anonymous namespace.
 
@@ -157,7 +157,7 @@
   if (snap_container_data.scroll_snap_type().strictness ==
       SnapStrictness::kProximity) {
     LayoutSize size = container_rect.Size();
-    size.Scale(kProximityRaio);
+    size.Scale(kProximityRatio);
     gfx::ScrollOffset range(size.Width().ToFloat(), size.Height().ToFloat());
     snap_container_data.set_proximity_range(range);
   }
@@ -235,11 +235,9 @@
   return snap_area_data;
 }
 
-base::Optional<FloatPoint> SnapCoordinator::GetSnapPositionForPoint(
+base::Optional<FloatPoint> SnapCoordinator::GetSnapPosition(
     const LayoutBox& snap_container,
-    const FloatPoint& point,
-    bool did_scroll_x,
-    bool did_scroll_y) {
+    const SnapSelectionStrategy& strategy) const {
   auto iter = snap_container_map_.find(&snap_container);
   if (iter == snap_container_map_.end())
     return base::nullopt;
@@ -249,34 +247,60 @@
     return base::nullopt;
 
   gfx::ScrollOffset snap_position;
-  if (data.FindSnapPosition(gfx::ScrollOffset(point.X(), point.Y()),
-                            did_scroll_x, did_scroll_y, &snap_position)) {
+  if (data.FindSnapPosition(strategy, &snap_position)) {
     FloatPoint snap_point(snap_position.x(), snap_position.y());
     return snap_point;
   }
+
   return base::nullopt;
 }
 
-void SnapCoordinator::PerformSnapping(const LayoutBox& snap_container,
-                                      bool did_scroll_x,
-                                      bool did_scroll_y) {
+bool SnapCoordinator::SnapForEndPosition(const LayoutBox& snap_container,
+                                         bool scrolled_x,
+                                         bool scrolled_y) const {
   ScrollableArea* scrollable_area = ScrollableAreaForSnapping(snap_container);
   if (!scrollable_area)
-    return;
-
+    return false;
   FloatPoint current_position = scrollable_area->ScrollPosition();
-  base::Optional<FloatPoint> snap_point = GetSnapPositionForPoint(
-      snap_container, current_position, did_scroll_x, did_scroll_y);
+  std::unique_ptr<SnapSelectionStrategy> strategy =
+      SnapSelectionStrategy::CreateForEndPosition(
+          gfx::ScrollOffset(current_position), scrolled_x, scrolled_y);
+  return PerformSnapping(snap_container, *strategy);
+}
+
+bool SnapCoordinator::SnapForDirection(const LayoutBox& snap_container,
+                                       const ScrollOffset& delta) const {
+  ScrollableArea* scrollable_area = ScrollableAreaForSnapping(snap_container);
+  if (!scrollable_area)
+    return false;
+  FloatPoint current_position = scrollable_area->ScrollPosition();
+  std::unique_ptr<SnapSelectionStrategy> strategy =
+      SnapSelectionStrategy::CreateForDirection(
+          gfx::ScrollOffset(current_position),
+          gfx::ScrollOffset(delta.Width(), delta.Height()));
+  return PerformSnapping(snap_container, *strategy);
+}
+
+bool SnapCoordinator::PerformSnapping(
+    const LayoutBox& snap_container,
+    const SnapSelectionStrategy& strategy) const {
+  ScrollableArea* scrollable_area = ScrollableAreaForSnapping(snap_container);
+  if (!scrollable_area)
+    return false;
+
+  base::Optional<FloatPoint> snap_point =
+      GetSnapPosition(snap_container, strategy);
   if (!snap_point.has_value())
-    return;
+    return false;
 
   scrollable_area->CancelScrollAnimation();
   scrollable_area->CancelProgrammaticScrollAnimation();
-  if (snap_point.value() != current_position) {
+  if (gfx::ScrollOffset(snap_point.value()) != strategy.current_position()) {
     scrollable_area->SetScrollOffset(
         scrollable_area->ScrollPositionToOffset(snap_point.value()),
         kProgrammaticScroll, kScrollBehaviorSmooth);
   }
+  return true;
 }
 
 void SnapCoordinator::SnapContainerDidChange(LayoutBox& snap_container,
@@ -308,30 +332,6 @@
   return base::nullopt;
 }
 
-bool SnapCoordinator::GetSnapFlingInfo(
-    const LayoutBox& snap_container,
-    const gfx::Vector2dF& natural_displacement,
-    gfx::Vector2dF* out_initial_offset,
-    gfx::Vector2dF* out_target_offset) {
-  ScrollableArea* scrollable_area = ScrollableAreaForSnapping(snap_container);
-  if (!scrollable_area)
-    return false;
-
-  FloatPoint current_position = scrollable_area->ScrollPosition();
-  *out_initial_offset = gfx::Vector2dF(current_position);
-  FloatPoint original_end =
-      current_position +
-      FloatPoint(natural_displacement.x(), natural_displacement.y());
-  bool did_scroll_x = natural_displacement.x() != 0;
-  bool did_scroll_y = natural_displacement.y() != 0;
-  base::Optional<FloatPoint> snap_end = GetSnapPositionForPoint(
-      snap_container, original_end, did_scroll_x, did_scroll_y);
-  if (!snap_end.has_value())
-    return false;
-  *out_target_offset = gfx::Vector2dF(snap_end.value());
-  return true;
-}
-
 #ifndef NDEBUG
 
 void SnapCoordinator::ShowSnapAreaMap() {
diff --git a/third_party/blink/renderer/core/page/scrolling/snap_coordinator.h b/third_party/blink/renderer/core/page/scrolling/snap_coordinator.h
index 2c3ad76..396ef6f 100644
--- a/third_party/blink/renderer/core/page/scrolling/snap_coordinator.h
+++ b/third_party/blink/renderer/core/page/scrolling/snap_coordinator.h
@@ -51,21 +51,17 @@
   void UpdateAllSnapContainerData();
   void UpdateSnapContainerData(const LayoutBox&);
 
-  // Called by ScrollManager::HandleGestureScrollEnd() to animate to the snap
-  // position for the current scroll on the specific direction if there is
-  // a valid snap position.
-  void PerformSnapping(const LayoutBox& snap_container,
-                       bool did_scroll_x,
-                       bool did_scroll_y);
-  base::Optional<FloatPoint> GetSnapPositionForPoint(
+  // SnapForEndPosition() and SnapForDirection() return true if snapping was
+  // performed, and false otherwise.
+  bool SnapForEndPosition(const LayoutBox& snap_container,
+                          bool scrolled_x,
+                          bool scrolled_y) const;
+  bool SnapForDirection(const LayoutBox& snap_container,
+                        const ScrollOffset& delta) const;
+
+  base::Optional<FloatPoint> GetSnapPosition(
       const LayoutBox& snap_container,
-      const FloatPoint& natural_position,
-      bool did_scroll_x,
-      bool did_scroll_y);
-  bool GetSnapFlingInfo(const LayoutBox& snap_container,
-                        const gfx::Vector2dF& natural_displacement,
-                        gfx::Vector2dF* out_initial_offset,
-                        gfx::Vector2dF* out_target_offset);
+      const SnapSelectionStrategy& strategy) const;
 
 #ifndef NDEBUG
   void ShowSnapAreaMap();
@@ -76,6 +72,8 @@
  private:
   friend class SnapCoordinatorTest;
   explicit SnapCoordinator();
+  bool PerformSnapping(const LayoutBox& snap_container,
+                       const SnapSelectionStrategy& strategy) const;
 
   HashMap<const LayoutBox*, SnapContainerData> snap_container_map_;
   DISALLOW_COPY_AND_ASSIGN(SnapCoordinator);
diff --git a/third_party/blink/renderer/core/page/scrolling/snap_coordinator_test.cc b/third_party/blink/renderer/core/page/scrolling/snap_coordinator_test.cc
index 254d079..8b749cdd 100644
--- a/third_party/blink/renderer/core/page/scrolling/snap_coordinator_test.cc
+++ b/third_party/blink/renderer/core/page/scrolling/snap_coordinator_test.cc
@@ -631,72 +631,4 @@
   EXPECT_EQ_AREA(expected_area, actual_container.at(0));
 }
 
-// The following tests check GetSnapPositionForPoint().
-TEST_F(SnapCoordinatorTest, SnapsIfScrolledAndSnappingAxesMatch) {
-  SetUpSingleSnapArea();
-  Element* area_element = GetDocument().getElementById("area");
-  Element* scroller_element = GetDocument().getElementById("scroller");
-  area_element->setAttribute(styleAttr, "scroll-snap-align: start;");
-  scroller_element->setAttribute(styleAttr, "scroll-snap-type: x mandatory");
-  GetDocument().UpdateStyleAndLayout();
-
-  SnapCoordinator* snap_coordinator = GetDocument().GetSnapCoordinator();
-  LayoutBox* snap_container = scroller_element->GetLayoutBox();
-  base::Optional<FloatPoint> snap_position =
-      snap_coordinator->GetSnapPositionForPoint(
-          *snap_container, FloatPoint(150, 150), true, false);
-  EXPECT_TRUE(snap_position.has_value());
-  EXPECT_EQ(200 - 8 - 10, snap_position.value().X());
-  EXPECT_EQ(150, snap_position.value().Y());
-}
-
-TEST_F(SnapCoordinatorTest, DoesNotSnapOnNonSnappingAxis) {
-  SetUpSingleSnapArea();
-  Element* area_element = GetDocument().getElementById("area");
-  Element* scroller_element = GetDocument().getElementById("scroller");
-  area_element->setAttribute(styleAttr, "scroll-snap-align: start;");
-  scroller_element->setAttribute(styleAttr, "scroll-snap-type: y mandatory");
-  GetDocument().UpdateStyleAndLayout();
-
-  SnapCoordinator* snap_coordinator = GetDocument().GetSnapCoordinator();
-  LayoutBox* snap_container = scroller_element->GetLayoutBox();
-  base::Optional<FloatPoint> snap_position =
-      snap_coordinator->GetSnapPositionForPoint(
-          *snap_container, FloatPoint(150, 150), true, false);
-  EXPECT_FALSE(snap_position.has_value());
-}
-
-TEST_F(SnapCoordinatorTest, DoesNotSnapOnEmptyContainer) {
-  SetUpSingleSnapArea();
-  Element* area_element = GetDocument().getElementById("area");
-  Element* scroller_element = GetDocument().getElementById("scroller");
-  area_element->setAttribute(styleAttr, "scroll-snap-align: none;");
-  scroller_element->setAttribute(styleAttr, "scroll-snap-type: x mandatory");
-  GetDocument().UpdateStyleAndLayout();
-
-  SnapCoordinator* snap_coordinator = GetDocument().GetSnapCoordinator();
-  LayoutBox* snap_container = scroller_element->GetLayoutBox();
-  base::Optional<FloatPoint> snap_position =
-      snap_coordinator->GetSnapPositionForPoint(
-          *snap_container, FloatPoint(150, 150), true, false);
-  ;
-  EXPECT_FALSE(snap_position.has_value());
-}
-
-TEST_F(SnapCoordinatorTest, DoesNotSnapOnNonSnapContainer) {
-  SetUpSingleSnapArea();
-  Element* area_element = GetDocument().getElementById("area");
-  Element* scroller_element = GetDocument().getElementById("scroller");
-  area_element->setAttribute(styleAttr, "scroll-snap-align: start;");
-  scroller_element->setAttribute(styleAttr, "scroll-snap-type: none");
-  GetDocument().UpdateStyleAndLayout();
-
-  SnapCoordinator* snap_coordinator = GetDocument().GetSnapCoordinator();
-  LayoutBox* snap_container = scroller_element->GetLayoutBox();
-  base::Optional<FloatPoint> snap_position =
-      snap_coordinator->GetSnapPositionForPoint(
-          *snap_container, FloatPoint(150, 150), true, false);
-  EXPECT_FALSE(snap_position.has_value());
-}
-
 }  // namespace
diff --git a/third_party/blink/renderer/core/paint/block_painter.cc b/third_party/blink/renderer/core/paint/block_painter.cc
index fe5ceef8..eba9e8a 100644
--- a/third_party/blink/renderer/core/paint/block_painter.cc
+++ b/third_party/blink/renderer/core/paint/block_painter.cc
@@ -201,30 +201,6 @@
   }
 }
 
-// TODO(pdr): Non-blocks also need to paint the hit test display item. Move this
-// to a more central place such as BoxPainter.
-void BlockPainter::RecordHitTestData(const PaintInfo& paint_info,
-                                     const LayoutPoint& paint_offset) {
-  // Hit test display items are only needed for compositing. This flag is used
-  // for for printing and drag images which do not need hit testing.
-  if (paint_info.GetGlobalPaintFlags() & kGlobalPaintFlattenCompositingLayers)
-    return;
-
-  auto touch_action = layout_block_.EffectiveWhitelistedTouchAction();
-  if (touch_action == TouchAction::kTouchActionAuto)
-    return;
-
-  // TODO(pdr): If we are painting the background into the scrolling contents
-  // layer, we need to use the overflow rect instead of the border box rect. We
-  // may want to move the call to RecordHitTestRect into
-  // BoxPainter::PaintBoxDecorationBackgroundWithRect and share the logic
-  // the background painting code already uses.
-  auto rect = layout_block_.BorderBoxRect();
-  rect.MoveBy(paint_offset);
-  HitTestData::RecordHitTestRect(paint_info.context, layout_block_,
-                                 HitTestRect(rect, touch_action));
-}
-
 DISABLE_CFI_PERF
 void BlockPainter::PaintObject(const PaintInfo& paint_info,
                                const LayoutPoint& paint_offset) {
@@ -252,14 +228,7 @@
   // kSelfBlockBackgroundOnly -  Paint background of the current object only),
   // paint those now. This is steps #1, 2, and 4 of the CSS spec (see above).
   if (ShouldPaintSelfBlockBackground(paint_phase)) {
-    // Paint the background if we're visible and this block has a box decoration
-    // (background, border, appearance, or box shadow).
-    if (layout_block_.StyleRef().Visibility() == EVisibility::kVisible &&
-        layout_block_.HasBoxDecorationBackground()) {
-      layout_block_.PaintBoxDecorationBackground(paint_info, paint_offset);
-    }
-    if (RuntimeEnabledFeatures::PaintTouchActionRectsEnabled())
-      RecordHitTestData(paint_info, paint_offset);
+    layout_block_.PaintBoxDecorationBackground(paint_info, paint_offset);
     // Record the scroll hit test after the background so background squashing
     // is not affected. Hit test order would be equivalent if this were
     // immediately before the background.
diff --git a/third_party/blink/renderer/core/paint/block_painter.h b/third_party/blink/renderer/core/paint/block_painter.h
index 175e962..e16f0be 100644
--- a/third_party/blink/renderer/core/paint/block_painter.h
+++ b/third_party/blink/renderer/core/paint/block_painter.h
@@ -40,10 +40,6 @@
   // Paint scroll hit test placeholders in the correct paint order (see:
   // ScrollHitTestDisplayItem.h).
   void PaintScrollHitTestDisplayItem(const PaintInfo&);
-  // Paint a hit test display item and record hit test data. This should be
-  // called in the background paint phase even if there is no other painted
-  // content.
-  void RecordHitTestData(const PaintInfo&, const LayoutPoint& paint_offset);
   void PaintBlockFlowContents(const PaintInfo&, const LayoutPoint&);
   void PaintCarets(const PaintInfo&, const LayoutPoint& paint_offset);
 
diff --git a/third_party/blink/renderer/core/paint/block_painter_test.cc b/third_party/blink/renderer/core/paint/block_painter_test.cc
index de3cd46..aff9343d 100644
--- a/third_party/blink/renderer/core/paint/block_painter_test.cc
+++ b/third_party/blink/renderer/core/paint/block_painter_test.cc
@@ -7,6 +7,7 @@
 #include <gtest/gtest.h>
 #include "third_party/blink/renderer/core/dom/events/event_listener.h"
 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
+#include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
 #include "third_party/blink/renderer/core/paint/paint_controller_paint_test.h"
 #include "third_party/blink/renderer/platform/graphics/paint/drawing_display_item.h"
 #include "third_party/blink/renderer/platform/graphics/paint/paint_chunk.h"
@@ -173,6 +174,7 @@
       .touchActionNone { touch-action: none; }
       #childVisible { width: 200px; height: 25px; }
       #childHidden { width: 200px; height: 30px; visibility: hidden; }
+      #childDisplayNone { width: 200px; height: 30px; display: none; }
     </style>
     <div id='parent'>
       <div id='childVisible'></div>
@@ -188,19 +190,17 @@
       TestDisplayItem(scrolling_client, kDocumentBackgroundType));
 
   // Add a touch action to parent and ensure that hit test display items are
-  // created for both the parent and child.
+  // created for both the parent and the visible child.
   auto* parent_element = GetElementById("parent");
   parent_element->setAttribute(HTMLNames::classAttr, "touchActionNone");
   GetDocument().View()->UpdateAllLifecyclePhases();
   auto* parent = GetLayoutObjectByElementId("parent");
   auto* childVisible = GetLayoutObjectByElementId("childVisible");
-  auto* childHidden = GetLayoutObjectByElementId("childHidden");
   EXPECT_DISPLAY_LIST(
-      RootPaintController().GetDisplayItemList(), 4,
+      RootPaintController().GetDisplayItemList(), 3,
       TestDisplayItem(scrolling_client, kDocumentBackgroundType),
       TestDisplayItem(*parent, DisplayItem::kHitTest),
-      TestDisplayItem(*childVisible, DisplayItem::kHitTest),
-      TestDisplayItem(*childHidden, DisplayItem::kHitTest));
+      TestDisplayItem(*childVisible, DisplayItem::kHitTest));
 
   // Remove the touch action from parent and ensure no hit test display items
   // are left.
@@ -281,6 +281,83 @@
   }
 }
 
+TEST_F(BlockPainterTestWithPaintTouchAction, TouchActionRectScrollingContents) {
+  SetBodyInnerHTML(R"HTML(
+    <style>
+      ::-webkit-scrollbar { display: none; }
+      body { margin: 0; }
+      #scroller {
+        width: 100px;
+        height: 100px;
+        overflow: scroll;
+        touch-action: none;
+        will-change: transform;
+        background-color: blue;
+      }
+      #child {
+        width: 10px;
+        height: 400px;
+      }
+    </style>
+    <div id='scroller'>
+      <div id='child'></div>
+    </div>
+  )HTML");
+
+  const auto& root_client = GetLayoutView()
+                                .GetScrollableArea()
+                                ->GetScrollingBackgroundDisplayItemClient();
+  auto* scroller_element = GetElementById("scroller");
+  LayoutBoxModelObject* scroller =
+      static_cast<LayoutBoxModelObject*>(scroller_element->GetLayoutObject());
+  auto* child_element = GetElementById("child");
+  auto* child = child_element->GetLayoutObject();
+  auto& non_scroller_paint_controller = RootPaintController();
+  auto& scroller_paint_controller = scroller->GetScrollableArea()
+                                        ->Layer()
+                                        ->GraphicsLayerBacking()
+                                        ->GetPaintController();
+  EXPECT_DISPLAY_LIST(
+      scroller_paint_controller.GetDisplayItemList(), 3,
+      TestDisplayItem(scroller->GetScrollableArea()
+                          ->GetScrollingBackgroundDisplayItemClient(),
+                      kBackgroundType),
+      TestDisplayItem(*scroller, DisplayItem::kHitTest),
+      TestDisplayItem(*child, DisplayItem::kHitTest));
+  EXPECT_DISPLAY_LIST(non_scroller_paint_controller.GetDisplayItemList(), 1,
+                      TestDisplayItem(root_client, kDocumentBackgroundType));
+
+  {
+    const auto& paint_chunks =
+        scroller_paint_controller.GetPaintArtifact().PaintChunks();
+    EXPECT_EQ(paint_chunks.size(), 1u);
+    auto& hit_test_chunk = paint_chunks[0];
+    DCHECK(hit_test_chunk.GetHitTestData());
+    EXPECT_EQ(2u, hit_test_chunk.GetHitTestData()->touch_action_rects.size());
+    {
+      auto& touch_action_rect =
+          hit_test_chunk.GetHitTestData()->touch_action_rects[0];
+      EXPECT_EQ(LayoutRect(0, 0, 100, 400), touch_action_rect.rect);
+      EXPECT_EQ(TouchAction::kTouchActionNone,
+                touch_action_rect.whitelisted_touch_action);
+    }
+    {
+      auto& touch_action_rect =
+          hit_test_chunk.GetHitTestData()->touch_action_rects[1];
+      EXPECT_EQ(LayoutRect(0, 0, 10, 400), touch_action_rect.rect);
+      EXPECT_EQ(TouchAction::kTouchActionNone,
+                touch_action_rect.whitelisted_touch_action);
+    }
+  }
+  {
+    const auto& paint_chunks =
+        non_scroller_paint_controller.GetPaintArtifact().PaintChunks();
+    EXPECT_EQ(paint_chunks.size(), 1u);
+    auto& hit_test_chunk = paint_chunks[0];
+    EXPECT_FALSE(hit_test_chunk.GetHitTestData());
+  }
+}
+
 TEST_F(BlockPainterTestWithPaintTouchAction, TouchActionRectPaintChunkChanges) {
   SetBodyInnerHTML(R"HTML(
     <style>
diff --git a/third_party/blink/renderer/core/paint/box_painter.cc b/third_party/blink/renderer/core/paint/box_painter.cc
index 91dbee4..3bcdd55 100644
--- a/third_party/blink/renderer/core/paint/box_painter.cc
+++ b/third_party/blink/renderer/core/paint/box_painter.cc
@@ -75,9 +75,19 @@
     paint_rect.MoveBy(paint_offset);
   }
 
-  PaintBoxDecorationBackgroundWithRect(
-      contents_paint_state ? contents_paint_state->GetPaintInfo() : paint_info,
-      paint_rect);
+  // Paint the background if we're visible and this block has a box decoration
+  // (background, border, appearance, or box shadow).
+  const ComputedStyle& style = layout_box_.StyleRef();
+  if (style.Visibility() == EVisibility::kVisible &&
+      layout_box_.HasBoxDecorationBackground()) {
+    PaintBoxDecorationBackgroundWithRect(
+        contents_paint_state ? contents_paint_state->GetPaintInfo()
+                             : paint_info,
+        paint_rect);
+  }
+
+  if (RuntimeEnabledFeatures::PaintTouchActionRectsEnabled())
+    RecordHitTestData(paint_info, paint_offset, paint_rect);
 }
 
 bool BoxPainter::BackgroundIsKnownToBeOpaque(const PaintInfo& paint_info) {
@@ -243,4 +253,30 @@
                           include_logical_right_edge);
 }
 
+void BoxPainter::RecordHitTestData(const PaintInfo& paint_info,
+                                   const LayoutPoint& paint_offset,
+                                   const LayoutRect& paint_rect) {
+  // TODO(sunxd): ReplacedPainter only record hit test data for svg root which
+  // skips clip. We should move the conditions and ReplacedPainter's
+  // RecordHitTestData here.
+  if (layout_box_.IsLayoutReplaced())
+    return;
+
+  // Hit test display items are only needed for compositing. This flag is used
+  // for for printing and drag images which do not need hit testing.
+  if (paint_info.GetGlobalPaintFlags() & kGlobalPaintFlattenCompositingLayers)
+    return;
+
+  // If an object is not visible, it does not participate in hit testing.
+  if (layout_box_.StyleRef().Visibility() != EVisibility::kVisible)
+    return;
+
+  auto touch_action = layout_box_.EffectiveWhitelistedTouchAction();
+  if (touch_action == TouchAction::kTouchActionAuto)
+    return;
+
+  HitTestData::RecordHitTestRect(paint_info.context, layout_box_,
+                                 HitTestRect(paint_rect, touch_action));
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/paint/box_painter.h b/third_party/blink/renderer/core/paint/box_painter.h
index 4045538..f151e9ee 100644
--- a/third_party/blink/renderer/core/paint/box_painter.h
+++ b/third_party/blink/renderer/core/paint/box_painter.h
@@ -34,6 +34,14 @@
   void PaintMaskImages(const PaintInfo&, const LayoutRect&);
   void PaintBoxDecorationBackgroundWithRect(const PaintInfo&,
                                             const LayoutRect&);
+
+  // Paint a hit test display item and record hit test data. This should be
+  // called in the background paint phase even if there is no other painted
+  // content.
+  void RecordHitTestData(const PaintInfo&,
+                         const LayoutPoint& paint_offset,
+                         const LayoutRect& paint_rect);
+
  private:
   bool BackgroundIsKnownToBeOpaque(const PaintInfo&);
   void PaintBackground(const PaintInfo&,
diff --git a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc
index 560a608a..bc5da99 100644
--- a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc
+++ b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc
@@ -550,7 +550,7 @@
               ? FloatPoint(child_containment_layer_->GetPosition())
               : FloatPoint();
       document_layer->SetPosition(FloatPoint(RoundedIntSize(
-          FloatPoint(ContentsBox().Location()) - parent_position)));
+          ContentsBox().Location() - LayoutPoint(parent_position))));
     }
   }
 }
diff --git a/third_party/blink/renderer/core/paint/fieldset_painter.cc b/third_party/blink/renderer/core/paint/fieldset_painter.cc
index 5d762f2c..fd38581 100644
--- a/third_party/blink/renderer/core/paint/fieldset_painter.cc
+++ b/third_party/blink/renderer/core/paint/fieldset_painter.cc
@@ -39,46 +39,50 @@
     return BoxPainter(layout_fieldset_)
         .PaintBoxDecorationBackground(paint_info, paint_offset);
 
-  if (DrawingRecorder::UseCachedDrawingIfPossible(
-          paint_info.context, layout_fieldset_, paint_info.phase))
-    return;
+  if (!DrawingRecorder::UseCachedDrawingIfPossible(
+          paint_info.context, layout_fieldset_, paint_info.phase)) {
+    FieldsetPaintInfo fieldset_paint_info =
+        CreateFieldsetPaintInfo(layout_fieldset_, *legend);
+    paint_rect.Contract(fieldset_paint_info.border_outsets);
 
-  FieldsetPaintInfo fieldset_paint_info =
-      CreateFieldsetPaintInfo(layout_fieldset_, *legend);
-  paint_rect.Contract(fieldset_paint_info.border_outsets);
+    DrawingRecorder recorder(paint_info.context, layout_fieldset_,
+                             paint_info.phase);
+    BoxDecorationData box_decoration_data(layout_fieldset_);
 
-  DrawingRecorder recorder(paint_info.context, layout_fieldset_,
-                           paint_info.phase);
-  BoxDecorationData box_decoration_data(layout_fieldset_);
+    BoxPainterBase::PaintNormalBoxShadow(paint_info, paint_rect,
+                                         layout_fieldset_.StyleRef());
+    BackgroundImageGeometry geometry(layout_fieldset_);
+    BoxModelObjectPainter(layout_fieldset_)
+        .PaintFillLayers(paint_info, box_decoration_data.background_color,
+                         layout_fieldset_.StyleRef().BackgroundLayers(),
+                         paint_rect, geometry);
+    BoxPainterBase::PaintInsetBoxShadowWithBorderRect(
+        paint_info, paint_rect, layout_fieldset_.StyleRef());
 
-  BoxPainterBase::PaintNormalBoxShadow(paint_info, paint_rect,
-                                       layout_fieldset_.StyleRef());
-  BackgroundImageGeometry geometry(layout_fieldset_);
-  BoxModelObjectPainter(layout_fieldset_)
-      .PaintFillLayers(paint_info, box_decoration_data.background_color,
-                       layout_fieldset_.StyleRef().BackgroundLayers(),
-                       paint_rect, geometry);
-  BoxPainterBase::PaintInsetBoxShadowWithBorderRect(
-      paint_info, paint_rect, layout_fieldset_.StyleRef());
+    if (box_decoration_data.has_border_decoration) {
+      // Create a clipping region around the legend and paint the border as
+      // normal
+      GraphicsContext& graphics_context = paint_info.context;
+      GraphicsContextStateSaver state_saver(graphics_context);
 
-  if (!box_decoration_data.has_border_decoration)
-    return;
+      LayoutRect legend_cutout_rect = fieldset_paint_info.legend_cutout_rect;
+      legend_cutout_rect.MoveBy(paint_offset);
+      graphics_context.ClipOut(PixelSnappedIntRect(legend_cutout_rect));
 
-  // Create a clipping region around the legend and paint the border as normal
-  GraphicsContext& graphics_context = paint_info.context;
-  GraphicsContextStateSaver state_saver(graphics_context);
+      Node* node = nullptr;
+      const LayoutObject* layout_object = &layout_fieldset_;
+      for (; layout_object && !node; layout_object = layout_object->Parent())
+        node = layout_object->GeneratingNode();
+      BoxPainterBase::PaintBorder(
+          layout_fieldset_, layout_fieldset_.GetDocument(), node, paint_info,
+          paint_rect, layout_fieldset_.StyleRef());
+    }
+  }
 
-  LayoutRect legend_cutout_rect = fieldset_paint_info.legend_cutout_rect;
-  legend_cutout_rect.MoveBy(paint_offset);
-  graphics_context.ClipOut(PixelSnappedIntRect(legend_cutout_rect));
-
-  Node* node = nullptr;
-  const LayoutObject* layout_object = &layout_fieldset_;
-  for (; layout_object && !node; layout_object = layout_object->Parent())
-    node = layout_object->GeneratingNode();
-  BoxPainterBase::PaintBorder(layout_fieldset_, layout_fieldset_.GetDocument(),
-                              node, paint_info, paint_rect,
-                              layout_fieldset_.StyleRef());
+  if (RuntimeEnabledFeatures::PaintTouchActionRectsEnabled()) {
+    BoxPainter(layout_fieldset_)
+        .RecordHitTestData(paint_info, paint_offset, paint_rect);
+  }
 }
 
 void FieldsetPainter::PaintMask(const PaintInfo& paint_info,
diff --git a/third_party/blink/renderer/core/paint/inline_flow_box_painter.cc b/third_party/blink/renderer/core/paint/inline_flow_box_painter.cc
index a5320c2..39aa6e16 100644
--- a/third_party/blink/renderer/core/paint/inline_flow_box_painter.cc
+++ b/third_party/blink/renderer/core/paint/inline_flow_box_painter.cc
@@ -337,6 +337,10 @@
   LayoutObject* layout_object =
       LineLayoutAPIShim::LayoutObjectFrom(inline_flow_box_.GetLineLayoutItem());
 
+  // If an object is not visible, it does not participate in hit testing.
+  if (layout_object->StyleRef().Visibility() != EVisibility::kVisible)
+    return;
+
   auto touch_action = layout_object->EffectiveWhitelistedTouchAction();
   if (touch_action == TouchAction::kTouchActionAuto)
     return;
diff --git a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
index c49ce02..809340a7 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
+++ b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
@@ -201,6 +201,10 @@
   if (paint_info.GetGlobalPaintFlags() & kGlobalPaintFlattenCompositingLayers)
     return;
 
+  // If an object is not visible, it does not participate in hit testing.
+  if (box_fragment_.Style().Visibility() != EVisibility::kVisible)
+    return;
+
   const NGPhysicalFragment& physical_fragment = PhysicalFragment();
   auto touch_action = physical_fragment.EffectiveWhitelistedTouchAction();
   if (touch_action == TouchAction::kTouchActionAuto)
diff --git a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
index 2c014783..88a6a8c 100644
--- a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
+++ b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
@@ -1630,9 +1630,10 @@
       GetLayoutBox()->GetDocument().GetSnapCoordinator();
   if (!snap_coordinator)
     return;
-  snap_coordinator->PerformSnapping(*GetLayoutBox(),
-                                    orientation == kHorizontalScrollbar,
-                                    orientation == kVerticalScrollbar);
+
+  snap_coordinator->SnapForEndPosition(*GetLayoutBox(),
+                                       orientation == kHorizontalScrollbar,
+                                       orientation == kVerticalScrollbar);
 }
 
 void PaintLayerScrollableArea::PositionOverflowControls() {
@@ -2842,9 +2843,16 @@
   auto scroll_size = scrollable_area_->overflow_rect_.Size();
   // Ensure scrolling contents are at least as large as the scroll clip
   scroll_size = scroll_size.ExpandedTo(overflow_clip_rect.Size());
-  return LayoutRect(
-      box->FirstFragment().PaintOffset() + overflow_clip_rect.Location(),
-      scroll_size);
+  LayoutRect result(overflow_clip_rect.Location(), scroll_size);
+  result.MoveBy(box->FirstFragment().PaintOffset());
+  result = LayoutRect(PixelSnappedIntRect(result));
+#if DCHECK_IS_ON()
+  if (!RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+    DCHECK_EQ(result,
+              scrollable_area_->layer_->GraphicsLayerBacking()->VisualRect());
+  }
+#endif
+  return result;
 }
 
 String
diff --git a/third_party/blink/renderer/core/paint/replaced_painter.cc b/third_party/blink/renderer/core/paint/replaced_painter.cc
index 09f7d3c2..19da39d4 100644
--- a/third_party/blink/renderer/core/paint/replaced_painter.cc
+++ b/third_party/blink/renderer/core/paint/replaced_painter.cc
@@ -186,6 +186,10 @@
   if (paint_info.phase != PaintPhase::kForeground)
     return;
 
+  // If an object is not visible, it does not participate in hit testing.
+  if (layout_replaced_.StyleRef().Visibility() != EVisibility::kVisible)
+    return;
+
   auto touch_action = layout_replaced_.EffectiveWhitelistedTouchAction();
   if (touch_action == TouchAction::kTouchActionAuto)
     return;
diff --git a/third_party/blink/renderer/core/paint/table_cell_painter.cc b/third_party/blink/renderer/core/paint/table_cell_painter.cc
index 4e45214..d5e9ad9 100644
--- a/third_party/blink/renderer/core/paint/table_cell_painter.cc
+++ b/third_party/blink/renderer/core/paint/table_cell_painter.cc
@@ -80,45 +80,48 @@
   bool has_box_shadow = style.BoxShadow();
   bool needs_to_paint_border =
       style.HasBorderDecoration() && !table->ShouldCollapseBorders();
-  if (!has_background && !has_box_shadow && !needs_to_paint_border)
-    return;
+  if (has_background || has_box_shadow || needs_to_paint_border) {
+    if (!DrawingRecorder::UseCachedDrawingIfPossible(
+            paint_info.context, layout_table_cell_,
+            DisplayItem::kBoxDecorationBackground)) {
+      // TODO(chrishtr): the pixel-snapping here is likely incorrect.
+      DrawingRecorder recorder(paint_info.context, layout_table_cell_,
+                               DisplayItem::kBoxDecorationBackground);
 
-  if (DrawingRecorder::UseCachedDrawingIfPossible(
-          paint_info.context, layout_table_cell_,
-          DisplayItem::kBoxDecorationBackground))
-    return;
+      LayoutRect paint_rect = PaintRectNotIncludingVisualOverflow(paint_offset);
 
-  // TODO(chrishtr): the pixel-snapping here is likely incorrect.
-  DrawingRecorder recorder(paint_info.context, layout_table_cell_,
-                           DisplayItem::kBoxDecorationBackground);
+      if (has_box_shadow)
+        BoxPainterBase::PaintNormalBoxShadow(paint_info, paint_rect, style);
 
-  LayoutRect paint_rect = PaintRectNotIncludingVisualOverflow(paint_offset);
+      if (has_background)
+        PaintBackground(paint_info, paint_rect, layout_table_cell_);
 
-  if (has_box_shadow)
-    BoxPainterBase::PaintNormalBoxShadow(paint_info, paint_rect, style);
+      if (has_box_shadow) {
+        // If the table collapses borders, the inner rect is the border box rect
+        // inset by inner half widths of collapsed borders (which are returned
+        // from the overriden BorderXXX() methods). Otherwise the following code
+        // is equivalent to BoxPainterBase::PaintInsetBoxShadowWithBorderRect().
+        auto inner_rect = paint_rect;
+        inner_rect.ContractEdges(
+            layout_table_cell_.BorderTop(), layout_table_cell_.BorderRight(),
+            layout_table_cell_.BorderBottom(), layout_table_cell_.BorderLeft());
+        BoxPainterBase::PaintInsetBoxShadowWithInnerRect(
+            paint_info, inner_rect, layout_table_cell_.StyleRef());
+      }
 
-  if (has_background)
-    PaintBackground(paint_info, paint_rect, layout_table_cell_);
-
-  if (has_box_shadow) {
-    // If the table collapses borders, the inner rect is the border box rect
-    // inset by inner half widths of collapsed borders (which are returned
-    // from the overriden BorderXXX() methods). Otherwise the following code is
-    // equivalent to BoxPainterBase::PaintInsetBoxShadowWithBorderRect().
-    auto inner_rect = paint_rect;
-    inner_rect.ContractEdges(
-        layout_table_cell_.BorderTop(), layout_table_cell_.BorderRight(),
-        layout_table_cell_.BorderBottom(), layout_table_cell_.BorderLeft());
-    BoxPainterBase::PaintInsetBoxShadowWithInnerRect(
-        paint_info, inner_rect, layout_table_cell_.StyleRef());
+      if (needs_to_paint_border) {
+        BoxPainterBase::PaintBorder(
+            layout_table_cell_, layout_table_cell_.GetDocument(),
+            layout_table_cell_.GeneratingNode(), paint_info, paint_rect, style);
+      }
+    }
   }
 
-  if (!needs_to_paint_border)
-    return;
-
-  BoxPainterBase::PaintBorder(
-      layout_table_cell_, layout_table_cell_.GetDocument(),
-      layout_table_cell_.GeneratingNode(), paint_info, paint_rect, style);
+  if (RuntimeEnabledFeatures::PaintTouchActionRectsEnabled()) {
+    LayoutRect rect = PaintRectNotIncludingVisualOverflow(paint_offset);
+    BoxPainter(layout_table_cell_)
+        .RecordHitTestData(paint_info, paint_offset, rect);
+  }
 }
 
 void TableCellPainter::PaintMask(const PaintInfo& paint_info,
diff --git a/third_party/blink/renderer/core/paint/table_painter.cc b/third_party/blink/renderer/core/paint/table_painter.cc
index 5508fb2..76eaf6d 100644
--- a/third_party/blink/renderer/core/paint/table_painter.cc
+++ b/third_party/blink/renderer/core/paint/table_painter.cc
@@ -52,37 +52,21 @@
     ObjectPainter(layout_table_).PaintOutline(paint_info, paint_offset);
 }
 
-void TablePainter::RecordHitTestData(const PaintInfo& paint_info,
-                                     const LayoutPoint& paint_offset) {
-  // Hit test display items are only needed for compositing. This flag is used
-  // for for printing and drag images which do not need hit testing.
-  if (paint_info.GetGlobalPaintFlags() & kGlobalPaintFlattenCompositingLayers)
-    return;
-
-  auto touch_action = layout_table_.EffectiveWhitelistedTouchAction();
-  if (touch_action == TouchAction::kTouchActionAuto)
-    return;
-
-  auto rect = layout_table_.BorderBoxRect();
-  rect.MoveBy(paint_offset);
-  HitTestData::RecordHitTestRect(paint_info.context, layout_table_,
-                                 HitTestRect(rect, touch_action));
-}
-
 void TablePainter::PaintBoxDecorationBackground(
     const PaintInfo& paint_info,
     const LayoutPoint& paint_offset) {
-  if (RuntimeEnabledFeatures::PaintTouchActionRectsEnabled())
-    RecordHitTestData(paint_info, paint_offset);
-
-  if (!layout_table_.HasBoxDecorationBackground() ||
-      layout_table_.StyleRef().Visibility() != EVisibility::kVisible)
-    return;
-
   LayoutRect rect(paint_offset, layout_table_.Size());
   layout_table_.SubtractCaptionRect(rect);
-  BoxPainter(layout_table_)
-      .PaintBoxDecorationBackgroundWithRect(paint_info, rect);
+
+  if (layout_table_.HasBoxDecorationBackground() &&
+      layout_table_.StyleRef().Visibility() == EVisibility::kVisible) {
+    BoxPainter(layout_table_)
+        .PaintBoxDecorationBackgroundWithRect(paint_info, rect);
+  }
+
+  if (RuntimeEnabledFeatures::PaintTouchActionRectsEnabled()) {
+    BoxPainter(layout_table_).RecordHitTestData(paint_info, paint_offset, rect);
+  }
 }
 
 void TablePainter::PaintMask(const PaintInfo& paint_info,
diff --git a/third_party/blink/renderer/core/paint/table_painter.h b/third_party/blink/renderer/core/paint/table_painter.h
index 7578ce44..3cea620 100644
--- a/third_party/blink/renderer/core/paint/table_painter.h
+++ b/third_party/blink/renderer/core/paint/table_painter.h
@@ -26,10 +26,6 @@
 
  private:
   void PaintCollapsedBorders(const PaintInfo&);
-  // Paint a hit test display item and record hit test data. This should be
-  // called in the background paint phase even if there is no other painted
-  // content.
-  void RecordHitTestData(const PaintInfo&, const LayoutPoint& paint_offset);
 
   const LayoutTable& layout_table_;
 };
diff --git a/third_party/blink/renderer/core/paint/table_row_painter.cc b/third_party/blink/renderer/core/paint/table_row_painter.cc
index 30b2a05..25a7617 100644
--- a/third_party/blink/renderer/core/paint/table_row_painter.cc
+++ b/third_party/blink/renderer/core/paint/table_row_painter.cc
@@ -74,6 +74,10 @@
   if (paint_info.GetGlobalPaintFlags() & kGlobalPaintFlattenCompositingLayers)
     return;
 
+  // If an object is not visible, it does not participate in hit testing.
+  if (layout_table_row_.StyleRef().Visibility() != EVisibility::kVisible)
+    return;
+
   auto touch_action = layout_table_row_.EffectiveWhitelistedTouchAction();
   if (touch_action == TouchAction::kTouchActionAuto)
     return;
diff --git a/third_party/blink/renderer/core/paint/view_painter.cc b/third_party/blink/renderer/core/paint/view_painter.cc
index ec368c7..3324606 100644
--- a/third_party/blink/renderer/core/paint/view_painter.cc
+++ b/third_party/blink/renderer/core/paint/view_painter.cc
@@ -32,6 +32,24 @@
 }
 
 void ViewPainter::PaintBoxDecorationBackground(const PaintInfo& paint_info) {
+  PaintBoxDecorationBackgroundInternal(paint_info);
+  if (RuntimeEnabledFeatures::PaintTouchActionRectsEnabled()) {
+    BoxPainter(layout_view_)
+        .RecordHitTestData(paint_info, LayoutPoint(),
+                           layout_view_.BorderBoxRect());
+  }
+}
+
+void ViewPainter::PaintBoxDecorationBackgroundInternal(
+    const PaintInfo& paint_info) {
+  // Paint the background if we're visible and this block has a box decoration
+  // (background, border, appearance, or box shadow).
+  const ComputedStyle& style = layout_view_.StyleRef();
+  if (style.Visibility() != EVisibility::kVisible ||
+      !layout_view_.HasBoxDecorationBackground()) {
+    return;
+  }
+
   if (paint_info.SkipRootBackground())
     return;
 
diff --git a/third_party/blink/renderer/core/paint/view_painter.h b/third_party/blink/renderer/core/paint/view_painter.h
index a5fcfbe0..9aa734fb 100644
--- a/third_party/blink/renderer/core/paint/view_painter.h
+++ b/third_party/blink/renderer/core/paint/view_painter.h
@@ -23,6 +23,8 @@
 
  private:
   const LayoutView& layout_view_;
+
+  void PaintBoxDecorationBackgroundInternal(const PaintInfo&);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/scroll/scrollable_area.h b/third_party/blink/renderer/core/scroll/scrollable_area.h
index 2734d4b..d21fbe9 100644
--- a/third_party/blink/renderer/core/scroll/scrollable_area.h
+++ b/third_party/blink/renderer/core/scroll/scrollable_area.h
@@ -398,6 +398,8 @@
 
   virtual ScrollbarTheme& GetPageScrollbarTheme() const = 0;
 
+  float ScrollStep(ScrollGranularity, ScrollbarOrientation) const;
+
  protected:
   // Deduces the ScrollBehavior based on the element style and the parameter set
   // by programmatic scroll into either instant or smooth scroll.
@@ -409,7 +411,6 @@
 
   ScrollbarOrientation ScrollbarOrientationFromDirection(
       ScrollDirectionPhysical) const;
-  float ScrollStep(ScrollGranularity, ScrollbarOrientation) const;
 
   // Needed to let the animators call scrollOffsetChanged.
   friend class ScrollAnimatorCompositorCoordinator;
diff --git a/third_party/blink/renderer/core/svg/animation/svg_smil_element.cc b/third_party/blink/renderer/core/svg/animation/svg_smil_element.cc
index 3079e14..609fbd6a 100644
--- a/third_party/blink/renderer/core/svg/animation/svg_smil_element.cc
+++ b/third_party/blink/renderer/core/svg/animation/svg_smil_element.cc
@@ -324,7 +324,7 @@
 
   // "If no attribute is present, the default begin value (an offset-value of 0)
   // must be evaluated."
-  if (!FastHasAttribute(SVGNames::beginAttr))
+  if (!FastHasAttribute(svg_names::kBeginAttr))
     begin_times_.push_back(SMILTimeWithOrigin());
 
   if (is_waiting_for_first_interval_)
@@ -508,10 +508,10 @@
 void SVGSMILElement::ParseAttribute(const AttributeModificationParams& params) {
   const QualifiedName& name = params.name;
   const AtomicString& value = params.new_value;
-  if (name == SVGNames::beginAttr) {
+  if (name == svg_names::kBeginAttr) {
     if (!conditions_.IsEmpty()) {
       ClearConditions();
-      ParseBeginOrEnd(FastGetAttribute(SVGNames::endAttr), kEnd);
+      ParseBeginOrEnd(FastGetAttribute(svg_names::kEndAttr), kEnd);
     }
     ParseBeginOrEnd(value.GetString(), kBegin);
     if (isConnected()) {
@@ -520,10 +520,10 @@
       BeginListChanged(Elapsed());
     }
     AnimationAttributeChanged();
-  } else if (name == SVGNames::endAttr) {
+  } else if (name == svg_names::kEndAttr) {
     if (!conditions_.IsEmpty()) {
       ClearConditions();
-      ParseBeginOrEnd(FastGetAttribute(SVGNames::beginAttr), kBegin);
+      ParseBeginOrEnd(FastGetAttribute(svg_names::kBeginAttr), kBegin);
     }
     ParseBeginOrEnd(value.GetString(), kEnd);
     if (isConnected()) {
@@ -532,23 +532,23 @@
       EndListChanged(Elapsed());
     }
     AnimationAttributeChanged();
-  } else if (name == SVGNames::onbeginAttr) {
+  } else if (name == svg_names::kOnbeginAttr) {
     SetAttributeEventListener(EventTypeNames::beginEvent,
                               CreateAttributeEventListener(this, name, value));
-  } else if (name == SVGNames::onendAttr) {
+  } else if (name == svg_names::kOnendAttr) {
     SetAttributeEventListener(EventTypeNames::endEvent,
                               CreateAttributeEventListener(this, name, value));
-  } else if (name == SVGNames::onrepeatAttr) {
+  } else if (name == svg_names::kOnrepeatAttr) {
     SetAttributeEventListener(EventTypeNames::repeatEvent,
                               CreateAttributeEventListener(this, name, value));
-  } else if (name == SVGNames::restartAttr) {
+  } else if (name == svg_names::kRestartAttr) {
     if (value == "never")
       restart_ = kRestartNever;
     else if (value == "whenNotActive")
       restart_ = kRestartWhenNotActive;
     else
       restart_ = kRestartAlways;
-  } else if (name == SVGNames::fillAttr) {
+  } else if (name == svg_names::kFillAttr) {
     fill_ = value == "freeze" ? kFillFreeze : kFillRemove;
   } else {
     SVGElement::ParseAttribute(params);
@@ -556,17 +556,17 @@
 }
 
 void SVGSMILElement::SvgAttributeChanged(const QualifiedName& attr_name) {
-  if (attr_name == SVGNames::durAttr) {
+  if (attr_name == svg_names::kDurAttr) {
     cached_dur_ = kInvalidCachedTime;
-  } else if (attr_name == SVGNames::repeatDurAttr) {
+  } else if (attr_name == svg_names::kRepeatDurAttr) {
     cached_repeat_dur_ = kInvalidCachedTime;
-  } else if (attr_name == SVGNames::repeatCountAttr) {
+  } else if (attr_name == svg_names::kRepeatCountAttr) {
     cached_repeat_count_ = kInvalidCachedTime;
-  } else if (attr_name == SVGNames::minAttr) {
+  } else if (attr_name == svg_names::kMinAttr) {
     cached_min_ = kInvalidCachedTime;
-  } else if (attr_name == SVGNames::maxAttr) {
+  } else if (attr_name == svg_names::kMaxAttr) {
     cached_max_ = kInvalidCachedTime;
-  } else if (attr_name.Matches(SVGNames::hrefAttr) ||
+  } else if (attr_name.Matches(svg_names::kHrefAttr) ||
              attr_name.Matches(xlink_names::kHrefAttr)) {
     // TODO(fs): Could be smarter here when 'href' is specified and 'xlink:href'
     // is changed.
@@ -647,7 +647,7 @@
 SMILTime SVGSMILElement::Dur() const {
   if (cached_dur_ != kInvalidCachedTime)
     return cached_dur_;
-  const AtomicString& value = FastGetAttribute(SVGNames::durAttr);
+  const AtomicString& value = FastGetAttribute(svg_names::kDurAttr);
   SMILTime clock_value = ParseClockValue(value);
   return cached_dur_ = clock_value <= 0 ? SMILTime::Unresolved() : clock_value;
 }
@@ -655,7 +655,7 @@
 SMILTime SVGSMILElement::RepeatDur() const {
   if (cached_repeat_dur_ != kInvalidCachedTime)
     return cached_repeat_dur_;
-  const AtomicString& value = FastGetAttribute(SVGNames::repeatDurAttr);
+  const AtomicString& value = FastGetAttribute(svg_names::kRepeatDurAttr);
   SMILTime clock_value = ParseClockValue(value);
   cached_repeat_dur_ = clock_value <= 0 ? SMILTime::Unresolved() : clock_value;
   return cached_repeat_dur_;
@@ -666,7 +666,7 @@
   if (cached_repeat_count_ != kInvalidCachedTime)
     return cached_repeat_count_;
   SMILTime computed_repeat_count = SMILTime::Unresolved();
-  const AtomicString& value = FastGetAttribute(SVGNames::repeatCountAttr);
+  const AtomicString& value = FastGetAttribute(svg_names::kRepeatCountAttr);
   if (!value.IsNull()) {
     DEFINE_STATIC_LOCAL(const AtomicString, indefinite_value, ("indefinite"));
     if (value == indefinite_value) {
@@ -685,7 +685,7 @@
 SMILTime SVGSMILElement::MaxValue() const {
   if (cached_max_ != kInvalidCachedTime)
     return cached_max_;
-  const AtomicString& value = FastGetAttribute(SVGNames::maxAttr);
+  const AtomicString& value = FastGetAttribute(svg_names::kMaxAttr);
   SMILTime result = ParseClockValue(value);
   return cached_max_ = (result.IsUnresolved() || result <= 0)
                            ? SMILTime::Indefinite()
@@ -695,7 +695,7 @@
 SMILTime SVGSMILElement::MinValue() const {
   if (cached_min_ != kInvalidCachedTime)
     return cached_min_;
-  const AtomicString& value = FastGetAttribute(SVGNames::minAttr);
+  const AtomicString& value = FastGetAttribute(svg_names::kMinAttr);
   SMILTime result = ParseClockValue(value);
   return cached_min_ = (result.IsUnresolved() || result < 0) ? 0 : result;
 }
diff --git a/third_party/blink/renderer/core/svg/animation/svg_smil_element.h b/third_party/blink/renderer/core/svg/animation/svg_smil_element.h
index b6545a42..a6f5efab 100644
--- a/third_party/blink/renderer/core/svg/animation/svg_smil_element.h
+++ b/third_party/blink/renderer/core/svg/animation/svg_smil_element.h
@@ -298,11 +298,11 @@
 };
 
 inline bool IsSVGSMILElement(const SVGElement& element) {
-  return element.HasTagName(SVGNames::setTag) ||
-         element.HasTagName(SVGNames::animateTag) ||
-         element.HasTagName(SVGNames::animateMotionTag) ||
-         element.HasTagName(SVGNames::animateTransformTag) ||
-         element.HasTagName((SVGNames::discardTag));
+  return element.HasTagName(svg_names::kSetTag) ||
+         element.HasTagName(svg_names::kAnimateTag) ||
+         element.HasTagName(svg_names::kAnimateMotionTag) ||
+         element.HasTagName(svg_names::kAnimateTransformTag) ||
+         element.HasTagName((svg_names::kDiscardTag));
 }
 
 DEFINE_SVGELEMENT_TYPE_CASTS_WITH_FUNCTION(SVGSMILElement);
diff --git a/third_party/blink/renderer/core/svg/svg_a_element.cc b/third_party/blink/renderer/core/svg/svg_a_element.cc
index a3a63d7..556a4fc 100644
--- a/third_party/blink/renderer/core/svg/svg_a_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_a_element.cc
@@ -50,9 +50,9 @@
 using namespace HTMLNames;
 
 inline SVGAElement::SVGAElement(Document& document)
-    : SVGGraphicsElement(SVGNames::aTag, document),
+    : SVGGraphicsElement(svg_names::kATag, document),
       SVGURIReference(this),
-      svg_target_(SVGAnimatedString::Create(this, SVGNames::targetAttr)) {
+      svg_target_(SVGAnimatedString::Create(this, svg_names::kTargetAttr)) {
   AddToPropertyMap(svg_target_);
 }
 
diff --git a/third_party/blink/renderer/core/svg/svg_animate_element.cc b/third_party/blink/renderer/core/svg/svg_animate_element.cc
index fef3a6d..9370ced 100644
--- a/third_party/blink/renderer/core/svg/svg_animate_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_animate_element.cc
@@ -92,7 +92,7 @@
   // for targetting the 'href' attribute."
   // https://svgwg.org/svg2-draft/types.html#__svg__SVGURIReference__href
   if (resolved_attr_name == xlink_names::kHrefAttr)
-    return SVGNames::hrefAttr;
+    return svg_names::kHrefAttr;
   return resolved_attr_name;
 }
 
@@ -108,19 +108,19 @@
       attribute_type_(kAttributeTypeAuto) {}
 
 SVGAnimateElement* SVGAnimateElement::Create(Document& document) {
-  return new SVGAnimateElement(SVGNames::animateTag, document);
+  return new SVGAnimateElement(svg_names::kAnimateTag, document);
 }
 
 SVGAnimateElement::~SVGAnimateElement() = default;
 
 bool SVGAnimateElement::IsSVGAnimationAttributeSettingJavaScriptURL(
     const Attribute& attribute) const {
-  if ((attribute.GetName() == SVGNames::fromAttr ||
-       attribute.GetName() == SVGNames::toAttr) &&
+  if ((attribute.GetName() == svg_names::kFromAttr ||
+       attribute.GetName() == svg_names::kToAttr) &&
       AttributeValueIsJavaScriptURL(attribute))
     return true;
 
-  if (attribute.GetName() == SVGNames::valuesAttr) {
+  if (attribute.GetName() == svg_names::kValuesAttr) {
     Vector<String> parts;
     if (!ParseValues(attribute.Value(), parts)) {
       // Assume the worst.
@@ -140,7 +140,7 @@
   SVGAnimationElement::InsertedInto(root_parent);
   if (root_parent.isConnected()) {
     SetAttributeName(ConstructQualifiedName(
-        *this, FastGetAttribute(SVGNames::attributeNameAttr)));
+        *this, FastGetAttribute(svg_names::kAttributeNameAttr)));
   }
   return kInsertionDone;
 }
@@ -153,12 +153,12 @@
 
 void SVGAnimateElement::ParseAttribute(
     const AttributeModificationParams& params) {
-  if (params.name == SVGNames::attributeTypeAttr) {
+  if (params.name == svg_names::kAttributeTypeAttr) {
     SetAttributeType(params.new_value);
     AnimationAttributeChanged();
     return;
   }
-  if (params.name == SVGNames::attributeNameAttr) {
+  if (params.name == svg_names::kAttributeNameAttr) {
     SetAttributeName(ConstructQualifiedName(*this, params.new_value));
     AnimationAttributeChanged();
     return;
diff --git a/third_party/blink/renderer/core/svg/svg_animate_element.h b/third_party/blink/renderer/core/svg/svg_animate_element.h
index 0a300c31..a551c660 100644
--- a/third_party/blink/renderer/core/svg/svg_animate_element.h
+++ b/third_party/blink/renderer/core/svg/svg_animate_element.h
@@ -133,9 +133,9 @@
 };
 
 inline bool IsSVGAnimateElement(const SVGElement& element) {
-  return element.HasTagName(SVGNames::animateTag) ||
-         element.HasTagName(SVGNames::animateTransformTag) ||
-         element.HasTagName(SVGNames::setTag);
+  return element.HasTagName(svg_names::kAnimateTag) ||
+         element.HasTagName(svg_names::kAnimateTransformTag) ||
+         element.HasTagName(svg_names::kSetTag);
 }
 
 DEFINE_SVGELEMENT_TYPE_CASTS_WITH_FUNCTION(SVGAnimateElement);
diff --git a/third_party/blink/renderer/core/svg/svg_animate_motion_element.cc b/third_party/blink/renderer/core/svg/svg_animate_motion_element.cc
index 5467317a..0c229b5 100644
--- a/third_party/blink/renderer/core/svg/svg_animate_motion_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_animate_motion_element.cc
@@ -57,7 +57,7 @@
 }
 
 inline SVGAnimateMotionElement::SVGAnimateMotionElement(Document& document)
-    : SVGAnimationElement(SVGNames::animateMotionTag, document),
+    : SVGAnimationElement(svg_names::kAnimateMotionTag, document),
       has_to_point_at_end_of_duration_(false) {
   SetCalcMode(kCalcModePaced);
 }
@@ -73,7 +73,7 @@
 
 void SVGAnimateMotionElement::ParseAttribute(
     const AttributeModificationParams& params) {
-  if (params.name == SVGNames::pathAttr) {
+  if (params.name == svg_names::kPathAttr) {
     path_ = Path();
     BuildPathFromString(params.new_value, path_);
     UpdateAnimationPath();
@@ -87,7 +87,7 @@
     const {
   DEFINE_STATIC_LOCAL(const AtomicString, auto_val, ("auto"));
   DEFINE_STATIC_LOCAL(const AtomicString, auto_reverse, ("auto-reverse"));
-  const AtomicString& rotate = getAttribute(SVGNames::rotateAttr);
+  const AtomicString& rotate = getAttribute(svg_names::kRotateAttr);
   if (rotate == auto_val)
     return kRotateAuto;
   if (rotate == auto_reverse)
@@ -108,7 +108,7 @@
     }
   }
 
-  if (!found_m_path && FastHasAttribute(SVGNames::pathAttr))
+  if (!found_m_path && FastHasAttribute(svg_names::kPathAttr))
     animation_path_ = path_;
 
   UpdateAnimationMode();
diff --git a/third_party/blink/renderer/core/svg/svg_animate_transform_element.cc b/third_party/blink/renderer/core/svg/svg_animate_transform_element.cc
index 12ecd8c..4972e03e 100644
--- a/third_party/blink/renderer/core/svg/svg_animate_transform_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_animate_transform_element.cc
@@ -30,7 +30,7 @@
 
 inline SVGAnimateTransformElement::SVGAnimateTransformElement(
     Document& document)
-    : SVGAnimateElement(SVGNames::animateTransformTag, document),
+    : SVGAnimateElement(svg_names::kAnimateTransformTag, document),
       transform_type_(kSvgTransformUnknown) {}
 
 DEFINE_NODE_FACTORY(SVGAnimateTransformElement)
@@ -67,7 +67,7 @@
 
 void SVGAnimateTransformElement::ParseAttribute(
     const AttributeModificationParams& params) {
-  if (params.name == SVGNames::typeAttr) {
+  if (params.name == svg_names::kTypeAttr) {
     transform_type_ = ParseTransformType(params.new_value);
     if (transform_type_ == kSvgTransformMatrix)
       transform_type_ = kSvgTransformUnknown;
diff --git a/third_party/blink/renderer/core/svg/svg_animated_angle.cc b/third_party/blink/renderer/core/svg/svg_animated_angle.cc
index 47ddc36..2f69e0e 100644
--- a/third_party/blink/renderer/core/svg/svg_animated_angle.cc
+++ b/third_party/blink/renderer/core/svg/svg_animated_angle.cc
@@ -36,11 +36,11 @@
 
 SVGAnimatedAngle::SVGAnimatedAngle(SVGElement* context_element)
     : SVGAnimatedProperty<SVGAngle>(context_element,
-                                    SVGNames::orientAttr,
+                                    svg_names::kOrientAttr,
                                     SVGAngle::Create()),
       orient_type_(SVGAnimatedEnumeration<SVGMarkerOrientType>::Create(
           context_element,
-          SVGNames::orientAttr,
+          svg_names::kOrientAttr,
           BaseValue()->OrientType())) {}
 
 SVGAnimatedAngle::~SVGAnimatedAngle() = default;
diff --git a/third_party/blink/renderer/core/svg/svg_animated_href.cc b/third_party/blink/renderer/core/svg/svg_animated_href.cc
index 25a9843..11b18d6d 100644
--- a/third_party/blink/renderer/core/svg/svg_animated_href.cc
+++ b/third_party/blink/renderer/core/svg/svg_animated_href.cc
@@ -21,7 +21,7 @@
 }
 
 SVGAnimatedHref::SVGAnimatedHref(SVGElement* context_element)
-    : SVGAnimatedString(context_element, SVGNames::hrefAttr),
+    : SVGAnimatedString(context_element, svg_names::kHrefAttr),
       xlink_href_(
           SVGAnimatedString::Create(context_element, xlink_names::kHrefAttr)) {}
 
@@ -31,7 +31,7 @@
 }
 
 bool SVGAnimatedHref::IsKnownAttribute(const QualifiedName& attr_name) {
-  return attr_name.Matches(SVGNames::hrefAttr) ||
+  return attr_name.Matches(svg_names::kHrefAttr) ||
          attr_name.Matches(xlink_names::kHrefAttr);
 }
 
diff --git a/third_party/blink/renderer/core/svg/svg_animation_element.cc b/third_party/blink/renderer/core/svg/svg_animation_element.cc
index 1c8e310..c3e36ccb 100644
--- a/third_party/blink/renderer/core/svg/svg_animation_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_animation_element.cc
@@ -156,7 +156,7 @@
 void SVGAnimationElement::ParseAttribute(
     const AttributeModificationParams& params) {
   const QualifiedName& name = params.name;
-  if (name == SVGNames::valuesAttr) {
+  if (name == svg_names::kValuesAttr) {
     if (!ParseValues(params.new_value, values_)) {
       ReportAttributeParsingError(SVGParseStatus::kParsingFailed, name,
                                   params.new_value);
@@ -166,7 +166,7 @@
     return;
   }
 
-  if (name == SVGNames::keyTimesAttr) {
+  if (name == svg_names::kKeyTimesAttr) {
     if (!ParseKeyTimes(params.new_value, key_times_, true)) {
       ReportAttributeParsingError(SVGParseStatus::kParsingFailed, name,
                                   params.new_value);
@@ -174,7 +174,7 @@
     return;
   }
 
-  if (name == SVGNames::keyPointsAttr) {
+  if (name == svg_names::kKeyPointsAttr) {
     if (IsSVGAnimateMotionElement(*this)) {
       // This is specified to be an animateMotion attribute only but it is
       // simpler to put it here where the other timing calculatations are.
@@ -186,7 +186,7 @@
     return;
   }
 
-  if (name == SVGNames::keySplinesAttr) {
+  if (name == svg_names::kKeySplinesAttr) {
     if (!ParseKeySplines(params.new_value, key_splines_)) {
       ReportAttributeParsingError(SVGParseStatus::kParsingFailed, name,
                                   params.new_value);
@@ -194,13 +194,13 @@
     return;
   }
 
-  if (name == SVGNames::calcModeAttr) {
+  if (name == svg_names::kCalcModeAttr) {
     SetCalcMode(params.new_value);
     return;
   }
 
-  if (name == SVGNames::fromAttr || name == SVGNames::toAttr ||
-      name == SVGNames::byAttr) {
+  if (name == svg_names::kFromAttr || name == svg_names::kToAttr ||
+      name == svg_names::kByAttr) {
     UpdateAnimationMode();
     return;
   }
@@ -209,12 +209,12 @@
 }
 
 void SVGAnimationElement::SvgAttributeChanged(const QualifiedName& attr_name) {
-  if (attr_name == SVGNames::valuesAttr || attr_name == SVGNames::byAttr ||
-      attr_name == SVGNames::fromAttr || attr_name == SVGNames::toAttr ||
-      attr_name == SVGNames::calcModeAttr ||
-      attr_name == SVGNames::keySplinesAttr ||
-      attr_name == SVGNames::keyPointsAttr ||
-      attr_name == SVGNames::keyTimesAttr) {
+  if (attr_name == svg_names::kValuesAttr || attr_name == svg_names::kByAttr ||
+      attr_name == svg_names::kFromAttr || attr_name == svg_names::kToAttr ||
+      attr_name == svg_names::kCalcModeAttr ||
+      attr_name == svg_names::kKeySplinesAttr ||
+      attr_name == svg_names::kKeyPointsAttr ||
+      attr_name == svg_names::kKeyTimesAttr) {
     AnimationAttributeChanged();
     return;
   }
@@ -272,7 +272,7 @@
 
 void SVGAnimationElement::UpdateAnimationMode() {
   // http://www.w3.org/TR/2001/REC-smil-animation-20010904/#AnimFuncValues
-  if (hasAttribute(SVGNames::valuesAttr))
+  if (hasAttribute(svg_names::kValuesAttr))
     SetAnimationMode(kValuesAnimation);
   else if (!ToValue().IsEmpty())
     SetAnimationMode(FromValue().IsEmpty() ? kToAnimation : kFromToAnimation);
@@ -310,26 +310,26 @@
 }
 
 String SVGAnimationElement::ToValue() const {
-  return FastGetAttribute(SVGNames::toAttr);
+  return FastGetAttribute(svg_names::kToAttr);
 }
 
 String SVGAnimationElement::ByValue() const {
-  return FastGetAttribute(SVGNames::byAttr);
+  return FastGetAttribute(svg_names::kByAttr);
 }
 
 String SVGAnimationElement::FromValue() const {
-  return FastGetAttribute(SVGNames::fromAttr);
+  return FastGetAttribute(svg_names::kFromAttr);
 }
 
 bool SVGAnimationElement::IsAdditive() {
   DEFINE_STATIC_LOCAL(const AtomicString, sum, ("sum"));
-  const AtomicString& value = FastGetAttribute(SVGNames::additiveAttr);
+  const AtomicString& value = FastGetAttribute(svg_names::kAdditiveAttr);
   return value == sum || GetAnimationMode() == kByAnimation;
 }
 
 bool SVGAnimationElement::IsAccumulated() const {
   DEFINE_STATIC_LOCAL(const AtomicString, sum, ("sum"));
-  const AtomicString& value = FastGetAttribute(SVGNames::accumulateAttr);
+  const AtomicString& value = FastGetAttribute(svg_names::kAccumulateAttr);
   return value == sum && GetAnimationMode() != kToAnimation;
 }
 
@@ -524,7 +524,7 @@
     return;
 
   // These validations are appropriate for all animation modes.
-  if (FastHasAttribute(SVGNames::keyPointsAttr) &&
+  if (FastHasAttribute(svg_names::kKeyPointsAttr) &&
       key_points_.size() != key_times_.size())
     return;
 
@@ -533,11 +533,11 @@
   if (calc_mode == kCalcModeSpline) {
     unsigned splines_count = key_splines_.size();
     if (!splines_count ||
-        (FastHasAttribute(SVGNames::keyPointsAttr) &&
+        (FastHasAttribute(svg_names::kKeyPointsAttr) &&
          key_points_.size() - 1 != splines_count) ||
         (animation_mode == kValuesAnimation &&
          values_.size() - 1 != splines_count) ||
-        (FastHasAttribute(SVGNames::keyTimesAttr) &&
+        (FastHasAttribute(svg_names::kKeyTimesAttr) &&
          key_times_.size() - 1 != splines_count))
       return;
   }
@@ -550,8 +550,8 @@
   if ((animation_mode == kFromToAnimation ||
        animation_mode == kFromByAnimation || animation_mode == kToAnimation ||
        animation_mode == kByAnimation) &&
-      (FastHasAttribute(SVGNames::keyPointsAttr) &&
-       FastHasAttribute(SVGNames::keyTimesAttr) &&
+      (FastHasAttribute(svg_names::kKeyPointsAttr) &&
+       FastHasAttribute(svg_names::kKeyTimesAttr) &&
        (key_times_.size() < 2 || key_times_.size() != key_points_.size())))
     return;
   if (animation_mode == kFromToAnimation) {
@@ -569,8 +569,8 @@
     animation_valid_ =
         values_.size() >= 1 &&
         (calc_mode == kCalcModePaced ||
-         !FastHasAttribute(SVGNames::keyTimesAttr) ||
-         FastHasAttribute(SVGNames::keyPointsAttr) ||
+         !FastHasAttribute(svg_names::kKeyTimesAttr) ||
+         FastHasAttribute(svg_names::kKeyPointsAttr) ||
          (values_.size() == key_times_.size())) &&
         (calc_mode == kCalcModeDiscrete || !key_times_.size() ||
          key_times_.back() == 1) &&
@@ -578,7 +578,7 @@
          ((key_splines_.size() &&
            (key_splines_.size() == values_.size() - 1)) ||
           key_splines_.size() == key_points_.size() - 1)) &&
-        (!FastHasAttribute(SVGNames::keyPointsAttr) ||
+        (!FastHasAttribute(svg_names::kKeyPointsAttr) ||
          (key_times_.size() > 1 && key_times_.size() == key_points_.size()));
     if (animation_valid_)
       animation_valid_ = CalculateToAtEndOfDurationValue(values_.back());
@@ -587,7 +587,7 @@
   } else if (animation_mode == kPathAnimation) {
     animation_valid_ =
         calc_mode == kCalcModePaced ||
-        !FastHasAttribute(SVGNames::keyPointsAttr) ||
+        !FastHasAttribute(svg_names::kKeyPointsAttr) ||
         (key_times_.size() > 1 && key_times_.size() == key_points_.size());
   }
 
diff --git a/third_party/blink/renderer/core/svg/svg_circle_element.cc b/third_party/blink/renderer/core/svg/svg_circle_element.cc
index 41d8006..317133f 100644
--- a/third_party/blink/renderer/core/svg/svg_circle_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_circle_element.cc
@@ -26,19 +26,19 @@
 namespace blink {
 
 inline SVGCircleElement::SVGCircleElement(Document& document)
-    : SVGGeometryElement(SVGNames::circleTag, document),
+    : SVGGeometryElement(svg_names::kCircleTag, document),
       cx_(SVGAnimatedLength::Create(this,
-                                    SVGNames::cxAttr,
+                                    svg_names::kCxAttr,
                                     SVGLengthMode::kWidth,
                                     SVGLength::Initial::kUnitlessZero,
                                     CSSPropertyCx)),
       cy_(SVGAnimatedLength::Create(this,
-                                    SVGNames::cyAttr,
+                                    svg_names::kCyAttr,
                                     SVGLengthMode::kHeight,
                                     SVGLength::Initial::kUnitlessZero,
                                     CSSPropertyCy)),
       r_(SVGAnimatedLength::Create(this,
-                                   SVGNames::rAttr,
+                                   svg_names::kRAttr,
                                    SVGLengthMode::kOther,
                                    SVGLength::Initial::kUnitlessZero,
                                    CSSPropertyR)) {
@@ -96,8 +96,8 @@
 }
 
 void SVGCircleElement::SvgAttributeChanged(const QualifiedName& attr_name) {
-  if (attr_name == SVGNames::rAttr || attr_name == SVGNames::cxAttr ||
-      attr_name == SVGNames::cyAttr) {
+  if (attr_name == svg_names::kRAttr || attr_name == svg_names::kCxAttr ||
+      attr_name == svg_names::kCyAttr) {
     UpdateRelativeLengthsInformation();
     GeometryPresentationAttributeChanged(attr_name);
     return;
diff --git a/third_party/blink/renderer/core/svg/svg_clip_path_element.cc b/third_party/blink/renderer/core/svg/svg_clip_path_element.cc
index 82b66e13..e7498fe 100644
--- a/third_party/blink/renderer/core/svg/svg_clip_path_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_clip_path_element.cc
@@ -26,11 +26,11 @@
 namespace blink {
 
 inline SVGClipPathElement::SVGClipPathElement(Document& document)
-    : SVGGraphicsElement(SVGNames::clipPathTag, document),
+    : SVGGraphicsElement(svg_names::kClipPathTag, document),
       clip_path_units_(
           SVGAnimatedEnumeration<SVGUnitTypes::SVGUnitType>::Create(
               this,
-              SVGNames::clipPathUnitsAttr,
+              svg_names::kClipPathUnitsAttr,
               SVGUnitTypes::kSvgUnitTypeUserspaceonuse)) {
   AddToPropertyMap(clip_path_units_);
 }
@@ -43,7 +43,7 @@
 DEFINE_NODE_FACTORY(SVGClipPathElement)
 
 void SVGClipPathElement::SvgAttributeChanged(const QualifiedName& attr_name) {
-  if (attr_name == SVGNames::clipPathUnitsAttr) {
+  if (attr_name == svg_names::kClipPathUnitsAttr) {
     SVGElement::InvalidationGuard invalidation_guard(this);
 
     LayoutSVGResourceContainer* layout_object =
diff --git a/third_party/blink/renderer/core/svg/svg_component_transfer_function_element.cc b/third_party/blink/renderer/core/svg/svg_component_transfer_function_element.cc
index 2781cab..c6fdc61 100644
--- a/third_party/blink/renderer/core/svg/svg_component_transfer_function_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_component_transfer_function_element.cc
@@ -49,16 +49,16 @@
     Document& document)
     : SVGElement(tag_name, document),
       table_values_(
-          SVGAnimatedNumberList::Create(this, SVGNames::tableValuesAttr)),
-      slope_(SVGAnimatedNumber::Create(this, SVGNames::slopeAttr, 1)),
+          SVGAnimatedNumberList::Create(this, svg_names::kTableValuesAttr)),
+      slope_(SVGAnimatedNumber::Create(this, svg_names::kSlopeAttr, 1)),
       intercept_(
-          SVGAnimatedNumber::Create(this, SVGNames::interceptAttr, 0.0f)),
-      amplitude_(SVGAnimatedNumber::Create(this, SVGNames::amplitudeAttr, 1)),
-      exponent_(SVGAnimatedNumber::Create(this, SVGNames::exponentAttr, 1)),
-      offset_(SVGAnimatedNumber::Create(this, SVGNames::offsetAttr, 0.0f)),
+          SVGAnimatedNumber::Create(this, svg_names::kInterceptAttr, 0.0f)),
+      amplitude_(SVGAnimatedNumber::Create(this, svg_names::kAmplitudeAttr, 1)),
+      exponent_(SVGAnimatedNumber::Create(this, svg_names::kExponentAttr, 1)),
+      offset_(SVGAnimatedNumber::Create(this, svg_names::kOffsetAttr, 0.0f)),
       type_(SVGAnimatedEnumeration<ComponentTransferType>::Create(
           this,
-          SVGNames::typeAttr,
+          svg_names::kTypeAttr,
           FECOMPONENTTRANSFER_TYPE_IDENTITY)) {
   AddToPropertyMap(table_values_);
   AddToPropertyMap(slope_);
@@ -82,13 +82,13 @@
 
 void SVGComponentTransferFunctionElement::SvgAttributeChanged(
     const QualifiedName& attr_name) {
-  if (attr_name == SVGNames::typeAttr ||
-      attr_name == SVGNames::tableValuesAttr ||
-      attr_name == SVGNames::slopeAttr ||
-      attr_name == SVGNames::interceptAttr ||
-      attr_name == SVGNames::amplitudeAttr ||
-      attr_name == SVGNames::exponentAttr ||
-      attr_name == SVGNames::offsetAttr) {
+  if (attr_name == svg_names::kTypeAttr ||
+      attr_name == svg_names::kTableValuesAttr ||
+      attr_name == svg_names::kSlopeAttr ||
+      attr_name == svg_names::kInterceptAttr ||
+      attr_name == svg_names::kAmplitudeAttr ||
+      attr_name == svg_names::kExponentAttr ||
+      attr_name == svg_names::kOffsetAttr) {
     SVGElement::InvalidationGuard invalidation_guard(this);
     InvalidateFilterPrimitiveParent(*this);
     return;
diff --git a/third_party/blink/renderer/core/svg/svg_defs_element.cc b/third_party/blink/renderer/core/svg/svg_defs_element.cc
index 598a160..7e8fbcf 100644
--- a/third_party/blink/renderer/core/svg/svg_defs_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_defs_element.cc
@@ -26,7 +26,7 @@
 namespace blink {
 
 inline SVGDefsElement::SVGDefsElement(Document& document)
-    : SVGGraphicsElement(SVGNames::defsTag, document) {}
+    : SVGGraphicsElement(svg_names::kDefsTag, document) {}
 
 DEFINE_NODE_FACTORY(SVGDefsElement)
 
diff --git a/third_party/blink/renderer/core/svg/svg_desc_element.cc b/third_party/blink/renderer/core/svg/svg_desc_element.cc
index fbab758..64364cd 100644
--- a/third_party/blink/renderer/core/svg/svg_desc_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_desc_element.cc
@@ -25,7 +25,7 @@
 namespace blink {
 
 inline SVGDescElement::SVGDescElement(Document& document)
-    : SVGElement(SVGNames::descTag, document) {}
+    : SVGElement(svg_names::kDescTag, document) {}
 
 DEFINE_NODE_FACTORY(SVGDescElement)
 }
diff --git a/third_party/blink/renderer/core/svg/svg_discard_element.cc b/third_party/blink/renderer/core/svg/svg_discard_element.cc
index 3604e8d..ad99768e 100644
--- a/third_party/blink/renderer/core/svg/svg_discard_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_discard_element.cc
@@ -35,7 +35,7 @@
 namespace blink {
 
 inline SVGDiscardElement::SVGDiscardElement(Document& document)
-    : SVGSMILElement(SVGNames::discardTag, document) {
+    : SVGSMILElement(svg_names::kDiscardTag, document) {
   DCHECK(RuntimeEnabledFeatures::SMILEnabled());
 }
 
diff --git a/third_party/blink/renderer/core/svg/svg_element.cc b/third_party/blink/renderer/core/svg/svg_element.cc
index aab9d982..3a16cb7 100644
--- a/third_party/blink/renderer/core/svg/svg_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_element.cc
@@ -62,7 +62,7 @@
 namespace blink {
 
 using namespace HTMLNames;
-using namespace SVGNames;
+using namespace svg_names;
 
 SVGElement::SVGElement(const QualifiedName& tag_name,
                        Document& document,
@@ -436,64 +436,64 @@
     // This is a list of all base CSS and SVG CSS properties which are exposed
     // as SVG XML attributes
     const QualifiedName* const attr_names[] = {
-        &alignment_baselineAttr,
-        &baseline_shiftAttr,
-        &buffered_renderingAttr,
-        &clipAttr,
-        &clip_pathAttr,
-        &clip_ruleAttr,
-        &SVGNames::colorAttr,
-        &color_interpolationAttr,
-        &color_interpolation_filtersAttr,
-        &color_renderingAttr,
-        &cursorAttr,
-        &SVGNames::directionAttr,
-        &displayAttr,
-        &dominant_baselineAttr,
-        &fillAttr,
-        &fill_opacityAttr,
-        &fill_ruleAttr,
-        &filterAttr,
-        &flood_colorAttr,
-        &flood_opacityAttr,
-        &font_familyAttr,
-        &font_sizeAttr,
-        &font_stretchAttr,
-        &font_styleAttr,
-        &font_variantAttr,
-        &font_weightAttr,
-        &image_renderingAttr,
-        &letter_spacingAttr,
-        &lighting_colorAttr,
-        &marker_endAttr,
-        &marker_midAttr,
-        &marker_startAttr,
-        &maskAttr,
-        &mask_typeAttr,
-        &opacityAttr,
-        &overflowAttr,
-        &paint_orderAttr,
-        &pointer_eventsAttr,
-        &shape_renderingAttr,
-        &stop_colorAttr,
-        &stop_opacityAttr,
-        &strokeAttr,
-        &stroke_dasharrayAttr,
-        &stroke_dashoffsetAttr,
-        &stroke_linecapAttr,
-        &stroke_linejoinAttr,
-        &stroke_miterlimitAttr,
-        &stroke_opacityAttr,
-        &stroke_widthAttr,
-        &text_anchorAttr,
-        &text_decorationAttr,
-        &text_renderingAttr,
-        &transform_originAttr,
-        &unicode_bidiAttr,
-        &vector_effectAttr,
-        &visibilityAttr,
-        &word_spacingAttr,
-        &writing_modeAttr,
+        &kAlignmentBaselineAttr,
+        &kBaselineShiftAttr,
+        &kBufferedRenderingAttr,
+        &kClipAttr,
+        &kClipPathAttr,
+        &kClipRuleAttr,
+        &svg_names::kColorAttr,
+        &kColorInterpolationAttr,
+        &kColorInterpolationFiltersAttr,
+        &kColorRenderingAttr,
+        &kCursorAttr,
+        &svg_names::kDirectionAttr,
+        &kDisplayAttr,
+        &kDominantBaselineAttr,
+        &kFillAttr,
+        &kFillOpacityAttr,
+        &kFillRuleAttr,
+        &kFilterAttr,
+        &kFloodColorAttr,
+        &kFloodOpacityAttr,
+        &kFontFamilyAttr,
+        &kFontSizeAttr,
+        &kFontStretchAttr,
+        &kFontStyleAttr,
+        &kFontVariantAttr,
+        &kFontWeightAttr,
+        &kImageRenderingAttr,
+        &kLetterSpacingAttr,
+        &kLightingColorAttr,
+        &kMarkerEndAttr,
+        &kMarkerMidAttr,
+        &kMarkerStartAttr,
+        &kMaskAttr,
+        &kMaskTypeAttr,
+        &kOpacityAttr,
+        &kOverflowAttr,
+        &kPaintOrderAttr,
+        &kPointerEventsAttr,
+        &kShapeRenderingAttr,
+        &kStopColorAttr,
+        &kStopOpacityAttr,
+        &kStrokeAttr,
+        &kStrokeDasharrayAttr,
+        &kStrokeDashoffsetAttr,
+        &kStrokeLinecapAttr,
+        &kStrokeLinejoinAttr,
+        &kStrokeMiterlimitAttr,
+        &kStrokeOpacityAttr,
+        &kStrokeWidthAttr,
+        &kTextAnchorAttr,
+        &kTextDecorationAttr,
+        &kTextRenderingAttr,
+        &kTransformOriginAttr,
+        &kUnicodeBidiAttr,
+        &kVectorEffectAttr,
+        &kVisibilityAttr,
+        &kWordSpacingAttr,
+        &kWritingModeAttr,
     };
     for (size_t i = 0; i < arraysize(attr_names); i++) {
       CSSPropertyID property_id = cssPropertyID(attr_names[i]->LocalName());
@@ -725,59 +725,59 @@
       const AnimatedPropertyType prop_type;
     };
     const AttrToTypeEntry attr_to_types[] = {
-        {alignment_baselineAttr, kAnimatedString},
-        {baseline_shiftAttr, kAnimatedString},
-        {buffered_renderingAttr, kAnimatedString},
-        {clip_pathAttr, kAnimatedString},
-        {clip_ruleAttr, kAnimatedString},
-        {SVGNames::colorAttr, kAnimatedColor},
-        {color_interpolationAttr, kAnimatedString},
-        {color_interpolation_filtersAttr, kAnimatedString},
-        {color_renderingAttr, kAnimatedString},
-        {cursorAttr, kAnimatedString},
-        {displayAttr, kAnimatedString},
-        {dominant_baselineAttr, kAnimatedString},
-        {fillAttr, kAnimatedColor},
-        {fill_opacityAttr, kAnimatedNumber},
-        {fill_ruleAttr, kAnimatedString},
-        {filterAttr, kAnimatedString},
-        {flood_colorAttr, kAnimatedColor},
-        {flood_opacityAttr, kAnimatedNumber},
-        {font_familyAttr, kAnimatedString},
-        {font_sizeAttr, kAnimatedLength},
-        {font_stretchAttr, kAnimatedString},
-        {font_styleAttr, kAnimatedString},
-        {font_variantAttr, kAnimatedString},
-        {font_weightAttr, kAnimatedString},
-        {image_renderingAttr, kAnimatedString},
-        {letter_spacingAttr, kAnimatedLength},
-        {lighting_colorAttr, kAnimatedColor},
-        {marker_endAttr, kAnimatedString},
-        {marker_midAttr, kAnimatedString},
-        {marker_startAttr, kAnimatedString},
-        {maskAttr, kAnimatedString},
-        {mask_typeAttr, kAnimatedString},
-        {opacityAttr, kAnimatedNumber},
-        {overflowAttr, kAnimatedString},
-        {paint_orderAttr, kAnimatedString},
-        {pointer_eventsAttr, kAnimatedString},
-        {shape_renderingAttr, kAnimatedString},
-        {stop_colorAttr, kAnimatedColor},
-        {stop_opacityAttr, kAnimatedNumber},
-        {strokeAttr, kAnimatedColor},
-        {stroke_dasharrayAttr, kAnimatedLengthList},
-        {stroke_dashoffsetAttr, kAnimatedLength},
-        {stroke_linecapAttr, kAnimatedString},
-        {stroke_linejoinAttr, kAnimatedString},
-        {stroke_miterlimitAttr, kAnimatedNumber},
-        {stroke_opacityAttr, kAnimatedNumber},
-        {stroke_widthAttr, kAnimatedLength},
-        {text_anchorAttr, kAnimatedString},
-        {text_decorationAttr, kAnimatedString},
-        {text_renderingAttr, kAnimatedString},
-        {vector_effectAttr, kAnimatedString},
-        {visibilityAttr, kAnimatedString},
-        {word_spacingAttr, kAnimatedLength},
+        {kAlignmentBaselineAttr, kAnimatedString},
+        {kBaselineShiftAttr, kAnimatedString},
+        {kBufferedRenderingAttr, kAnimatedString},
+        {kClipPathAttr, kAnimatedString},
+        {kClipRuleAttr, kAnimatedString},
+        {svg_names::kColorAttr, kAnimatedColor},
+        {kColorInterpolationAttr, kAnimatedString},
+        {kColorInterpolationFiltersAttr, kAnimatedString},
+        {kColorRenderingAttr, kAnimatedString},
+        {kCursorAttr, kAnimatedString},
+        {kDisplayAttr, kAnimatedString},
+        {kDominantBaselineAttr, kAnimatedString},
+        {kFillAttr, kAnimatedColor},
+        {kFillOpacityAttr, kAnimatedNumber},
+        {kFillRuleAttr, kAnimatedString},
+        {kFilterAttr, kAnimatedString},
+        {kFloodColorAttr, kAnimatedColor},
+        {kFloodOpacityAttr, kAnimatedNumber},
+        {kFontFamilyAttr, kAnimatedString},
+        {kFontSizeAttr, kAnimatedLength},
+        {kFontStretchAttr, kAnimatedString},
+        {kFontStyleAttr, kAnimatedString},
+        {kFontVariantAttr, kAnimatedString},
+        {kFontWeightAttr, kAnimatedString},
+        {kImageRenderingAttr, kAnimatedString},
+        {kLetterSpacingAttr, kAnimatedLength},
+        {kLightingColorAttr, kAnimatedColor},
+        {kMarkerEndAttr, kAnimatedString},
+        {kMarkerMidAttr, kAnimatedString},
+        {kMarkerStartAttr, kAnimatedString},
+        {kMaskAttr, kAnimatedString},
+        {kMaskTypeAttr, kAnimatedString},
+        {kOpacityAttr, kAnimatedNumber},
+        {kOverflowAttr, kAnimatedString},
+        {kPaintOrderAttr, kAnimatedString},
+        {kPointerEventsAttr, kAnimatedString},
+        {kShapeRenderingAttr, kAnimatedString},
+        {kStopColorAttr, kAnimatedColor},
+        {kStopOpacityAttr, kAnimatedNumber},
+        {kStrokeAttr, kAnimatedColor},
+        {kStrokeDasharrayAttr, kAnimatedLengthList},
+        {kStrokeDashoffsetAttr, kAnimatedLength},
+        {kStrokeLinecapAttr, kAnimatedString},
+        {kStrokeLinejoinAttr, kAnimatedString},
+        {kStrokeMiterlimitAttr, kAnimatedNumber},
+        {kStrokeOpacityAttr, kAnimatedNumber},
+        {kStrokeWidthAttr, kAnimatedLength},
+        {kTextAnchorAttr, kAnimatedString},
+        {kTextDecorationAttr, kAnimatedString},
+        {kTextRenderingAttr, kAnimatedString},
+        {kVectorEffectAttr, kAnimatedString},
+        {kVisibilityAttr, kAnimatedString},
+        {kWordSpacingAttr, kAnimatedLength},
     };
     for (size_t i = 0; i < arraysize(attr_to_types); i++)
       css_property_map.Set(attr_to_types[i].attr, attr_to_types[i].prop_type);
@@ -1133,97 +1133,97 @@
   // a race when dumping debug data for a layer.
   DEFINE_THREAD_SAFE_STATIC_LOCAL(HashSet<QualifiedName>, animatable_attributes,
                                   ({
-                                      SVGNames::amplitudeAttr,
-                                      SVGNames::azimuthAttr,
-                                      SVGNames::baseFrequencyAttr,
-                                      SVGNames::biasAttr,
-                                      SVGNames::clipPathUnitsAttr,
-                                      SVGNames::cxAttr,
-                                      SVGNames::cyAttr,
-                                      SVGNames::diffuseConstantAttr,
-                                      SVGNames::divisorAttr,
-                                      SVGNames::dxAttr,
-                                      SVGNames::dyAttr,
-                                      SVGNames::edgeModeAttr,
-                                      SVGNames::elevationAttr,
-                                      SVGNames::exponentAttr,
-                                      SVGNames::filterUnitsAttr,
-                                      SVGNames::fxAttr,
-                                      SVGNames::fyAttr,
-                                      SVGNames::gradientTransformAttr,
-                                      SVGNames::gradientUnitsAttr,
-                                      SVGNames::heightAttr,
-                                      SVGNames::hrefAttr,
-                                      SVGNames::in2Attr,
-                                      SVGNames::inAttr,
-                                      SVGNames::interceptAttr,
-                                      SVGNames::k1Attr,
-                                      SVGNames::k2Attr,
-                                      SVGNames::k3Attr,
-                                      SVGNames::k4Attr,
-                                      SVGNames::kernelMatrixAttr,
-                                      SVGNames::kernelUnitLengthAttr,
-                                      SVGNames::lengthAdjustAttr,
-                                      SVGNames::limitingConeAngleAttr,
-                                      SVGNames::markerHeightAttr,
-                                      SVGNames::markerUnitsAttr,
-                                      SVGNames::markerWidthAttr,
-                                      SVGNames::maskContentUnitsAttr,
-                                      SVGNames::maskUnitsAttr,
-                                      SVGNames::methodAttr,
-                                      SVGNames::modeAttr,
-                                      SVGNames::numOctavesAttr,
-                                      SVGNames::offsetAttr,
-                                      SVGNames::operatorAttr,
-                                      SVGNames::orderAttr,
-                                      SVGNames::orientAttr,
-                                      SVGNames::pathLengthAttr,
-                                      SVGNames::patternContentUnitsAttr,
-                                      SVGNames::patternTransformAttr,
-                                      SVGNames::patternUnitsAttr,
-                                      SVGNames::pointsAtXAttr,
-                                      SVGNames::pointsAtYAttr,
-                                      SVGNames::pointsAtZAttr,
-                                      SVGNames::preserveAlphaAttr,
-                                      SVGNames::preserveAspectRatioAttr,
-                                      SVGNames::primitiveUnitsAttr,
-                                      SVGNames::radiusAttr,
-                                      SVGNames::rAttr,
-                                      SVGNames::refXAttr,
-                                      SVGNames::refYAttr,
-                                      SVGNames::resultAttr,
-                                      SVGNames::rotateAttr,
-                                      SVGNames::rxAttr,
-                                      SVGNames::ryAttr,
-                                      SVGNames::scaleAttr,
-                                      SVGNames::seedAttr,
-                                      SVGNames::slopeAttr,
-                                      SVGNames::spacingAttr,
-                                      SVGNames::specularConstantAttr,
-                                      SVGNames::specularExponentAttr,
-                                      SVGNames::spreadMethodAttr,
-                                      SVGNames::startOffsetAttr,
-                                      SVGNames::stdDeviationAttr,
-                                      SVGNames::stitchTilesAttr,
-                                      SVGNames::surfaceScaleAttr,
-                                      SVGNames::tableValuesAttr,
-                                      SVGNames::targetAttr,
-                                      SVGNames::targetXAttr,
-                                      SVGNames::targetYAttr,
-                                      SVGNames::transformAttr,
-                                      SVGNames::typeAttr,
-                                      SVGNames::valuesAttr,
-                                      SVGNames::viewBoxAttr,
-                                      SVGNames::widthAttr,
-                                      SVGNames::x1Attr,
-                                      SVGNames::x2Attr,
-                                      SVGNames::xAttr,
-                                      SVGNames::xChannelSelectorAttr,
-                                      SVGNames::y1Attr,
-                                      SVGNames::y2Attr,
-                                      SVGNames::yAttr,
-                                      SVGNames::yChannelSelectorAttr,
-                                      SVGNames::zAttr,
+                                      svg_names::kAmplitudeAttr,
+                                      svg_names::kAzimuthAttr,
+                                      svg_names::kBaseFrequencyAttr,
+                                      svg_names::kBiasAttr,
+                                      svg_names::kClipPathUnitsAttr,
+                                      svg_names::kCxAttr,
+                                      svg_names::kCyAttr,
+                                      svg_names::kDiffuseConstantAttr,
+                                      svg_names::kDivisorAttr,
+                                      svg_names::kDxAttr,
+                                      svg_names::kDyAttr,
+                                      svg_names::kEdgeModeAttr,
+                                      svg_names::kElevationAttr,
+                                      svg_names::kExponentAttr,
+                                      svg_names::kFilterUnitsAttr,
+                                      svg_names::kFxAttr,
+                                      svg_names::kFyAttr,
+                                      svg_names::kGradientTransformAttr,
+                                      svg_names::kGradientUnitsAttr,
+                                      svg_names::kHeightAttr,
+                                      svg_names::kHrefAttr,
+                                      svg_names::kIn2Attr,
+                                      svg_names::kInAttr,
+                                      svg_names::kInterceptAttr,
+                                      svg_names::kK1Attr,
+                                      svg_names::kK2Attr,
+                                      svg_names::kK3Attr,
+                                      svg_names::kK4Attr,
+                                      svg_names::kKernelMatrixAttr,
+                                      svg_names::kKernelUnitLengthAttr,
+                                      svg_names::kLengthAdjustAttr,
+                                      svg_names::kLimitingConeAngleAttr,
+                                      svg_names::kMarkerHeightAttr,
+                                      svg_names::kMarkerUnitsAttr,
+                                      svg_names::kMarkerWidthAttr,
+                                      svg_names::kMaskContentUnitsAttr,
+                                      svg_names::kMaskUnitsAttr,
+                                      svg_names::kMethodAttr,
+                                      svg_names::kModeAttr,
+                                      svg_names::kNumOctavesAttr,
+                                      svg_names::kOffsetAttr,
+                                      svg_names::kOperatorAttr,
+                                      svg_names::kOrderAttr,
+                                      svg_names::kOrientAttr,
+                                      svg_names::kPathLengthAttr,
+                                      svg_names::kPatternContentUnitsAttr,
+                                      svg_names::kPatternTransformAttr,
+                                      svg_names::kPatternUnitsAttr,
+                                      svg_names::kPointsAtXAttr,
+                                      svg_names::kPointsAtYAttr,
+                                      svg_names::kPointsAtZAttr,
+                                      svg_names::kPreserveAlphaAttr,
+                                      svg_names::kPreserveAspectRatioAttr,
+                                      svg_names::kPrimitiveUnitsAttr,
+                                      svg_names::kRadiusAttr,
+                                      svg_names::kRAttr,
+                                      svg_names::kRefXAttr,
+                                      svg_names::kRefYAttr,
+                                      svg_names::kResultAttr,
+                                      svg_names::kRotateAttr,
+                                      svg_names::kRxAttr,
+                                      svg_names::kRyAttr,
+                                      svg_names::kScaleAttr,
+                                      svg_names::kSeedAttr,
+                                      svg_names::kSlopeAttr,
+                                      svg_names::kSpacingAttr,
+                                      svg_names::kSpecularConstantAttr,
+                                      svg_names::kSpecularExponentAttr,
+                                      svg_names::kSpreadMethodAttr,
+                                      svg_names::kStartOffsetAttr,
+                                      svg_names::kStdDeviationAttr,
+                                      svg_names::kStitchTilesAttr,
+                                      svg_names::kSurfaceScaleAttr,
+                                      svg_names::kTableValuesAttr,
+                                      svg_names::kTargetAttr,
+                                      svg_names::kTargetXAttr,
+                                      svg_names::kTargetYAttr,
+                                      svg_names::kTransformAttr,
+                                      svg_names::kTypeAttr,
+                                      svg_names::kValuesAttr,
+                                      svg_names::kViewBoxAttr,
+                                      svg_names::kWidthAttr,
+                                      svg_names::kX1Attr,
+                                      svg_names::kX2Attr,
+                                      svg_names::kXAttr,
+                                      svg_names::kXChannelSelectorAttr,
+                                      svg_names::kY1Attr,
+                                      svg_names::kY2Attr,
+                                      svg_names::kYAttr,
+                                      svg_names::kYChannelSelectorAttr,
+                                      svg_names::kZAttr,
                                   }));
 
   if (name == classAttr)
@@ -1270,7 +1270,7 @@
     // Before rebuilding |sourceElement| ensure it was not removed from under
     // us.
     if (incoming_references.Contains(source_element))
-      source_element->SvgAttributeChanged(SVGNames::hrefAttr);
+      source_element->SvgAttributeChanged(svg_names::kHrefAttr);
   }
 }
 
diff --git a/third_party/blink/renderer/core/svg/svg_ellipse_element.cc b/third_party/blink/renderer/core/svg/svg_ellipse_element.cc
index a20bdbcc..8815419a 100644
--- a/third_party/blink/renderer/core/svg/svg_ellipse_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_ellipse_element.cc
@@ -26,24 +26,24 @@
 namespace blink {
 
 inline SVGEllipseElement::SVGEllipseElement(Document& document)
-    : SVGGeometryElement(SVGNames::ellipseTag, document),
+    : SVGGeometryElement(svg_names::kEllipseTag, document),
       cx_(SVGAnimatedLength::Create(this,
-                                    SVGNames::cxAttr,
+                                    svg_names::kCxAttr,
                                     SVGLengthMode::kWidth,
                                     SVGLength::Initial::kUnitlessZero,
                                     CSSPropertyCx)),
       cy_(SVGAnimatedLength::Create(this,
-                                    SVGNames::cyAttr,
+                                    svg_names::kCyAttr,
                                     SVGLengthMode::kHeight,
                                     SVGLength::Initial::kUnitlessZero,
                                     CSSPropertyCy)),
       rx_(SVGAnimatedLength::Create(this,
-                                    SVGNames::rxAttr,
+                                    svg_names::kRxAttr,
                                     SVGLengthMode::kWidth,
                                     SVGLength::Initial::kUnitlessZero,
                                     CSSPropertyRx)),
       ry_(SVGAnimatedLength::Create(this,
-                                    SVGNames::ryAttr,
+                                    svg_names::kRyAttr,
                                     SVGLengthMode::kHeight,
                                     SVGLength::Initial::kUnitlessZero,
                                     CSSPropertyRy)) {
@@ -111,8 +111,8 @@
 }
 
 void SVGEllipseElement::SvgAttributeChanged(const QualifiedName& attr_name) {
-  if (attr_name == SVGNames::cxAttr || attr_name == SVGNames::cyAttr ||
-      attr_name == SVGNames::rxAttr || attr_name == SVGNames::ryAttr) {
+  if (attr_name == svg_names::kCxAttr || attr_name == svg_names::kCyAttr ||
+      attr_name == svg_names::kRxAttr || attr_name == svg_names::kRyAttr) {
     UpdateRelativeLengthsInformation();
     GeometryPresentationAttributeChanged(attr_name);
     return;
diff --git a/third_party/blink/renderer/core/svg/svg_fe_blend_element.cc b/third_party/blink/renderer/core/svg/svg_fe_blend_element.cc
index 3f12323..468a7bc 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_blend_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_blend_element.cc
@@ -97,12 +97,12 @@
 }
 
 inline SVGFEBlendElement::SVGFEBlendElement(Document& document)
-    : SVGFilterPrimitiveStandardAttributes(SVGNames::feBlendTag, document),
-      in1_(SVGAnimatedString::Create(this, SVGNames::inAttr)),
-      in2_(SVGAnimatedString::Create(this, SVGNames::in2Attr)),
+    : SVGFilterPrimitiveStandardAttributes(svg_names::kFEBlendTag, document),
+      in1_(SVGAnimatedString::Create(this, svg_names::kInAttr)),
+      in2_(SVGAnimatedString::Create(this, svg_names::kIn2Attr)),
       mode_(SVGAnimatedEnumeration<Mode>::Create(
           this,
-          SVGNames::modeAttr,
+          svg_names::kModeAttr,
           SVGFEBlendElement::kModeNormal)) {
   AddToPropertyMap(in1_);
   AddToPropertyMap(in2_);
@@ -122,7 +122,7 @@
     FilterEffect* effect,
     const QualifiedName& attr_name) {
   FEBlend* blend = static_cast<FEBlend*>(effect);
-  if (attr_name == SVGNames::modeAttr)
+  if (attr_name == svg_names::kModeAttr)
     return blend->SetBlendMode(ToBlendMode(mode_->CurrentValue()->EnumValue()));
 
   return SVGFilterPrimitiveStandardAttributes::SetFilterEffectAttribute(
@@ -130,13 +130,13 @@
 }
 
 void SVGFEBlendElement::SvgAttributeChanged(const QualifiedName& attr_name) {
-  if (attr_name == SVGNames::modeAttr) {
+  if (attr_name == svg_names::kModeAttr) {
     SVGElement::InvalidationGuard invalidation_guard(this);
     PrimitiveAttributeChanged(attr_name);
     return;
   }
 
-  if (attr_name == SVGNames::inAttr || attr_name == SVGNames::in2Attr) {
+  if (attr_name == svg_names::kInAttr || attr_name == svg_names::kIn2Attr) {
     SVGElement::InvalidationGuard invalidation_guard(this);
     Invalidate();
     return;
diff --git a/third_party/blink/renderer/core/svg/svg_fe_color_matrix_element.cc b/third_party/blink/renderer/core/svg/svg_fe_color_matrix_element.cc
index 1d4ec5d9..c23b63e5 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_color_matrix_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_color_matrix_element.cc
@@ -40,13 +40,13 @@
 }
 
 inline SVGFEColorMatrixElement::SVGFEColorMatrixElement(Document& document)
-    : SVGFilterPrimitiveStandardAttributes(SVGNames::feColorMatrixTag,
+    : SVGFilterPrimitiveStandardAttributes(svg_names::kFEColorMatrixTag,
                                            document),
-      values_(SVGAnimatedNumberList::Create(this, SVGNames::valuesAttr)),
-      in1_(SVGAnimatedString::Create(this, SVGNames::inAttr)),
+      values_(SVGAnimatedNumberList::Create(this, svg_names::kValuesAttr)),
+      in1_(SVGAnimatedString::Create(this, svg_names::kInAttr)),
       type_(SVGAnimatedEnumeration<ColorMatrixType>::Create(
           this,
-          SVGNames::typeAttr,
+          svg_names::kTypeAttr,
           FECOLORMATRIX_TYPE_MATRIX)) {
   AddToPropertyMap(values_);
   AddToPropertyMap(in1_);
@@ -66,9 +66,9 @@
     FilterEffect* effect,
     const QualifiedName& attr_name) {
   FEColorMatrix* color_matrix = static_cast<FEColorMatrix*>(effect);
-  if (attr_name == SVGNames::typeAttr)
+  if (attr_name == svg_names::kTypeAttr)
     return color_matrix->SetType(type_->CurrentValue()->EnumValue());
-  if (attr_name == SVGNames::valuesAttr)
+  if (attr_name == svg_names::kValuesAttr)
     return color_matrix->SetValues(values_->CurrentValue()->ToFloatVector());
 
   return SVGFilterPrimitiveStandardAttributes::SetFilterEffectAttribute(
@@ -77,13 +77,14 @@
 
 void SVGFEColorMatrixElement::SvgAttributeChanged(
     const QualifiedName& attr_name) {
-  if (attr_name == SVGNames::typeAttr || attr_name == SVGNames::valuesAttr) {
+  if (attr_name == svg_names::kTypeAttr ||
+      attr_name == svg_names::kValuesAttr) {
     SVGElement::InvalidationGuard invalidation_guard(this);
     PrimitiveAttributeChanged(attr_name);
     return;
   }
 
-  if (attr_name == SVGNames::inAttr) {
+  if (attr_name == svg_names::kInAttr) {
     SVGElement::InvalidationGuard invalidation_guard(this);
     Invalidate();
     return;
diff --git a/third_party/blink/renderer/core/svg/svg_fe_component_transfer_element.cc b/third_party/blink/renderer/core/svg/svg_fe_component_transfer_element.cc
index 75664208..6255f1e 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_component_transfer_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_component_transfer_element.cc
@@ -33,9 +33,9 @@
 
 inline SVGFEComponentTransferElement::SVGFEComponentTransferElement(
     Document& document)
-    : SVGFilterPrimitiveStandardAttributes(SVGNames::feComponentTransferTag,
+    : SVGFilterPrimitiveStandardAttributes(svg_names::kFEComponentTransferTag,
                                            document),
-      in1_(SVGAnimatedString::Create(this, SVGNames::inAttr)) {
+      in1_(SVGAnimatedString::Create(this, svg_names::kInAttr)) {
   AddToPropertyMap(in1_);
 }
 
@@ -48,7 +48,7 @@
 
 void SVGFEComponentTransferElement::SvgAttributeChanged(
     const QualifiedName& attr_name) {
-  if (attr_name == SVGNames::inAttr) {
+  if (attr_name == svg_names::kInAttr) {
     SVGElement::InvalidationGuard invalidation_guard(this);
     Invalidate();
     return;
diff --git a/third_party/blink/renderer/core/svg/svg_fe_composite_element.cc b/third_party/blink/renderer/core/svg/svg_fe_composite_element.cc
index a86fdd0e..2db5c2e 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_composite_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_composite_element.cc
@@ -48,16 +48,17 @@
 }
 
 inline SVGFECompositeElement::SVGFECompositeElement(Document& document)
-    : SVGFilterPrimitiveStandardAttributes(SVGNames::feCompositeTag, document),
-      k1_(SVGAnimatedNumber::Create(this, SVGNames::k1Attr, 0.0f)),
-      k2_(SVGAnimatedNumber::Create(this, SVGNames::k2Attr, 0.0f)),
-      k3_(SVGAnimatedNumber::Create(this, SVGNames::k3Attr, 0.0f)),
-      k4_(SVGAnimatedNumber::Create(this, SVGNames::k4Attr, 0.0f)),
-      in1_(SVGAnimatedString::Create(this, SVGNames::inAttr)),
-      in2_(SVGAnimatedString::Create(this, SVGNames::in2Attr)),
+    : SVGFilterPrimitiveStandardAttributes(svg_names::kFECompositeTag,
+                                           document),
+      k1_(SVGAnimatedNumber::Create(this, svg_names::kK1Attr, 0.0f)),
+      k2_(SVGAnimatedNumber::Create(this, svg_names::kK2Attr, 0.0f)),
+      k3_(SVGAnimatedNumber::Create(this, svg_names::kK3Attr, 0.0f)),
+      k4_(SVGAnimatedNumber::Create(this, svg_names::kK4Attr, 0.0f)),
+      in1_(SVGAnimatedString::Create(this, svg_names::kInAttr)),
+      in2_(SVGAnimatedString::Create(this, svg_names::kIn2Attr)),
       svg_operator_(SVGAnimatedEnumeration<CompositeOperationType>::Create(
           this,
-          SVGNames::operatorAttr,
+          svg_names::kOperatorAttr,
           FECOMPOSITE_OPERATOR_OVER)) {
   AddToPropertyMap(k1_);
   AddToPropertyMap(k2_);
@@ -85,15 +86,15 @@
     FilterEffect* effect,
     const QualifiedName& attr_name) {
   FEComposite* composite = static_cast<FEComposite*>(effect);
-  if (attr_name == SVGNames::operatorAttr)
+  if (attr_name == svg_names::kOperatorAttr)
     return composite->SetOperation(svg_operator_->CurrentValue()->EnumValue());
-  if (attr_name == SVGNames::k1Attr)
+  if (attr_name == svg_names::kK1Attr)
     return composite->SetK1(k1_->CurrentValue()->Value());
-  if (attr_name == SVGNames::k2Attr)
+  if (attr_name == svg_names::kK2Attr)
     return composite->SetK2(k2_->CurrentValue()->Value());
-  if (attr_name == SVGNames::k3Attr)
+  if (attr_name == svg_names::kK3Attr)
     return composite->SetK3(k3_->CurrentValue()->Value());
-  if (attr_name == SVGNames::k4Attr)
+  if (attr_name == svg_names::kK4Attr)
     return composite->SetK4(k4_->CurrentValue()->Value());
 
   return SVGFilterPrimitiveStandardAttributes::SetFilterEffectAttribute(
@@ -102,15 +103,15 @@
 
 void SVGFECompositeElement::SvgAttributeChanged(
     const QualifiedName& attr_name) {
-  if (attr_name == SVGNames::operatorAttr || attr_name == SVGNames::k1Attr ||
-      attr_name == SVGNames::k2Attr || attr_name == SVGNames::k3Attr ||
-      attr_name == SVGNames::k4Attr) {
+  if (attr_name == svg_names::kOperatorAttr ||
+      attr_name == svg_names::kK1Attr || attr_name == svg_names::kK2Attr ||
+      attr_name == svg_names::kK3Attr || attr_name == svg_names::kK4Attr) {
     SVGElement::InvalidationGuard invalidation_guard(this);
     PrimitiveAttributeChanged(attr_name);
     return;
   }
 
-  if (attr_name == SVGNames::inAttr || attr_name == SVGNames::in2Attr) {
+  if (attr_name == svg_names::kInAttr || attr_name == svg_names::kIn2Attr) {
     SVGElement::InvalidationGuard invalidation_guard(this);
     Invalidate();
     return;
diff --git a/third_party/blink/renderer/core/svg/svg_fe_convolve_matrix_element.cc b/third_party/blink/renderer/core/svg/svg_fe_convolve_matrix_element.cc
index 78cda0df..2dad749 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_convolve_matrix_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_convolve_matrix_element.cc
@@ -49,7 +49,7 @@
  protected:
   SVGAnimatedOrder(SVGElement* context_element)
       : SVGAnimatedIntegerOptionalInteger(context_element,
-                                          SVGNames::orderAttr,
+                                          svg_names::kOrderAttr,
                                           3) {}
 
   static SVGParsingError CheckValue(SVGParsingError parse_status, int value) {
@@ -75,26 +75,26 @@
 
 inline SVGFEConvolveMatrixElement::SVGFEConvolveMatrixElement(
     Document& document)
-    : SVGFilterPrimitiveStandardAttributes(SVGNames::feConvolveMatrixTag,
+    : SVGFilterPrimitiveStandardAttributes(svg_names::kFEConvolveMatrixTag,
                                            document),
-      bias_(SVGAnimatedNumber::Create(this, SVGNames::biasAttr, 0.0f)),
-      divisor_(SVGAnimatedNumber::Create(this, SVGNames::divisorAttr, 1)),
-      in1_(SVGAnimatedString::Create(this, SVGNames::inAttr)),
+      bias_(SVGAnimatedNumber::Create(this, svg_names::kBiasAttr, 0.0f)),
+      divisor_(SVGAnimatedNumber::Create(this, svg_names::kDivisorAttr, 1)),
+      in1_(SVGAnimatedString::Create(this, svg_names::kInAttr)),
       edge_mode_(
           SVGAnimatedEnumeration<EdgeModeType>::Create(this,
-                                                       SVGNames::edgeModeAttr,
+                                                       svg_names::kEdgeModeAttr,
                                                        EDGEMODE_DUPLICATE)),
       kernel_matrix_(
-          SVGAnimatedNumberList::Create(this, SVGNames::kernelMatrixAttr)),
+          SVGAnimatedNumberList::Create(this, svg_names::kKernelMatrixAttr)),
       kernel_unit_length_(SVGAnimatedNumberOptionalNumber::Create(
           this,
-          SVGNames::kernelUnitLengthAttr,
+          svg_names::kKernelUnitLengthAttr,
           0.0f)),
       order_(SVGAnimatedOrder::Create(this)),
       preserve_alpha_(
-          SVGAnimatedBoolean::Create(this, SVGNames::preserveAlphaAttr)),
-      target_x_(SVGAnimatedInteger::Create(this, SVGNames::targetXAttr, 0)),
-      target_y_(SVGAnimatedInteger::Create(this, SVGNames::targetYAttr, 0)) {
+          SVGAnimatedBoolean::Create(this, svg_names::kPreserveAlphaAttr)),
+      target_x_(SVGAnimatedInteger::Create(this, svg_names::kTargetXAttr, 0)),
+      target_y_(SVGAnimatedInteger::Create(this, svg_names::kTargetYAttr, 0)) {
   AddToPropertyMap(preserve_alpha_);
   AddToPropertyMap(divisor_);
   AddToPropertyMap(bias_);
@@ -158,16 +158,17 @@
     FilterEffect* effect,
     const QualifiedName& attr_name) {
   FEConvolveMatrix* convolve_matrix = static_cast<FEConvolveMatrix*>(effect);
-  if (attr_name == SVGNames::edgeModeAttr)
+  if (attr_name == svg_names::kEdgeModeAttr)
     return convolve_matrix->SetEdgeMode(
         edge_mode_->CurrentValue()->EnumValue());
-  if (attr_name == SVGNames::divisorAttr)
+  if (attr_name == svg_names::kDivisorAttr)
     return convolve_matrix->SetDivisor(ComputeDivisor());
-  if (attr_name == SVGNames::biasAttr)
+  if (attr_name == svg_names::kBiasAttr)
     return convolve_matrix->SetBias(bias_->CurrentValue()->Value());
-  if (attr_name == SVGNames::targetXAttr || attr_name == SVGNames::targetYAttr)
+  if (attr_name == svg_names::kTargetXAttr ||
+      attr_name == svg_names::kTargetYAttr)
     return convolve_matrix->SetTargetOffset(TargetPoint());
-  if (attr_name == SVGNames::preserveAlphaAttr)
+  if (attr_name == svg_names::kPreserveAlphaAttr)
     return convolve_matrix->SetPreserveAlpha(
         preserve_alpha_->CurrentValue()->Value());
   return SVGFilterPrimitiveStandardAttributes::SetFilterEffectAttribute(
@@ -176,18 +177,19 @@
 
 void SVGFEConvolveMatrixElement::SvgAttributeChanged(
     const QualifiedName& attr_name) {
-  if (attr_name == SVGNames::edgeModeAttr ||
-      attr_name == SVGNames::divisorAttr || attr_name == SVGNames::biasAttr ||
-      attr_name == SVGNames::targetXAttr ||
-      attr_name == SVGNames::targetYAttr ||
-      attr_name == SVGNames::preserveAlphaAttr) {
+  if (attr_name == svg_names::kEdgeModeAttr ||
+      attr_name == svg_names::kDivisorAttr ||
+      attr_name == svg_names::kBiasAttr ||
+      attr_name == svg_names::kTargetXAttr ||
+      attr_name == svg_names::kTargetYAttr ||
+      attr_name == svg_names::kPreserveAlphaAttr) {
     SVGElement::InvalidationGuard invalidation_guard(this);
     PrimitiveAttributeChanged(attr_name);
     return;
   }
 
-  if (attr_name == SVGNames::inAttr || attr_name == SVGNames::orderAttr ||
-      attr_name == SVGNames::kernelMatrixAttr) {
+  if (attr_name == svg_names::kInAttr || attr_name == svg_names::kOrderAttr ||
+      attr_name == svg_names::kKernelMatrixAttr) {
     SVGElement::InvalidationGuard invalidation_guard(this);
     Invalidate();
     return;
diff --git a/third_party/blink/renderer/core/svg/svg_fe_diffuse_lighting_element.cc b/third_party/blink/renderer/core/svg/svg_fe_diffuse_lighting_element.cc
index 737f6524..ab43b2a0 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_diffuse_lighting_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_diffuse_lighting_element.cc
@@ -29,17 +29,17 @@
 
 inline SVGFEDiffuseLightingElement::SVGFEDiffuseLightingElement(
     Document& document)
-    : SVGFilterPrimitiveStandardAttributes(SVGNames::feDiffuseLightingTag,
+    : SVGFilterPrimitiveStandardAttributes(svg_names::kFEDiffuseLightingTag,
                                            document),
       diffuse_constant_(
-          SVGAnimatedNumber::Create(this, SVGNames::diffuseConstantAttr, 1)),
+          SVGAnimatedNumber::Create(this, svg_names::kDiffuseConstantAttr, 1)),
       surface_scale_(
-          SVGAnimatedNumber::Create(this, SVGNames::surfaceScaleAttr, 1)),
+          SVGAnimatedNumber::Create(this, svg_names::kSurfaceScaleAttr, 1)),
       kernel_unit_length_(SVGAnimatedNumberOptionalNumber::Create(
           this,
-          SVGNames::kernelUnitLengthAttr,
+          svg_names::kKernelUnitLengthAttr,
           0.0f)),
-      in1_(SVGAnimatedString::Create(this, SVGNames::inAttr)) {
+      in1_(SVGAnimatedString::Create(this, svg_names::kInAttr)) {
   AddToPropertyMap(diffuse_constant_);
   AddToPropertyMap(surface_scale_);
   AddToPropertyMap(kernel_unit_length_);
@@ -61,15 +61,15 @@
     const QualifiedName& attr_name) {
   FEDiffuseLighting* diffuse_lighting = static_cast<FEDiffuseLighting*>(effect);
 
-  if (attr_name == SVGNames::lighting_colorAttr) {
+  if (attr_name == svg_names::kLightingColorAttr) {
     const ComputedStyle& style = ComputedStyleRef();
     return diffuse_lighting->SetLightingColor(
         style.VisitedDependentColor(GetCSSPropertyLightingColor()));
   }
-  if (attr_name == SVGNames::surfaceScaleAttr)
+  if (attr_name == svg_names::kSurfaceScaleAttr)
     return diffuse_lighting->SetSurfaceScale(
         surface_scale_->CurrentValue()->Value());
-  if (attr_name == SVGNames::diffuseConstantAttr)
+  if (attr_name == svg_names::kDiffuseConstantAttr)
     return diffuse_lighting->SetDiffuseConstant(
         diffuse_constant_->CurrentValue()->Value());
 
@@ -81,25 +81,25 @@
   DCHECK(light_element);
   DCHECK(effect->GetFilter());
 
-  if (attr_name == SVGNames::azimuthAttr)
+  if (attr_name == svg_names::kAzimuthAttr)
     return light_source->SetAzimuth(
         light_element->azimuth()->CurrentValue()->Value());
-  if (attr_name == SVGNames::elevationAttr)
+  if (attr_name == svg_names::kElevationAttr)
     return light_source->SetElevation(
         light_element->elevation()->CurrentValue()->Value());
-  if (attr_name == SVGNames::xAttr || attr_name == SVGNames::yAttr ||
-      attr_name == SVGNames::zAttr)
+  if (attr_name == svg_names::kXAttr || attr_name == svg_names::kYAttr ||
+      attr_name == svg_names::kZAttr)
     return light_source->SetPosition(
         effect->GetFilter()->Resolve3dPoint(light_element->GetPosition()));
-  if (attr_name == SVGNames::pointsAtXAttr ||
-      attr_name == SVGNames::pointsAtYAttr ||
-      attr_name == SVGNames::pointsAtZAttr)
+  if (attr_name == svg_names::kPointsAtXAttr ||
+      attr_name == svg_names::kPointsAtYAttr ||
+      attr_name == svg_names::kPointsAtZAttr)
     return light_source->SetPointsAt(
         effect->GetFilter()->Resolve3dPoint(light_element->PointsAt()));
-  if (attr_name == SVGNames::specularExponentAttr)
+  if (attr_name == svg_names::kSpecularExponentAttr)
     return light_source->SetSpecularExponent(
         light_element->specularExponent()->CurrentValue()->Value());
-  if (attr_name == SVGNames::limitingConeAngleAttr)
+  if (attr_name == svg_names::kLimitingConeAngleAttr)
     return light_source->SetLimitingConeAngle(
         light_element->limitingConeAngle()->CurrentValue()->Value());
 
@@ -109,15 +109,15 @@
 
 void SVGFEDiffuseLightingElement::SvgAttributeChanged(
     const QualifiedName& attr_name) {
-  if (attr_name == SVGNames::surfaceScaleAttr ||
-      attr_name == SVGNames::diffuseConstantAttr ||
-      attr_name == SVGNames::lighting_colorAttr) {
+  if (attr_name == svg_names::kSurfaceScaleAttr ||
+      attr_name == svg_names::kDiffuseConstantAttr ||
+      attr_name == svg_names::kLightingColorAttr) {
     SVGElement::InvalidationGuard invalidation_guard(this);
     PrimitiveAttributeChanged(attr_name);
     return;
   }
 
-  if (attr_name == SVGNames::inAttr) {
+  if (attr_name == svg_names::kInAttr) {
     SVGElement::InvalidationGuard invalidation_guard(this);
     Invalidate();
     return;
diff --git a/third_party/blink/renderer/core/svg/svg_fe_displacement_map_element.cc b/third_party/blink/renderer/core/svg/svg_fe_displacement_map_element.cc
index 653f37e20..39c0ef8c 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_displacement_map_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_displacement_map_element.cc
@@ -39,18 +39,18 @@
 
 inline SVGFEDisplacementMapElement::SVGFEDisplacementMapElement(
     Document& document)
-    : SVGFilterPrimitiveStandardAttributes(SVGNames::feDisplacementMapTag,
+    : SVGFilterPrimitiveStandardAttributes(svg_names::kFEDisplacementMapTag,
                                            document),
-      scale_(SVGAnimatedNumber::Create(this, SVGNames::scaleAttr, 0.0f)),
-      in1_(SVGAnimatedString::Create(this, SVGNames::inAttr)),
-      in2_(SVGAnimatedString::Create(this, SVGNames::in2Attr)),
+      scale_(SVGAnimatedNumber::Create(this, svg_names::kScaleAttr, 0.0f)),
+      in1_(SVGAnimatedString::Create(this, svg_names::kInAttr)),
+      in2_(SVGAnimatedString::Create(this, svg_names::kIn2Attr)),
       x_channel_selector_(SVGAnimatedEnumeration<ChannelSelectorType>::Create(
           this,
-          SVGNames::xChannelSelectorAttr,
+          svg_names::kXChannelSelectorAttr,
           CHANNEL_A)),
       y_channel_selector_(SVGAnimatedEnumeration<ChannelSelectorType>::Create(
           this,
-          SVGNames::yChannelSelectorAttr,
+          svg_names::kYChannelSelectorAttr,
           CHANNEL_A)) {
   AddToPropertyMap(scale_);
   AddToPropertyMap(in1_);
@@ -74,13 +74,13 @@
     FilterEffect* effect,
     const QualifiedName& attr_name) {
   FEDisplacementMap* displacement_map = static_cast<FEDisplacementMap*>(effect);
-  if (attr_name == SVGNames::xChannelSelectorAttr)
+  if (attr_name == svg_names::kXChannelSelectorAttr)
     return displacement_map->SetXChannelSelector(
         x_channel_selector_->CurrentValue()->EnumValue());
-  if (attr_name == SVGNames::yChannelSelectorAttr)
+  if (attr_name == svg_names::kYChannelSelectorAttr)
     return displacement_map->SetYChannelSelector(
         y_channel_selector_->CurrentValue()->EnumValue());
-  if (attr_name == SVGNames::scaleAttr)
+  if (attr_name == svg_names::kScaleAttr)
     return displacement_map->SetScale(scale_->CurrentValue()->Value());
 
   return SVGFilterPrimitiveStandardAttributes::SetFilterEffectAttribute(
@@ -89,15 +89,15 @@
 
 void SVGFEDisplacementMapElement::SvgAttributeChanged(
     const QualifiedName& attr_name) {
-  if (attr_name == SVGNames::xChannelSelectorAttr ||
-      attr_name == SVGNames::yChannelSelectorAttr ||
-      attr_name == SVGNames::scaleAttr) {
+  if (attr_name == svg_names::kXChannelSelectorAttr ||
+      attr_name == svg_names::kYChannelSelectorAttr ||
+      attr_name == svg_names::kScaleAttr) {
     SVGElement::InvalidationGuard invalidation_guard(this);
     PrimitiveAttributeChanged(attr_name);
     return;
   }
 
-  if (attr_name == SVGNames::inAttr || attr_name == SVGNames::in2Attr) {
+  if (attr_name == svg_names::kInAttr || attr_name == svg_names::kIn2Attr) {
     SVGElement::InvalidationGuard invalidation_guard(this);
     Invalidate();
     return;
diff --git a/third_party/blink/renderer/core/svg/svg_fe_distant_light_element.cc b/third_party/blink/renderer/core/svg/svg_fe_distant_light_element.cc
index 99645e2..f6b135f 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_distant_light_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_distant_light_element.cc
@@ -25,7 +25,7 @@
 namespace blink {
 
 inline SVGFEDistantLightElement::SVGFEDistantLightElement(Document& document)
-    : SVGFELightElement(SVGNames::feDistantLightTag, document) {}
+    : SVGFELightElement(svg_names::kFEDistantLightTag, document) {}
 
 DEFINE_NODE_FACTORY(SVGFEDistantLightElement)
 
diff --git a/third_party/blink/renderer/core/svg/svg_fe_drop_shadow_element.cc b/third_party/blink/renderer/core/svg/svg_fe_drop_shadow_element.cc
index 64656de..561173cc 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_drop_shadow_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_drop_shadow_element.cc
@@ -29,14 +29,15 @@
 namespace blink {
 
 inline SVGFEDropShadowElement::SVGFEDropShadowElement(Document& document)
-    : SVGFilterPrimitiveStandardAttributes(SVGNames::feDropShadowTag, document),
-      dx_(SVGAnimatedNumber::Create(this, SVGNames::dxAttr, 2)),
-      dy_(SVGAnimatedNumber::Create(this, SVGNames::dyAttr, 2)),
+    : SVGFilterPrimitiveStandardAttributes(svg_names::kFEDropShadowTag,
+                                           document),
+      dx_(SVGAnimatedNumber::Create(this, svg_names::kDxAttr, 2)),
+      dy_(SVGAnimatedNumber::Create(this, svg_names::kDyAttr, 2)),
       std_deviation_(
           SVGAnimatedNumberOptionalNumber::Create(this,
-                                                  SVGNames::stdDeviationAttr,
+                                                  svg_names::kStdDeviationAttr,
                                                   2)),
-      in1_(SVGAnimatedString::Create(this, SVGNames::inAttr)) {
+      in1_(SVGAnimatedString::Create(this, svg_names::kInAttr)) {
   AddToPropertyMap(dx_);
   AddToPropertyMap(dy_);
   AddToPropertyMap(std_deviation_);
@@ -65,12 +66,12 @@
   const ComputedStyle& style = ComputedStyleRef();
 
   FEDropShadow* drop_shadow = static_cast<FEDropShadow*>(effect);
-  if (attr_name == SVGNames::flood_colorAttr) {
+  if (attr_name == svg_names::kFloodColorAttr) {
     drop_shadow->SetShadowColor(
         style.VisitedDependentColor(GetCSSPropertyFloodColor()));
     return true;
   }
-  if (attr_name == SVGNames::flood_opacityAttr) {
+  if (attr_name == svg_names::kFloodOpacityAttr) {
     drop_shadow->SetShadowOpacity(style.SvgStyle().FloodOpacity());
     return true;
   }
@@ -80,9 +81,9 @@
 
 void SVGFEDropShadowElement::SvgAttributeChanged(
     const QualifiedName& attr_name) {
-  if (attr_name == SVGNames::inAttr ||
-      attr_name == SVGNames::stdDeviationAttr ||
-      attr_name == SVGNames::dxAttr || attr_name == SVGNames::dyAttr) {
+  if (attr_name == svg_names::kInAttr ||
+      attr_name == svg_names::kStdDeviationAttr ||
+      attr_name == svg_names::kDxAttr || attr_name == svg_names::kDyAttr) {
     SVGElement::InvalidationGuard invalidation_guard(this);
     Invalidate();
     return;
diff --git a/third_party/blink/renderer/core/svg/svg_fe_flood_element.cc b/third_party/blink/renderer/core/svg/svg_fe_flood_element.cc
index 318b3f4..3b43613 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_flood_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_flood_element.cc
@@ -29,7 +29,7 @@
 namespace blink {
 
 inline SVGFEFloodElement::SVGFEFloodElement(Document& document)
-    : SVGFilterPrimitiveStandardAttributes(SVGNames::feFloodTag, document) {}
+    : SVGFilterPrimitiveStandardAttributes(svg_names::kFEFloodTag, document) {}
 
 DEFINE_NODE_FACTORY(SVGFEFloodElement)
 
@@ -39,11 +39,11 @@
   const ComputedStyle& style = ComputedStyleRef();
 
   FEFlood* flood = static_cast<FEFlood*>(effect);
-  if (attr_name == SVGNames::flood_colorAttr) {
+  if (attr_name == svg_names::kFloodColorAttr) {
     return flood->SetFloodColor(
         style.VisitedDependentColor(GetCSSPropertyFloodColor()));
   }
-  if (attr_name == SVGNames::flood_opacityAttr)
+  if (attr_name == svg_names::kFloodOpacityAttr)
     return flood->SetFloodOpacity(style.SvgStyle().FloodOpacity());
 
   return SVGFilterPrimitiveStandardAttributes::SetFilterEffectAttribute(
diff --git a/third_party/blink/renderer/core/svg/svg_fe_func_a_element.cc b/third_party/blink/renderer/core/svg/svg_fe_func_a_element.cc
index b725ce5c..c7b40ee 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_func_a_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_func_a_element.cc
@@ -23,7 +23,7 @@
 namespace blink {
 
 inline SVGFEFuncAElement::SVGFEFuncAElement(Document& document)
-    : SVGComponentTransferFunctionElement(SVGNames::feFuncATag, document) {}
+    : SVGComponentTransferFunctionElement(svg_names::kFEFuncATag, document) {}
 
 DEFINE_NODE_FACTORY(SVGFEFuncAElement)
 }
diff --git a/third_party/blink/renderer/core/svg/svg_fe_func_b_element.cc b/third_party/blink/renderer/core/svg/svg_fe_func_b_element.cc
index bcb4d9d..00f0835 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_func_b_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_func_b_element.cc
@@ -23,7 +23,7 @@
 namespace blink {
 
 inline SVGFEFuncBElement::SVGFEFuncBElement(Document& document)
-    : SVGComponentTransferFunctionElement(SVGNames::feFuncBTag, document) {}
+    : SVGComponentTransferFunctionElement(svg_names::kFEFuncBTag, document) {}
 
 DEFINE_NODE_FACTORY(SVGFEFuncBElement)
 }
diff --git a/third_party/blink/renderer/core/svg/svg_fe_func_g_element.cc b/third_party/blink/renderer/core/svg/svg_fe_func_g_element.cc
index 78bbcad47..ab64f16 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_func_g_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_func_g_element.cc
@@ -23,7 +23,7 @@
 namespace blink {
 
 inline SVGFEFuncGElement::SVGFEFuncGElement(Document& document)
-    : SVGComponentTransferFunctionElement(SVGNames::feFuncGTag, document) {}
+    : SVGComponentTransferFunctionElement(svg_names::kFEFuncGTag, document) {}
 
 DEFINE_NODE_FACTORY(SVGFEFuncGElement)
 }
diff --git a/third_party/blink/renderer/core/svg/svg_fe_func_r_element.cc b/third_party/blink/renderer/core/svg/svg_fe_func_r_element.cc
index 1f6aa0d..1b3b77b 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_func_r_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_func_r_element.cc
@@ -23,7 +23,7 @@
 namespace blink {
 
 inline SVGFEFuncRElement::SVGFEFuncRElement(Document& document)
-    : SVGComponentTransferFunctionElement(SVGNames::feFuncRTag, document) {}
+    : SVGComponentTransferFunctionElement(svg_names::kFEFuncRTag, document) {}
 
 DEFINE_NODE_FACTORY(SVGFEFuncRElement)
 }
diff --git a/third_party/blink/renderer/core/svg/svg_fe_gaussian_blur_element.cc b/third_party/blink/renderer/core/svg/svg_fe_gaussian_blur_element.cc
index 2c234c1..6bee7ec 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_gaussian_blur_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_gaussian_blur_element.cc
@@ -27,13 +27,13 @@
 namespace blink {
 
 inline SVGFEGaussianBlurElement::SVGFEGaussianBlurElement(Document& document)
-    : SVGFilterPrimitiveStandardAttributes(SVGNames::feGaussianBlurTag,
+    : SVGFilterPrimitiveStandardAttributes(svg_names::kFEGaussianBlurTag,
                                            document),
       std_deviation_(
           SVGAnimatedNumberOptionalNumber::Create(this,
-                                                  SVGNames::stdDeviationAttr,
+                                                  svg_names::kStdDeviationAttr,
                                                   0.0f)),
-      in1_(SVGAnimatedString::Create(this, SVGNames::inAttr)) {
+      in1_(SVGAnimatedString::Create(this, svg_names::kInAttr)) {
   AddToPropertyMap(std_deviation_);
   AddToPropertyMap(in1_);
 }
@@ -54,8 +54,8 @@
 
 void SVGFEGaussianBlurElement::SvgAttributeChanged(
     const QualifiedName& attr_name) {
-  if (attr_name == SVGNames::inAttr ||
-      attr_name == SVGNames::stdDeviationAttr) {
+  if (attr_name == svg_names::kInAttr ||
+      attr_name == svg_names::kStdDeviationAttr) {
     SVGElement::InvalidationGuard invalidation_guard(this);
     Invalidate();
     return;
diff --git a/third_party/blink/renderer/core/svg/svg_fe_image_element.cc b/third_party/blink/renderer/core/svg/svg_fe_image_element.cc
index 475a22e..1172134 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_image_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_image_element.cc
@@ -35,11 +35,11 @@
 namespace blink {
 
 inline SVGFEImageElement::SVGFEImageElement(Document& document)
-    : SVGFilterPrimitiveStandardAttributes(SVGNames::feImageTag, document),
+    : SVGFilterPrimitiveStandardAttributes(svg_names::kFEImageTag, document),
       SVGURIReference(this),
       preserve_aspect_ratio_(SVGAnimatedPreserveAspectRatio::Create(
           this,
-          SVGNames::preserveAspectRatioAttr)) {
+          svg_names::kPreserveAspectRatioAttr)) {
   AddToPropertyMap(preserve_aspect_ratio_);
 }
 
@@ -108,7 +108,7 @@
 }
 
 void SVGFEImageElement::SvgAttributeChanged(const QualifiedName& attr_name) {
-  if (attr_name == SVGNames::preserveAspectRatioAttr) {
+  if (attr_name == svg_names::kPreserveAspectRatioAttr) {
     SVGElement::InvalidationGuard invalidation_guard(this);
     Invalidate();
     return;
diff --git a/third_party/blink/renderer/core/svg/svg_fe_light_element.cc b/third_party/blink/renderer/core/svg/svg_fe_light_element.cc
index fc0d2d72..3c9ae10 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_light_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_light_element.cc
@@ -32,23 +32,23 @@
 SVGFELightElement::SVGFELightElement(const QualifiedName& tag_name,
                                      Document& document)
     : SVGElement(tag_name, document),
-      azimuth_(SVGAnimatedNumber::Create(this, SVGNames::azimuthAttr, 0.0f)),
+      azimuth_(SVGAnimatedNumber::Create(this, svg_names::kAzimuthAttr, 0.0f)),
       elevation_(
-          SVGAnimatedNumber::Create(this, SVGNames::elevationAttr, 0.0f)),
-      x_(SVGAnimatedNumber::Create(this, SVGNames::xAttr, 0.0f)),
-      y_(SVGAnimatedNumber::Create(this, SVGNames::yAttr, 0.0f)),
-      z_(SVGAnimatedNumber::Create(this, SVGNames::zAttr, 0.0f)),
+          SVGAnimatedNumber::Create(this, svg_names::kElevationAttr, 0.0f)),
+      x_(SVGAnimatedNumber::Create(this, svg_names::kXAttr, 0.0f)),
+      y_(SVGAnimatedNumber::Create(this, svg_names::kYAttr, 0.0f)),
+      z_(SVGAnimatedNumber::Create(this, svg_names::kZAttr, 0.0f)),
       points_at_x_(
-          SVGAnimatedNumber::Create(this, SVGNames::pointsAtXAttr, 0.0f)),
+          SVGAnimatedNumber::Create(this, svg_names::kPointsAtXAttr, 0.0f)),
       points_at_y_(
-          SVGAnimatedNumber::Create(this, SVGNames::pointsAtYAttr, 0.0f)),
+          SVGAnimatedNumber::Create(this, svg_names::kPointsAtYAttr, 0.0f)),
       points_at_z_(
-          SVGAnimatedNumber::Create(this, SVGNames::pointsAtZAttr, 0.0f)),
+          SVGAnimatedNumber::Create(this, svg_names::kPointsAtZAttr, 0.0f)),
       specular_exponent_(
-          SVGAnimatedNumber::Create(this, SVGNames::specularExponentAttr, 1)),
+          SVGAnimatedNumber::Create(this, svg_names::kSpecularExponentAttr, 1)),
       limiting_cone_angle_(
           SVGAnimatedNumber::Create(this,
-                                    SVGNames::limitingConeAngleAttr,
+                                    svg_names::kLimitingConeAngleAttr,
                                     0.0f)) {
   AddToPropertyMap(azimuth_);
   AddToPropertyMap(elevation_);
@@ -94,14 +94,15 @@
 }
 
 void SVGFELightElement::SvgAttributeChanged(const QualifiedName& attr_name) {
-  if (attr_name == SVGNames::azimuthAttr ||
-      attr_name == SVGNames::elevationAttr || attr_name == SVGNames::xAttr ||
-      attr_name == SVGNames::yAttr || attr_name == SVGNames::zAttr ||
-      attr_name == SVGNames::pointsAtXAttr ||
-      attr_name == SVGNames::pointsAtYAttr ||
-      attr_name == SVGNames::pointsAtZAttr ||
-      attr_name == SVGNames::specularExponentAttr ||
-      attr_name == SVGNames::limitingConeAngleAttr) {
+  if (attr_name == svg_names::kAzimuthAttr ||
+      attr_name == svg_names::kElevationAttr ||
+      attr_name == svg_names::kXAttr || attr_name == svg_names::kYAttr ||
+      attr_name == svg_names::kZAttr ||
+      attr_name == svg_names::kPointsAtXAttr ||
+      attr_name == svg_names::kPointsAtYAttr ||
+      attr_name == svg_names::kPointsAtZAttr ||
+      attr_name == svg_names::kSpecularExponentAttr ||
+      attr_name == svg_names::kLimitingConeAngleAttr) {
     ContainerNode* parent = parentNode();
     if (!parent)
       return;
diff --git a/third_party/blink/renderer/core/svg/svg_fe_light_element.h b/third_party/blink/renderer/core/svg/svg_fe_light_element.h
index 7ffddd7..aad4aad8 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_light_element.h
+++ b/third_party/blink/renderer/core/svg/svg_fe_light_element.h
@@ -91,9 +91,9 @@
 };
 
 inline bool IsSVGFELightElement(const SVGElement& element) {
-  return element.HasTagName(SVGNames::feDistantLightTag) ||
-         element.HasTagName(SVGNames::fePointLightTag) ||
-         element.HasTagName(SVGNames::feSpotLightTag);
+  return element.HasTagName(svg_names::kFEDistantLightTag) ||
+         element.HasTagName(svg_names::kFEPointLightTag) ||
+         element.HasTagName(svg_names::kFESpotLightTag);
 }
 
 DEFINE_SVGELEMENT_TYPE_CASTS_WITH_FUNCTION(SVGFELightElement);
diff --git a/third_party/blink/renderer/core/svg/svg_fe_merge_element.cc b/third_party/blink/renderer/core/svg/svg_fe_merge_element.cc
index c32f8ee..aa7b48e4 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_merge_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_merge_element.cc
@@ -29,7 +29,7 @@
 namespace blink {
 
 inline SVGFEMergeElement::SVGFEMergeElement(Document& document)
-    : SVGFilterPrimitiveStandardAttributes(SVGNames::feMergeTag, document) {}
+    : SVGFilterPrimitiveStandardAttributes(svg_names::kFEMergeTag, document) {}
 
 DEFINE_NODE_FACTORY(SVGFEMergeElement)
 
diff --git a/third_party/blink/renderer/core/svg/svg_fe_merge_node_element.cc b/third_party/blink/renderer/core/svg/svg_fe_merge_node_element.cc
index 7662fc4..4f8b7b38 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_merge_node_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_merge_node_element.cc
@@ -25,8 +25,8 @@
 namespace blink {
 
 inline SVGFEMergeNodeElement::SVGFEMergeNodeElement(Document& document)
-    : SVGElement(SVGNames::feMergeNodeTag, document),
-      in1_(SVGAnimatedString::Create(this, SVGNames::inAttr)) {
+    : SVGElement(svg_names::kFEMergeNodeTag, document),
+      in1_(SVGAnimatedString::Create(this, svg_names::kInAttr)) {
   AddToPropertyMap(in1_);
 }
 
@@ -39,7 +39,7 @@
 
 void SVGFEMergeNodeElement::SvgAttributeChanged(
     const QualifiedName& attr_name) {
-  if (attr_name == SVGNames::inAttr) {
+  if (attr_name == svg_names::kInAttr) {
     SVGElement::InvalidationGuard invalidation_guard(this);
     InvalidateFilterPrimitiveParent(*this);
     return;
diff --git a/third_party/blink/renderer/core/svg/svg_fe_morphology_element.cc b/third_party/blink/renderer/core/svg/svg_fe_morphology_element.cc
index f673929..12361646 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_morphology_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_morphology_element.cc
@@ -36,14 +36,15 @@
 }
 
 inline SVGFEMorphologyElement::SVGFEMorphologyElement(Document& document)
-    : SVGFilterPrimitiveStandardAttributes(SVGNames::feMorphologyTag, document),
+    : SVGFilterPrimitiveStandardAttributes(svg_names::kFEMorphologyTag,
+                                           document),
       radius_(SVGAnimatedNumberOptionalNumber::Create(this,
-                                                      SVGNames::radiusAttr,
+                                                      svg_names::kRadiusAttr,
                                                       0.0f)),
-      in1_(SVGAnimatedString::Create(this, SVGNames::inAttr)),
+      in1_(SVGAnimatedString::Create(this, svg_names::kInAttr)),
       svg_operator_(SVGAnimatedEnumeration<MorphologyOperatorType>::Create(
           this,
-          SVGNames::operatorAttr,
+          svg_names::kOperatorAttr,
           FEMORPHOLOGY_OPERATOR_ERODE)) {
   AddToPropertyMap(radius_);
   AddToPropertyMap(in1_);
@@ -63,10 +64,10 @@
     FilterEffect* effect,
     const QualifiedName& attr_name) {
   FEMorphology* morphology = static_cast<FEMorphology*>(effect);
-  if (attr_name == SVGNames::operatorAttr)
+  if (attr_name == svg_names::kOperatorAttr)
     return morphology->SetMorphologyOperator(
         svg_operator_->CurrentValue()->EnumValue());
-  if (attr_name == SVGNames::radiusAttr) {
+  if (attr_name == svg_names::kRadiusAttr) {
     // Both setRadius functions should be evaluated separately.
     bool is_radius_x_changed =
         morphology->SetRadiusX(radiusX()->CurrentValue()->Value());
@@ -80,14 +81,14 @@
 
 void SVGFEMorphologyElement::SvgAttributeChanged(
     const QualifiedName& attr_name) {
-  if (attr_name == SVGNames::operatorAttr ||
-      attr_name == SVGNames::radiusAttr) {
+  if (attr_name == svg_names::kOperatorAttr ||
+      attr_name == svg_names::kRadiusAttr) {
     SVGElement::InvalidationGuard invalidation_guard(this);
     PrimitiveAttributeChanged(attr_name);
     return;
   }
 
-  if (attr_name == SVGNames::inAttr) {
+  if (attr_name == svg_names::kInAttr) {
     SVGElement::InvalidationGuard invalidation_guard(this);
     Invalidate();
     return;
diff --git a/third_party/blink/renderer/core/svg/svg_fe_offset_element.cc b/third_party/blink/renderer/core/svg/svg_fe_offset_element.cc
index 05dd198..349fc64 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_offset_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_offset_element.cc
@@ -27,10 +27,10 @@
 namespace blink {
 
 inline SVGFEOffsetElement::SVGFEOffsetElement(Document& document)
-    : SVGFilterPrimitiveStandardAttributes(SVGNames::feOffsetTag, document),
-      dx_(SVGAnimatedNumber::Create(this, SVGNames::dxAttr, 0.0f)),
-      dy_(SVGAnimatedNumber::Create(this, SVGNames::dyAttr, 0.0f)),
-      in1_(SVGAnimatedString::Create(this, SVGNames::inAttr)) {
+    : SVGFilterPrimitiveStandardAttributes(svg_names::kFEOffsetTag, document),
+      dx_(SVGAnimatedNumber::Create(this, svg_names::kDxAttr, 0.0f)),
+      dy_(SVGAnimatedNumber::Create(this, svg_names::kDyAttr, 0.0f)),
+      in1_(SVGAnimatedString::Create(this, svg_names::kInAttr)) {
   AddToPropertyMap(dx_);
   AddToPropertyMap(dy_);
   AddToPropertyMap(in1_);
@@ -46,8 +46,8 @@
 DEFINE_NODE_FACTORY(SVGFEOffsetElement)
 
 void SVGFEOffsetElement::SvgAttributeChanged(const QualifiedName& attr_name) {
-  if (attr_name == SVGNames::inAttr || attr_name == SVGNames::dxAttr ||
-      attr_name == SVGNames::dyAttr) {
+  if (attr_name == svg_names::kInAttr || attr_name == svg_names::kDxAttr ||
+      attr_name == svg_names::kDyAttr) {
     SVGElement::InvalidationGuard invalidation_guard(this);
     Invalidate();
     return;
diff --git a/third_party/blink/renderer/core/svg/svg_fe_point_light_element.cc b/third_party/blink/renderer/core/svg/svg_fe_point_light_element.cc
index b6d7cd2..4d2d8fef 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_point_light_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_point_light_element.cc
@@ -26,7 +26,7 @@
 namespace blink {
 
 inline SVGFEPointLightElement::SVGFEPointLightElement(Document& document)
-    : SVGFELightElement(SVGNames::fePointLightTag, document) {}
+    : SVGFELightElement(svg_names::kFEPointLightTag, document) {}
 
 DEFINE_NODE_FACTORY(SVGFEPointLightElement)
 
diff --git a/third_party/blink/renderer/core/svg/svg_fe_specular_lighting_element.cc b/third_party/blink/renderer/core/svg/svg_fe_specular_lighting_element.cc
index 3f56237..f2bda029e 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_specular_lighting_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_specular_lighting_element.cc
@@ -31,19 +31,19 @@
 
 inline SVGFESpecularLightingElement::SVGFESpecularLightingElement(
     Document& document)
-    : SVGFilterPrimitiveStandardAttributes(SVGNames::feSpecularLightingTag,
+    : SVGFilterPrimitiveStandardAttributes(svg_names::kFESpecularLightingTag,
                                            document),
       specular_constant_(
-          SVGAnimatedNumber::Create(this, SVGNames::specularConstantAttr, 1)),
+          SVGAnimatedNumber::Create(this, svg_names::kSpecularConstantAttr, 1)),
       specular_exponent_(
-          SVGAnimatedNumber::Create(this, SVGNames::specularExponentAttr, 1)),
+          SVGAnimatedNumber::Create(this, svg_names::kSpecularExponentAttr, 1)),
       surface_scale_(
-          SVGAnimatedNumber::Create(this, SVGNames::surfaceScaleAttr, 1)),
+          SVGAnimatedNumber::Create(this, svg_names::kSurfaceScaleAttr, 1)),
       kernel_unit_length_(SVGAnimatedNumberOptionalNumber::Create(
           this,
-          SVGNames::kernelUnitLengthAttr,
+          svg_names::kKernelUnitLengthAttr,
           0.0f)),
-      in1_(SVGAnimatedString::Create(this, SVGNames::inAttr)) {
+      in1_(SVGAnimatedString::Create(this, svg_names::kInAttr)) {
   AddToPropertyMap(specular_constant_);
   AddToPropertyMap(specular_exponent_);
   AddToPropertyMap(surface_scale_);
@@ -68,18 +68,18 @@
   FESpecularLighting* specular_lighting =
       static_cast<FESpecularLighting*>(effect);
 
-  if (attr_name == SVGNames::lighting_colorAttr) {
+  if (attr_name == svg_names::kLightingColorAttr) {
     const ComputedStyle& style = ComputedStyleRef();
     return specular_lighting->SetLightingColor(
         style.VisitedDependentColor(GetCSSPropertyLightingColor()));
   }
-  if (attr_name == SVGNames::surfaceScaleAttr)
+  if (attr_name == svg_names::kSurfaceScaleAttr)
     return specular_lighting->SetSurfaceScale(
         surface_scale_->CurrentValue()->Value());
-  if (attr_name == SVGNames::specularConstantAttr)
+  if (attr_name == svg_names::kSpecularConstantAttr)
     return specular_lighting->SetSpecularConstant(
         specular_constant_->CurrentValue()->Value());
-  if (attr_name == SVGNames::specularExponentAttr)
+  if (attr_name == svg_names::kSpecularExponentAttr)
     return specular_lighting->SetSpecularExponent(
         specular_exponent_->CurrentValue()->Value());
 
@@ -90,25 +90,25 @@
   DCHECK(light_element);
   DCHECK(effect->GetFilter());
 
-  if (attr_name == SVGNames::azimuthAttr)
+  if (attr_name == svg_names::kAzimuthAttr)
     return light_source->SetAzimuth(
         light_element->azimuth()->CurrentValue()->Value());
-  if (attr_name == SVGNames::elevationAttr)
+  if (attr_name == svg_names::kElevationAttr)
     return light_source->SetElevation(
         light_element->elevation()->CurrentValue()->Value());
-  if (attr_name == SVGNames::xAttr || attr_name == SVGNames::yAttr ||
-      attr_name == SVGNames::zAttr)
+  if (attr_name == svg_names::kXAttr || attr_name == svg_names::kYAttr ||
+      attr_name == svg_names::kZAttr)
     return light_source->SetPosition(
         effect->GetFilter()->Resolve3dPoint(light_element->GetPosition()));
-  if (attr_name == SVGNames::pointsAtXAttr ||
-      attr_name == SVGNames::pointsAtYAttr ||
-      attr_name == SVGNames::pointsAtZAttr)
+  if (attr_name == svg_names::kPointsAtXAttr ||
+      attr_name == svg_names::kPointsAtYAttr ||
+      attr_name == svg_names::kPointsAtZAttr)
     return light_source->SetPointsAt(
         effect->GetFilter()->Resolve3dPoint(light_element->PointsAt()));
-  if (attr_name == SVGNames::specularExponentAttr)
+  if (attr_name == svg_names::kSpecularExponentAttr)
     return light_source->SetSpecularExponent(
         light_element->specularExponent()->CurrentValue()->Value());
-  if (attr_name == SVGNames::limitingConeAngleAttr)
+  if (attr_name == svg_names::kLimitingConeAngleAttr)
     return light_source->SetLimitingConeAngle(
         light_element->limitingConeAngle()->CurrentValue()->Value());
 
@@ -118,15 +118,15 @@
 
 void SVGFESpecularLightingElement::SvgAttributeChanged(
     const QualifiedName& attr_name) {
-  if (attr_name == SVGNames::surfaceScaleAttr ||
-      attr_name == SVGNames::specularConstantAttr ||
-      attr_name == SVGNames::specularExponentAttr) {
+  if (attr_name == svg_names::kSurfaceScaleAttr ||
+      attr_name == svg_names::kSpecularConstantAttr ||
+      attr_name == svg_names::kSpecularExponentAttr) {
     SVGElement::InvalidationGuard invalidation_guard(this);
     PrimitiveAttributeChanged(attr_name);
     return;
   }
 
-  if (attr_name == SVGNames::inAttr) {
+  if (attr_name == svg_names::kInAttr) {
     SVGElement::InvalidationGuard invalidation_guard(this);
     Invalidate();
     return;
diff --git a/third_party/blink/renderer/core/svg/svg_fe_spot_light_element.cc b/third_party/blink/renderer/core/svg/svg_fe_spot_light_element.cc
index 7e63ff4..3d6be82 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_spot_light_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_spot_light_element.cc
@@ -26,7 +26,7 @@
 namespace blink {
 
 inline SVGFESpotLightElement::SVGFESpotLightElement(Document& document)
-    : SVGFELightElement(SVGNames::feSpotLightTag, document) {}
+    : SVGFELightElement(svg_names::kFESpotLightTag, document) {}
 
 DEFINE_NODE_FACTORY(SVGFESpotLightElement)
 
diff --git a/third_party/blink/renderer/core/svg/svg_fe_tile_element.cc b/third_party/blink/renderer/core/svg/svg_fe_tile_element.cc
index 0be047e..aa39c46 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_tile_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_tile_element.cc
@@ -27,8 +27,8 @@
 namespace blink {
 
 inline SVGFETileElement::SVGFETileElement(Document& document)
-    : SVGFilterPrimitiveStandardAttributes(SVGNames::feTileTag, document),
-      in1_(SVGAnimatedString::Create(this, SVGNames::inAttr)) {
+    : SVGFilterPrimitiveStandardAttributes(svg_names::kFETileTag, document),
+      in1_(SVGAnimatedString::Create(this, svg_names::kInAttr)) {
   AddToPropertyMap(in1_);
 }
 
@@ -40,7 +40,7 @@
 DEFINE_NODE_FACTORY(SVGFETileElement)
 
 void SVGFETileElement::SvgAttributeChanged(const QualifiedName& attr_name) {
-  if (attr_name == SVGNames::inAttr) {
+  if (attr_name == svg_names::kInAttr) {
     SVGElement::InvalidationGuard invalidation_guard(this);
     Invalidate();
     return;
diff --git a/third_party/blink/renderer/core/svg/svg_fe_turbulence_element.cc b/third_party/blink/renderer/core/svg/svg_fe_turbulence_element.cc
index 6ace7ca2..b98c65a 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_turbulence_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_turbulence_element.cc
@@ -47,22 +47,23 @@
 }
 
 inline SVGFETurbulenceElement::SVGFETurbulenceElement(Document& document)
-    : SVGFilterPrimitiveStandardAttributes(SVGNames::feTurbulenceTag, document),
+    : SVGFilterPrimitiveStandardAttributes(svg_names::kFETurbulenceTag,
+                                           document),
       base_frequency_(
           SVGAnimatedNumberOptionalNumber::Create(this,
-                                                  SVGNames::baseFrequencyAttr,
+                                                  svg_names::kBaseFrequencyAttr,
                                                   0.0f)),
-      seed_(SVGAnimatedNumber::Create(this, SVGNames::seedAttr, 0.0f)),
+      seed_(SVGAnimatedNumber::Create(this, svg_names::kSeedAttr, 0.0f)),
       stitch_tiles_(SVGAnimatedEnumeration<SVGStitchOptions>::Create(
           this,
-          SVGNames::stitchTilesAttr,
+          svg_names::kStitchTilesAttr,
           kSvgStitchtypeNostitch)),
       type_(SVGAnimatedEnumeration<TurbulenceType>::Create(
           this,
-          SVGNames::typeAttr,
+          svg_names::kTypeAttr,
           FETURBULENCE_TYPE_TURBULENCE)),
       num_octaves_(
-          SVGAnimatedInteger::Create(this, SVGNames::numOctavesAttr, 1)) {
+          SVGAnimatedInteger::Create(this, svg_names::kNumOctavesAttr, 1)) {
   AddToPropertyMap(base_frequency_);
   AddToPropertyMap(seed_);
   AddToPropertyMap(stitch_tiles_);
@@ -85,21 +86,21 @@
     FilterEffect* effect,
     const QualifiedName& attr_name) {
   FETurbulence* turbulence = static_cast<FETurbulence*>(effect);
-  if (attr_name == SVGNames::typeAttr)
+  if (attr_name == svg_names::kTypeAttr)
     return turbulence->SetType(type_->CurrentValue()->EnumValue());
-  if (attr_name == SVGNames::stitchTilesAttr)
+  if (attr_name == svg_names::kStitchTilesAttr)
     return turbulence->SetStitchTiles(
         stitch_tiles_->CurrentValue()->EnumValue() == kSvgStitchtypeStitch);
-  if (attr_name == SVGNames::baseFrequencyAttr) {
+  if (attr_name == svg_names::kBaseFrequencyAttr) {
     bool base_frequency_x_changed = turbulence->SetBaseFrequencyX(
         baseFrequencyX()->CurrentValue()->Value());
     bool base_frequency_y_changed = turbulence->SetBaseFrequencyY(
         baseFrequencyY()->CurrentValue()->Value());
     return (base_frequency_x_changed || base_frequency_y_changed);
   }
-  if (attr_name == SVGNames::seedAttr)
+  if (attr_name == svg_names::kSeedAttr)
     return turbulence->SetSeed(seed_->CurrentValue()->Value());
-  if (attr_name == SVGNames::numOctavesAttr)
+  if (attr_name == svg_names::kNumOctavesAttr)
     return turbulence->SetNumOctaves(num_octaves_->CurrentValue()->Value());
 
   return SVGFilterPrimitiveStandardAttributes::SetFilterEffectAttribute(
@@ -108,11 +109,11 @@
 
 void SVGFETurbulenceElement::SvgAttributeChanged(
     const QualifiedName& attr_name) {
-  if (attr_name == SVGNames::baseFrequencyAttr ||
-      attr_name == SVGNames::numOctavesAttr ||
-      attr_name == SVGNames::seedAttr ||
-      attr_name == SVGNames::stitchTilesAttr ||
-      attr_name == SVGNames::typeAttr) {
+  if (attr_name == svg_names::kBaseFrequencyAttr ||
+      attr_name == svg_names::kNumOctavesAttr ||
+      attr_name == svg_names::kSeedAttr ||
+      attr_name == svg_names::kStitchTilesAttr ||
+      attr_name == svg_names::kTypeAttr) {
     SVGElement::InvalidationGuard invalidation_guard(this);
     PrimitiveAttributeChanged(attr_name);
     return;
diff --git a/third_party/blink/renderer/core/svg/svg_filter_element.cc b/third_party/blink/renderer/core/svg/svg_filter_element.cc
index 137c33f..641af3e 100644
--- a/third_party/blink/renderer/core/svg/svg_filter_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_filter_element.cc
@@ -30,36 +30,36 @@
 namespace blink {
 
 inline SVGFilterElement::SVGFilterElement(Document& document)
-    : SVGElement(SVGNames::filterTag, document),
+    : SVGElement(svg_names::kFilterTag, document),
       SVGURIReference(this),
       // Spec: If the x/y attribute is not specified, the effect is as if a
       // value of "-10%" were specified.
       x_(SVGAnimatedLength::Create(this,
-                                   SVGNames::xAttr,
+                                   svg_names::kXAttr,
                                    SVGLengthMode::kWidth,
                                    SVGLength::Initial::kPercentMinus10)),
       y_(SVGAnimatedLength::Create(this,
-                                   SVGNames::yAttr,
+                                   svg_names::kYAttr,
                                    SVGLengthMode::kHeight,
                                    SVGLength::Initial::kPercentMinus10)),
       // Spec: If the width/height attribute is not specified, the effect is as
       // if a value of "120%" were specified.
       width_(SVGAnimatedLength::Create(this,
-                                       SVGNames::widthAttr,
+                                       svg_names::kWidthAttr,
                                        SVGLengthMode::kWidth,
                                        SVGLength::Initial::kPercent120)),
       height_(SVGAnimatedLength::Create(this,
-                                        SVGNames::heightAttr,
+                                        svg_names::kHeightAttr,
                                         SVGLengthMode::kHeight,
                                         SVGLength::Initial::kPercent120)),
       filter_units_(SVGAnimatedEnumeration<SVGUnitTypes::SVGUnitType>::Create(
           this,
-          SVGNames::filterUnitsAttr,
+          svg_names::kFilterUnitsAttr,
           SVGUnitTypes::kSvgUnitTypeObjectboundingbox)),
       primitive_units_(
           SVGAnimatedEnumeration<SVGUnitTypes::SVGUnitType>::Create(
               this,
-              SVGNames::primitiveUnitsAttr,
+              svg_names::kPrimitiveUnitsAttr,
               SVGUnitTypes::kSvgUnitTypeUserspaceonuse)) {
   AddToPropertyMap(x_);
   AddToPropertyMap(y_);
@@ -85,14 +85,14 @@
 }
 
 void SVGFilterElement::SvgAttributeChanged(const QualifiedName& attr_name) {
-  bool is_xywh = attr_name == SVGNames::xAttr || attr_name == SVGNames::yAttr ||
-                 attr_name == SVGNames::widthAttr ||
-                 attr_name == SVGNames::heightAttr;
+  bool is_xywh =
+      attr_name == svg_names::kXAttr || attr_name == svg_names::kYAttr ||
+      attr_name == svg_names::kWidthAttr || attr_name == svg_names::kHeightAttr;
   if (is_xywh)
     UpdateRelativeLengthsInformation();
 
-  if (is_xywh || attr_name == SVGNames::filterUnitsAttr ||
-      attr_name == SVGNames::primitiveUnitsAttr) {
+  if (is_xywh || attr_name == svg_names::kFilterUnitsAttr ||
+      attr_name == svg_names::kPrimitiveUnitsAttr) {
     SVGElement::InvalidationGuard invalidation_guard(this);
     InvalidateFilterChain();
     return;
diff --git a/third_party/blink/renderer/core/svg/svg_filter_primitive_standard_attributes.cc b/third_party/blink/renderer/core/svg/svg_filter_primitive_standard_attributes.cc
index 0edfa01..20ee460 100644
--- a/third_party/blink/renderer/core/svg/svg_filter_primitive_standard_attributes.cc
+++ b/third_party/blink/renderer/core/svg/svg_filter_primitive_standard_attributes.cc
@@ -38,24 +38,24 @@
       // Spec: If the x/y attribute is not specified, the effect is as if a
       // value of "0%" were specified.
       x_(SVGAnimatedLength::Create(this,
-                                   SVGNames::xAttr,
+                                   svg_names::kXAttr,
                                    SVGLengthMode::kWidth,
                                    SVGLength::Initial::kPercent0)),
       y_(SVGAnimatedLength::Create(this,
-                                   SVGNames::yAttr,
+                                   svg_names::kYAttr,
                                    SVGLengthMode::kHeight,
                                    SVGLength::Initial::kPercent0)),
       // Spec: If the width/height attribute is not specified, the effect is as
       // if a value of "100%" were specified.
       width_(SVGAnimatedLength::Create(this,
-                                       SVGNames::widthAttr,
+                                       svg_names::kWidthAttr,
                                        SVGLengthMode::kWidth,
                                        SVGLength::Initial::kPercent100)),
       height_(SVGAnimatedLength::Create(this,
-                                        SVGNames::heightAttr,
+                                        svg_names::kHeightAttr,
                                         SVGLengthMode::kHeight,
                                         SVGLength::Initial::kPercent100)),
-      result_(SVGAnimatedString::Create(this, SVGNames::resultAttr)) {
+      result_(SVGAnimatedString::Create(this, svg_names::kResultAttr)) {
   AddToPropertyMap(x_);
   AddToPropertyMap(y_);
   AddToPropertyMap(width_);
@@ -75,7 +75,7 @@
 bool SVGFilterPrimitiveStandardAttributes::SetFilterEffectAttribute(
     FilterEffect* effect,
     const QualifiedName& attr_name) {
-  DCHECK(attr_name == SVGNames::color_interpolation_filtersAttr);
+  DCHECK(attr_name == svg_names::kColorInterpolationFiltersAttr);
   DCHECK(GetLayoutObject());
   EColorInterpolation color_interpolation =
       GetLayoutObject()->StyleRef().SvgStyle().ColorInterpolationFilters();
@@ -89,9 +89,10 @@
 
 void SVGFilterPrimitiveStandardAttributes::SvgAttributeChanged(
     const QualifiedName& attr_name) {
-  if (attr_name == SVGNames::xAttr || attr_name == SVGNames::yAttr ||
-      attr_name == SVGNames::widthAttr || attr_name == SVGNames::heightAttr ||
-      attr_name == SVGNames::resultAttr) {
+  if (attr_name == svg_names::kXAttr || attr_name == svg_names::kYAttr ||
+      attr_name == svg_names::kWidthAttr ||
+      attr_name == svg_names::kHeightAttr ||
+      attr_name == svg_names::kResultAttr) {
     SVGElement::InvalidationGuard invalidation_guard(this);
     Invalidate();
     return;
diff --git a/third_party/blink/renderer/core/svg/svg_fit_to_view_box.cc b/third_party/blink/renderer/core/svg/svg_fit_to_view_box.cc
index 4fab9310..afb0bae 100644
--- a/third_party/blink/renderer/core/svg/svg_fit_to_view_box.cc
+++ b/third_party/blink/renderer/core/svg/svg_fit_to_view_box.cc
@@ -39,7 +39,7 @@
 
  protected:
   SVGAnimatedViewBoxRect(SVGElement* context_element)
-      : SVGAnimatedRect(context_element, SVGNames::viewBoxAttr) {}
+      : SVGAnimatedRect(context_element, svg_names::kViewBoxAttr) {}
 };
 
 SVGParsingError SVGAnimatedViewBoxRect::AttributeChanged(const String& value) {
@@ -57,7 +57,7 @@
     : view_box_(SVGAnimatedViewBoxRect::Create(element)),
       preserve_aspect_ratio_(SVGAnimatedPreserveAspectRatio::Create(
           element,
-          SVGNames::preserveAspectRatioAttr)) {
+          svg_names::kPreserveAspectRatioAttr)) {
   DCHECK(element);
   element->AddToPropertyMap(view_box_);
   element->AddToPropertyMap(preserve_aspect_ratio_);
@@ -83,8 +83,8 @@
 }
 
 bool SVGFitToViewBox::IsKnownAttribute(const QualifiedName& attr_name) {
-  return attr_name == SVGNames::viewBoxAttr ||
-         attr_name == SVGNames::preserveAspectRatioAttr;
+  return attr_name == svg_names::kViewBoxAttr ||
+         attr_name == svg_names::kPreserveAspectRatioAttr;
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/svg/svg_foreign_object_element.cc b/third_party/blink/renderer/core/svg/svg_foreign_object_element.cc
index 269ffa87..96ba4d1 100644
--- a/third_party/blink/renderer/core/svg/svg_foreign_object_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_foreign_object_element.cc
@@ -29,24 +29,24 @@
 namespace blink {
 
 inline SVGForeignObjectElement::SVGForeignObjectElement(Document& document)
-    : SVGGraphicsElement(SVGNames::foreignObjectTag, document),
+    : SVGGraphicsElement(svg_names::kForeignObjectTag, document),
       x_(SVGAnimatedLength::Create(this,
-                                   SVGNames::xAttr,
+                                   svg_names::kXAttr,
                                    SVGLengthMode::kWidth,
                                    SVGLength::Initial::kUnitlessZero,
                                    CSSPropertyX)),
       y_(SVGAnimatedLength::Create(this,
-                                   SVGNames::yAttr,
+                                   svg_names::kYAttr,
                                    SVGLengthMode::kHeight,
                                    SVGLength::Initial::kUnitlessZero,
                                    CSSPropertyY)),
       width_(SVGAnimatedLength::Create(this,
-                                       SVGNames::widthAttr,
+                                       svg_names::kWidthAttr,
                                        SVGLengthMode::kWidth,
                                        SVGLength::Initial::kUnitlessZero,
                                        CSSPropertyWidth)),
       height_(SVGAnimatedLength::Create(this,
-                                        SVGNames::heightAttr,
+                                        svg_names::kHeightAttr,
                                         SVGLengthMode::kHeight,
                                         SVGLength::Initial::kUnitlessZero,
                                         CSSPropertyHeight)) {
@@ -94,9 +94,9 @@
 void SVGForeignObjectElement::SvgAttributeChanged(
     const QualifiedName& attr_name) {
   bool is_width_height_attribute =
-      attr_name == SVGNames::widthAttr || attr_name == SVGNames::heightAttr;
+      attr_name == svg_names::kWidthAttr || attr_name == svg_names::kHeightAttr;
   bool is_xy_attribute =
-      attr_name == SVGNames::xAttr || attr_name == SVGNames::yAttr;
+      attr_name == svg_names::kXAttr || attr_name == svg_names::kYAttr;
 
   if (is_xy_attribute || is_width_height_attribute) {
     SVGElement::InvalidationGuard invalidation_guard(this);
diff --git a/third_party/blink/renderer/core/svg/svg_g_element.cc b/third_party/blink/renderer/core/svg/svg_g_element.cc
index b13a737..3ecd675 100644
--- a/third_party/blink/renderer/core/svg/svg_g_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_g_element.cc
@@ -28,7 +28,7 @@
 
 inline SVGGElement::SVGGElement(Document& document,
                                 ConstructionType construction_type)
-    : SVGGraphicsElement(SVGNames::gTag, document, construction_type) {}
+    : SVGGraphicsElement(svg_names::kGTag, document, construction_type) {}
 
 DEFINE_NODE_FACTORY(SVGGElement)
 
diff --git a/third_party/blink/renderer/core/svg/svg_geometry_element.cc b/third_party/blink/renderer/core/svg/svg_geometry_element.cc
index 71e06f9..4f53e83 100644
--- a/third_party/blink/renderer/core/svg/svg_geometry_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_geometry_element.cc
@@ -56,7 +56,7 @@
  private:
   explicit SVGAnimatedPathLength(SVGGeometryElement* context_element)
       : SVGAnimatedNumber(context_element,
-                          SVGNames::pathLengthAttr,
+                          svg_names::kPathLengthAttr,
                           SVGNumber::Create()) {}
 };
 
@@ -69,7 +69,7 @@
 }
 
 void SVGGeometryElement::SvgAttributeChanged(const QualifiedName& attr_name) {
-  if (attr_name == SVGNames::pathLengthAttr) {
+  if (attr_name == svg_names::kPathLengthAttr) {
     SVGElement::InvalidationGuard invalidation_guard(this);
     if (LayoutObject* layout_object = GetLayoutObject())
       MarkForLayoutAndParentResourceInvalidation(*layout_object);
diff --git a/third_party/blink/renderer/core/svg/svg_gradient_element.cc b/third_party/blink/renderer/core/svg/svg_gradient_element.cc
index 033e8c5..b3ba6f9 100644
--- a/third_party/blink/renderer/core/svg/svg_gradient_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_gradient_element.cc
@@ -50,15 +50,15 @@
       SVGURIReference(this),
       gradient_transform_(
           SVGAnimatedTransformList::Create(this,
-                                           SVGNames::gradientTransformAttr,
+                                           svg_names::kGradientTransformAttr,
                                            CSSPropertyTransform)),
       spread_method_(SVGAnimatedEnumeration<SVGSpreadMethodType>::Create(
           this,
-          SVGNames::spreadMethodAttr,
+          svg_names::kSpreadMethodAttr,
           kSVGSpreadMethodPad)),
       gradient_units_(SVGAnimatedEnumeration<SVGUnitTypes::SVGUnitType>::Create(
           this,
-          SVGNames::gradientUnitsAttr,
+          svg_names::kGradientUnitsAttr,
           SVGUnitTypes::kSvgUnitTypeObjectboundingbox)) {
   AddToPropertyMap(gradient_transform_);
   AddToPropertyMap(spread_method_);
@@ -94,7 +94,7 @@
     const QualifiedName& name,
     const AtomicString& value,
     MutableCSSPropertyValueSet* style) {
-  if (name == SVGNames::gradientTransformAttr) {
+  if (name == svg_names::kGradientTransformAttr) {
     AddPropertyToPresentationAttributeStyle(
         style, CSSPropertyTransform,
         *gradient_transform_->CurrentValue()->CssValue());
@@ -104,15 +104,15 @@
 }
 
 void SVGGradientElement::SvgAttributeChanged(const QualifiedName& attr_name) {
-  if (attr_name == SVGNames::gradientTransformAttr) {
+  if (attr_name == svg_names::kGradientTransformAttr) {
     InvalidateSVGPresentationAttributeStyle();
     SetNeedsStyleRecalc(kLocalStyleChange,
                         StyleChangeReasonForTracing::FromAttribute(attr_name));
   }
 
-  if (attr_name == SVGNames::gradientUnitsAttr ||
-      attr_name == SVGNames::gradientTransformAttr ||
-      attr_name == SVGNames::spreadMethodAttr) {
+  if (attr_name == svg_names::kGradientUnitsAttr ||
+      attr_name == svg_names::kGradientTransformAttr ||
+      attr_name == svg_names::kSpreadMethodAttr) {
     SVGElement::InvalidationGuard invalidation_guard(this);
     InvalidateGradient(LayoutInvalidationReason::kAttributeChanged);
     return;
diff --git a/third_party/blink/renderer/core/svg/svg_gradient_element.h b/third_party/blink/renderer/core/svg/svg_gradient_element.h
index 2e6116e..226f9b7 100644
--- a/third_party/blink/renderer/core/svg/svg_gradient_element.h
+++ b/third_party/blink/renderer/core/svg/svg_gradient_element.h
@@ -97,8 +97,8 @@
 };
 
 inline bool IsSVGGradientElement(const SVGElement& element) {
-  return element.HasTagName(SVGNames::radialGradientTag) ||
-         element.HasTagName(SVGNames::linearGradientTag);
+  return element.HasTagName(svg_names::kRadialGradientTag) ||
+         element.HasTagName(svg_names::kLinearGradientTag);
 }
 
 DEFINE_SVGELEMENT_TYPE_CASTS_WITH_FUNCTION(SVGGradientElement);
diff --git a/third_party/blink/renderer/core/svg/svg_graphics_element.cc b/third_party/blink/renderer/core/svg/svg_graphics_element.cc
index 288eed1..bfca480f 100644
--- a/third_party/blink/renderer/core/svg/svg_graphics_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_graphics_element.cc
@@ -37,7 +37,7 @@
     : SVGElement(tag_name, document, construction_type),
       SVGTests(this),
       transform_(SVGAnimatedTransformList::Create(this,
-                                                  SVGNames::transformAttr,
+                                                  svg_names::kTransformAttr,
                                                   CSSPropertyTransform)) {
   AddToPropertyMap(transform_);
 }
@@ -103,7 +103,7 @@
     const QualifiedName& name,
     const AtomicString& value,
     MutableCSSPropertyValueSet* style) {
-  if (name == SVGNames::transformAttr) {
+  if (name == svg_names::kTransformAttr) {
     AddPropertyToPresentationAttributeStyle(
         style, CSSPropertyTransform, *transform_->CurrentValue()->CssValue());
     return;
@@ -124,7 +124,7 @@
     return;
   }
 
-  if (attr_name == SVGNames::transformAttr) {
+  if (attr_name == svg_names::kTransformAttr) {
     SVGElement::InvalidationGuard invalidation_guard(this);
     InvalidateSVGPresentationAttributeStyle();
     // TODO(fs): The InvalidationGuard will make sure all instances are
diff --git a/third_party/blink/renderer/core/svg/svg_image_element.cc b/third_party/blink/renderer/core/svg/svg_image_element.cc
index e0c3484..59995d3 100644
--- a/third_party/blink/renderer/core/svg/svg_image_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_image_element.cc
@@ -34,32 +34,32 @@
 namespace blink {
 
 inline SVGImageElement::SVGImageElement(Document& document)
-    : SVGGraphicsElement(SVGNames::imageTag, document),
+    : SVGGraphicsElement(svg_names::kImageTag, document),
       SVGURIReference(this),
       is_default_overridden_intrinsic_size_(false),
       x_(SVGAnimatedLength::Create(this,
-                                   SVGNames::xAttr,
+                                   svg_names::kXAttr,
                                    SVGLengthMode::kWidth,
                                    SVGLength::Initial::kUnitlessZero,
                                    CSSPropertyX)),
       y_(SVGAnimatedLength::Create(this,
-                                   SVGNames::yAttr,
+                                   svg_names::kYAttr,
                                    SVGLengthMode::kHeight,
                                    SVGLength::Initial::kUnitlessZero,
                                    CSSPropertyY)),
       width_(SVGAnimatedLength::Create(this,
-                                       SVGNames::widthAttr,
+                                       svg_names::kWidthAttr,
                                        SVGLengthMode::kWidth,
                                        SVGLength::Initial::kUnitlessZero,
                                        CSSPropertyWidth)),
       height_(SVGAnimatedLength::Create(this,
-                                        SVGNames::heightAttr,
+                                        svg_names::kHeightAttr,
                                         SVGLengthMode::kHeight,
                                         SVGLength::Initial::kUnitlessZero,
                                         CSSPropertyHeight)),
       preserve_aspect_ratio_(SVGAnimatedPreserveAspectRatio::Create(
           this,
-          SVGNames::preserveAspectRatioAttr)),
+          svg_names::kPreserveAspectRatioAttr)),
       image_loader_(SVGImageLoader::Create(this)) {
   AddToPropertyMap(x_);
   AddToPropertyMap(y_);
@@ -131,10 +131,10 @@
 
 void SVGImageElement::SvgAttributeChanged(const QualifiedName& attr_name) {
   bool is_length_attribute =
-      attr_name == SVGNames::xAttr || attr_name == SVGNames::yAttr ||
-      attr_name == SVGNames::widthAttr || attr_name == SVGNames::heightAttr;
+      attr_name == svg_names::kXAttr || attr_name == svg_names::kYAttr ||
+      attr_name == svg_names::kWidthAttr || attr_name == svg_names::kHeightAttr;
 
-  if (is_length_attribute || attr_name == SVGNames::preserveAspectRatioAttr) {
+  if (is_length_attribute || attr_name == svg_names::kPreserveAspectRatioAttr) {
     SVGElement::InvalidationGuard invalidation_guard(this);
 
     if (is_length_attribute) {
@@ -168,10 +168,10 @@
 
 void SVGImageElement::ParseAttribute(
     const AttributeModificationParams& params) {
-  if (params.name == SVGNames::decodingAttr) {
+  if (params.name == svg_names::kDecodingAttr) {
     UseCounter::Count(GetDocument(), WebFeature::kImageDecodingAttribute);
     decoding_mode_ = ParseImageDecodingMode(params.new_value);
-  } else if (params.name == SVGNames::intrinsicsizeAttr &&
+  } else if (params.name == svg_names::kIntrinsicsizeAttr &&
              RuntimeEnabledFeatures::
                  ExperimentalProductivityFeaturesEnabled()) {
     String message;
diff --git a/third_party/blink/renderer/core/svg/svg_length.cc b/third_party/blink/renderer/core/svg/svg_length.cc
index 8a82679..6ee3162 100644
--- a/third_party/blink/renderer/core/svg/svg_length.cc
+++ b/third_party/blink/renderer/core/svg/svg_length.cc
@@ -191,30 +191,30 @@
   DEFINE_STATIC_LOCAL(LengthModeForLengthAttributeMap, length_mode_map, ());
 
   if (length_mode_map.IsEmpty()) {
-    length_mode_map.Set(SVGNames::xAttr, SVGLengthMode::kWidth);
-    length_mode_map.Set(SVGNames::yAttr, SVGLengthMode::kHeight);
-    length_mode_map.Set(SVGNames::cxAttr, SVGLengthMode::kWidth);
-    length_mode_map.Set(SVGNames::cyAttr, SVGLengthMode::kHeight);
-    length_mode_map.Set(SVGNames::dxAttr, SVGLengthMode::kWidth);
-    length_mode_map.Set(SVGNames::dyAttr, SVGLengthMode::kHeight);
-    length_mode_map.Set(SVGNames::frAttr, SVGLengthMode::kOther);
-    length_mode_map.Set(SVGNames::fxAttr, SVGLengthMode::kWidth);
-    length_mode_map.Set(SVGNames::fyAttr, SVGLengthMode::kHeight);
-    length_mode_map.Set(SVGNames::rAttr, SVGLengthMode::kOther);
-    length_mode_map.Set(SVGNames::rxAttr, SVGLengthMode::kWidth);
-    length_mode_map.Set(SVGNames::ryAttr, SVGLengthMode::kHeight);
-    length_mode_map.Set(SVGNames::widthAttr, SVGLengthMode::kWidth);
-    length_mode_map.Set(SVGNames::heightAttr, SVGLengthMode::kHeight);
-    length_mode_map.Set(SVGNames::x1Attr, SVGLengthMode::kWidth);
-    length_mode_map.Set(SVGNames::x2Attr, SVGLengthMode::kWidth);
-    length_mode_map.Set(SVGNames::y1Attr, SVGLengthMode::kHeight);
-    length_mode_map.Set(SVGNames::y2Attr, SVGLengthMode::kHeight);
-    length_mode_map.Set(SVGNames::refXAttr, SVGLengthMode::kWidth);
-    length_mode_map.Set(SVGNames::refYAttr, SVGLengthMode::kHeight);
-    length_mode_map.Set(SVGNames::markerWidthAttr, SVGLengthMode::kWidth);
-    length_mode_map.Set(SVGNames::markerHeightAttr, SVGLengthMode::kHeight);
-    length_mode_map.Set(SVGNames::textLengthAttr, SVGLengthMode::kWidth);
-    length_mode_map.Set(SVGNames::startOffsetAttr, SVGLengthMode::kWidth);
+    length_mode_map.Set(svg_names::kXAttr, SVGLengthMode::kWidth);
+    length_mode_map.Set(svg_names::kYAttr, SVGLengthMode::kHeight);
+    length_mode_map.Set(svg_names::kCxAttr, SVGLengthMode::kWidth);
+    length_mode_map.Set(svg_names::kCyAttr, SVGLengthMode::kHeight);
+    length_mode_map.Set(svg_names::kDxAttr, SVGLengthMode::kWidth);
+    length_mode_map.Set(svg_names::kDyAttr, SVGLengthMode::kHeight);
+    length_mode_map.Set(svg_names::kFrAttr, SVGLengthMode::kOther);
+    length_mode_map.Set(svg_names::kFxAttr, SVGLengthMode::kWidth);
+    length_mode_map.Set(svg_names::kFyAttr, SVGLengthMode::kHeight);
+    length_mode_map.Set(svg_names::kRAttr, SVGLengthMode::kOther);
+    length_mode_map.Set(svg_names::kRxAttr, SVGLengthMode::kWidth);
+    length_mode_map.Set(svg_names::kRyAttr, SVGLengthMode::kHeight);
+    length_mode_map.Set(svg_names::kWidthAttr, SVGLengthMode::kWidth);
+    length_mode_map.Set(svg_names::kHeightAttr, SVGLengthMode::kHeight);
+    length_mode_map.Set(svg_names::kX1Attr, SVGLengthMode::kWidth);
+    length_mode_map.Set(svg_names::kX2Attr, SVGLengthMode::kWidth);
+    length_mode_map.Set(svg_names::kY1Attr, SVGLengthMode::kHeight);
+    length_mode_map.Set(svg_names::kY2Attr, SVGLengthMode::kHeight);
+    length_mode_map.Set(svg_names::kRefXAttr, SVGLengthMode::kWidth);
+    length_mode_map.Set(svg_names::kRefYAttr, SVGLengthMode::kHeight);
+    length_mode_map.Set(svg_names::kMarkerWidthAttr, SVGLengthMode::kWidth);
+    length_mode_map.Set(svg_names::kMarkerHeightAttr, SVGLengthMode::kHeight);
+    length_mode_map.Set(svg_names::kTextLengthAttr, SVGLengthMode::kWidth);
+    length_mode_map.Set(svg_names::kStartOffsetAttr, SVGLengthMode::kWidth);
   }
 
   if (length_mode_map.Contains(attr_name))
@@ -228,9 +228,10 @@
   DEFINE_STATIC_LOCAL(
       HashSet<QualifiedName>, no_negative_values_set,
       ({
-          SVGNames::frAttr, SVGNames::rAttr, SVGNames::rxAttr, SVGNames::ryAttr,
-          SVGNames::widthAttr, SVGNames::heightAttr, SVGNames::markerWidthAttr,
-          SVGNames::markerHeightAttr, SVGNames::textLengthAttr,
+          svg_names::kFrAttr, svg_names::kRAttr, svg_names::kRxAttr,
+          svg_names::kRyAttr, svg_names::kWidthAttr, svg_names::kHeightAttr,
+          svg_names::kMarkerWidthAttr, svg_names::kMarkerHeightAttr,
+          svg_names::kTextLengthAttr,
       }));
   return no_negative_values_set.Contains(attr_name);
 }
diff --git a/third_party/blink/renderer/core/svg/svg_line_element.cc b/third_party/blink/renderer/core/svg/svg_line_element.cc
index 056d4ff..b7bd143 100644
--- a/third_party/blink/renderer/core/svg/svg_line_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_line_element.cc
@@ -26,21 +26,21 @@
 namespace blink {
 
 inline SVGLineElement::SVGLineElement(Document& document)
-    : SVGGeometryElement(SVGNames::lineTag, document),
+    : SVGGeometryElement(svg_names::kLineTag, document),
       x1_(SVGAnimatedLength::Create(this,
-                                    SVGNames::x1Attr,
+                                    svg_names::kX1Attr,
                                     SVGLengthMode::kWidth,
                                     SVGLength::Initial::kUnitlessZero)),
       y1_(SVGAnimatedLength::Create(this,
-                                    SVGNames::y1Attr,
+                                    svg_names::kY1Attr,
                                     SVGLengthMode::kHeight,
                                     SVGLength::Initial::kUnitlessZero)),
       x2_(SVGAnimatedLength::Create(this,
-                                    SVGNames::x2Attr,
+                                    svg_names::kX2Attr,
                                     SVGLengthMode::kWidth,
                                     SVGLength::Initial::kUnitlessZero)),
       y2_(SVGAnimatedLength::Create(this,
-                                    SVGNames::y2Attr,
+                                    svg_names::kY2Attr,
                                     SVGLengthMode::kHeight,
                                     SVGLength::Initial::kUnitlessZero)) {
   AddToPropertyMap(x1_);
@@ -72,8 +72,8 @@
 }
 
 void SVGLineElement::SvgAttributeChanged(const QualifiedName& attr_name) {
-  if (attr_name == SVGNames::x1Attr || attr_name == SVGNames::y1Attr ||
-      attr_name == SVGNames::x2Attr || attr_name == SVGNames::y2Attr) {
+  if (attr_name == svg_names::kX1Attr || attr_name == svg_names::kY1Attr ||
+      attr_name == svg_names::kX2Attr || attr_name == svg_names::kY2Attr) {
     UpdateRelativeLengthsInformation();
     GeometryAttributeChanged();
     return;
diff --git a/third_party/blink/renderer/core/svg/svg_linear_gradient_element.cc b/third_party/blink/renderer/core/svg/svg_linear_gradient_element.cc
index 80a243d..4e227a8 100644
--- a/third_party/blink/renderer/core/svg/svg_linear_gradient_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_linear_gradient_element.cc
@@ -30,25 +30,25 @@
 namespace blink {
 
 inline SVGLinearGradientElement::SVGLinearGradientElement(Document& document)
-    : SVGGradientElement(SVGNames::linearGradientTag, document),
+    : SVGGradientElement(svg_names::kLinearGradientTag, document),
       // Spec: If the x1|y1|y2 attribute is not specified, the effect is as if a
       // value of "0%" were specified.
       // Spec: If the x2 attribute is not specified, the effect is as if a value
       // of "100%" were specified.
       x1_(SVGAnimatedLength::Create(this,
-                                    SVGNames::x1Attr,
+                                    svg_names::kX1Attr,
                                     SVGLengthMode::kWidth,
                                     SVGLength::Initial::kPercent0)),
       y1_(SVGAnimatedLength::Create(this,
-                                    SVGNames::y1Attr,
+                                    svg_names::kY1Attr,
                                     SVGLengthMode::kHeight,
                                     SVGLength::Initial::kPercent0)),
       x2_(SVGAnimatedLength::Create(this,
-                                    SVGNames::x2Attr,
+                                    svg_names::kX2Attr,
                                     SVGLengthMode::kWidth,
                                     SVGLength::Initial::kPercent100)),
       y2_(SVGAnimatedLength::Create(this,
-                                    SVGNames::y2Attr,
+                                    svg_names::kY2Attr,
                                     SVGLengthMode::kHeight,
                                     SVGLength::Initial::kPercent0)) {
   AddToPropertyMap(x1_);
@@ -69,8 +69,8 @@
 
 void SVGLinearGradientElement::SvgAttributeChanged(
     const QualifiedName& attr_name) {
-  if (attr_name == SVGNames::x1Attr || attr_name == SVGNames::x2Attr ||
-      attr_name == SVGNames::y1Attr || attr_name == SVGNames::y2Attr) {
+  if (attr_name == svg_names::kX1Attr || attr_name == svg_names::kX2Attr ||
+      attr_name == svg_names::kY1Attr || attr_name == svg_names::kY2Attr) {
     SVGElement::InvalidationGuard invalidation_guard(this);
     UpdateRelativeLengthsInformation();
     InvalidateGradient(LayoutInvalidationReason::kAttributeChanged);
diff --git a/third_party/blink/renderer/core/svg/svg_marker_element.cc b/third_party/blink/renderer/core/svg/svg_marker_element.cc
index f4968f9..844fc725 100644
--- a/third_party/blink/renderer/core/svg/svg_marker_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_marker_element.cc
@@ -42,30 +42,30 @@
 }
 
 inline SVGMarkerElement::SVGMarkerElement(Document& document)
-    : SVGElement(SVGNames::markerTag, document),
+    : SVGElement(svg_names::kMarkerTag, document),
       SVGFitToViewBox(this),
       ref_x_(SVGAnimatedLength::Create(this,
-                                       SVGNames::refXAttr,
+                                       svg_names::kRefXAttr,
                                        SVGLengthMode::kWidth,
                                        SVGLength::Initial::kUnitlessZero)),
       ref_y_(SVGAnimatedLength::Create(this,
-                                       SVGNames::refYAttr,
+                                       svg_names::kRefYAttr,
                                        SVGLengthMode::kHeight,
                                        SVGLength::Initial::kUnitlessZero)),
       // Spec: If the markerWidth/markerHeight attribute is not specified, the
       // effect is as if a value of "3" were specified.
       marker_width_(SVGAnimatedLength::Create(this,
-                                              SVGNames::markerWidthAttr,
+                                              svg_names::kMarkerWidthAttr,
                                               SVGLengthMode::kWidth,
                                               SVGLength::Initial::kNumber3)),
       marker_height_(SVGAnimatedLength::Create(this,
-                                               SVGNames::markerHeightAttr,
+                                               svg_names::kMarkerHeightAttr,
                                                SVGLengthMode::kHeight,
                                                SVGLength::Initial::kNumber3)),
       orient_angle_(SVGAnimatedAngle::Create(this)),
       marker_units_(SVGAnimatedEnumeration<SVGMarkerUnitsType>::Create(
           this,
-          SVGNames::markerUnitsAttr,
+          svg_names::kMarkerUnitsAttr,
           kSVGMarkerUnitsStrokeWidth)) {
   AddToPropertyMap(ref_x_);
   AddToPropertyMap(ref_y_);
@@ -98,16 +98,16 @@
 
 void SVGMarkerElement::SvgAttributeChanged(const QualifiedName& attr_name) {
   bool viewbox_attribute_changed = SVGFitToViewBox::IsKnownAttribute(attr_name);
-  bool length_attribute_changed = attr_name == SVGNames::refXAttr ||
-                                  attr_name == SVGNames::refYAttr ||
-                                  attr_name == SVGNames::markerWidthAttr ||
-                                  attr_name == SVGNames::markerHeightAttr;
+  bool length_attribute_changed = attr_name == svg_names::kRefXAttr ||
+                                  attr_name == svg_names::kRefYAttr ||
+                                  attr_name == svg_names::kMarkerWidthAttr ||
+                                  attr_name == svg_names::kMarkerHeightAttr;
   if (length_attribute_changed)
     UpdateRelativeLengthsInformation();
 
   if (viewbox_attribute_changed || length_attribute_changed ||
-      attr_name == SVGNames::markerUnitsAttr ||
-      attr_name == SVGNames::orientAttr) {
+      attr_name == svg_names::kMarkerUnitsAttr ||
+      attr_name == svg_names::kOrientAttr) {
     SVGElement::InvalidationGuard invalidation_guard(this);
     auto* resource_container = ToLayoutSVGResourceContainer(GetLayoutObject());
     if (resource_container) {
@@ -136,13 +136,13 @@
 }
 
 void SVGMarkerElement::setOrientToAuto() {
-  setAttribute(SVGNames::orientAttr, "auto");
+  setAttribute(svg_names::kOrientAttr, "auto");
 }
 
 void SVGMarkerElement::setOrientToAngle(SVGAngleTearOff* angle) {
   DCHECK(angle);
   SVGAngle* target = angle->Target();
-  setAttribute(SVGNames::orientAttr, AtomicString(target->ValueAsString()));
+  setAttribute(svg_names::kOrientAttr, AtomicString(target->ValueAsString()));
 }
 
 LayoutObject* SVGMarkerElement::CreateLayoutObject(const ComputedStyle&) {
diff --git a/third_party/blink/renderer/core/svg/svg_mask_element.cc b/third_party/blink/renderer/core/svg/svg_mask_element.cc
index 0d6cd76..beb203f 100644
--- a/third_party/blink/renderer/core/svg/svg_mask_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_mask_element.cc
@@ -29,40 +29,40 @@
 namespace blink {
 
 inline SVGMaskElement::SVGMaskElement(Document& document)
-    : SVGElement(SVGNames::maskTag, document),
+    : SVGElement(svg_names::kMaskTag, document),
       SVGTests(this),
       // Spec: If the x/y attribute is not specified, the effect is as if a
       // value of "-10%" were specified.
       x_(SVGAnimatedLength::Create(this,
-                                   SVGNames::xAttr,
+                                   svg_names::kXAttr,
                                    SVGLengthMode::kWidth,
                                    SVGLength::Initial::kPercentMinus10,
                                    CSSPropertyX)),
       y_(SVGAnimatedLength::Create(this,
-                                   SVGNames::yAttr,
+                                   svg_names::kYAttr,
                                    SVGLengthMode::kHeight,
                                    SVGLength::Initial::kPercentMinus10,
                                    CSSPropertyY)),
       // Spec: If the width/height attribute is not specified, the effect is as
       // if a value of "120%" were specified.
       width_(SVGAnimatedLength::Create(this,
-                                       SVGNames::widthAttr,
+                                       svg_names::kWidthAttr,
                                        SVGLengthMode::kWidth,
                                        SVGLength::Initial::kPercent120,
                                        CSSPropertyWidth)),
       height_(SVGAnimatedLength::Create(this,
-                                        SVGNames::heightAttr,
+                                        svg_names::kHeightAttr,
                                         SVGLengthMode::kHeight,
                                         SVGLength::Initial::kPercent120,
                                         CSSPropertyHeight)),
       mask_units_(SVGAnimatedEnumeration<SVGUnitTypes::SVGUnitType>::Create(
           this,
-          SVGNames::maskUnitsAttr,
+          svg_names::kMaskUnitsAttr,
           SVGUnitTypes::kSvgUnitTypeObjectboundingbox)),
       mask_content_units_(
           SVGAnimatedEnumeration<SVGUnitTypes::SVGUnitType>::Create(
               this,
-              SVGNames::maskContentUnitsAttr,
+              svg_names::kMaskContentUnitsAttr,
               SVGUnitTypes::kSvgUnitTypeUserspaceonuse)) {
   AddToPropertyMap(x_);
   AddToPropertyMap(y_);
@@ -109,11 +109,11 @@
 
 void SVGMaskElement::SvgAttributeChanged(const QualifiedName& attr_name) {
   bool is_length_attr =
-      attr_name == SVGNames::xAttr || attr_name == SVGNames::yAttr ||
-      attr_name == SVGNames::widthAttr || attr_name == SVGNames::heightAttr;
+      attr_name == svg_names::kXAttr || attr_name == svg_names::kYAttr ||
+      attr_name == svg_names::kWidthAttr || attr_name == svg_names::kHeightAttr;
 
-  if (is_length_attr || attr_name == SVGNames::maskUnitsAttr ||
-      attr_name == SVGNames::maskContentUnitsAttr ||
+  if (is_length_attr || attr_name == svg_names::kMaskUnitsAttr ||
+      attr_name == svg_names::kMaskContentUnitsAttr ||
       SVGTests::IsKnownAttribute(attr_name)) {
     SVGElement::InvalidationGuard invalidation_guard(this);
 
diff --git a/third_party/blink/renderer/core/svg/svg_metadata_element.cc b/third_party/blink/renderer/core/svg/svg_metadata_element.cc
index 6caa0d60..0fd9920e1 100644
--- a/third_party/blink/renderer/core/svg/svg_metadata_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_metadata_element.cc
@@ -25,7 +25,7 @@
 namespace blink {
 
 inline SVGMetadataElement::SVGMetadataElement(Document& document)
-    : SVGElement(SVGNames::metadataTag, document) {}
+    : SVGElement(svg_names::kMetadataTag, document) {}
 
 DEFINE_NODE_FACTORY(SVGMetadataElement)
 }
diff --git a/third_party/blink/renderer/core/svg/svg_mpath_element.cc b/third_party/blink/renderer/core/svg/svg_mpath_element.cc
index 8256e3f..8b7f73e5 100644
--- a/third_party/blink/renderer/core/svg/svg_mpath_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_mpath_element.cc
@@ -28,7 +28,7 @@
 namespace blink {
 
 inline SVGMPathElement::SVGMPathElement(Document& document)
-    : SVGElement(SVGNames::mpathTag, document), SVGURIReference(this) {
+    : SVGElement(svg_names::kMPathTag, document), SVGURIReference(this) {
   DCHECK(RuntimeEnabledFeatures::SMILEnabled());
 }
 
diff --git a/third_party/blink/renderer/core/svg/svg_path_element.cc b/third_party/blink/renderer/core/svg/svg_path_element.cc
index 1f96415..6b8cffd 100644
--- a/third_party/blink/renderer/core/svg/svg_path_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_path_element.cc
@@ -29,8 +29,8 @@
 namespace blink {
 
 inline SVGPathElement::SVGPathElement(Document& document)
-    : SVGGeometryElement(SVGNames::pathTag, document),
-      path_(SVGAnimatedPath::Create(this, SVGNames::dAttr, CSSPropertyD)) {
+    : SVGGeometryElement(svg_names::kPathTag, document),
+      path_(SVGAnimatedPath::Create(this, svg_names::kDAttr, CSSPropertyD)) {
   AddToPropertyMap(path_);
 }
 
@@ -83,7 +83,7 @@
 }
 
 void SVGPathElement::SvgAttributeChanged(const QualifiedName& attr_name) {
-  if (attr_name == SVGNames::dAttr) {
+  if (attr_name == svg_names::kDAttr) {
     InvalidateMPathDependencies();
     GeometryPresentationAttributeChanged(attr_name);
     return;
diff --git a/third_party/blink/renderer/core/svg/svg_path_parser.h b/third_party/blink/renderer/core/svg/svg_path_parser.h
index b8cc121..32191f18 100644
--- a/third_party/blink/renderer/core/svg/svg_path_parser.h
+++ b/third_party/blink/renderer/core/svg/svg_path_parser.h
@@ -33,7 +33,7 @@
 
 class SVGPathConsumer;
 
-namespace SVGPathParser {
+namespace svg_path_parser {
 
 template <typename SourceType, typename ConsumerType>
 inline bool ParsePath(SourceType& source, ConsumerType& consumer) {
@@ -47,7 +47,7 @@
   return true;
 }
 
-}  // namespace SVGPathParser
+}  // namespace svg_path_parser
 
 class SVGPathNormalizer {
   STACK_ALLOCATED();
diff --git a/third_party/blink/renderer/core/svg/svg_path_parser_test.cc b/third_party/blink/renderer/core/svg/svg_path_parser_test.cc
index f4c6425..231dbe7d2 100644
--- a/third_party/blink/renderer/core/svg/svg_path_parser_test.cc
+++ b/third_party/blink/renderer/core/svg/svg_path_parser_test.cc
@@ -16,7 +16,7 @@
   String input_string(input);
   SVGPathStringSource source(input_string);
   SVGPathStringBuilder builder;
-  bool had_error = SVGPathParser::ParsePath(source, builder);
+  bool had_error = svg_path_parser::ParsePath(source, builder);
   output = builder.Result();
   // Coerce a null result to empty.
   if (output.IsNull())
@@ -160,7 +160,7 @@
   String input_string(input);
   SVGPathStringSource source(input_string);
   SVGPathStringBuilder builder;
-  SVGPathParser::ParsePath(source, builder);
+  svg_path_parser::ParsePath(source, builder);
   return source.ParseError();
 }
 
diff --git a/third_party/blink/renderer/core/svg/svg_path_utilities.cc b/third_party/blink/renderer/core/svg/svg_path_utilities.cc
index 4fb92cd..37e46ea 100644
--- a/third_party/blink/renderer/core/svg/svg_path_utilities.cc
+++ b/third_party/blink/renderer/core/svg/svg_path_utilities.cc
@@ -34,7 +34,7 @@
 
   SVGPathBuilder builder(result);
   SVGPathStringSource source(d);
-  return SVGPathParser::ParsePath(source, builder);
+  return svg_path_parser::ParsePath(source, builder);
 }
 
 bool BuildPathFromByteStream(const SVGPathByteStream& stream, Path& result) {
@@ -43,7 +43,7 @@
 
   SVGPathBuilder builder(result);
   SVGPathByteStreamSource source(stream);
-  return SVGPathParser::ParsePath(source, builder);
+  return svg_path_parser::ParsePath(source, builder);
 }
 
 String BuildStringFromByteStream(const SVGPathByteStream& stream,
@@ -55,9 +55,9 @@
   SVGPathByteStreamSource source(stream);
   if (format == kTransformToAbsolute) {
     SVGPathAbsolutizer absolutizer(&builder);
-    SVGPathParser::ParsePath(source, absolutizer);
+    svg_path_parser::ParsePath(source, absolutizer);
   } else {
-    SVGPathParser::ParsePath(source, builder);
+    svg_path_parser::ParsePath(source, builder);
   }
   return builder.Result();
 }
@@ -74,7 +74,7 @@
 
   SVGPathByteStreamBuilder builder(result);
   SVGPathStringSource source(d);
-  SVGPathParser::ParsePath(source, builder);
+  svg_path_parser::ParsePath(source, builder);
   result.ShrinkToFit();
   return source.ParseError();
 }
diff --git a/third_party/blink/renderer/core/svg/svg_pattern_element.cc b/third_party/blink/renderer/core/svg/svg_pattern_element.cc
index 1ed75ec..7ead564 100644
--- a/third_party/blink/renderer/core/svg/svg_pattern_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_pattern_element.cc
@@ -34,38 +34,38 @@
 namespace blink {
 
 inline SVGPatternElement::SVGPatternElement(Document& document)
-    : SVGElement(SVGNames::patternTag, document),
+    : SVGElement(svg_names::kPatternTag, document),
       SVGURIReference(this),
       SVGTests(this),
       SVGFitToViewBox(this),
       x_(SVGAnimatedLength::Create(this,
-                                   SVGNames::xAttr,
+                                   svg_names::kXAttr,
                                    SVGLengthMode::kWidth,
                                    SVGLength::Initial::kUnitlessZero)),
       y_(SVGAnimatedLength::Create(this,
-                                   SVGNames::yAttr,
+                                   svg_names::kYAttr,
                                    SVGLengthMode::kHeight,
                                    SVGLength::Initial::kUnitlessZero)),
       width_(SVGAnimatedLength::Create(this,
-                                       SVGNames::widthAttr,
+                                       svg_names::kWidthAttr,
                                        SVGLengthMode::kWidth,
                                        SVGLength::Initial::kUnitlessZero)),
       height_(SVGAnimatedLength::Create(this,
-                                        SVGNames::heightAttr,
+                                        svg_names::kHeightAttr,
                                         SVGLengthMode::kHeight,
                                         SVGLength::Initial::kUnitlessZero)),
       pattern_transform_(
           SVGAnimatedTransformList::Create(this,
-                                           SVGNames::patternTransformAttr,
+                                           svg_names::kPatternTransformAttr,
                                            CSSPropertyTransform)),
       pattern_units_(SVGAnimatedEnumeration<SVGUnitTypes::SVGUnitType>::Create(
           this,
-          SVGNames::patternUnitsAttr,
+          svg_names::kPatternUnitsAttr,
           SVGUnitTypes::kSvgUnitTypeObjectboundingbox)),
       pattern_content_units_(
           SVGAnimatedEnumeration<SVGUnitTypes::SVGUnitType>::Create(
               this,
-              SVGNames::patternContentUnitsAttr,
+              svg_names::kPatternContentUnitsAttr,
               SVGUnitTypes::kSvgUnitTypeUserspaceonuse)) {
   AddToPropertyMap(x_);
   AddToPropertyMap(y_);
@@ -121,7 +121,7 @@
     const QualifiedName& name,
     const AtomicString& value,
     MutableCSSPropertyValueSet* style) {
-  if (name == SVGNames::patternTransformAttr) {
+  if (name == svg_names::kPatternTransformAttr) {
     AddPropertyToPresentationAttributeStyle(
         style, CSSPropertyTransform,
         *pattern_transform_->CurrentValue()->CssValue());
@@ -132,18 +132,18 @@
 
 void SVGPatternElement::SvgAttributeChanged(const QualifiedName& attr_name) {
   bool is_length_attr =
-      attr_name == SVGNames::xAttr || attr_name == SVGNames::yAttr ||
-      attr_name == SVGNames::widthAttr || attr_name == SVGNames::heightAttr;
+      attr_name == svg_names::kXAttr || attr_name == svg_names::kYAttr ||
+      attr_name == svg_names::kWidthAttr || attr_name == svg_names::kHeightAttr;
 
-  if (attr_name == SVGNames::patternTransformAttr) {
+  if (attr_name == svg_names::kPatternTransformAttr) {
     InvalidateSVGPresentationAttributeStyle();
     SetNeedsStyleRecalc(kLocalStyleChange,
                         StyleChangeReasonForTracing::FromAttribute(attr_name));
   }
 
-  if (is_length_attr || attr_name == SVGNames::patternUnitsAttr ||
-      attr_name == SVGNames::patternContentUnitsAttr ||
-      attr_name == SVGNames::patternTransformAttr ||
+  if (is_length_attr || attr_name == svg_names::kPatternUnitsAttr ||
+      attr_name == svg_names::kPatternContentUnitsAttr ||
+      attr_name == svg_names::kPatternTransformAttr ||
       SVGFitToViewBox::IsKnownAttribute(attr_name) ||
       SVGTests::IsKnownAttribute(attr_name)) {
     SVGElement::InvalidationGuard invalidation_guard(this);
diff --git a/third_party/blink/renderer/core/svg/svg_poly_element.cc b/third_party/blink/renderer/core/svg/svg_poly_element.cc
index b1d40b4..dacf944 100644
--- a/third_party/blink/renderer/core/svg/svg_poly_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_poly_element.cc
@@ -29,7 +29,7 @@
                                Document& document)
     : SVGGeometryElement(tag_name, document),
       points_(SVGAnimatedPointList::Create(this,
-                                           SVGNames::pointsAttr,
+                                           svg_names::kPointsAttr,
                                            SVGPointList::Create())) {
   AddToPropertyMap(points_);
 }
@@ -59,7 +59,7 @@
 }
 
 void SVGPolyElement::SvgAttributeChanged(const QualifiedName& attr_name) {
-  if (attr_name == SVGNames::pointsAttr) {
+  if (attr_name == svg_names::kPointsAttr) {
     GeometryAttributeChanged();
     return;
   }
diff --git a/third_party/blink/renderer/core/svg/svg_poly_element.h b/third_party/blink/renderer/core/svg/svg_poly_element.h
index 37c6613..87a146c 100644
--- a/third_party/blink/renderer/core/svg/svg_poly_element.h
+++ b/third_party/blink/renderer/core/svg/svg_poly_element.h
@@ -50,8 +50,8 @@
 };
 
 inline bool IsSVGPolyElement(const SVGElement& element) {
-  return element.HasTagName(SVGNames::polygonTag) ||
-         element.HasTagName(SVGNames::polylineTag);
+  return element.HasTagName(svg_names::kPolygonTag) ||
+         element.HasTagName(svg_names::kPolylineTag);
 }
 
 DEFINE_SVGELEMENT_TYPE_CASTS_WITH_FUNCTION(SVGPolyElement);
diff --git a/third_party/blink/renderer/core/svg/svg_polygon_element.cc b/third_party/blink/renderer/core/svg/svg_polygon_element.cc
index b2ba991e..4149711 100644
--- a/third_party/blink/renderer/core/svg/svg_polygon_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_polygon_element.cc
@@ -25,7 +25,7 @@
 namespace blink {
 
 inline SVGPolygonElement::SVGPolygonElement(Document& document)
-    : SVGPolyElement(SVGNames::polygonTag, document) {}
+    : SVGPolyElement(svg_names::kPolygonTag, document) {}
 
 DEFINE_NODE_FACTORY(SVGPolygonElement)
 
diff --git a/third_party/blink/renderer/core/svg/svg_polyline_element.cc b/third_party/blink/renderer/core/svg/svg_polyline_element.cc
index 5e355c9b..1d2b1f1 100644
--- a/third_party/blink/renderer/core/svg/svg_polyline_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_polyline_element.cc
@@ -25,7 +25,7 @@
 namespace blink {
 
 SVGPolylineElement::SVGPolylineElement(Document& document)
-    : SVGPolyElement(SVGNames::polylineTag, document) {}
+    : SVGPolyElement(svg_names::kPolylineTag, document) {}
 
 DEFINE_NODE_FACTORY(SVGPolylineElement)
 
diff --git a/third_party/blink/renderer/core/svg/svg_radial_gradient_element.cc b/third_party/blink/renderer/core/svg/svg_radial_gradient_element.cc
index c855caf..078685d 100644
--- a/third_party/blink/renderer/core/svg/svg_radial_gradient_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_radial_gradient_element.cc
@@ -29,33 +29,33 @@
 namespace blink {
 
 inline SVGRadialGradientElement::SVGRadialGradientElement(Document& document)
-    : SVGGradientElement(SVGNames::radialGradientTag, document),
+    : SVGGradientElement(svg_names::kRadialGradientTag, document),
       // Spec: If the cx/cy/r attribute is not specified, the effect is as if a
       // value of "50%" were specified.
       cx_(SVGAnimatedLength::Create(this,
-                                    SVGNames::cxAttr,
+                                    svg_names::kCxAttr,
                                     SVGLengthMode::kWidth,
                                     SVGLength::Initial::kPercent50)),
       cy_(SVGAnimatedLength::Create(this,
-                                    SVGNames::cyAttr,
+                                    svg_names::kCyAttr,
                                     SVGLengthMode::kHeight,
                                     SVGLength::Initial::kPercent50)),
       r_(SVGAnimatedLength::Create(this,
-                                   SVGNames::rAttr,
+                                   svg_names::kRAttr,
                                    SVGLengthMode::kOther,
                                    SVGLength::Initial::kPercent50)),
       fx_(SVGAnimatedLength::Create(this,
-                                    SVGNames::fxAttr,
+                                    svg_names::kFxAttr,
                                     SVGLengthMode::kWidth,
                                     SVGLength::Initial::kPercent50)),
       fy_(SVGAnimatedLength::Create(this,
-                                    SVGNames::fyAttr,
+                                    svg_names::kFyAttr,
                                     SVGLengthMode::kHeight,
                                     SVGLength::Initial::kPercent50)),
       // SVG2-Draft Spec: If the fr attribute is not specified, the effect is as
       // if a value of "0%" were specified.
       fr_(SVGAnimatedLength::Create(this,
-                                    SVGNames::frAttr,
+                                    svg_names::kFrAttr,
                                     SVGLengthMode::kOther,
                                     SVGLength::Initial::kPercent0)) {
   AddToPropertyMap(cx_);
@@ -80,9 +80,9 @@
 
 void SVGRadialGradientElement::SvgAttributeChanged(
     const QualifiedName& attr_name) {
-  if (attr_name == SVGNames::cxAttr || attr_name == SVGNames::cyAttr ||
-      attr_name == SVGNames::fxAttr || attr_name == SVGNames::fyAttr ||
-      attr_name == SVGNames::rAttr || attr_name == SVGNames::frAttr) {
+  if (attr_name == svg_names::kCxAttr || attr_name == svg_names::kCyAttr ||
+      attr_name == svg_names::kFxAttr || attr_name == svg_names::kFyAttr ||
+      attr_name == svg_names::kRAttr || attr_name == svg_names::kFrAttr) {
     SVGElement::InvalidationGuard invalidation_guard(this);
     UpdateRelativeLengthsInformation();
     InvalidateGradient(LayoutInvalidationReason::kAttributeChanged);
diff --git a/third_party/blink/renderer/core/svg/svg_rect_element.cc b/third_party/blink/renderer/core/svg/svg_rect_element.cc
index ed62484..9bfa867 100644
--- a/third_party/blink/renderer/core/svg/svg_rect_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_rect_element.cc
@@ -26,34 +26,34 @@
 namespace blink {
 
 inline SVGRectElement::SVGRectElement(Document& document)
-    : SVGGeometryElement(SVGNames::rectTag, document),
+    : SVGGeometryElement(svg_names::kRectTag, document),
       x_(SVGAnimatedLength::Create(this,
-                                   SVGNames::xAttr,
+                                   svg_names::kXAttr,
                                    SVGLengthMode::kWidth,
                                    SVGLength::Initial::kUnitlessZero,
                                    CSSPropertyX)),
       y_(SVGAnimatedLength::Create(this,
-                                   SVGNames::yAttr,
+                                   svg_names::kYAttr,
                                    SVGLengthMode::kHeight,
                                    SVGLength::Initial::kUnitlessZero,
                                    CSSPropertyY)),
       width_(SVGAnimatedLength::Create(this,
-                                       SVGNames::widthAttr,
+                                       svg_names::kWidthAttr,
                                        SVGLengthMode::kWidth,
                                        SVGLength::Initial::kUnitlessZero,
                                        CSSPropertyWidth)),
       height_(SVGAnimatedLength::Create(this,
-                                        SVGNames::heightAttr,
+                                        svg_names::kHeightAttr,
                                         SVGLengthMode::kHeight,
                                         SVGLength::Initial::kUnitlessZero,
                                         CSSPropertyHeight)),
       rx_(SVGAnimatedLength::Create(this,
-                                    SVGNames::rxAttr,
+                                    svg_names::kRxAttr,
                                     SVGLengthMode::kWidth,
                                     SVGLength::Initial::kUnitlessZero,
                                     CSSPropertyRx)),
       ry_(SVGAnimatedLength::Create(this,
-                                    SVGNames::ryAttr,
+                                    svg_names::kRyAttr,
                                     SVGLengthMode::kHeight,
                                     SVGLength::Initial::kUnitlessZero,
                                     CSSPropertyRy)) {
@@ -139,9 +139,10 @@
 }
 
 void SVGRectElement::SvgAttributeChanged(const QualifiedName& attr_name) {
-  if (attr_name == SVGNames::xAttr || attr_name == SVGNames::yAttr ||
-      attr_name == SVGNames::widthAttr || attr_name == SVGNames::heightAttr ||
-      attr_name == SVGNames::rxAttr || attr_name == SVGNames::ryAttr) {
+  if (attr_name == svg_names::kXAttr || attr_name == svg_names::kYAttr ||
+      attr_name == svg_names::kWidthAttr ||
+      attr_name == svg_names::kHeightAttr || attr_name == svg_names::kRxAttr ||
+      attr_name == svg_names::kRyAttr) {
     UpdateRelativeLengthsInformation();
     GeometryPresentationAttributeChanged(attr_name);
     return;
diff --git a/third_party/blink/renderer/core/svg/svg_script_element.cc b/third_party/blink/renderer/core/svg/svg_script_element.cc
index f7f14a35..1385322 100644
--- a/third_party/blink/renderer/core/svg/svg_script_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_script_element.cc
@@ -35,7 +35,7 @@
 
 inline SVGScriptElement::SVGScriptElement(Document& document,
                                           const CreateElementFlags flags)
-    : SVGElement(SVGNames::scriptTag, document),
+    : SVGElement(svg_names::kScriptTag, document),
       SVGURIReference(this),
       loader_(InitializeScriptLoader(flags.IsCreatedByParser(),
                                      flags.WasAlreadyStarted())) {}
@@ -109,7 +109,7 @@
 }
 
 String SVGScriptElement::TypeAttributeValue() const {
-  return getAttribute(SVGNames::typeAttr).GetString();
+  return getAttribute(svg_names::kTypeAttr).GetString();
 }
 
 String SVGScriptElement::TextFromChildren() {
@@ -172,7 +172,7 @@
 
 #if DCHECK_IS_ON()
 bool SVGScriptElement::IsAnimatableAttribute(const QualifiedName& name) const {
-  if (name == SVGNames::typeAttr || name == SVGNames::hrefAttr ||
+  if (name == svg_names::kTypeAttr || name == svg_names::kHrefAttr ||
       name == xlink_names::kHrefAttr)
     return false;
   return SVGElement::IsAnimatableAttribute(name);
diff --git a/third_party/blink/renderer/core/svg/svg_set_element.cc b/third_party/blink/renderer/core/svg/svg_set_element.cc
index 9d5836e..8d889daf 100644
--- a/third_party/blink/renderer/core/svg/svg_set_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_set_element.cc
@@ -25,7 +25,7 @@
 namespace blink {
 
 inline SVGSetElement::SVGSetElement(Document& document)
-    : SVGAnimateElement(SVGNames::setTag, document) {
+    : SVGAnimateElement(svg_names::kSetTag, document) {
   SetAnimationMode(kToAnimation);
 }
 
diff --git a/third_party/blink/renderer/core/svg/svg_stop_element.cc b/third_party/blink/renderer/core/svg/svg_stop_element.cc
index 214b3359f..0aaaaa2e 100644
--- a/third_party/blink/renderer/core/svg/svg_stop_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_stop_element.cc
@@ -26,9 +26,9 @@
 namespace blink {
 
 inline SVGStopElement::SVGStopElement(Document& document)
-    : SVGElement(SVGNames::stopTag, document),
+    : SVGElement(svg_names::kStopTag, document),
       offset_(SVGAnimatedNumber::Create(this,
-                                        SVGNames::offsetAttr,
+                                        svg_names::kOffsetAttr,
                                         SVGNumberAcceptPercentage::Create())) {
   AddToPropertyMap(offset_);
 
@@ -57,7 +57,7 @@
 }  // namespace
 
 void SVGStopElement::SvgAttributeChanged(const QualifiedName& attr_name) {
-  if (attr_name == SVGNames::offsetAttr) {
+  if (attr_name == svg_names::kOffsetAttr) {
     InvalidateInstancesAndAncestorResources(this);
     return;
   }
diff --git a/third_party/blink/renderer/core/svg/svg_style_element.cc b/third_party/blink/renderer/core/svg/svg_style_element.cc
index 1559d25..26f1ee3 100644
--- a/third_party/blink/renderer/core/svg/svg_style_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_style_element.cc
@@ -32,7 +32,7 @@
 
 inline SVGStyleElement::SVGStyleElement(Document& document,
                                         const CreateElementFlags flags)
-    : SVGElement(SVGNames::styleTag, document),
+    : SVGElement(svg_names::kStyleTag, document),
       StyleElement(&document, flags.IsCreatedByParser()) {}
 
 SVGStyleElement::~SVGStyleElement() = default;
@@ -56,34 +56,34 @@
 
 const AtomicString& SVGStyleElement::type() const {
   DEFINE_STATIC_LOCAL(const AtomicString, default_value, ("text/css"));
-  const AtomicString& n = getAttribute(SVGNames::typeAttr);
+  const AtomicString& n = getAttribute(svg_names::kTypeAttr);
   return n.IsNull() ? default_value : n;
 }
 
 void SVGStyleElement::setType(const AtomicString& type) {
-  setAttribute(SVGNames::typeAttr, type);
+  setAttribute(svg_names::kTypeAttr, type);
 }
 
 const AtomicString& SVGStyleElement::media() const {
-  const AtomicString& n = FastGetAttribute(SVGNames::mediaAttr);
+  const AtomicString& n = FastGetAttribute(svg_names::kMediaAttr);
   return n.IsNull() ? media_type_names::kAll : n;
 }
 
 void SVGStyleElement::setMedia(const AtomicString& media) {
-  setAttribute(SVGNames::mediaAttr, media);
+  setAttribute(svg_names::kMediaAttr, media);
 }
 
 String SVGStyleElement::title() const {
-  return FastGetAttribute(SVGNames::titleAttr);
+  return FastGetAttribute(svg_names::kTitleAttr);
 }
 
 void SVGStyleElement::setTitle(const AtomicString& title) {
-  setAttribute(SVGNames::titleAttr, title);
+  setAttribute(svg_names::kTitleAttr, title);
 }
 
 void SVGStyleElement::ParseAttribute(
     const AttributeModificationParams& params) {
-  if (params.name == SVGNames::titleAttr) {
+  if (params.name == svg_names::kTitleAttr) {
     if (sheet_ && IsInDocumentTree())
       sheet_->SetTitle(params.new_value);
 
diff --git a/third_party/blink/renderer/core/svg/svg_svg_element.cc b/third_party/blink/renderer/core/svg/svg_svg_element.cc
index 35f22ba..0d20b407 100644
--- a/third_party/blink/renderer/core/svg/svg_svg_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_svg_element.cc
@@ -62,25 +62,25 @@
 namespace blink {
 
 inline SVGSVGElement::SVGSVGElement(Document& doc)
-    : SVGGraphicsElement(SVGNames::svgTag, doc),
+    : SVGGraphicsElement(svg_names::kSVGTag, doc),
       SVGFitToViewBox(this),
       x_(SVGAnimatedLength::Create(this,
-                                   SVGNames::xAttr,
+                                   svg_names::kXAttr,
                                    SVGLengthMode::kWidth,
                                    SVGLength::Initial::kUnitlessZero,
                                    CSSPropertyX)),
       y_(SVGAnimatedLength::Create(this,
-                                   SVGNames::yAttr,
+                                   svg_names::kYAttr,
                                    SVGLengthMode::kHeight,
                                    SVGLength::Initial::kUnitlessZero,
                                    CSSPropertyY)),
       width_(SVGAnimatedLength::Create(this,
-                                       SVGNames::widthAttr,
+                                       svg_names::kWidthAttr,
                                        SVGLengthMode::kWidth,
                                        SVGLength::Initial::kPercent100,
                                        CSSPropertyWidth)),
       height_(SVGAnimatedLength::Create(this,
-                                        SVGNames::heightAttr,
+                                        svg_names::kHeightAttr,
                                         SVGLengthMode::kHeight,
                                         SVGLength::Initial::kPercent100,
                                         CSSPropertyHeight)),
@@ -197,7 +197,7 @@
 }
 
 bool SVGSVGElement::IsPresentationAttribute(const QualifiedName& name) const {
-  if ((name == SVGNames::widthAttr || name == SVGNames::heightAttr) &&
+  if ((name == svg_names::kWidthAttr || name == svg_names::kHeightAttr) &&
       !IsOutermostSVGSVGElement())
     return false;
   return SVGGraphicsElement::IsPresentationAttribute(name);
@@ -205,7 +205,7 @@
 
 bool SVGSVGElement::IsPresentationAttributeWithSVGDOM(
     const QualifiedName& attr_name) const {
-  if (attr_name == SVGNames::widthAttr || attr_name == SVGNames::heightAttr)
+  if (attr_name == svg_names::kWidthAttr || attr_name == svg_names::kHeightAttr)
     return false;
   return SVGGraphicsElement::IsPresentationAttributeWithSVGDOM(attr_name);
 }
@@ -239,9 +239,9 @@
 void SVGSVGElement::SvgAttributeChanged(const QualifiedName& attr_name) {
   bool update_relative_lengths_or_view_box = false;
   bool width_or_height_changed =
-      attr_name == SVGNames::widthAttr || attr_name == SVGNames::heightAttr;
-  if (width_or_height_changed || attr_name == SVGNames::xAttr ||
-      attr_name == SVGNames::yAttr) {
+      attr_name == svg_names::kWidthAttr || attr_name == svg_names::kHeightAttr;
+  if (width_or_height_changed || attr_name == svg_names::kXAttr ||
+      attr_name == svg_names::kYAttr) {
     update_relative_lengths_or_view_box = true;
     UpdateRelativeLengthsInformation();
     InvalidateRelativeLengthClients();
@@ -275,7 +275,7 @@
     InvalidateRelativeLengthClients();
     if (LayoutObject* object = GetLayoutObject()) {
       object->SetNeedsTransformUpdate();
-      if (attr_name == SVGNames::viewBoxAttr && object->IsSVGRoot())
+      if (attr_name == svg_names::kViewBoxAttr && object->IsSVGRoot())
         ToLayoutSVGRoot(object)->IntrinsicSizingInfoChanged();
     }
   }
diff --git a/third_party/blink/renderer/core/svg/svg_switch_element.cc b/third_party/blink/renderer/core/svg/svg_switch_element.cc
index 4612379..7b516fc 100644
--- a/third_party/blink/renderer/core/svg/svg_switch_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_switch_element.cc
@@ -27,7 +27,7 @@
 namespace blink {
 
 inline SVGSwitchElement::SVGSwitchElement(Document& document)
-    : SVGGraphicsElement(SVGNames::switchTag, document) {
+    : SVGGraphicsElement(svg_names::kSwitchTag, document) {
   UseCounter::Count(document, WebFeature::kSVGSwitchElement);
 }
 
diff --git a/third_party/blink/renderer/core/svg/svg_symbol_element.cc b/third_party/blink/renderer/core/svg/svg_symbol_element.cc
index 3e6fd01..d13c35e 100644
--- a/third_party/blink/renderer/core/svg/svg_symbol_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_symbol_element.cc
@@ -26,7 +26,7 @@
 namespace blink {
 
 inline SVGSymbolElement::SVGSymbolElement(Document& document)
-    : SVGElement(SVGNames::symbolTag, document), SVGFitToViewBox(this) {}
+    : SVGElement(svg_names::kSymbolTag, document), SVGFitToViewBox(this) {}
 
 void SVGSymbolElement::Trace(blink::Visitor* visitor) {
   SVGElement::Trace(visitor);
diff --git a/third_party/blink/renderer/core/svg/svg_tests.cc b/third_party/blink/renderer/core/svg/svg_tests.cc
index ca20e917..dbbc2e9 100644
--- a/third_party/blink/renderer/core/svg/svg_tests.cc
+++ b/third_party/blink/renderer/core/svg/svg_tests.cc
@@ -32,10 +32,10 @@
 SVGTests::SVGTests(SVGElement* context_element)
     : required_extensions_(
           SVGStaticStringList::Create<' '>(context_element,
-                                           SVGNames::requiredExtensionsAttr)),
+                                           svg_names::kRequiredExtensionsAttr)),
       system_language_(
           SVGStaticStringList::Create<','>(context_element,
-                                           SVGNames::systemLanguageAttr)) {
+                                           svg_names::kSystemLanguageAttr)) {
   DCHECK(context_element);
 
   context_element->AddToPropertyMap(required_extensions_);
@@ -98,8 +98,8 @@
 }
 
 bool SVGTests::IsKnownAttribute(const QualifiedName& attr_name) {
-  return attr_name == SVGNames::requiredExtensionsAttr ||
-         attr_name == SVGNames::systemLanguageAttr;
+  return attr_name == svg_names::kRequiredExtensionsAttr ||
+         attr_name == svg_names::kSystemLanguageAttr;
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/svg/svg_text_content_element.cc b/third_party/blink/renderer/core/svg/svg_text_content_element.cc
index eaea8d68..dffac79 100644
--- a/third_party/blink/renderer/core/svg/svg_text_content_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_text_content_element.cc
@@ -71,7 +71,7 @@
  private:
   SVGAnimatedTextLength(SVGTextContentElement* context_element)
       : SVGAnimatedLength(context_element,
-                          SVGNames::textLengthAttr,
+                          svg_names::kTextLengthAttr,
                           SVGLengthMode::kWidth,
                           SVGLength::Initial::kUnitlessZero) {}
 };
@@ -83,7 +83,7 @@
       text_length_is_specified_by_user_(false),
       length_adjust_(SVGAnimatedEnumeration<SVGLengthAdjustType>::Create(
           this,
-          SVGNames::lengthAdjustAttr,
+          svg_names::kLengthAdjustAttr,
           kSVGLengthAdjustSpacing)) {
   AddToPropertyMap(text_length_);
   AddToPropertyMap(length_adjust_);
@@ -254,11 +254,11 @@
 
 void SVGTextContentElement::SvgAttributeChanged(
     const QualifiedName& attr_name) {
-  if (attr_name == SVGNames::textLengthAttr)
+  if (attr_name == svg_names::kTextLengthAttr)
     text_length_is_specified_by_user_ = true;
 
-  if (attr_name == SVGNames::textLengthAttr ||
-      attr_name == SVGNames::lengthAdjustAttr ||
+  if (attr_name == svg_names::kTextLengthAttr ||
+      attr_name == svg_names::kLengthAdjustAttr ||
       attr_name == xml_names::kSpaceAttr) {
     SVGElement::InvalidationGuard invalidation_guard(this);
 
diff --git a/third_party/blink/renderer/core/svg/svg_text_element.cc b/third_party/blink/renderer/core/svg/svg_text_element.cc
index 49862d0..2a034fd29 100644
--- a/third_party/blink/renderer/core/svg/svg_text_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_text_element.cc
@@ -25,7 +25,7 @@
 namespace blink {
 
 inline SVGTextElement::SVGTextElement(Document& doc)
-    : SVGTextPositioningElement(SVGNames::textTag, doc) {}
+    : SVGTextPositioningElement(svg_names::kTextTag, doc) {}
 
 DEFINE_NODE_FACTORY(SVGTextElement)
 
diff --git a/third_party/blink/renderer/core/svg/svg_text_path_element.cc b/third_party/blink/renderer/core/svg/svg_text_path_element.cc
index e0c5228c..5bcf33c 100644
--- a/third_party/blink/renderer/core/svg/svg_text_path_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_text_path_element.cc
@@ -48,20 +48,20 @@
 }
 
 inline SVGTextPathElement::SVGTextPathElement(Document& document)
-    : SVGTextContentElement(SVGNames::textPathTag, document),
+    : SVGTextContentElement(svg_names::kTextPathTag, document),
       SVGURIReference(this),
       start_offset_(
           SVGAnimatedLength::Create(this,
-                                    SVGNames::startOffsetAttr,
+                                    svg_names::kStartOffsetAttr,
                                     SVGLengthMode::kWidth,
                                     SVGLength::Initial::kUnitlessZero)),
       method_(SVGAnimatedEnumeration<SVGTextPathMethodType>::Create(
           this,
-          SVGNames::methodAttr,
+          svg_names::kMethodAttr,
           kSVGTextPathMethodAlign)),
       spacing_(SVGAnimatedEnumeration<SVGTextPathSpacingType>::Create(
           this,
-          SVGNames::spacingAttr,
+          svg_names::kSpacingAttr,
           kSVGTextPathSpacingExact)) {
   AddToPropertyMap(start_offset_);
   AddToPropertyMap(method_);
@@ -93,11 +93,12 @@
     return;
   }
 
-  if (attr_name == SVGNames::startOffsetAttr)
+  if (attr_name == svg_names::kStartOffsetAttr)
     UpdateRelativeLengthsInformation();
 
-  if (attr_name == SVGNames::startOffsetAttr ||
-      attr_name == SVGNames::methodAttr || attr_name == SVGNames::spacingAttr) {
+  if (attr_name == svg_names::kStartOffsetAttr ||
+      attr_name == svg_names::kMethodAttr ||
+      attr_name == svg_names::kSpacingAttr) {
     SVGElement::InvalidationGuard invalidation_guard(this);
     if (LayoutObject* object = GetLayoutObject())
       MarkForLayoutAndParentResourceInvalidation(*object);
diff --git a/third_party/blink/renderer/core/svg/svg_text_positioning_element.cc b/third_party/blink/renderer/core/svg/svg_text_positioning_element.cc
index d529137..1d41c7a2 100644
--- a/third_party/blink/renderer/core/svg/svg_text_positioning_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_text_positioning_element.cc
@@ -33,21 +33,21 @@
     : SVGTextContentElement(tag_name, document),
       x_(SVGAnimatedLengthList::Create(
           this,
-          SVGNames::xAttr,
+          svg_names::kXAttr,
           SVGLengthList::Create(SVGLengthMode::kWidth))),
       y_(SVGAnimatedLengthList::Create(
           this,
-          SVGNames::yAttr,
+          svg_names::kYAttr,
           SVGLengthList::Create(SVGLengthMode::kHeight))),
       dx_(SVGAnimatedLengthList::Create(
           this,
-          SVGNames::dxAttr,
+          svg_names::kDxAttr,
           SVGLengthList::Create(SVGLengthMode::kWidth))),
       dy_(SVGAnimatedLengthList::Create(
           this,
-          SVGNames::dyAttr,
+          svg_names::kDyAttr,
           SVGLengthList::Create(SVGLengthMode::kHeight))),
-      rotate_(SVGAnimatedNumberList::Create(this, SVGNames::rotateAttr)) {
+      rotate_(SVGAnimatedNumberList::Create(this, svg_names::kRotateAttr)) {
   AddToPropertyMap(x_);
   AddToPropertyMap(y_);
   AddToPropertyMap(dx_);
@@ -67,13 +67,13 @@
 void SVGTextPositioningElement::SvgAttributeChanged(
     const QualifiedName& attr_name) {
   bool update_relative_lengths =
-      attr_name == SVGNames::xAttr || attr_name == SVGNames::yAttr ||
-      attr_name == SVGNames::dxAttr || attr_name == SVGNames::dyAttr;
+      attr_name == svg_names::kXAttr || attr_name == svg_names::kYAttr ||
+      attr_name == svg_names::kDxAttr || attr_name == svg_names::kDyAttr;
 
   if (update_relative_lengths)
     UpdateRelativeLengthsInformation();
 
-  if (update_relative_lengths || attr_name == SVGNames::rotateAttr) {
+  if (update_relative_lengths || attr_name == svg_names::kRotateAttr) {
     SVGElement::InvalidationGuard invalidation_guard(this);
 
     LayoutObject* layout_object = GetLayoutObject();
diff --git a/third_party/blink/renderer/core/svg/svg_title_element.cc b/third_party/blink/renderer/core/svg/svg_title_element.cc
index c98d0599b..8609f51d 100644
--- a/third_party/blink/renderer/core/svg/svg_title_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_title_element.cc
@@ -29,7 +29,7 @@
 namespace blink {
 
 inline SVGTitleElement::SVGTitleElement(Document& document)
-    : SVGElement(SVGNames::titleTag, document),
+    : SVGElement(svg_names::kTitleTag, document),
       ignore_title_updates_when_children_change_(false) {}
 
 DEFINE_NODE_FACTORY(SVGTitleElement)
diff --git a/third_party/blink/renderer/core/svg/svg_tspan_element.cc b/third_party/blink/renderer/core/svg/svg_tspan_element.cc
index 1bc48d8..7b6047f 100644
--- a/third_party/blink/renderer/core/svg/svg_tspan_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_tspan_element.cc
@@ -26,7 +26,7 @@
 namespace blink {
 
 inline SVGTSpanElement::SVGTSpanElement(Document& document)
-    : SVGTextPositioningElement(SVGNames::tspanTag, document) {}
+    : SVGTextPositioningElement(svg_names::kTSpanTag, document) {}
 
 DEFINE_NODE_FACTORY(SVGTSpanElement)
 
diff --git a/third_party/blink/renderer/core/svg/svg_uri_reference.cc b/third_party/blink/renderer/core/svg/svg_uri_reference.cc
index dda7577..bce67926 100644
--- a/third_party/blink/renderer/core/svg/svg_uri_reference.cc
+++ b/third_party/blink/renderer/core/svg/svg_uri_reference.cc
@@ -61,8 +61,8 @@
 
 const AtomicString& SVGURIReference::LegacyHrefString(
     const SVGElement& element) {
-  if (element.hasAttribute(SVGNames::hrefAttr))
-    return element.getAttribute(SVGNames::hrefAttr);
+  if (element.hasAttribute(svg_names::kHrefAttr))
+    return element.getAttribute(svg_names::kHrefAttr);
   return element.getAttribute(xlink_names::kHrefAttr);
 }
 
diff --git a/third_party/blink/renderer/core/svg/svg_use_element.cc b/third_party/blink/renderer/core/svg/svg_use_element.cc
index ca331d88..193c9356 100644
--- a/third_party/blink/renderer/core/svg/svg_use_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_use_element.cc
@@ -49,24 +49,24 @@
 namespace blink {
 
 inline SVGUseElement::SVGUseElement(Document& document)
-    : SVGGraphicsElement(SVGNames::useTag, document),
+    : SVGGraphicsElement(svg_names::kUseTag, document),
       SVGURIReference(this),
       x_(SVGAnimatedLength::Create(this,
-                                   SVGNames::xAttr,
+                                   svg_names::kXAttr,
                                    SVGLengthMode::kWidth,
                                    SVGLength::Initial::kUnitlessZero,
                                    CSSPropertyX)),
       y_(SVGAnimatedLength::Create(this,
-                                   SVGNames::yAttr,
+                                   svg_names::kYAttr,
                                    SVGLengthMode::kHeight,
                                    SVGLength::Initial::kUnitlessZero,
                                    CSSPropertyY)),
       width_(SVGAnimatedLength::Create(this,
-                                       SVGNames::widthAttr,
+                                       svg_names::kWidthAttr,
                                        SVGLengthMode::kWidth,
                                        SVGLength::Initial::kUnitlessZero)),
       height_(SVGAnimatedLength::Create(this,
-                                        SVGNames::heightAttr,
+                                        svg_names::kHeightAttr,
                                         SVGLengthMode::kHeight,
                                         SVGLength::Initial::kUnitlessZero)),
       element_url_is_local_(true),
@@ -150,12 +150,12 @@
     // width and/or height are not specified, the generated 'svg' element
     // will use values of 100% for these attributes.
     shadow_element.setAttribute(
-        SVGNames::widthAttr,
+        svg_names::kWidthAttr,
         use.width()->IsSpecified()
             ? AtomicString(use.width()->CurrentValue()->ValueAsString())
             : hundred_percent_string);
     shadow_element.setAttribute(
-        SVGNames::heightAttr,
+        svg_names::kHeightAttr,
         use.height()->IsSpecified()
             ? AtomicString(use.height()->CurrentValue()->ValueAsString())
             : hundred_percent_string);
@@ -164,15 +164,15 @@
     // provided on the 'use' element, then these values will override the
     // corresponding attributes on the 'svg' in the generated tree.
     shadow_element.setAttribute(
-        SVGNames::widthAttr,
+        svg_names::kWidthAttr,
         use.width()->IsSpecified()
             ? AtomicString(use.width()->CurrentValue()->ValueAsString())
-            : original_element.getAttribute(SVGNames::widthAttr));
+            : original_element.getAttribute(svg_names::kWidthAttr));
     shadow_element.setAttribute(
-        SVGNames::heightAttr,
+        svg_names::kHeightAttr,
         use.height()->IsSpecified()
             ? AtomicString(use.height()->CurrentValue()->ValueAsString())
-            : original_element.getAttribute(SVGNames::heightAttr));
+            : original_element.getAttribute(svg_names::kHeightAttr));
   }
 }
 
@@ -220,11 +220,12 @@
 }
 
 void SVGUseElement::SvgAttributeChanged(const QualifiedName& attr_name) {
-  if (attr_name == SVGNames::xAttr || attr_name == SVGNames::yAttr ||
-      attr_name == SVGNames::widthAttr || attr_name == SVGNames::heightAttr) {
+  if (attr_name == svg_names::kXAttr || attr_name == svg_names::kYAttr ||
+      attr_name == svg_names::kWidthAttr ||
+      attr_name == svg_names::kHeightAttr) {
     SVGElement::InvalidationGuard invalidation_guard(this);
 
-    if (attr_name == SVGNames::xAttr || attr_name == SVGNames::yAttr) {
+    if (attr_name == svg_names::kXAttr || attr_name == svg_names::kYAttr) {
       InvalidateSVGPresentationAttributeStyle();
       SetNeedsStyleRecalc(
           kLocalStyleChange,
@@ -264,17 +265,19 @@
   if (!element.IsSVGElement())
     return true;
 
-  DEFINE_STATIC_LOCAL(
-      HashSet<QualifiedName>, allowed_element_tags,
-      ({
-          SVGNames::aTag,       SVGNames::circleTag,   SVGNames::descTag,
-          SVGNames::ellipseTag, SVGNames::gTag,        SVGNames::imageTag,
-          SVGNames::lineTag,    SVGNames::metadataTag, SVGNames::pathTag,
-          SVGNames::polygonTag, SVGNames::polylineTag, SVGNames::rectTag,
-          SVGNames::svgTag,     SVGNames::switchTag,   SVGNames::symbolTag,
-          SVGNames::textTag,    SVGNames::textPathTag, SVGNames::titleTag,
-          SVGNames::tspanTag,   SVGNames::useTag,
-      }));
+  DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, allowed_element_tags,
+                      ({
+                          svg_names::kATag,        svg_names::kCircleTag,
+                          svg_names::kDescTag,     svg_names::kEllipseTag,
+                          svg_names::kGTag,        svg_names::kImageTag,
+                          svg_names::kLineTag,     svg_names::kMetadataTag,
+                          svg_names::kPathTag,     svg_names::kPolygonTag,
+                          svg_names::kPolylineTag, svg_names::kRectTag,
+                          svg_names::kSVGTag,      svg_names::kSwitchTag,
+                          svg_names::kSymbolTag,   svg_names::kTextTag,
+                          svg_names::kTextPathTag, svg_names::kTitleTag,
+                          svg_names::kTSpanTag,    svg_names::kUseTag,
+                      }));
   return !allowed_element_tags.Contains<SVGAttributeHashTranslator>(
       element.TagQName());
 }
@@ -577,11 +580,11 @@
 // xlink:href are transferred to the generated 'g' element.
 static void RemoveAttributesFromReplacementElement(
     SVGElement& replacement_element) {
-  replacement_element.removeAttribute(SVGNames::xAttr);
-  replacement_element.removeAttribute(SVGNames::yAttr);
-  replacement_element.removeAttribute(SVGNames::widthAttr);
-  replacement_element.removeAttribute(SVGNames::heightAttr);
-  replacement_element.removeAttribute(SVGNames::hrefAttr);
+  replacement_element.removeAttribute(svg_names::kXAttr);
+  replacement_element.removeAttribute(svg_names::kYAttr);
+  replacement_element.removeAttribute(svg_names::kWidthAttr);
+  replacement_element.removeAttribute(svg_names::kHeightAttr);
+  replacement_element.removeAttribute(svg_names::kHrefAttr);
   replacement_element.removeAttribute(xlink_names::kHrefAttr);
 }
 
diff --git a/third_party/blink/renderer/core/svg/svg_view_element.cc b/third_party/blink/renderer/core/svg/svg_view_element.cc
index 0b75e9a..3406b2b 100644
--- a/third_party/blink/renderer/core/svg/svg_view_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_view_element.cc
@@ -26,7 +26,7 @@
 namespace blink {
 
 inline SVGViewElement::SVGViewElement(Document& document)
-    : SVGElement(SVGNames::viewTag, document), SVGFitToViewBox(this) {
+    : SVGElement(svg_names::kViewTag, document), SVGFitToViewBox(this) {
   UseCounter::Count(document, WebFeature::kSVGViewElement);
 }
 
diff --git a/third_party/blink/renderer/core/svg/svg_view_spec.cc b/third_party/blink/renderer/core/svg/svg_view_spec.cc
index 3fff5202..09a9d458 100644
--- a/third_party/blink/renderer/core/svg/svg_view_spec.cc
+++ b/third_party/blink/renderer/core/svg/svg_view_spec.cc
@@ -51,7 +51,7 @@
     view_spec->preserve_aspect_ratio_ =
         view.preserveAspectRatio()->CurrentValue()->Clone();
   }
-  if (view.hasAttribute(SVGNames::zoomAndPanAttr))
+  if (view.hasAttribute(svg_names::kZoomAndPanAttr))
     view_spec->zoom_and_pan_ = view.zoomAndPan();
   return view_spec;
 }
diff --git a/third_party/blink/renderer/core/svg/svg_zoom_and_pan.cc b/third_party/blink/renderer/core/svg/svg_zoom_and_pan.cc
index 5ae806fc..967dff12 100644
--- a/third_party/blink/renderer/core/svg/svg_zoom_and_pan.cc
+++ b/third_party/blink/renderer/core/svg/svg_zoom_and_pan.cc
@@ -28,12 +28,12 @@
 SVGZoomAndPan::SVGZoomAndPan() : zoom_and_pan_(kSVGZoomAndPanMagnify) {}
 
 bool SVGZoomAndPan::IsKnownAttribute(const QualifiedName& attr_name) {
-  return attr_name == SVGNames::zoomAndPanAttr;
+  return attr_name == svg_names::kZoomAndPanAttr;
 }
 
 bool SVGZoomAndPan::ParseAttribute(const QualifiedName& name,
                                    const AtomicString& value) {
-  if (name != SVGNames::zoomAndPanAttr)
+  if (name != svg_names::kZoomAndPanAttr)
     return false;
   zoom_and_pan_ = kSVGZoomAndPanUnknown;
   if (!value.IsEmpty()) {
diff --git a/third_party/blink/renderer/core/svg/unsafe_svg_attribute_sanitization_test.cc b/third_party/blink/renderer/core/svg/unsafe_svg_attribute_sanitization_test.cc
index ab55f3e..b8930eda 100644
--- a/third_party/blink/renderer/core/svg/unsafe_svg_attribute_sanitization_test.cc
+++ b/third_party/blink/renderer/core/svg/unsafe_svg_attribute_sanitization_test.cc
@@ -284,7 +284,7 @@
 
   EXPECT_FALSE(element->AnimatedPropertyTypeSupportsAddition());
 
-  element->SetAttributeName(SVGNames::hrefAttr);
+  element->SetAttributeName(svg_names::kHrefAttr);
 
   // Sanity check that href was identified as a "string" attribute
   EXPECT_EQ(kAnimatedString, element->GetAnimatedPropertyType());
@@ -296,9 +296,9 @@
      stripScriptingAttributes_animateElement) {
   Vector<Attribute> attributes;
   attributes.push_back(Attribute(xlink_names::kHrefAttr, "javascript:alert()"));
-  attributes.push_back(Attribute(SVGNames::hrefAttr, "javascript:alert()"));
-  attributes.push_back(Attribute(SVGNames::fromAttr, "/home"));
-  attributes.push_back(Attribute(SVGNames::toAttr, "javascript:own3d()"));
+  attributes.push_back(Attribute(svg_names::kHrefAttr, "javascript:alert()"));
+  attributes.push_back(Attribute(svg_names::kFromAttr, "/home"));
+  attributes.push_back(Attribute(svg_names::kToAttr, "javascript:own3d()"));
 
   Document* document = Document::CreateForTest();
   Element* element = SVGAnimateElement::Create(*document);
@@ -309,17 +309,17 @@
   EXPECT_EQ(xlink_names::kHrefAttr, attributes[0].GetName())
       << "The 'xlink:href' attribute should not have been stripped from "
          "<animate> because it is not a URL attribute of <animate>.";
-  EXPECT_EQ(SVGNames::hrefAttr, attributes[1].GetName())
+  EXPECT_EQ(svg_names::kHrefAttr, attributes[1].GetName())
       << "The 'href' attribute should not have been stripped from "
          "<animate> because it is not a URL attribute of <animate>.";
-  EXPECT_EQ(SVGNames::fromAttr, attributes[2].GetName())
+  EXPECT_EQ(svg_names::kFromAttr, attributes[2].GetName())
       << "The 'from' attribute should not have been strippef from <animate> "
          "because its value is innocuous.";
 }
 
 TEST(UnsafeSVGAttributeSanitizationTest,
      isJavaScriptURLAttribute_hrefContainingJavascriptURL) {
-  Attribute attribute(SVGNames::hrefAttr, "javascript:alert()");
+  Attribute attribute(svg_names::kHrefAttr, "javascript:alert()");
   Document* document = Document::CreateForTest();
   Element* element = SVGAElement::Create(*document);
   EXPECT_TRUE(element->IsJavaScriptURLAttribute(attribute))
@@ -353,7 +353,7 @@
 
 TEST(UnsafeSVGAttributeSanitizationTest,
      isSVGAnimationAttributeSettingJavaScriptURL_fromContainingJavaScriptURL) {
-  Attribute evil_attribute(SVGNames::fromAttr, "javascript:alert()");
+  Attribute evil_attribute(svg_names::kFromAttr, "javascript:alert()");
   Document* document = Document::CreateForTest();
   Element* element = SVGAnimateElement::Create(*document);
   EXPECT_TRUE(
@@ -364,7 +364,7 @@
 
 TEST(UnsafeSVGAttributeSanitizationTest,
      isSVGAnimationAttributeSettingJavaScriptURL_toContainingJavaScripURL) {
-  Attribute evil_attribute(SVGNames::toAttr, "javascript:window.close()");
+  Attribute evil_attribute(svg_names::kToAttr, "javascript:window.close()");
   Document* document = Document::CreateForTest();
   Element* element = SVGSetElement::Create(*document);
   EXPECT_TRUE(
@@ -376,7 +376,7 @@
 TEST(
     UnsafeSVGAttributeSanitizationTest,
     isSVGAnimationAttributeSettingJavaScriptURL_valuesContainingJavaScriptURL) {
-  Attribute evil_attribute(SVGNames::valuesAttr, "hi!; javascript:confirm()");
+  Attribute evil_attribute(svg_names::kValuesAttr, "hi!; javascript:confirm()");
   Document* document = Document::CreateForTest();
   Element* element = SVGAnimateElement::Create(*document);
   element = SVGAnimateElement::Create(*document);
@@ -388,7 +388,7 @@
 
 TEST(UnsafeSVGAttributeSanitizationTest,
      isSVGAnimationAttributeSettingJavaScriptURL_innocuousAnimationAttribute) {
-  Attribute fine_attribute(SVGNames::fromAttr, "hello, world!");
+  Attribute fine_attribute(svg_names::kFromAttr, "hello, world!");
   Document* document = Document::CreateForTest();
   Element* element = SVGSetElement::Create(*document);
   EXPECT_FALSE(
diff --git a/third_party/blink/renderer/core/testing/internals.cc b/third_party/blink/renderer/core/testing/internals.cc
index a0b0f69a..8e5acb29 100644
--- a/third_party/blink/renderer/core/testing/internals.cc
+++ b/third_party/blink/renderer/core/testing/internals.cc
@@ -1956,14 +1956,14 @@
 }
 
 AtomicString Internals::svgNamespace() {
-  return SVGNames::svgNamespaceURI;
+  return svg_names::kNamespaceURI;
 }
 
 Vector<AtomicString> Internals::svgTags() {
-  Vector<AtomicString> tags(SVGNames::kTagsCount);
+  Vector<AtomicString> tags(svg_names::kTagsCount);
   std::unique_ptr<const SVGQualifiedName* []> qualified_names =
-      SVGNames::GetTags();
-  for (wtf_size_t i = 0; i < SVGNames::kTagsCount; ++i)
+      svg_names::GetTags();
+  for (wtf_size_t i = 0; i < svg_names::kTagsCount; ++i)
     tags[i] = qualified_names[i]->LocalName();
   return tags;
 }
diff --git a/third_party/blink/renderer/core/testing/v8/web_core_test_support.cc b/third_party/blink/renderer/core/testing/v8/web_core_test_support.cc
index 83591801..f8095ce 100644
--- a/third_party/blink/renderer/core/testing/v8/web_core_test_support.cc
+++ b/third_party/blink/renderer/core/testing/v8/web_core_test_support.cc
@@ -38,27 +38,27 @@
 #include "third_party/blink/renderer/platform/bindings/origin_trial_features.h"
 #include "third_party/blink/renderer/platform/bindings/v8_per_context_data.h"
 
-namespace WebCoreTestSupport {
+namespace blink {
+
+namespace web_core_test_support {
 
 namespace {
 
-blink::InstallOriginTrialFeaturesFunction
+InstallOriginTrialFeaturesFunction
     s_original_install_origin_trial_features_function = nullptr;
-blink::InstallPendingOriginTrialFeatureFunction
+InstallPendingOriginTrialFeatureFunction
     s_original_install_pending_origin_trial_feature_function = nullptr;
 
 v8::Local<v8::Value> CreateInternalsObject(v8::Local<v8::Context> context) {
-  blink::ScriptState* script_state = blink::ScriptState::From(context);
+  ScriptState* script_state = ScriptState::From(context);
   v8::Local<v8::Object> global = script_state->GetContext()->Global();
-  blink::ExecutionContext* execution_context =
-      blink::ExecutionContext::From(script_state);
+  ExecutionContext* execution_context = ExecutionContext::From(script_state);
   if (execution_context->IsDocument()) {
-    return blink::ToV8(blink::Internals::Create(execution_context), global,
-                       script_state->GetIsolate());
+    return ToV8(Internals::Create(execution_context), global,
+                script_state->GetIsolate());
   }
   if (execution_context->IsWorkerGlobalScope()) {
-    return blink::ToV8(blink::WorkerInternals::Create(), global,
-                       script_state->GetIsolate());
+    return ToV8(WorkerInternals::Create(), global, script_state->GetIsolate());
   }
   return v8::Local<v8::Value>();
 }
@@ -68,8 +68,8 @@
 void InjectInternalsObject(v8::Local<v8::Context> context) {
   RegisterInstallOriginTrialFeaturesForTesting();
 
-  blink::ScriptState* script_state = blink::ScriptState::From(context);
-  blink::ScriptState::Scope scope(script_state);
+  ScriptState* script_state = ScriptState::From(context);
+  ScriptState::Scope scope(script_state);
   v8::Local<v8::Object> global = script_state->GetContext()->Global();
   v8::Local<v8::Value> internals = CreateInternalsObject(context);
   if (internals.IsEmpty())
@@ -78,31 +78,28 @@
   global
       ->CreateDataProperty(
           script_state->GetContext(),
-          blink::V8AtomicString(script_state->GetIsolate(), "internals"),
-          internals)
+          V8AtomicString(script_state->GetIsolate(), "internals"), internals)
       .ToChecked();
 }
 
 void InstallOriginTrialFeaturesForTesting(
-    const blink::WrapperTypeInfo* type,
-    const blink::ScriptState* script_state,
+    const WrapperTypeInfo* type,
+    const ScriptState* script_state,
     v8::Local<v8::Object> prototype_object,
     v8::Local<v8::Function> interface_object) {
   (*s_original_install_origin_trial_features_function)(
       type, script_state, prototype_object, interface_object);
 
-  blink::ExecutionContext* execution_context =
-      blink::ExecutionContext::From(script_state);
+  ExecutionContext* execution_context = ExecutionContext::From(script_state);
 
-  if (type == &blink::V8OriginTrialsTest::wrapperTypeInfo) {
-    if (blink::OriginTrials::OriginTrialsSampleAPIEnabled(execution_context)) {
-      blink::V8OriginTrialsTest::installOriginTrialsSampleAPI(
+  if (type == &V8OriginTrialsTest::wrapperTypeInfo) {
+    if (OriginTrials::OriginTrialsSampleAPIEnabled(execution_context)) {
+      V8OriginTrialsTest::installOriginTrialsSampleAPI(
           script_state->GetIsolate(), script_state->World(),
           v8::Local<v8::Object>(), prototype_object, interface_object);
     }
-    if (blink::OriginTrials::OriginTrialsSampleAPIImpliedEnabled(
-            execution_context)) {
-      blink::V8OriginTrialsTest::installOriginTrialsSampleAPIImplied(
+    if (OriginTrials::OriginTrialsSampleAPIImpliedEnabled(execution_context)) {
+      V8OriginTrialsTest::installOriginTrialsSampleAPIImplied(
           script_state->GetIsolate(), script_state->World(),
           v8::Local<v8::Object>(), prototype_object, interface_object);
     }
@@ -114,46 +111,45 @@
   if (context.IsEmpty())
     return;
 
-  blink::ScriptState* script_state = blink::ScriptState::From(context);
-  blink::ScriptState::Scope scope(script_state);
-  blink::Document* document =
-      blink::To<blink::Document>(blink::ExecutionContext::From(script_state));
+  ScriptState* script_state = ScriptState::From(context);
+  ScriptState::Scope scope(script_state);
+  Document* document = To<Document>(ExecutionContext::From(script_state));
   DCHECK(document);
-  blink::LocalFrame* frame = document->GetFrame();
+  LocalFrame* frame = document->GetFrame();
   // Should the document have been detached, the page is assumed being destroyed
   // (=> no reset required.)
   if (!frame)
     return;
-  blink::Page* page = frame->GetPage();
+  Page* page = frame->GetPage();
   DCHECK(page);
-  blink::Internals::ResetToConsistentState(page);
-  blink::InternalSettings::From(*page)->ResetToConsistentState();
+  Internals::ResetToConsistentState(page);
+  InternalSettings::From(*page)->ResetToConsistentState();
 }
 
 void InstallPendingOriginTrialFeatureForTesting(
     const String& feature,
-    const blink::ScriptState* script_state) {
+    const ScriptState* script_state) {
   (*s_original_install_pending_origin_trial_feature_function)(feature,
                                                               script_state);
   v8::Local<v8::Object> prototype_object;
   v8::Local<v8::Function> interface_object;
-  if (feature == blink::OriginTrials::kOriginTrialsSampleAPITrialName) {
+  if (feature == OriginTrials::kOriginTrialsSampleAPITrialName) {
     if (script_state->PerContextData()
             ->GetExistingConstructorAndPrototypeForType(
-                &blink::V8OriginTrialsTest::wrapperTypeInfo, &prototype_object,
+                &V8OriginTrialsTest::wrapperTypeInfo, &prototype_object,
                 &interface_object)) {
-      blink::V8OriginTrialsTest::installOriginTrialsSampleAPI(
+      V8OriginTrialsTest::installOriginTrialsSampleAPI(
           script_state->GetIsolate(), script_state->World(),
           v8::Local<v8::Object>(), prototype_object, interface_object);
     }
     return;
   }
-  if (feature == blink::OriginTrials::kOriginTrialsSampleAPIImpliedTrialName) {
+  if (feature == OriginTrials::kOriginTrialsSampleAPIImpliedTrialName) {
     if (script_state->PerContextData()
             ->GetExistingConstructorAndPrototypeForType(
-                &blink::V8OriginTrialsTest::wrapperTypeInfo, &prototype_object,
+                &V8OriginTrialsTest::wrapperTypeInfo, &prototype_object,
                 &interface_object)) {
-      blink::V8OriginTrialsTest::installOriginTrialsSampleAPIImplied(
+      V8OriginTrialsTest::installOriginTrialsSampleAPIImplied(
           script_state->GetIsolate(), script_state->World(),
           v8::Local<v8::Object>(), prototype_object, interface_object);
     }
@@ -174,4 +170,6 @@
   }
 }
 
-}  // namespace WebCoreTestSupport
+}  // namespace web_core_test_support
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/testing/v8/web_core_test_support.h b/third_party/blink/renderer/core/testing/v8/web_core_test_support.h
index 689f77a..8cfa066 100644
--- a/third_party/blink/renderer/core/testing/v8/web_core_test_support.h
+++ b/third_party/blink/renderer/core/testing/v8/web_core_test_support.h
@@ -28,12 +28,16 @@
 
 #include "v8/include/v8.h"
 
-namespace WebCoreTestSupport {
+namespace blink {
+
+namespace web_core_test_support {
 
 void InjectInternalsObject(v8::Local<v8::Context>);
 void ResetInternalsObject(v8::Local<v8::Context>);
 void RegisterInstallOriginTrialFeaturesForTesting();
 
-}  // namespace WebCoreTestSupport
+}  // namespace web_core_test_support
+
+}  // namespace blink
 
 #endif
diff --git a/third_party/blink/renderer/core/xml/parser/xml_errors.cc b/third_party/blink/renderer/core/xml/parser/xml_errors.cc
index 98c610ec5..e9aee86 100644
--- a/third_party/blink/renderer/core/xml/parser/xml_errors.cc
+++ b/third_party/blink/renderer/core/xml/parser/xml_errors.cc
@@ -144,7 +144,7 @@
     root_element->ParserAppendChild(body);
     document_->ParserAppendChild(root_element);
     document_element = body;
-  } else if (document_element->namespaceURI() == SVGNames::svgNamespaceURI) {
+  } else if (document_element->namespaceURI() == svg_names::kNamespaceURI) {
     Element* root_element = document_->CreateRawElement(htmlTag, flags);
     Element* head = document_->CreateRawElement(headTag, flags);
     Element* style = document_->CreateRawElement(styleTag, flags);
diff --git a/third_party/blink/renderer/devtools/front_end/persistence/Automapping.js b/third_party/blink/renderer/devtools/front_end/persistence/Automapping.js
index 68feae27..6a486db 100644
--- a/third_party/blink/renderer/devtools/front_end/persistence/Automapping.js
+++ b/third_party/blink/renderer/devtools/front_end/persistence/Automapping.js
@@ -166,6 +166,8 @@
     if (networkSourceCode[Persistence.Automapping._processingPromise] ||
         networkSourceCode[Persistence.Automapping._status])
       return;
+    if (networkSourceCode.url().startsWith('wasm://'))
+      return;
     const createBindingPromise =
         this._createBinding(networkSourceCode).then(validateStatus.bind(this)).then(onStatus.bind(this));
     networkSourceCode[Persistence.Automapping._processingPromise] = createBindingPromise;
diff --git a/third_party/blink/renderer/devtools/front_end/resources/IndexedDBViews.js b/third_party/blink/renderer/devtools/front_end/resources/IndexedDBViews.js
index 65ec8ed..c102c673 100644
--- a/third_party/blink/renderer/devtools/front_end/resources/IndexedDBViews.js
+++ b/third_party/blink/renderer/devtools/front_end/resources/IndexedDBViews.js
@@ -223,13 +223,9 @@
     this._pageForwardButton.addEventListener(UI.ToolbarButton.Events.Click, this._pageForwardButtonClicked, this);
     editorToolbar.appendToolbarItem(this._pageForwardButton);
 
-    this._keyInputElement = UI.createInput('toolbar-input');
-    editorToolbar.appendToolbarItem(new UI.ToolbarItem(this._keyInputElement));
-    this._keyInputElement.placeholder = Common.UIString('Start from key');
-    this._keyInputElement.addEventListener('paste', this._keyInputChanged.bind(this), false);
-    this._keyInputElement.addEventListener('cut', this._keyInputChanged.bind(this), false);
-    this._keyInputElement.addEventListener('keypress', this._keyInputChanged.bind(this), false);
-    this._keyInputElement.addEventListener('keydown', this._keyInputChanged.bind(this), false);
+    this._keyInput = new UI.ToolbarInput(ls`Start from key`, 0.5);
+    this._keyInput.addEventListener(UI.ToolbarInput.Event.TextChanged, this._updateData.bind(this, false));
+    editorToolbar.appendToolbarItem(this._keyInput);
 
     editorToolbar.appendToolbarItem(this._needsRefresh);
   }
@@ -250,10 +246,6 @@
     this._updateData(false);
   }
 
-  _keyInputChanged() {
-    window.setTimeout(this._updateData.bind(this, false), 0);
-  }
-
   refreshData() {
     this._updateData(true);
   }
@@ -292,7 +284,7 @@
    * @param {boolean} force
    */
   _updateData(force) {
-    const key = this._parseKey(this._keyInputElement.value);
+    const key = this._parseKey(this._keyInput.value());
     const pageSize = this._pageSize;
     let skipCount = this._skipCount;
     let selected = this._dataGrid.selectedNode ? this._dataGrid.selectedNode.data['number'] : 0;
diff --git a/third_party/blink/renderer/modules/accessibility/ax_node_object.cc b/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
index 026de394..ad732b8 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
@@ -3031,7 +3031,7 @@
     }
     DCHECK(GetNode()->IsContainerNode());
     Element* title = ElementTraversal::FirstChild(
-        ToContainerNode(*(GetNode())), HasTagName(SVGNames::titleTag));
+        ToContainerNode(*(GetNode())), HasTagName(svg_names::kTitleTag));
 
     if (title) {
       AXObject* title_ax_object = AXObjectCache().GetOrCreate(title);
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc b/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc
index 297ea67f..682d7a5 100644
--- a/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc
+++ b/third_party/blink/renderer/modules/canvas/canvas2d/base_rendering_context_2d.cc
@@ -1186,76 +1186,7 @@
   if (!DrawingCanvas())
     return;
 
-  TimeTicks start_time;
-  base::Optional<CustomCountHistogram> timer;
-  if (!IsPaint2D()) {
-    start_time = WTF::CurrentTimeTicks();
-    if (CanCreateCanvas2dResourceProvider() && IsAccelerated()) {
-      if (image_source->IsVideoElement()) {
-        DEFINE_THREAD_SAFE_STATIC_LOCAL(
-            CustomCountHistogram, scoped_us_counter_video_gpu,
-            ("Blink.Canvas.DrawImage.Video.GPU", 0, 10000000, 50));
-        timer.emplace(scoped_us_counter_video_gpu);
-      } else if (image_source->IsCanvasElement()) {
-        DEFINE_THREAD_SAFE_STATIC_LOCAL(
-            CustomCountHistogram, scoped_us_counter_canvas_gpu,
-            ("Blink.Canvas.DrawImage.Canvas.GPU", 0, 10000000, 50));
-        timer.emplace(scoped_us_counter_canvas_gpu);
-      } else if (image_source->IsSVGSource()) {
-        DEFINE_THREAD_SAFE_STATIC_LOCAL(
-            CustomCountHistogram, scoped_us_counter_svggpu,
-            ("Blink.Canvas.DrawImage.SVG.GPU", 0, 10000000, 50));
-        timer.emplace(scoped_us_counter_svggpu);
-      } else if (image_source->IsImageBitmap()) {
-        DEFINE_THREAD_SAFE_STATIC_LOCAL(
-            CustomCountHistogram, scoped_us_counter_image_bitmap_gpu,
-            ("Blink.Canvas.DrawImage.ImageBitmap.GPU", 0, 10000000, 50));
-        timer.emplace(scoped_us_counter_image_bitmap_gpu);
-      } else if (image_source->IsOffscreenCanvas()) {
-        DEFINE_THREAD_SAFE_STATIC_LOCAL(
-            CustomCountHistogram, scoped_us_counter_offscreencanvas_gpu,
-            ("Blink.Canvas.DrawImage.OffscreenCanvas.GPU", 0, 10000000, 50));
-        timer.emplace(scoped_us_counter_offscreencanvas_gpu);
-      } else {
-        DEFINE_THREAD_SAFE_STATIC_LOCAL(
-            CustomCountHistogram, scoped_us_counter_others_gpu,
-            ("Blink.Canvas.DrawImage.Others.GPU", 0, 10000000, 50));
-        timer.emplace(scoped_us_counter_others_gpu);
-      }
-    } else {
-      if (image_source->IsVideoElement()) {
-        DEFINE_THREAD_SAFE_STATIC_LOCAL(
-            CustomCountHistogram, scoped_us_counter_video_cpu,
-            ("Blink.Canvas.DrawImage.Video.CPU", 0, 10000000, 50));
-        timer.emplace(scoped_us_counter_video_cpu);
-      } else if (image_source->IsCanvasElement()) {
-        DEFINE_THREAD_SAFE_STATIC_LOCAL(
-            CustomCountHistogram, scoped_us_counter_canvas_cpu,
-            ("Blink.Canvas.DrawImage.Canvas.CPU", 0, 10000000, 50));
-        timer.emplace(scoped_us_counter_canvas_cpu);
-      } else if (image_source->IsSVGSource()) {
-        DEFINE_THREAD_SAFE_STATIC_LOCAL(
-            CustomCountHistogram, scoped_us_counter_svgcpu,
-            ("Blink.Canvas.DrawImage.SVG.CPU", 0, 10000000, 50));
-        timer.emplace(scoped_us_counter_svgcpu);
-      } else if (image_source->IsImageBitmap()) {
-        DEFINE_THREAD_SAFE_STATIC_LOCAL(
-            CustomCountHistogram, scoped_us_counter_image_bitmap_cpu,
-            ("Blink.Canvas.DrawImage.ImageBitmap.CPU", 0, 10000000, 50));
-        timer.emplace(scoped_us_counter_image_bitmap_cpu);
-      } else if (image_source->IsOffscreenCanvas()) {
-        DEFINE_THREAD_SAFE_STATIC_LOCAL(
-            CustomCountHistogram, scoped_us_counter_offscreencanvas_cpu,
-            ("Blink.Canvas.DrawImage.OffscreenCanvas.CPU", 0, 10000000, 50));
-        timer.emplace(scoped_us_counter_offscreencanvas_cpu);
-      } else {
-        DEFINE_THREAD_SAFE_STATIC_LOCAL(
-            CustomCountHistogram, scoped_us_counter_others_cpu,
-            ("Blink.Canvas.DrawImage.Others.CPU", 0, 10000000, 50));
-        timer.emplace(scoped_us_counter_others_cpu);
-      }
-    }
-  }
+  base::TimeTicks start_time = base::TimeTicks::Now();
 
   scoped_refptr<Image> image;
   FloatSize default_object_size(Width(), Height());
@@ -1362,8 +1293,28 @@
   ValidateStateStack();
 
   if (!IsPaint2D()) {
-    DCHECK(!start_time.is_null());
-    timer->CountMicroseconds(WTF::CurrentTimeTicks() - start_time);
+    std::string histogram_name = "Blink.Canvas.DrawImage.Duration.";
+    if (image_source->IsCanvasElement()) {
+      histogram_name.append("Canvas.");
+    } else if (image_source->IsCSSImageValue()) {
+      histogram_name.append("CssImage.");
+    } else if (image_source->IsImageElement()) {
+      histogram_name.append("ImageElement.");
+    } else if (image_source->IsImageBitmap()) {
+      histogram_name.append("ImageBitmap.");
+    } else if (image_source->IsOffscreenCanvas()) {
+      histogram_name.append("OffscreenCanvas.");
+    } else if (image_source->IsSVGSource()) {
+      histogram_name.append("SVG.");
+    } else if (image_source->IsVideoElement()) {
+      histogram_name.append("Video.");
+    } else {  // Unknown source.
+      histogram_name.append("Unknown.");
+    }
+    histogram_name.append(
+        CanCreateCanvas2dResourceProvider() && IsAccelerated() ? "GPU" : "CPU");
+    base::TimeDelta elapsed = TimeTicks::Now() - start_time;
+    UmaHistogramMicrosecondsTimes(histogram_name, elapsed);
   }
 }
 
diff --git a/third_party/blink/renderer/modules/exported/web_testing_support.cc b/third_party/blink/renderer/modules/exported/web_testing_support.cc
index e7b057a..e70c105 100644
--- a/third_party/blink/renderer/modules/exported/web_testing_support.cc
+++ b/third_party/blink/renderer/modules/exported/web_testing_support.cc
@@ -35,18 +35,18 @@
 void WebTestingSupport::InjectInternalsObject(WebLocalFrame* frame) {
   V8InternalsPartial::initialize();
   v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
-  WebCoreTestSupport::InjectInternalsObject(frame->MainWorldScriptContext());
+  web_core_test_support::InjectInternalsObject(frame->MainWorldScriptContext());
 }
 
 void WebTestingSupport::ResetInternalsObject(WebLocalFrame* frame) {
   v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
-  WebCoreTestSupport::ResetInternalsObject(frame->MainWorldScriptContext());
+  web_core_test_support::ResetInternalsObject(frame->MainWorldScriptContext());
 }
 
 void WebTestingSupport::InjectInternalsObject(v8::Local<v8::Context> context) {
   V8InternalsPartial::initialize();
   v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
-  WebCoreTestSupport::InjectInternalsObject(context);
+  web_core_test_support::InjectInternalsObject(context);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/filesystem/local_file_system_client.cc b/third_party/blink/renderer/modules/filesystem/local_file_system_client.cc
index 8b661c9..98d9354 100644
--- a/third_party/blink/renderer/modules/filesystem/local_file_system_client.cc
+++ b/third_party/blink/renderer/modules/filesystem/local_file_system_client.cc
@@ -33,8 +33,8 @@
 #include <memory>
 
 #include "base/memory/ptr_util.h"
+#include "third_party/blink/public/platform/web_content_settings_client.h"
 #include "third_party/blink/renderer/core/dom/document.h"
-#include "third_party/blink/renderer/core/frame/content_settings_client.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/workers/worker_content_settings_client.h"
 #include "third_party/blink/renderer/core/workers/worker_global_scope.h"
@@ -75,10 +75,11 @@
     return;
   }
 
-  DCHECK(document->GetFrame());
-  document->GetFrame()
-      ->GetContentSettingsClient()
-      ->RequestFileSystemAccessAsync(std::move(callbacks));
+  if (auto* client = document->GetFrame()->GetContentSettingsClient()) {
+    client->RequestFileSystemAccessAsync(std::move(callbacks));
+  } else {
+    callbacks->OnAllowed();
+  }
 }
 
 LocalFileSystemClient::LocalFileSystemClient() = default;
diff --git a/third_party/blink/renderer/modules/indexeddb/indexed_db_client.cc b/third_party/blink/renderer/modules/indexeddb/indexed_db_client.cc
index 39f879f..b495303 100644
--- a/third_party/blink/renderer/modules/indexeddb/indexed_db_client.cc
+++ b/third_party/blink/renderer/modules/indexeddb/indexed_db_client.cc
@@ -4,11 +4,11 @@
 
 #include "third_party/blink/renderer/modules/indexeddb/indexed_db_client.h"
 
+#include "third_party/blink/public/platform/web_content_settings_client.h"
 #include "third_party/blink/public/platform/web_security_origin.h"
 #include "third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.h"
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
-#include "third_party/blink/renderer/core/frame/content_settings_client.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/workers/worker_clients.h"
 #include "third_party/blink/renderer/core/workers/worker_content_settings_client.h"
@@ -50,9 +50,11 @@
     LocalFrame* frame = document->GetFrame();
     if (!frame)
       return false;
-    DCHECK(frame->GetContentSettingsClient());
-    return frame->GetContentSettingsClient()->AllowIndexedDB(
-        name, context->GetSecurityOrigin());
+    if (auto* settings_client = frame->GetContentSettingsClient()) {
+      return settings_client->AllowIndexedDB(
+          name, WebSecurityOrigin(context->GetSecurityOrigin()));
+    }
+    return true;
   }
 
   WorkerGlobalScope& worker_global_scope = *To<WorkerGlobalScope>(context);
diff --git a/third_party/blink/renderer/modules/storage/storage_controller.cc b/third_party/blink/renderer/modules/storage/storage_controller.cc
index 855e3ba..226df21 100644
--- a/third_party/blink/renderer/modules/storage/storage_controller.cc
+++ b/third_party/blink/renderer/modules/storage/storage_controller.cc
@@ -9,9 +9,9 @@
 #include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/platform/interface_provider.h"
 #include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/public/platform/web_content_settings_client.h"
 #include "third_party/blink/public/platform/web_storage_area.h"
 #include "third_party/blink/public/platform/web_storage_namespace.h"
-#include "third_party/blink/renderer/core/frame/content_settings_client.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/modules/storage/cached_storage_area.h"
 #include "third_party/blink/renderer/modules/storage/storage_namespace.h"
@@ -23,14 +23,6 @@
 namespace blink {
 namespace {
 
-#define STATIC_ASSERT_MATCHING_ENUM(enum_name1, enum_name2)                   \
-  static_assert(static_cast<int>(enum_name1) == static_cast<int>(enum_name2), \
-                "mismatching enums: " #enum_name1)
-STATIC_ASSERT_MATCHING_ENUM(StorageArea::StorageType::kLocalStorage,
-                            ContentSettingsClient::StorageType::kLocal);
-STATIC_ASSERT_MATCHING_ENUM(StorageArea::StorageType::kSessionStorage,
-                            ContentSettingsClient::StorageType::kSession);
-
 const size_t kStorageControllerTotalCacheLimitInBytesLowEnd = 1 * 1024 * 1024;
 const size_t kStorageControllerTotalCacheLimitInBytes = 5 * 1024 * 1024;
 
@@ -57,9 +49,11 @@
 // static
 bool StorageController::CanAccessStorageArea(LocalFrame* frame,
                                              StorageArea::StorageType type) {
-  DCHECK(frame->GetContentSettingsClient());
-  return frame->GetContentSettingsClient()->AllowStorage(
-      static_cast<ContentSettingsClient::StorageType>(type));
+  if (auto* settings_client = frame->GetContentSettingsClient()) {
+    return settings_client->AllowStorage(
+        type == StorageArea::StorageType::kLocalStorage);
+  }
+  return true;
 }
 
 StorageController::StorageController(
diff --git a/third_party/blink/renderer/modules/webdatabase/database_client.cc b/third_party/blink/renderer/modules/webdatabase/database_client.cc
index 5c93639..a05e62d 100644
--- a/third_party/blink/renderer/modules/webdatabase/database_client.cc
+++ b/third_party/blink/renderer/modules/webdatabase/database_client.cc
@@ -30,8 +30,8 @@
 
 #include "third_party/blink/renderer/modules/webdatabase/database_client.h"
 
+#include "third_party/blink/public/platform/web_content_settings_client.h"
 #include "third_party/blink/renderer/core/dom/document.h"
-#include "third_party/blink/renderer/core/frame/content_settings_client.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/page/page.h"
 #include "third_party/blink/renderer/modules/webdatabase/database.h"
@@ -62,11 +62,8 @@
                                    unsigned estimated_size) {
   DCHECK(context->IsContextThread());
   Document* document = To<Document>(context);
-  DCHECK(document->GetFrame());
-  if (document->GetFrame()->GetContentSettingsClient()) {
-    return document->GetFrame()->GetContentSettingsClient()->AllowDatabase(
-        name, display_name, estimated_size);
-  }
+  if (auto* client = document->GetFrame()->GetContentSettingsClient())
+    return client->AllowDatabase(name, display_name, estimated_size);
   return true;
 }
 
diff --git a/third_party/blink/renderer/platform/exported/platform.cc b/third_party/blink/renderer/platform/exported/platform.cc
index a8f07f7..f4415a71 100644
--- a/third_party/blink/renderer/platform/exported/platform.cc
+++ b/third_party/blink/renderer/platform/exported/platform.cc
@@ -68,6 +68,7 @@
 #include "third_party/blink/renderer/platform/web_task_runner.h"
 #include "third_party/blink/renderer/platform/wtf/hash_map.h"
 #include "third_party/webrtc/api/rtpparameters.h"
+#include "third_party/webrtc/p2p/base/portallocator.h"
 
 namespace blink {
 
@@ -327,6 +328,11 @@
   return nullptr;
 }
 
+std::unique_ptr<cricket::PortAllocator> Platform::CreateWebRtcPortAllocator(
+    WebLocalFrame* frame) {
+  return nullptr;
+}
+
 std::unique_ptr<WebMediaRecorderHandler> Platform::CreateMediaRecorderHandler(
     scoped_refptr<base::SingleThreadTaskRunner>) {
   return nullptr;
diff --git a/third_party/blink/renderer/platform/exported/web_canonical_cookie.cc b/third_party/blink/renderer/platform/exported/web_canonical_cookie.cc
index bfd464b..048c413 100644
--- a/third_party/blink/renderer/platform/exported/web_canonical_cookie.cc
+++ b/third_party/blink/renderer/platform/exported/web_canonical_cookie.cc
@@ -84,16 +84,6 @@
 
 WebCanonicalCookie::~WebCanonicalCookie() = default;
 
-// static
-String WebCanonicalCookie::BuildCookieLine(
-    const Vector<WebCanonicalCookie>& cookies) {
-  std::vector<net::CanonicalCookie> copy;
-  copy.reserve(cookies.size());
-  for (const auto& cookie : cookies)
-    copy.push_back(ToNetCanonicalCookie(cookie));
-  return WebString::FromUTF8(net::CanonicalCookie::BuildCookieLine(copy));
-}
-
 namespace {
 
 // TODO(crbug.com/851889): WebURL::operator GURL() is only available if
diff --git a/third_party/blink/renderer/platform/exported/web_canonical_cookie_test.cc b/third_party/blink/renderer/platform/exported/web_canonical_cookie_test.cc
index 71d59fd8..b2e7a5a 100644
--- a/third_party/blink/renderer/platform/exported/web_canonical_cookie_test.cc
+++ b/third_party/blink/renderer/platform/exported/web_canonical_cookie_test.cc
@@ -98,17 +98,4 @@
   }
 }
 
-TEST(WebCanonicalCookieTest, BuildLine) {
-  const WebURL url(KURL("http://example.com"));
-  Vector<WebCanonicalCookie> cookies;
-
-  cookies.push_back(
-      WebCanonicalCookie::Create(url, "a=1", base::Time::Now()).value());
-  EXPECT_EQ("a=1", WebCanonicalCookie::BuildCookieLine(cookies));
-
-  cookies.push_back(
-      WebCanonicalCookie::Create(url, "b=2", base::Time::Now()).value());
-  EXPECT_EQ("a=1; b=2", WebCanonicalCookie::BuildCookieLine(cookies));
-}
-
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/fonts/opentype/open_type_types.h b/third_party/blink/renderer/platform/fonts/opentype/open_type_types.h
index d605c17..12c90c9 100644
--- a/third_party/blink/renderer/platform/fonts/opentype/open_type_types.h
+++ b/third_party/blink/renderer/platform/fonts/opentype/open_type_types.h
@@ -29,7 +29,7 @@
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 
 namespace blink {
-namespace OpenType {
+namespace open_type {
 
 struct Int16 {
   DISALLOW_NEW();
@@ -101,6 +101,6 @@
   }
 };
 
-}  // namespace OpenType
+}  // namespace open_type
 }  // namespace blink
 #endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_FONTS_OPENTYPE_OPEN_TYPE_TYPES_H_
diff --git a/third_party/blink/renderer/platform/fonts/opentype/open_type_vertical_data.cc b/third_party/blink/renderer/platform/fonts/opentype/open_type_vertical_data.cc
index 3236274..638e7633 100644
--- a/third_party/blink/renderer/platform/fonts/opentype/open_type_vertical_data.cc
+++ b/third_party/blink/renderer/platform/fonts/opentype/open_type_vertical_data.cc
@@ -33,7 +33,7 @@
 #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
 
 namespace blink {
-namespace OpenType {
+namespace open_type {
 
 // The input characters are big-endian (first is most significant).
 #define OT_MAKE_TAG(ch1, ch2, ch3, ch4)                    \
@@ -50,46 +50,46 @@
 
 struct HheaTable {
   DISALLOW_NEW();
-  OpenType::Fixed version;
-  OpenType::Int16 ascender;
-  OpenType::Int16 descender;
-  OpenType::Int16 line_gap;
-  OpenType::Int16 advance_width_max;
-  OpenType::Int16 min_left_side_bearing;
-  OpenType::Int16 min_right_side_bearing;
-  OpenType::Int16 x_max_extent;
-  OpenType::Int16 caret_slope_rise;
-  OpenType::Int16 caret_slope_run;
-  OpenType::Int16 caret_offset;
-  OpenType::Int16 reserved[4];
-  OpenType::Int16 metric_data_format;
-  OpenType::UInt16 number_of_h_metrics;
+  open_type::Fixed version;
+  open_type::Int16 ascender;
+  open_type::Int16 descender;
+  open_type::Int16 line_gap;
+  open_type::Int16 advance_width_max;
+  open_type::Int16 min_left_side_bearing;
+  open_type::Int16 min_right_side_bearing;
+  open_type::Int16 x_max_extent;
+  open_type::Int16 caret_slope_rise;
+  open_type::Int16 caret_slope_run;
+  open_type::Int16 caret_offset;
+  open_type::Int16 reserved[4];
+  open_type::Int16 metric_data_format;
+  open_type::UInt16 number_of_h_metrics;
 };
 
 struct VheaTable {
   DISALLOW_NEW();
-  OpenType::Fixed version;
-  OpenType::Int16 ascent;
-  OpenType::Int16 descent;
-  OpenType::Int16 line_gap;
-  OpenType::Int16 advance_height_max;
-  OpenType::Int16 min_top_side_bearing;
-  OpenType::Int16 min_bottom_side_bearing;
-  OpenType::Int16 y_max_extent;
-  OpenType::Int16 caret_slope_rise;
-  OpenType::Int16 caret_slope_run;
-  OpenType::Int16 caret_offset;
-  OpenType::Int16 reserved[4];
-  OpenType::Int16 metric_data_format;
-  OpenType::UInt16 num_of_long_ver_metrics;
+  open_type::Fixed version;
+  open_type::Int16 ascent;
+  open_type::Int16 descent;
+  open_type::Int16 line_gap;
+  open_type::Int16 advance_height_max;
+  open_type::Int16 min_top_side_bearing;
+  open_type::Int16 min_bottom_side_bearing;
+  open_type::Int16 y_max_extent;
+  open_type::Int16 caret_slope_rise;
+  open_type::Int16 caret_slope_run;
+  open_type::Int16 caret_offset;
+  open_type::Int16 reserved[4];
+  open_type::Int16 metric_data_format;
+  open_type::UInt16 num_of_long_ver_metrics;
 };
 
 struct HmtxTable {
   DISALLOW_NEW();
   struct Entry {
     DISALLOW_NEW();
-    OpenType::UInt16 advance_width;
-    OpenType::Int16 lsb;
+    open_type::UInt16 advance_width;
+    open_type::Int16 lsb;
   } entries[1];
 };
 
@@ -97,21 +97,21 @@
   DISALLOW_NEW();
   struct Entry {
     DISALLOW_NEW();
-    OpenType::UInt16 advance_height;
-    OpenType::Int16 top_side_bearing;
+    open_type::UInt16 advance_height;
+    open_type::Int16 top_side_bearing;
   } entries[1];
 };
 
 struct VORGTable {
   DISALLOW_NEW();
-  OpenType::UInt16 major_version;
-  OpenType::UInt16 minor_version;
-  OpenType::Int16 default_vert_origin_y;
-  OpenType::UInt16 num_vert_origin_y_metrics;
+  open_type::UInt16 major_version;
+  open_type::UInt16 minor_version;
+  open_type::Int16 default_vert_origin_y;
+  open_type::UInt16 num_vert_origin_y_metrics;
   struct VertOriginYMetrics {
     DISALLOW_NEW();
-    OpenType::UInt16 glyph_index;
-    OpenType::Int16 vert_origin_y;
+    open_type::UInt16 glyph_index;
+    open_type::Int16 vert_origin_y;
   } vert_origin_y_metrics[1];
 
   size_t RequiredSize() const {
@@ -122,7 +122,7 @@
 
 #pragma pack()
 
-}  // namespace OpenType
+}  // namespace open_type
 
 OpenTypeVerticalData::OpenTypeVerticalData(sk_sp<SkTypeface> typeface)
     : default_vert_origin_y_(0),
@@ -146,9 +146,9 @@
   // Load hhea and hmtx to get x-component of vertical origins.
   // If these tables are missing, it's not an OpenType font.
   Vector<char> buffer;
-  CopyOpenTypeTable(typeface, OpenType::kHheaTag, buffer);
-  const OpenType::HheaTable* hhea =
-      OpenType::ValidateTable<OpenType::HheaTable>(buffer);
+  CopyOpenTypeTable(typeface, open_type::kHheaTag, buffer);
+  const open_type::HheaTable* hhea =
+      open_type::ValidateTable<open_type::HheaTable>(buffer);
   if (!hhea)
     return;
   uint16_t count_hmtx_entries = hhea->number_of_h_metrics;
@@ -157,9 +157,10 @@
     return;
   }
 
-  CopyOpenTypeTable(typeface, OpenType::kHmtxTag, buffer);
-  const OpenType::HmtxTable* hmtx =
-      OpenType::ValidateTable<OpenType::HmtxTable>(buffer, count_hmtx_entries);
+  CopyOpenTypeTable(typeface, open_type::kHmtxTag, buffer);
+  const open_type::HmtxTable* hmtx =
+      open_type::ValidateTable<open_type::HmtxTable>(buffer,
+                                                     count_hmtx_entries);
   if (!hmtx) {
     DLOG(ERROR) << "hhea exists but hmtx does not (or broken)";
     return;
@@ -170,9 +171,9 @@
 
   // Load vhea first. This table is required for fonts that support vertical
   // flow.
-  CopyOpenTypeTable(typeface, OpenType::kVheaTag, buffer);
-  const OpenType::VheaTable* vhea =
-      OpenType::ValidateTable<OpenType::VheaTable>(buffer);
+  CopyOpenTypeTable(typeface, open_type::kVheaTag, buffer);
+  const open_type::VheaTable* vhea =
+      open_type::ValidateTable<open_type::VheaTable>(buffer);
   if (!vhea)
     return;
   uint16_t count_vmtx_entries = vhea->num_of_long_ver_metrics;
@@ -182,9 +183,9 @@
   }
 
   // Load VORG. This table is optional.
-  CopyOpenTypeTable(typeface, OpenType::kVORGTag, buffer);
-  const OpenType::VORGTable* vorg =
-      OpenType::ValidateTable<OpenType::VORGTable>(buffer);
+  CopyOpenTypeTable(typeface, open_type::kVORGTag, buffer);
+  const open_type::VORGTable* vorg =
+      open_type::ValidateTable<open_type::VORGTable>(buffer);
   if (vorg && buffer.size() >= vorg->RequiredSize()) {
     default_vert_origin_y_ = vorg->default_vert_origin_y;
     uint16_t count_vert_origin_y_metrics = vorg->num_vert_origin_y_metrics;
@@ -193,7 +194,7 @@
       vert_origin_y_.Set(0, default_vert_origin_y_);
     } else {
       for (uint16_t i = 0; i < count_vert_origin_y_metrics; ++i) {
-        const OpenType::VORGTable::VertOriginYMetrics& metrics =
+        const open_type::VORGTable::VertOriginYMetrics& metrics =
             vorg->vert_origin_y_metrics[i];
         vert_origin_y_.Set(metrics.glyph_index, metrics.vert_origin_y);
       }
@@ -202,9 +203,10 @@
 
   // Load vmtx then. This table is required for fonts that support vertical
   // flow.
-  CopyOpenTypeTable(typeface, OpenType::kVmtxTag, buffer);
-  const OpenType::VmtxTable* vmtx =
-      OpenType::ValidateTable<OpenType::VmtxTable>(buffer, count_vmtx_entries);
+  CopyOpenTypeTable(typeface, open_type::kVmtxTag, buffer);
+  const open_type::VmtxTable* vmtx =
+      open_type::ValidateTable<open_type::VmtxTable>(buffer,
+                                                     count_vmtx_entries);
   if (!vmtx) {
     DLOG(ERROR) << "vhea exists but vmtx does not (or broken)";
     return;
@@ -219,20 +221,20 @@
     return;
 
   wtf_size_t size_extra =
-      buffer.size() - sizeof(OpenType::VmtxTable::Entry) * count_vmtx_entries;
-  if (size_extra % sizeof(OpenType::Int16)) {
+      buffer.size() - sizeof(open_type::VmtxTable::Entry) * count_vmtx_entries;
+  if (size_extra % sizeof(open_type::Int16)) {
     DLOG(ERROR) << "vmtx has incorrect tsb count";
     return;
   }
   wtf_size_t count_top_side_bearings =
-      count_vmtx_entries + size_extra / sizeof(OpenType::Int16);
+      count_vmtx_entries + size_extra / sizeof(open_type::Int16);
   top_side_bearings_.resize(count_top_side_bearings);
   wtf_size_t i;
   for (i = 0; i < count_vmtx_entries; ++i)
     top_side_bearings_[i] = vmtx->entries[i].top_side_bearing;
   if (i < count_top_side_bearings) {
-    const OpenType::Int16* p_top_side_bearings_extra =
-        reinterpret_cast<const OpenType::Int16*>(
+    const open_type::Int16* p_top_side_bearings_extra =
+        reinterpret_cast<const open_type::Int16*>(
             &vmtx->entries[count_vmtx_entries]);
     for (; i < count_top_side_bearings; ++i, ++p_top_side_bearings_extra)
       top_side_bearings_[i] = *p_top_side_bearings_extra;
diff --git a/third_party/blink/renderer/platform/fonts/opentype/open_type_vertical_data_test.cc b/third_party/blink/renderer/platform/fonts/opentype/open_type_vertical_data_test.cc
index cd03dc5..bdb7d7b 100644
--- a/third_party/blink/renderer/platform/fonts/opentype/open_type_vertical_data_test.cc
+++ b/third_party/blink/renderer/platform/fonts/opentype/open_type_vertical_data_test.cc
@@ -28,9 +28,9 @@
 
 namespace blink {
 
-struct TestTable : OpenType::TableBase {
-  OpenType::Fixed version;
-  OpenType::Int16 ascender;
+struct TestTable : open_type::TableBase {
+  open_type::Fixed version;
+  open_type::Int16 ascender;
 
   template <typename T>
   const T* ValidateOffset(const Vector<char>& buffer, uint16_t offset) const {
@@ -40,21 +40,21 @@
 
 TEST(OpenTypeVerticalDataTest, ValidateTableTest) {
   Vector<char> buffer(sizeof(TestTable));
-  const TestTable* table = OpenType::ValidateTable<TestTable>(buffer);
+  const TestTable* table = open_type::ValidateTable<TestTable>(buffer);
   EXPECT_TRUE(table);
 
   buffer = Vector<char>(sizeof(TestTable) - 1);
-  table = OpenType::ValidateTable<TestTable>(buffer);
+  table = open_type::ValidateTable<TestTable>(buffer);
   EXPECT_FALSE(table);
 
   buffer = Vector<char>(sizeof(TestTable) + 1);
-  table = OpenType::ValidateTable<TestTable>(buffer);
+  table = open_type::ValidateTable<TestTable>(buffer);
   EXPECT_TRUE(table);
 }
 
 TEST(OpenTypeVerticalDataTest, ValidateOffsetTest) {
   Vector<char> buffer(sizeof(TestTable));
-  const TestTable* table = OpenType::ValidateTable<TestTable>(buffer);
+  const TestTable* table = open_type::ValidateTable<TestTable>(buffer);
   ASSERT_TRUE(table);
 
   // Test overflow
diff --git a/third_party/blink/renderer/platform/heap/heap.h b/third_party/blink/renderer/platform/heap/heap.h
index 499750c..9dd7d5a 100644
--- a/third_party/blink/renderer/platform/heap/heap.h
+++ b/third_party/blink/renderer/platform/heap/heap.h
@@ -524,6 +524,17 @@
   DISALLOW_COPY_AND_ASSIGN(GarbageCollected);
 };
 
+// Constructs an instance of T, which is a garbage collected type.
+template <typename T, typename... Args>
+T* MakeGarbageCollected(Args&&... args) {
+  static_assert(WTF::IsGarbageCollectedType<T>::value,
+                "T needs to be a garbage collected object");
+  // Uses placement new so we can force MakeGarbageCollected usage by deleting
+  // the new operator.
+  return ::new (T::AllocateObject(sizeof(T), IsEagerlyFinalizedType<T>::value))
+      T(std::forward<Args>(args)...);
+}
+
 // Assigning class types to their arenas.
 //
 // We use sized arenas for most 'normal' objects to improve memory locality.
diff --git a/third_party/blink/renderer/platform/heap/heap_allocator.h b/third_party/blink/renderer/platform/heap/heap_allocator.h
index d66766a..c13b643 100644
--- a/third_party/blink/renderer/platform/heap/heap_allocator.h
+++ b/third_party/blink/renderer/platform/heap/heap_allocator.h
@@ -508,24 +508,23 @@
                   "instead of HeapVector<>");
   }
 
-  void* operator new(size_t size) {
-    static_assert(
-        inlineCapacity == 0 || !VectorTraits<T>::kNeedsDestruction,
-        "on-heap HeapVector<Persistent<>> should not have an inline capacity");
-    return Base::operator new(size);
+  static void* AllocateObject(size_t size, bool eagerly_sweep) {
+    // On-heap HeapVectors generally should not have inline capacity, but it is
+    // hard to avoid when using a type alias. Hence we only disallow the
+    // VectorTraits<T>::kNeedsDestruction case for now.
+    static_assert(inlineCapacity == 0 || !VectorTraits<T>::kNeedsDestruction,
+                  "on-heap HeapVector<> should not have an inline capacity");
+    return ThreadHeap::Allocate<HeapVector<T, inlineCapacity>>(size,
+                                                               eagerly_sweep);
   }
+
+  // TODO(keishi): Delete new/delete after transition to MakeGarbageCollected is
+  // complete.
+  void* operator new(size_t size) { return Base::operator new(size); }
   void operator delete(void* p) { return Base::operator delete(p); };
-  void* operator new[](size_t size) {
-    static_assert(
-        inlineCapacity == 0 || !VectorTraits<T>::kNeedsDestruction,
-        "on-heap HeapVector<Persistent<>> should not have an inline capacity");
-    return Base::operator new[](size);
-  }
-  void operator delete[](void* p) { return Base::operator delete[](p); };
+  void* operator new[](size_t size) = delete;
+  void operator delete[](void* p) = delete;
   void* operator new(size_t size, NotNullTag null_tag, void* location) {
-    static_assert(
-        inlineCapacity == 0 || !VectorTraits<T>::kNeedsDestruction,
-        "on-heap HeapVector<Persistent<>> should not have an inline capacity");
     return Base::operator new(size, null_tag, location);
   }
   void* operator new(size_t size, void* location) {
@@ -555,24 +554,23 @@
                   "of HeapDeque<>");
   }
 
-  void* operator new(size_t size) {
-    static_assert(
-        inlineCapacity == 0 || !VectorTraits<T>::kNeedsDestruction,
-        "on-heap HeapDeque<Persistent<>> should not have an inline capacity");
-    return Base::operator new(size);
+  static void* AllocateObject(size_t size, bool eagerly_sweep) {
+    // On-heap HeapDeques generally should not have inline capacity, but it is
+    // hard to avoid when using a type alias. Hence we only disallow the
+    // VectorTraits<T>::kNeedsDestruction case for now.
+    static_assert(inlineCapacity == 0 || !VectorTraits<T>::kNeedsDestruction,
+                  "on-heap HeapDeque<> should not have an inline capacity");
+    return ThreadHeap::Allocate<HeapVector<T, inlineCapacity>>(size,
+                                                               eagerly_sweep);
   }
+
+  // TODO(keishi): Delete new/delete after transition to MakeGarbageCollected is
+  // complete.
+  void* operator new(size_t size) { return Base::operator new(size); }
   void operator delete(void* p) { return Base::operator delete(p); };
-  void* operator new[](size_t size) {
-    static_assert(
-        inlineCapacity == 0 || !VectorTraits<T>::kNeedsDestruction,
-        "on-heap HeapDequer<Persistent<>> should not have an inline capacity");
-    return Base::operator new[](size);
-  }
-  void operator delete[](void* p) { return Base::operator delete[](p); };
+  void* operator new[](size_t size) = delete;
+  void operator delete[](void* p) = delete;
   void* operator new(size_t size, NotNullTag null_tag, void* location) {
-    static_assert(
-        inlineCapacity == 0 || !VectorTraits<T>::kNeedsDestruction,
-        "on-heap HeapDeque<Persistent<>> should not have an inline capacity");
     return Base::operator new(size, null_tag, location);
   }
   void* operator new(size_t size, void* location) {
diff --git a/third_party/blink/renderer/platform/heap/heap_compact.cc b/third_party/blink/renderer/platform/heap/heap_compact.cc
index 4b6e34c..841dde0 100644
--- a/third_party/blink/renderer/platform/heap/heap_compact.cc
+++ b/third_party/blink/renderer/platform/heap/heap_compact.cc
@@ -367,14 +367,10 @@
     return force_compaction_gc_;
   }
 
-  // TODO(keishi): Should be enable after fixing the crashes.
-  if (marking_type == BlinkGC::kIncrementalMarking)
-    return false;
-
-  // TODO(harukamt): Add kIncrementalIdleGC and kIncrementalV8FollowupGC when we
-  // enable heap compaction for incremental marking.
   if (reason != BlinkGC::GCReason::kIdleGC &&
       reason != BlinkGC::GCReason::kPreciseGC &&
+      reason != BlinkGC::GCReason::kIncrementalIdleGC &&
+      reason != BlinkGC::GCReason::kIncrementalV8FollowupGC &&
       reason != BlinkGC::GCReason::kForcedGC)
     return false;
 
diff --git a/third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h b/third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h
index aa96a2b..131469f0 100644
--- a/third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h
+++ b/third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h
@@ -11,19 +11,14 @@
 #include "third_party/blink/renderer/platform/wtf/text/cstring.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
-namespace WTF {
-
-// CString version of SetTraceValue so that trace arguments can be strings.
-static inline void SetTraceValue(const CString& arg,
-                                 unsigned char* type,
-                                 unsigned long long* value) {
-  trace_event_internal::TraceValueUnion type_value;
-  type_value.as_string = arg.data();
-  *type = TRACE_VALUE_TYPE_COPY_STRING;
-  *value = type_value.as_uint;
-}
-
-}  // namespace WTF
+// Conversion from CString to TraceValue so that trace arguments can be strings.
+template <>
+struct base::trace_event::TraceValue::Helper<WTF::CString> {
+  static constexpr unsigned char kType = TRACE_VALUE_TYPE_COPY_STRING;
+  static inline void SetValue(TraceValue* v, const WTF::CString& value) {
+    v->as_string = value.data();
+  }
+};
 
 namespace blink {
 namespace TraceEvent {
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_load_scheduler.cc b/third_party/blink/renderer/platform/loader/fetch/resource_load_scheduler.cc
index f8d0f07..dfbe8329 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_load_scheduler.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_load_scheduler.cc
@@ -11,8 +11,8 @@
 #include "third_party/blink/renderer/platform/histogram.h"
 #include "third_party/blink/renderer/platform/loader/fetch/fetch_context.h"
 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
-#include "third_party/blink/renderer/platform/scheduler/renderer/frame_status.h"
-#include "third_party/blink/renderer/platform/scheduler/util/aggregated_metric_reporter.h"
+#include "third_party/blink/renderer/platform/scheduler/public/aggregated_metric_reporter.h"
+#include "third_party/blink/renderer/platform/scheduler/public/frame_status.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/platform/scheduler/BUILD.gn b/third_party/blink/renderer/platform/scheduler/BUILD.gn
index cc1609aa..413cfe73 100644
--- a/third_party/blink/renderer/platform/scheduler/BUILD.gn
+++ b/third_party/blink/renderer/platform/scheduler/BUILD.gn
@@ -9,16 +9,11 @@
 
 blink_platform_sources("scheduler") {
   sources = [
-    "child/features.cc",
-    "child/features.h",
-    "child/pollable_thread_safe_flag.cc",
-    "child/pollable_thread_safe_flag.h",
-    "child/process_state.cc",
-    "child/process_state.h",
-    "child/single_thread_idle_task_runner.cc",
     "common/background_scheduler.cc",
     "common/cancelable_closure_holder.cc",
     "common/cancelable_closure_holder.h",
+    "common/features.cc",
+    "common/features.h",
     "common/frame_or_worker_scheduler.cc",
     "common/idle_canceled_delayed_task_sweeper.cc",
     "common/idle_canceled_delayed_task_sweeper.h",
@@ -26,12 +21,20 @@
     "common/idle_helper.h",
     "common/metrics_helper.cc",
     "common/metrics_helper.h",
+    "common/pollable_thread_safe_flag.cc",
+    "common/pollable_thread_safe_flag.h",
+    "common/process_state.cc",
+    "common/process_state.h",
     "common/scheduler_helper.cc",
     "common/scheduler_helper.h",
     "common/scheduling_lifecycle_state.cc",
     "common/simple_thread_scheduler.cc",
     "common/simple_thread_scheduler.h",
+    "common/single_thread_idle_task_runner.cc",
     "common/thread.cc",
+    "common/thread_cpu_throttler.cc",
+    "common/thread_load_tracker.cc",
+    "common/thread_load_tracker.h",
     "common/thread_scheduler.cc",
     "common/thread_scheduler_impl.cc",
     "common/thread_scheduler_impl.h",
@@ -45,6 +48,8 @@
     "common/throttling/throttled_time_domain.h",
     "common/throttling/wake_up_budget_pool.cc",
     "common/throttling/wake_up_budget_pool.h",
+    "common/tracing_helper.cc",
+    "common/tracing_helper.h",
     "common/unprioritized_resource_loading_task_runner_handle.cc",
     "common/unprioritized_resource_loading_task_runner_handle.h",
     "common/web_resource_loading_task_runner_handle.cc",
@@ -57,6 +62,7 @@
     "main_thread/frame_origin_type.h",
     "main_thread/frame_scheduler_impl.cc",
     "main_thread/frame_scheduler_impl.h",
+    "main_thread/frame_status.cc",
     "main_thread/frame_task_queue_controller.cc",
     "main_thread/frame_task_queue_controller.h",
     "main_thread/idle_time_estimator.cc",
@@ -91,25 +97,19 @@
     "main_thread/user_model.cc",
     "main_thread/user_model.h",
     "main_thread/web_render_widget_scheduling_state.cc",
+    "main_thread/web_scoped_virtual_time_pauser.cc",
+    "public/aggregated_metric_reporter.h",
     "public/background_scheduler.h",
     "public/frame_or_worker_scheduler.h",
     "public/frame_scheduler.h",
+    "public/frame_status.h",
     "public/page_lifecycle_state.h",
     "public/page_scheduler.h",
     "public/scheduling_lifecycle_state.h",
     "public/thread.h",
+    "public/thread_cpu_throttler.h",
     "public/thread_scheduler.h",
     "public/worker_scheduler.h",
-    "renderer/frame_status.cc",
-    "renderer/frame_status.h",
-    "renderer/web_scoped_virtual_time_pauser.cc",
-    "util/aggregated_metric_reporter.h",
-    "util/thread_cpu_throttler.cc",
-    "util/thread_cpu_throttler.h",
-    "util/thread_load_tracker.cc",
-    "util/thread_load_tracker.h",
-    "util/tracing_helper.cc",
-    "util/tracing_helper.h",
     "worker/compositor_metrics_helper.cc",
     "worker/compositor_metrics_helper.h",
     "worker/compositor_thread.cc",
@@ -178,8 +178,10 @@
     "common/idle_helper_unittest.cc",
     "common/metrics_helper_unittest.cc",
     "common/scheduler_helper_unittest.cc",
+    "common/thread_load_tracker_unittest.cc",
     "common/throttling/budget_pool_unittest.cc",
     "common/throttling/task_queue_throttler_unittest.cc",
+    "common/tracing_helper_unittest.cc",
     "main_thread/auto_advancing_virtual_time_domain_unittest.cc",
     "main_thread/deadline_task_runner_unittest.cc",
     "main_thread/frame_scheduler_impl_unittest.cc",
@@ -193,8 +195,6 @@
     "main_thread/render_widget_signals_unittest.cc",
     "main_thread/task_cost_estimator_unittest.cc",
     "main_thread/user_model_unittest.cc",
-    "util/thread_load_tracker_unittest.cc",
-    "util/tracing_helper_unittest.cc",
     "worker/compositor_thread_scheduler_unittest.cc",
     "worker/worker_scheduler_proxy_unittest.cc",
     "worker/worker_scheduler_unittest.cc",
diff --git a/third_party/blink/renderer/platform/scheduler/child/DEPS b/third_party/blink/renderer/platform/scheduler/child/DEPS
deleted file mode 100644
index f3b7e66..0000000
--- a/third_party/blink/renderer/platform/scheduler/child/DEPS
+++ /dev/null
@@ -1,4 +0,0 @@
-include_rules = [
-  "+third_party/blink/public/platform/scheduler/base",
-  "+third_party/blink/renderer/platform/scheduler/base",
-]
diff --git a/third_party/blink/renderer/platform/scheduler/child/OWNERS b/third_party/blink/renderer/platform/scheduler/child/OWNERS
deleted file mode 100644
index 8423b49..0000000
--- a/third_party/blink/renderer/platform/scheduler/child/OWNERS
+++ /dev/null
@@ -1,7 +0,0 @@
-altimin@chromium.org
-alexclarke@chromium.org
-rmcilroy@chromium.org
-skyostil@chromium.org
-
-# TEAM: scheduler-dev@chromium.org
-# COMPONENT: Blink>Scheduling
diff --git a/third_party/blink/renderer/platform/scheduler/child/features.cc b/third_party/blink/renderer/platform/scheduler/common/features.cc
similarity index 90%
rename from third_party/blink/renderer/platform/scheduler/child/features.cc
rename to third_party/blink/renderer/platform/scheduler/common/features.cc
index e16aa5d..b49ffd2 100644
--- a/third_party/blink/renderer/platform/scheduler/child/features.cc
+++ b/third_party/blink/renderer/platform/scheduler/common/features.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "third_party/blink/renderer/platform/scheduler/child/features.h"
+#include "third_party/blink/renderer/platform/scheduler/common/features.h"
 
 namespace blink {
 namespace scheduler {
diff --git a/third_party/blink/renderer/platform/scheduler/child/features.h b/third_party/blink/renderer/platform/scheduler/common/features.h
similarity index 96%
rename from third_party/blink/renderer/platform/scheduler/child/features.h
rename to third_party/blink/renderer/platform/scheduler/common/features.h
index 79e1b401b..dd978f3 100644
--- a/third_party/blink/renderer/platform/scheduler/child/features.h
+++ b/third_party/blink/renderer/platform/scheduler/common/features.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_CHILD_FEATURES_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_CHILD_FEATURES_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_COMMON_FEATURES_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_COMMON_FEATURES_H_
 
 #include "base/feature_list.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
@@ -162,4 +162,4 @@
 }  // namespace scheduler
 }  // namespace blink
 
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_CHILD_FEATURES_H_
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_COMMON_FEATURES_H_
diff --git a/third_party/blink/renderer/platform/scheduler/common/metrics_helper.cc b/third_party/blink/renderer/platform/scheduler/common/metrics_helper.cc
index 4e98e26..2d57044 100644
--- a/third_party/blink/renderer/platform/scheduler/common/metrics_helper.cc
+++ b/third_party/blink/renderer/platform/scheduler/common/metrics_helper.cc
@@ -4,7 +4,7 @@
 
 #include "third_party/blink/renderer/platform/scheduler/common/metrics_helper.h"
 
-#include "third_party/blink/renderer/platform/scheduler/child/process_state.h"
+#include "third_party/blink/renderer/platform/scheduler/common/process_state.h"
 
 namespace blink {
 namespace scheduler {
diff --git a/third_party/blink/renderer/platform/scheduler/child/pollable_thread_safe_flag.cc b/third_party/blink/renderer/platform/scheduler/common/pollable_thread_safe_flag.cc
similarity index 86%
rename from third_party/blink/renderer/platform/scheduler/child/pollable_thread_safe_flag.cc
rename to third_party/blink/renderer/platform/scheduler/common/pollable_thread_safe_flag.cc
index 409d276..d26f6d7a 100644
--- a/third_party/blink/renderer/platform/scheduler/child/pollable_thread_safe_flag.cc
+++ b/third_party/blink/renderer/platform/scheduler/common/pollable_thread_safe_flag.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "third_party/blink/renderer/platform/scheduler/child/pollable_thread_safe_flag.h"
+#include "third_party/blink/renderer/platform/scheduler/common/pollable_thread_safe_flag.h"
 
 PollableThreadSafeFlag::PollableThreadSafeFlag(base::Lock* write_lock_)
     : flag_(false), write_lock_(write_lock_) {}
diff --git a/third_party/blink/renderer/platform/scheduler/child/pollable_thread_safe_flag.h b/third_party/blink/renderer/platform/scheduler/common/pollable_thread_safe_flag.h
similarity index 80%
rename from third_party/blink/renderer/platform/scheduler/child/pollable_thread_safe_flag.h
rename to third_party/blink/renderer/platform/scheduler/common/pollable_thread_safe_flag.h
index d3e4a53..5a8d1b1 100644
--- a/third_party/blink/renderer/platform/scheduler/child/pollable_thread_safe_flag.h
+++ b/third_party/blink/renderer/platform/scheduler/common/pollable_thread_safe_flag.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_CHILD_POLLABLE_THREAD_SAFE_FLAG_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_CHILD_POLLABLE_THREAD_SAFE_FLAG_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_COMMON_POLLABLE_THREAD_SAFE_FLAG_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_COMMON_POLLABLE_THREAD_SAFE_FLAG_H_
 
 #include "base/atomicops.h"
 #include "base/macros.h"
@@ -33,4 +33,4 @@
   DISALLOW_COPY_AND_ASSIGN(PollableThreadSafeFlag);
 };
 
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_CHILD_POLLABLE_THREAD_SAFE_FLAG_H_
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_COMMON_POLLABLE_THREAD_SAFE_FLAG_H_
diff --git a/third_party/blink/renderer/platform/scheduler/child/process_state.cc b/third_party/blink/renderer/platform/scheduler/common/process_state.cc
similarity index 86%
rename from third_party/blink/renderer/platform/scheduler/child/process_state.cc
rename to third_party/blink/renderer/platform/scheduler/common/process_state.cc
index e62069f..a769976 100644
--- a/third_party/blink/renderer/platform/scheduler/child/process_state.cc
+++ b/third_party/blink/renderer/platform/scheduler/common/process_state.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "third_party/blink/renderer/platform/scheduler/child/process_state.h"
+#include "third_party/blink/renderer/platform/scheduler/common/process_state.h"
 
 #include "base/lazy_instance.h"
 
diff --git a/third_party/blink/renderer/platform/scheduler/child/process_state.h b/third_party/blink/renderer/platform/scheduler/common/process_state.h
similarity index 74%
rename from third_party/blink/renderer/platform/scheduler/child/process_state.h
rename to third_party/blink/renderer/platform/scheduler/common/process_state.h
index 37d0fbc..4a3a072 100644
--- a/third_party/blink/renderer/platform/scheduler/child/process_state.h
+++ b/third_party/blink/renderer/platform/scheduler/common/process_state.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_CHILD_PROCESS_STATE_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_CHILD_PROCESS_STATE_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_COMMON_PROCESS_STATE_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_COMMON_PROCESS_STATE_H_
 
 #include <atomic>
 
@@ -26,4 +26,4 @@
 }  // namespace scheduler
 }  // namespace blink
 
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_CHILD_PROCESS_STATE_H_
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_COMMON_PROCESS_STATE_H_
diff --git a/third_party/blink/renderer/platform/scheduler/child/single_thread_idle_task_runner.cc b/third_party/blink/renderer/platform/scheduler/common/single_thread_idle_task_runner.cc
similarity index 100%
rename from third_party/blink/renderer/platform/scheduler/child/single_thread_idle_task_runner.cc
rename to third_party/blink/renderer/platform/scheduler/common/single_thread_idle_task_runner.cc
diff --git a/third_party/blink/renderer/platform/scheduler/util/thread_cpu_throttler.cc b/third_party/blink/renderer/platform/scheduler/common/thread_cpu_throttler.cc
similarity index 98%
rename from third_party/blink/renderer/platform/scheduler/util/thread_cpu_throttler.cc
rename to third_party/blink/renderer/platform/scheduler/common/thread_cpu_throttler.cc
index a38dd34..6c2458e 100644
--- a/third_party/blink/renderer/platform/scheduler/util/thread_cpu_throttler.cc
+++ b/third_party/blink/renderer/platform/scheduler/common/thread_cpu_throttler.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "third_party/blink/renderer/platform/scheduler/util/thread_cpu_throttler.h"
+#include "third_party/blink/renderer/platform/scheduler/public/thread_cpu_throttler.h"
 
 #include "base/atomicops.h"
 #include "base/macros.h"
@@ -79,7 +79,7 @@
   SetThrottlingRate(rate);
   CHECK_EQ(base::subtle::NoBarrier_AtomicExchange(&thread_exists_, 1), 0);
   Start();
-}
+}  // namespace scheduler
 
 ThreadCPUThrottler::ThrottlingThread::~ThrottlingThread() {
   Stop();
diff --git a/third_party/blink/renderer/platform/scheduler/util/thread_load_tracker.cc b/third_party/blink/renderer/platform/scheduler/common/thread_load_tracker.cc
similarity index 97%
rename from third_party/blink/renderer/platform/scheduler/util/thread_load_tracker.cc
rename to third_party/blink/renderer/platform/scheduler/common/thread_load_tracker.cc
index f84529e..54dc1b56 100644
--- a/third_party/blink/renderer/platform/scheduler/util/thread_load_tracker.cc
+++ b/third_party/blink/renderer/platform/scheduler/common/thread_load_tracker.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "third_party/blink/renderer/platform/scheduler/util/thread_load_tracker.h"
+#include "third_party/blink/renderer/platform/scheduler/common/thread_load_tracker.h"
 
 #include <algorithm>
 
diff --git a/third_party/blink/renderer/platform/scheduler/util/thread_load_tracker.h b/third_party/blink/renderer/platform/scheduler/common/thread_load_tracker.h
similarity index 89%
rename from third_party/blink/renderer/platform/scheduler/util/thread_load_tracker.h
rename to third_party/blink/renderer/platform/scheduler/common/thread_load_tracker.h
index 1cd7ee89..35014aaa 100644
--- a/third_party/blink/renderer/platform/scheduler/util/thread_load_tracker.h
+++ b/third_party/blink/renderer/platform/scheduler/common/thread_load_tracker.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_UTIL_THREAD_LOAD_TRACKER_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_UTIL_THREAD_LOAD_TRACKER_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_COMMON_THREAD_LOAD_TRACKER_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_COMMON_THREAD_LOAD_TRACKER_H_
 
 #include "base/callback.h"
 #include "base/macros.h"
@@ -70,4 +70,4 @@
 }  // namespace scheduler
 }  // namespace blink
 
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_UTIL_THREAD_LOAD_TRACKER_H_
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_COMMON_THREAD_LOAD_TRACKER_H_
diff --git a/third_party/blink/renderer/platform/scheduler/util/thread_load_tracker_unittest.cc b/third_party/blink/renderer/platform/scheduler/common/thread_load_tracker_unittest.cc
similarity index 98%
rename from third_party/blink/renderer/platform/scheduler/util/thread_load_tracker_unittest.cc
rename to third_party/blink/renderer/platform/scheduler/common/thread_load_tracker_unittest.cc
index 7f015763..48443c2 100644
--- a/third_party/blink/renderer/platform/scheduler/util/thread_load_tracker_unittest.cc
+++ b/third_party/blink/renderer/platform/scheduler/common/thread_load_tracker_unittest.cc
@@ -1,4 +1,4 @@
-#include "third_party/blink/renderer/platform/scheduler/util/thread_load_tracker.h"
+#include "third_party/blink/renderer/platform/scheduler/common/thread_load_tracker.h"
 
 #include "base/bind.h"
 #include "testing/gmock/include/gmock/gmock.h"
diff --git a/third_party/blink/renderer/platform/scheduler/common/throttling/cpu_time_budget_pool.h b/third_party/blink/renderer/platform/scheduler/common/throttling/cpu_time_budget_pool.h
index db1571e9..0d0fea4e9 100644
--- a/third_party/blink/renderer/platform/scheduler/common/throttling/cpu_time_budget_pool.h
+++ b/third_party/blink/renderer/platform/scheduler/common/throttling/cpu_time_budget_pool.h
@@ -10,7 +10,7 @@
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
 #include "base/optional.h"
-#include "third_party/blink/renderer/platform/scheduler/util/tracing_helper.h"
+#include "third_party/blink/renderer/platform/scheduler/common/tracing_helper.h"
 
 namespace blink {
 namespace scheduler {
diff --git a/third_party/blink/renderer/platform/scheduler/common/throttling/task_queue_throttler.h b/third_party/blink/renderer/platform/scheduler/common/throttling/task_queue_throttler.h
index 42269fa..b29f409b 100644
--- a/third_party/blink/renderer/platform/scheduler/common/throttling/task_queue_throttler.h
+++ b/third_party/blink/renderer/platform/scheduler/common/throttling/task_queue_throttler.h
@@ -20,7 +20,7 @@
 #include "third_party/blink/renderer/platform/scheduler/common/throttling/budget_pool.h"
 #include "third_party/blink/renderer/platform/scheduler/common/throttling/cpu_time_budget_pool.h"
 #include "third_party/blink/renderer/platform/scheduler/common/throttling/wake_up_budget_pool.h"
-#include "third_party/blink/renderer/platform/scheduler/util/tracing_helper.h"
+#include "third_party/blink/renderer/platform/scheduler/common/tracing_helper.h"
 
 namespace base {
 namespace trace_event {
diff --git a/third_party/blink/renderer/platform/scheduler/common/throttling/wake_up_budget_pool.cc b/third_party/blink/renderer/platform/scheduler/common/throttling/wake_up_budget_pool.cc
index 48bee55d..e90fda4 100644
--- a/third_party/blink/renderer/platform/scheduler/common/throttling/wake_up_budget_pool.cc
+++ b/third_party/blink/renderer/platform/scheduler/common/throttling/wake_up_budget_pool.cc
@@ -7,7 +7,7 @@
 #include <cstdint>
 
 #include "third_party/blink/renderer/platform/scheduler/common/throttling/task_queue_throttler.h"
-#include "third_party/blink/renderer/platform/scheduler/util/tracing_helper.h"
+#include "third_party/blink/renderer/platform/scheduler/common/tracing_helper.h"
 
 namespace blink {
 namespace scheduler {
diff --git a/third_party/blink/renderer/platform/scheduler/util/tracing_helper.cc b/third_party/blink/renderer/platform/scheduler/common/tracing_helper.cc
similarity index 94%
rename from third_party/blink/renderer/platform/scheduler/util/tracing_helper.cc
rename to third_party/blink/renderer/platform/scheduler/common/tracing_helper.cc
index f24c423..46a18f9 100644
--- a/third_party/blink/renderer/platform/scheduler/util/tracing_helper.cc
+++ b/third_party/blink/renderer/platform/scheduler/common/tracing_helper.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "third_party/blink/renderer/platform/scheduler/util/tracing_helper.h"
+#include "third_party/blink/renderer/platform/scheduler/common/tracing_helper.h"
 
 #include "base/format_macros.h"
 #include "base/strings/stringprintf.h"
@@ -57,8 +57,7 @@
   }
 }
 
-TraceableVariableController::TraceableVariableController() {
-}
+TraceableVariableController::TraceableVariableController() {}
 
 TraceableVariableController::~TraceableVariableController() {
   // Controller should have very same lifetime as their tracers.
diff --git a/third_party/blink/renderer/platform/scheduler/util/tracing_helper.h b/third_party/blink/renderer/platform/scheduler/common/tracing_helper.h
similarity index 83%
rename from third_party/blink/renderer/platform/scheduler/util/tracing_helper.h
rename to third_party/blink/renderer/platform/scheduler/common/tracing_helper.h
index 75e41431..c28776d 100644
--- a/third_party/blink/renderer/platform/scheduler/util/tracing_helper.h
+++ b/third_party/blink/renderer/platform/scheduler/common/tracing_helper.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_UTIL_TRACING_HELPER_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_UTIL_TRACING_HELPER_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_COMMON_TRACING_HELPER_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_COMMON_TRACING_HELPER_H_
 
 #include <string>
 #include <unordered_set>
@@ -101,9 +101,7 @@
 
   // Trace compile-time defined const string, so no copy needed.
   // Null may be passed to indicate the absence of state.
-  void TraceCompileTimeString(const char* state) {
-    TraceImpl(state, false);
-  }
+  void TraceCompileTimeString(const char* state) { TraceImpl(state, false); }
 
  protected:
   bool is_enabled() const {
@@ -168,25 +166,19 @@
 
   ~TraceableState() override = default;
 
-  TraceableState& operator =(const T& value) {
+  TraceableState& operator=(const T& value) {
     Assign(value);
     return *this;
   }
-  TraceableState& operator =(const TraceableState& another) {
+  TraceableState& operator=(const TraceableState& another) {
     Assign(another.state_);
     return *this;
   }
 
-  operator T() const {
-    return state_;
-  }
-  const T& get() const {
-    return state_;
-  }
+  operator T() const { return state_; }
+  const T& get() const { return state_; }
 
-  void OnTraceLogEnabled() final {
-    Trace();
-  }
+  void OnTraceLogEnabled() final { Trace(); }
 
  protected:
   void Assign(T new_state) {
@@ -254,48 +246,40 @@
     Trace();
   }
 
-  TraceableCounter& operator =(const T& value) {
+  TraceableCounter& operator=(const T& value) {
     value_ = value;
     Trace();
     return *this;
   }
-  TraceableCounter& operator =(const TraceableCounter& another) {
+  TraceableCounter& operator=(const TraceableCounter& another) {
     value_ = another.value_;
     Trace();
     return *this;
   }
 
-  TraceableCounter& operator +=(const T& value) {
+  TraceableCounter& operator+=(const T& value) {
     value_ += value;
     Trace();
     return *this;
   }
-  TraceableCounter& operator -=(const T& value) {
+  TraceableCounter& operator-=(const T& value) {
     value_ -= value;
     Trace();
     return *this;
   }
 
-  const T& value() const {
-    return value_;
-  }
-  const T* operator ->() const {
-    return &value_;
-  }
-  operator T() const {
-    return value_;
-  }
+  const T& value() const { return value_; }
+  const T* operator->() const { return &value_; }
+  operator T() const { return value_; }
 
-  void OnTraceLogEnabled() final {
-    Trace();
-  }
+  void OnTraceLogEnabled() final { Trace(); }
 
   void Trace() const {
     TRACE_COUNTER_ID1(category, name_, object_, converter_(value_));
   }
 
  private:
-  const char* const name_;  // Not owned.
+  const char* const name_;    // Not owned.
   const void* const object_;  // Not owned.
   const ConverterFuncPtr converter_;
 
@@ -306,54 +290,54 @@
 // Add operators when it's needed.
 
 template <typename T, const char* category>
-constexpr T operator -(const TraceableCounter<T, category>& counter) {
+constexpr T operator-(const TraceableCounter<T, category>& counter) {
   return -counter.value();
 }
 
 template <typename T, const char* category>
-constexpr T operator /(const TraceableCounter<T, category>& lhs, const T& rhs) {
+constexpr T operator/(const TraceableCounter<T, category>& lhs, const T& rhs) {
   return lhs.value() / rhs;
 }
 
 template <typename T, const char* category>
-constexpr bool operator >(
-    const TraceableCounter<T, category>& lhs, const T& rhs) {
+constexpr bool operator>(const TraceableCounter<T, category>& lhs,
+                         const T& rhs) {
   return lhs.value() > rhs;
 }
 
 template <typename T, const char* category>
-constexpr bool operator <(
-    const TraceableCounter<T, category>& lhs, const T& rhs) {
+constexpr bool operator<(const TraceableCounter<T, category>& lhs,
+                         const T& rhs) {
   return lhs.value() < rhs;
 }
 
 template <typename T, const char* category>
-constexpr bool operator !=(
-    const TraceableCounter<T, category>& lhs, const T& rhs) {
+constexpr bool operator!=(const TraceableCounter<T, category>& lhs,
+                          const T& rhs) {
   return lhs.value() != rhs;
 }
 
 template <typename T, const char* category>
-constexpr T operator ++(TraceableCounter<T, category>& counter) {
+constexpr T operator++(TraceableCounter<T, category>& counter) {
   counter = counter.value() + 1;
   return counter.value();
 }
 
 template <typename T, const char* category>
-constexpr T operator --(TraceableCounter<T, category>& counter) {
+constexpr T operator--(TraceableCounter<T, category>& counter) {
   counter = counter.value() - 1;
   return counter.value();
 }
 
 template <typename T, const char* category>
-constexpr T operator ++(TraceableCounter<T, category>& counter, int) {
+constexpr T operator++(TraceableCounter<T, category>& counter, int) {
   T value = counter.value();
   counter = value + 1;
   return value;
 }
 
 template <typename T, const char* category>
-constexpr T operator --(TraceableCounter<T, category>& counter, int) {
+constexpr T operator--(TraceableCounter<T, category>& counter, int) {
   T value = counter.value();
   counter = value - 1;
   return value;
@@ -362,4 +346,4 @@
 }  // namespace scheduler
 }  // namespace blink
 
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_UTIL_TRACING_HELPER_H_
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_COMMON_TRACING_HELPER_H_
diff --git a/third_party/blink/renderer/platform/scheduler/util/tracing_helper_unittest.cc b/third_party/blink/renderer/platform/scheduler/common/tracing_helper_unittest.cc
similarity index 82%
rename from third_party/blink/renderer/platform/scheduler/util/tracing_helper_unittest.cc
rename to third_party/blink/renderer/platform/scheduler/common/tracing_helper_unittest.cc
index 61931729..8d31aae7 100644
--- a/third_party/blink/renderer/platform/scheduler/util/tracing_helper_unittest.cc
+++ b/third_party/blink/renderer/platform/scheduler/common/tracing_helper_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "third_party/blink/renderer/platform/scheduler/util/tracing_helper.h"
+#include "third_party/blink/renderer/platform/scheduler/common/tracing_helper.h"
 
 #include <unordered_set>
 
@@ -43,7 +43,7 @@
     mock_trace_for_test_ = &MockTrace;
   }
 
-  TraceableStateForTest& operator =(const int& value) {
+  TraceableStateForTest& operator=(const int& value) {
     Assign(value);
     return *this;
   }
@@ -74,10 +74,10 @@
 
 TEST(TracingHelperTest, TraceableStateOperators) {
   TraceableVariableController controller;
-  TraceableState<int, kTracingCategoryNameDebug> x(
-      -1, "X", &controller, &controller, SignOfInt);
-  TraceableState<int, kTracingCategoryNameDebug> y(
-      1, "Y", &controller, &controller, SignOfInt);
+  TraceableState<int, kTracingCategoryNameDebug> x(-1, "X", &controller,
+                                                   &controller, SignOfInt);
+  TraceableState<int, kTracingCategoryNameDebug> y(1, "Y", &controller,
+                                                   &controller, SignOfInt);
   EXPECT_EQ(0, x + y);
   EXPECT_FALSE(x == y);
   EXPECT_TRUE(x != y);
diff --git a/third_party/blink/renderer/platform/scheduler/common/web_thread_scheduler.cc b/third_party/blink/renderer/platform/scheduler/common/web_thread_scheduler.cc
index e81a397..b3afb817 100644
--- a/third_party/blink/renderer/platform/scheduler/common/web_thread_scheduler.cc
+++ b/third_party/blink/renderer/platform/scheduler/common/web_thread_scheduler.cc
@@ -7,8 +7,8 @@
 #include <utility>
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
+#include "third_party/blink/renderer/platform/scheduler/common/tracing_helper.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h"
-#include "third_party/blink/renderer/platform/scheduler/util/tracing_helper.h"
 
 namespace blink {
 namespace scheduler {
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc
index 8398bbb..fe2a37f 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc
@@ -15,15 +15,15 @@
 #include "third_party/blink/public/platform/blame_context.h"
 #include "third_party/blink/public/platform/web_string.h"
 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
-#include "third_party/blink/renderer/platform/scheduler/child/features.h"
+#include "third_party/blink/renderer/platform/scheduler/common/features.h"
 #include "third_party/blink/renderer/platform/scheduler/common/throttling/budget_pool.h"
+#include "third_party/blink/renderer/platform/scheduler/common/tracing_helper.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/auto_advancing_virtual_time_domain.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/page_visibility_state.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/resource_loading_task_runner_handle_impl.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/task_type_names.h"
-#include "third_party/blink/renderer/platform/scheduler/util/tracing_helper.h"
 #include "third_party/blink/renderer/platform/scheduler/worker/worker_scheduler_proxy.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h
index 2513a49f..6c8001f 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h
@@ -20,12 +20,12 @@
 #include "services/metrics/public/cpp/ukm_source_id.h"
 #include "third_party/blink/public/platform/task_type.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
+#include "third_party/blink/renderer/platform/scheduler/common/tracing_helper.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/frame_origin_type.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/frame_task_queue_controller.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/page_visibility_state.h"
 #include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h"
-#include "third_party/blink/renderer/platform/scheduler/util/tracing_helper.h"
 #include "third_party/blink/renderer/platform/scheduler/worker/worker_scheduler_proxy.h"
 #include "third_party/blink/renderer/platform/wtf/hash_map.h"
 
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc
index aa6a0979..d00eeb9e 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc
@@ -17,7 +17,7 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/common/features.h"
-#include "third_party/blink/renderer/platform/scheduler/child/features.h"
+#include "third_party/blink/renderer/platform/scheduler/common/features.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/frame_task_queue_controller.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h"
diff --git a/third_party/blink/renderer/platform/scheduler/renderer/frame_status.cc b/third_party/blink/renderer/platform/scheduler/main_thread/frame_status.cc
similarity index 96%
rename from third_party/blink/renderer/platform/scheduler/renderer/frame_status.cc
rename to third_party/blink/renderer/platform/scheduler/main_thread/frame_status.cc
index da08cbda..cfda104e 100644
--- a/third_party/blink/renderer/platform/scheduler/renderer/frame_status.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/frame_status.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "third_party/blink/renderer/platform/scheduler/renderer/frame_status.h"
+#include "third_party/blink/renderer/platform/scheduler/public/frame_status.h"
 
 #include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h"
 #include "third_party/blink/renderer/platform/scheduler/public/page_scheduler.h"
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/frame_task_queue_controller.cc b/third_party/blink/renderer/platform/scheduler/main_thread/frame_task_queue_controller.cc
index a76631f..7afcea95 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/frame_task_queue_controller.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/frame_task_queue_controller.cc
@@ -12,10 +12,10 @@
 #include "base/logging.h"
 #include "base/trace_event/traced_value.h"
 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
+#include "third_party/blink/renderer/platform/scheduler/common/tracing_helper.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h"
-#include "third_party/blink/renderer/platform/scheduler/util/tracing_helper.h"
 
 namespace blink {
 namespace scheduler {
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_metrics_helper.h b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_metrics_helper.h
index c024e31..f1b9906 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_metrics_helper.h
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_metrics_helper.h
@@ -14,10 +14,10 @@
 #include "third_party/blink/public/platform/web_thread_type.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
 #include "third_party/blink/renderer/platform/scheduler/common/metrics_helper.h"
+#include "third_party/blink/renderer/platform/scheduler/common/thread_load_tracker.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/use_case.h"
-#include "third_party/blink/renderer/platform/scheduler/renderer/frame_status.h"
-#include "third_party/blink/renderer/platform/scheduler/util/thread_load_tracker.h"
+#include "third_party/blink/renderer/platform/scheduler/public/frame_status.h"
 
 namespace blink {
 namespace scheduler {
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 25bc22b3..c76622a 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
@@ -30,8 +30,8 @@
 #include "third_party/blink/renderer/platform/bindings/parkable_string_manager.h"
 #include "third_party/blink/renderer/platform/instrumentation/resource_coordinator/renderer_resource_coordinator.h"
 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
-#include "third_party/blink/renderer/platform/scheduler/child/features.h"
-#include "third_party/blink/renderer/platform/scheduler/child/process_state.h"
+#include "third_party/blink/renderer/platform/scheduler/common/features.h"
+#include "third_party/blink/renderer/platform/scheduler/common/process_state.h"
 #include "third_party/blink/renderer/platform/scheduler/common/throttling/task_queue_throttler.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/auto_advancing_virtual_time_domain.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h"
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 97d61fb..7832f6a 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
@@ -26,10 +26,11 @@
 #include "build/build_config.h"
 #include "third_party/blink/public/platform/scheduler/web_thread_scheduler.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
-#include "third_party/blink/renderer/platform/scheduler/child/pollable_thread_safe_flag.h"
 #include "third_party/blink/renderer/platform/scheduler/common/idle_canceled_delayed_task_sweeper.h"
 #include "third_party/blink/renderer/platform/scheduler/common/idle_helper.h"
+#include "third_party/blink/renderer/platform/scheduler/common/pollable_thread_safe_flag.h"
 #include "third_party/blink/renderer/platform/scheduler/common/thread_scheduler_impl.h"
+#include "third_party/blink/renderer/platform/scheduler/common/tracing_helper.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/auto_advancing_virtual_time_domain.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/deadline_task_runner.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/idle_time_estimator.h"
@@ -44,7 +45,6 @@
 #include "third_party/blink/renderer/platform/scheduler/main_thread/use_case.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/user_model.h"
 #include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h"
-#include "third_party/blink/renderer/platform/scheduler/util/tracing_helper.h"
 
 namespace base {
 namespace trace_event {
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl_unittest.cc b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl_unittest.cc
index 5fbaf37..f96edccc 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl_unittest.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl_unittest.cc
@@ -27,7 +27,7 @@
 #include "third_party/blink/public/common/page/launching_process_state.h"
 #include "third_party/blink/public/platform/web_mouse_wheel_event.h"
 #include "third_party/blink/public/platform/web_touch_event.h"
-#include "third_party/blink/renderer/platform/scheduler/child/features.h"
+#include "third_party/blink/renderer/platform/scheduler/common/features.h"
 #include "third_party/blink/renderer/platform/scheduler/common/throttling/budget_pool.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/auto_advancing_virtual_time_domain.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h"
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.h b/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.h
index 175131de..7b277b0 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.h
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.h
@@ -17,11 +17,11 @@
 #include "base/time/time.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
 #include "third_party/blink/renderer/platform/scheduler/common/throttling/task_queue_throttler.h"
+#include "third_party/blink/renderer/platform/scheduler/common/tracing_helper.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/page_visibility_state.h"
 #include "third_party/blink/renderer/platform/scheduler/public/page_lifecycle_state.h"
 #include "third_party/blink/renderer/platform/scheduler/public/page_scheduler.h"
 #include "third_party/blink/renderer/platform/scheduler/public/thread_scheduler.h"
-#include "third_party/blink/renderer/platform/scheduler/util/tracing_helper.h"
 
 namespace base {
 namespace trace_event {
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/prioritize_compositing_after_input_experiment.cc b/third_party/blink/renderer/platform/scheduler/main_thread/prioritize_compositing_after_input_experiment.cc
index aaebb58..3b660d3 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/prioritize_compositing_after_input_experiment.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/prioritize_compositing_after_input_experiment.cc
@@ -6,7 +6,7 @@
 
 #include "base/metrics/field_trial_params.h"
 #include "base/strings/string_number_conversions.h"
-#include "third_party/blink/renderer/platform/scheduler/child/features.h"
+#include "third_party/blink/renderer/platform/scheduler/common/features.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h"
 
diff --git a/third_party/blink/renderer/platform/scheduler/renderer/web_scoped_virtual_time_pauser.cc b/third_party/blink/renderer/platform/scheduler/main_thread/web_scoped_virtual_time_pauser.cc
similarity index 100%
rename from third_party/blink/renderer/platform/scheduler/renderer/web_scoped_virtual_time_pauser.cc
rename to third_party/blink/renderer/platform/scheduler/main_thread/web_scoped_virtual_time_pauser.cc
diff --git a/third_party/blink/renderer/platform/scheduler/util/aggregated_metric_reporter.h b/third_party/blink/renderer/platform/scheduler/public/aggregated_metric_reporter.h
similarity index 90%
rename from third_party/blink/renderer/platform/scheduler/util/aggregated_metric_reporter.h
rename to third_party/blink/renderer/platform/scheduler/public/aggregated_metric_reporter.h
index 9e4e423..a705015 100644
--- a/third_party/blink/renderer/platform/scheduler/util/aggregated_metric_reporter.h
+++ b/third_party/blink/renderer/platform/scheduler/public/aggregated_metric_reporter.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_UTIL_AGGREGATED_METRIC_REPORTER_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_UTIL_AGGREGATED_METRIC_REPORTER_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_PUBLIC_AGGREGATED_METRIC_REPORTER_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_PUBLIC_AGGREGATED_METRIC_REPORTER_H_
 
 #include <array>
 
@@ -86,4 +86,4 @@
 }  // namespace scheduler
 }  // namespace blink
 
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_UTIL_AGGREGATED_METRIC_REPORTER_H_
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_PUBLIC_AGGREGATED_METRIC_REPORTER_H_
diff --git a/third_party/blink/renderer/platform/scheduler/renderer/frame_status.h b/third_party/blink/renderer/platform/scheduler/public/frame_status.h
similarity index 91%
rename from third_party/blink/renderer/platform/scheduler/renderer/frame_status.h
rename to third_party/blink/renderer/platform/scheduler/public/frame_status.h
index d1dfdc8..a7dbd98 100644
--- a/third_party/blink/renderer/platform/scheduler/renderer/frame_status.h
+++ b/third_party/blink/renderer/platform/scheduler/public/frame_status.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_RENDERER_FRAME_STATUS_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_RENDERER_FRAME_STATUS_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_PUBLIC_FRAME_STATUS_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_PUBLIC_FRAME_STATUS_H_
 
 #include "third_party/blink/renderer/platform/platform_export.h"
 
@@ -82,4 +82,4 @@
 }  // namespace scheduler
 }  // namespace blink
 
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_RENDERER_FRAME_STATUS_H_
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_PUBLIC_FRAME_STATUS_H_
diff --git a/third_party/blink/renderer/platform/scheduler/util/thread_cpu_throttler.h b/third_party/blink/renderer/platform/scheduler/public/thread_cpu_throttler.h
similarity index 82%
rename from third_party/blink/renderer/platform/scheduler/util/thread_cpu_throttler.h
rename to third_party/blink/renderer/platform/scheduler/public/thread_cpu_throttler.h
index 95c5c4c..6f02b7a 100644
--- a/third_party/blink/renderer/platform/scheduler/util/thread_cpu_throttler.h
+++ b/third_party/blink/renderer/platform/scheduler/public/thread_cpu_throttler.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_UTIL_THREAD_CPU_THROTTLER_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_UTIL_THREAD_CPU_THROTTLER_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_PUBLIC_THREAD_CPU_THROTTLER_H_
+#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_PUBLIC_THREAD_CPU_THROTTLER_H_
 
 #include <memory>
 
@@ -46,4 +46,4 @@
 }  // namespace scheduler
 }  // namespace blink
 
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_UTIL_THREAD_CPU_THROTTLER_H_
+#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_PUBLIC_THREAD_CPU_THROTTLER_H_
diff --git a/third_party/blink/renderer/platform/scheduler/renderer/DEPS b/third_party/blink/renderer/platform/scheduler/renderer/DEPS
deleted file mode 100644
index e6bf2b8..0000000
--- a/third_party/blink/renderer/platform/scheduler/renderer/DEPS
+++ /dev/null
@@ -1,8 +0,0 @@
-include_rules = [
-  "+base/metrics/single_sample_metrics.h",
-  "+cc",
-  "+components/viz/common",
-  "+services/resource_coordinator/public/cpp/resource_coordinator_features.h",
-  "+third_party/blink/renderer/platform/scheduler/base",
-  "+third_party/blink/renderer/platform/scheduler/child",
-]
diff --git a/third_party/blink/renderer/platform/scheduler/worker/compositor_thread_scheduler.cc b/third_party/blink/renderer/platform/scheduler/worker/compositor_thread_scheduler.cc
index a500417..6ce154e 100644
--- a/third_party/blink/renderer/platform/scheduler/worker/compositor_thread_scheduler.cc
+++ b/third_party/blink/renderer/platform/scheduler/worker/compositor_thread_scheduler.cc
@@ -13,7 +13,7 @@
 #include "base/threading/thread.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "third_party/blink/public/platform/task_type.h"
-#include "third_party/blink/renderer/platform/scheduler/child/features.h"
+#include "third_party/blink/renderer/platform/scheduler/common/features.h"
 #include "third_party/blink/renderer/platform/scheduler/common/scheduler_helper.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/platform/scheduler/worker/compositor_thread_scheduler_unittest.cc b/third_party/blink/renderer/platform/scheduler/worker/compositor_thread_scheduler_unittest.cc
index 2aaf26be..c5c61ff 100644
--- a/third_party/blink/renderer/platform/scheduler/worker/compositor_thread_scheduler_unittest.cc
+++ b/third_party/blink/renderer/platform/scheduler/worker/compositor_thread_scheduler_unittest.cc
@@ -11,7 +11,7 @@
 #include "base/test/test_mock_time_task_runner.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/renderer/platform/scheduler/child/features.h"
+#include "third_party/blink/renderer/platform/scheduler/common/features.h"
 #include "third_party/blink/renderer/platform/wtf/functional.h"
 
 using testing::ElementsAreArray;
diff --git a/third_party/blink/renderer/platform/scheduler/worker/non_main_thread_scheduler_impl.h b/third_party/blink/renderer/platform/scheduler/worker/non_main_thread_scheduler_impl.h
index a06d242c..0ce014c2 100644
--- a/third_party/blink/renderer/platform/scheduler/worker/non_main_thread_scheduler_impl.h
+++ b/third_party/blink/renderer/platform/scheduler/worker/non_main_thread_scheduler_impl.h
@@ -14,8 +14,8 @@
 #include "third_party/blink/public/platform/web_thread_type.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
 #include "third_party/blink/renderer/platform/scheduler/common/thread_scheduler_impl.h"
+#include "third_party/blink/renderer/platform/scheduler/common/tracing_helper.h"
 #include "third_party/blink/renderer/platform/scheduler/public/thread_scheduler.h"
-#include "third_party/blink/renderer/platform/scheduler/util/tracing_helper.h"
 #include "third_party/blink/renderer/platform/scheduler/worker/non_main_thread_scheduler_helper.h"
 #include "third_party/blink/renderer/platform/scheduler/worker/non_main_thread_task_queue.h"
 
diff --git a/third_party/blink/renderer/platform/scheduler/worker/worker_metrics_helper.cc b/third_party/blink/renderer/platform/scheduler/worker/worker_metrics_helper.cc
index 71bd7ae3..553db17d 100644
--- a/third_party/blink/renderer/platform/scheduler/worker/worker_metrics_helper.cc
+++ b/third_party/blink/renderer/platform/scheduler/worker/worker_metrics_helper.cc
@@ -4,7 +4,7 @@
 
 #include "third_party/blink/renderer/platform/scheduler/worker/worker_metrics_helper.h"
 
-#include "third_party/blink/renderer/platform/scheduler/child/process_state.h"
+#include "third_party/blink/renderer/platform/scheduler/common/process_state.h"
 
 namespace blink {
 namespace scheduler {
diff --git a/third_party/blink/renderer/platform/scheduler/worker/worker_metrics_helper.h b/third_party/blink/renderer/platform/scheduler/worker/worker_metrics_helper.h
index d4a1535..56db0582 100644
--- a/third_party/blink/renderer/platform/scheduler/worker/worker_metrics_helper.h
+++ b/third_party/blink/renderer/platform/scheduler/worker/worker_metrics_helper.h
@@ -7,8 +7,8 @@
 
 #include "third_party/blink/public/platform/task_type.h"
 #include "third_party/blink/renderer/platform/scheduler/common/metrics_helper.h"
+#include "third_party/blink/renderer/platform/scheduler/common/thread_load_tracker.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/frame_origin_type.h"
-#include "third_party/blink/renderer/platform/scheduler/util/thread_load_tracker.h"
 #include "third_party/blink/renderer/platform/scheduler/worker/non_main_thread_task_queue.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/platform/scheduler/worker/worker_scheduler_proxy.h b/third_party/blink/renderer/platform/scheduler/worker/worker_scheduler_proxy.h
index 60ed4b6..f0ebe21 100644
--- a/third_party/blink/renderer/platform/scheduler/worker/worker_scheduler_proxy.h
+++ b/third_party/blink/renderer/platform/scheduler/worker/worker_scheduler_proxy.h
@@ -16,7 +16,7 @@
 #include "third_party/blink/renderer/platform/platform_export.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/frame_origin_type.h"
 #include "third_party/blink/renderer/platform/scheduler/public/frame_or_worker_scheduler.h"
-#include "third_party/blink/renderer/platform/scheduler/renderer/frame_status.h"
+#include "third_party/blink/renderer/platform/scheduler/public/frame_status.h"
 #include "third_party/blink/renderer/platform/wtf/wtf.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler.cc b/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler.cc
index cbc26ff..c4abb8f 100644
--- a/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler.cc
+++ b/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler.cc
@@ -18,8 +18,8 @@
 #include "services/metrics/public/cpp/mojo_ukm_recorder.h"
 #include "services/metrics/public/cpp/ukm_builders.h"
 #include "third_party/blink/renderer/platform/histogram.h"
-#include "third_party/blink/renderer/platform/scheduler/child/features.h"
-#include "third_party/blink/renderer/platform/scheduler/child/process_state.h"
+#include "third_party/blink/renderer/platform/scheduler/common/features.h"
+#include "third_party/blink/renderer/platform/scheduler/common/process_state.h"
 #include "third_party/blink/renderer/platform/scheduler/common/throttling/task_queue_throttler.h"
 #include "third_party/blink/renderer/platform/scheduler/public/worker_scheduler.h"
 #include "third_party/blink/renderer/platform/scheduler/worker/non_main_thread_scheduler_helper.h"
diff --git a/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler.h b/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler.h
index 3ddbe4d0..4b4727c 100644
--- a/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler.h
+++ b/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler.h
@@ -13,9 +13,9 @@
 #include "third_party/blink/public/platform/web_thread_type.h"
 #include "third_party/blink/renderer/platform/scheduler/common/idle_canceled_delayed_task_sweeper.h"
 #include "third_party/blink/renderer/platform/scheduler/common/idle_helper.h"
+#include "third_party/blink/renderer/platform/scheduler/common/thread_load_tracker.h"
 #include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h"
-#include "third_party/blink/renderer/platform/scheduler/renderer/frame_status.h"
-#include "third_party/blink/renderer/platform/scheduler/util/thread_load_tracker.h"
+#include "third_party/blink/renderer/platform/scheduler/public/frame_status.h"
 #include "third_party/blink/renderer/platform/scheduler/worker/non_main_thread_scheduler_impl.h"
 #include "third_party/blink/renderer/platform/scheduler/worker/worker_metrics_helper.h"
 
diff --git a/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler_unittest.cc b/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler_unittest.cc
index acf14e7..44ca277 100644
--- a/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler_unittest.cc
+++ b/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler_unittest.cc
@@ -13,7 +13,7 @@
 #include "components/ukm/test_ukm_recorder.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/renderer/platform/scheduler/child/process_state.h"
+#include "third_party/blink/renderer/platform/scheduler/common/process_state.h"
 #include "third_party/blink/renderer/platform/scheduler/test/fake_frame_scheduler.h"
 
 using testing::ElementsAreArray;
diff --git a/third_party/blink/renderer/platform/scroll/scroll_snap_data.h b/third_party/blink/renderer/platform/scroll/scroll_snap_data.h
index 0aa5294..81c8a55 100644
--- a/third_party/blink/renderer/platform/scroll/scroll_snap_data.h
+++ b/third_party/blink/renderer/platform/scroll/scroll_snap_data.h
@@ -7,6 +7,7 @@
 
 #include "cc/input/scroll_snap_data.h"
 #include "cc/input/snap_fling_controller.h"
+#include "cc/input/snap_selection_strategy.h"
 
 // This file defines classes and structs used in SnapCoordinator.h
 
@@ -16,6 +17,7 @@
 using SearchAxis = cc::SearchAxis;
 using SnapStrictness = cc::SnapStrictness;
 using SnapAlignment = cc::SnapAlignment;
+using SnapSelectionStrategy = cc::SnapSelectionStrategy;
 using ScrollSnapType = cc::ScrollSnapType;
 using ScrollSnapAlign = cc::ScrollSnapAlign;
 using SnapAreaData = cc::SnapAreaData;
diff --git a/third_party/blink/tools/blinkpy/common/net/git_cl.py b/third_party/blink/tools/blinkpy/common/net/git_cl.py
index ce18a085..b425939 100644
--- a/third_party/blink/tools/blinkpy/common/net/git_cl.py
+++ b/third_party/blink/tools/blinkpy/common/net/git_cl.py
@@ -248,10 +248,14 @@
         url = result_dict['url']
         if url is None:
             return Build(builder_name, None)
-        match = re.match(r'.*/(\d+)/?$', url)
-        if match:
-            build_number = match.group(1)
-            return Build(builder_name, int(build_number))
+        # TODO(martiniss): Switch to using build number once `git cl
+        # try-results` uses buildbucket v2 API.
+        tags = result_dict.get('tags', [])
+        for tag in tags:
+            if tag.startswith("build_address:"):
+                build_number = tag.split('/')[-1]
+                return Build(builder_name, int(build_number))
+
         match = re.match(r'.*/task/([0-9a-f]+)(/?|\?.*)$', url)
         assert match, '%s did not match expected format' % url
         task_id = match.group(1)
diff --git a/third_party/blink/tools/blinkpy/common/net/git_cl_unittest.py b/third_party/blink/tools/blinkpy/common/net/git_cl_unittest.py
index b16a3ab..755fa41b 100644
--- a/third_party/blink/tools/blinkpy/common/net/git_cl_unittest.py
+++ b/third_party/blink/tools/blinkpy/common/net/git_cl_unittest.py
@@ -201,7 +201,10 @@
                 'builder_name': 'some-builder',
                 'status': 'COMPLETED',
                 'result': 'FAILURE',
-                'url': 'http://ci.chromium.org/master/some-builder/100',
+                'tags': [
+                    'build_address:luci.chromium.try/chromium_presubmit/100',
+                ],
+                'url': 'http://ci.chromium.org/b/8931586523737389552',
             },
         ]
         self.assertEqual(
@@ -348,12 +351,18 @@
                 'builder_name': 'builder-b',
                 'status': 'COMPLETED',
                 'result': 'SUCCESS',
-                'url': 'http://build.chromium.org/p/master/builders/builder-b/builds/100',
+                'tags': [
+                    'build_address:luci.chromium.try/chromium_presubmit/100',
+                ],
+                'url': 'http://build.chromium.org/b/123123123132123123',
             },
             {
                 'builder_name': 'builder-b',
                 'status': 'COMPLETED',
                 'result': 'SUCCESS',
+                'tags': [
+                    'build_address:luci.chromium.try/chromium_presubmit/90',
+                ],
                 'url': 'http://build.chromium.org/p/master/builders/builder-b/builds/90',
             },
             {
@@ -366,7 +375,10 @@
                 'builder_name': 'builder-c',
                 'status': 'COMPLETED',
                 'result': 'SUCCESS',
-                'url': 'http://ci.chromium.org/master/builder-c/123',
+                'tags': [
+                    'build_address:luci.chromium.try/chromium_presubmit/123',
+                ],
+                'url': 'http://ci.chromium.org/b/123123123123123123',
             },
         ]
         self.assertEqual(
@@ -383,21 +395,10 @@
                 'builder_name': 'builder-a',
                 'status': 'STARTED',
                 'result': None,
-                'url': 'http://ci.chromium.org/p/master/some-builder/100',
-            },
-        ]
-        self.assertEqual(
-            git_cl.latest_try_jobs(['builder-a']),
-            {Build('builder-a', 100): TryJobStatus('STARTED')})
-
-    def test_latest_try_jobs_started_build_buildbot_url(self):
-        git_cl = GitCL(MockHost())
-        git_cl.fetch_raw_try_job_results = lambda **_: [
-            {
-                'builder_name': 'builder-a',
-                'status': 'STARTED',
-                'result': None,
-                'url': 'http://build.chromium.org/master/builders/some-builder/builds/100',
+                'tags': [
+                    'build_address:luci.chromium.try/chromium_presubmit/100',
+                ],
+                'url': 'http://ci.chromium.org/b/123123123123123',
             },
         ]
         self.assertEqual(
@@ -412,14 +413,20 @@
                 'status': 'COMPLETED',
                 'result': 'FAILURE',
                 'failure_reason': 'BUILD_FAILURE',
-                'url': 'http://ci.chromium.org/p/master/builder-a/100',
+                'tags': [
+                    'build_address:luci.chromium.try/chromium_presubmit/100',
+                ],
+                'url': 'http://ci.chromium.org/b/123123123123123123',
             },
             {
                 'builder_name': 'builder-b',
                 'status': 'COMPLETED',
                 'result': 'FAILURE',
                 'failure_reason': 'INFRA_FAILURE',
-                'url': 'http://ci.chromium.org/p/master/builder-b/200',
+                'tags': [
+                    'build_address:luci.chromium.try/chromium_presubmit/200',
+                ],
+                'url': 'http://ci.chromium.org/b/1293871928371923719',
             },
         ]
         self.assertEqual(
@@ -436,7 +443,10 @@
                 'builder_name': 'builder-b',
                 'status': 'COMPLETED',
                 'result': 'SUCCESS',
-                'url': 'https://ci.chromium.org/buildbot/mymaster/builder-b/10',
+                'tags': [
+                    'build_address:luci.chromium.try/chromium_presubmit/10',
+                ],
+                'url': 'https://ci.chromium.org/b/123918239182739',
             },
             {
                 'builder_name': 'builder-b',
diff --git a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
index 670c4f3f..11e77b1 100755
--- a/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
+++ b/third_party/blink/tools/blinkpy/presubmit/audit_non_blink_usage.py
@@ -233,8 +233,10 @@
             'root_scroller_util::.+',
             'scheduler::.+',
             'style_change_reason::.+',
+            'svg_path_parser::.+',
             'touch_action_util::.+',
             'vector_math::.+',
+            'web_core_test_support::.+',
             'xpath::.+',
             '[a-z_]+_names::.+',
 
diff --git a/third_party/openh264/openh264_sources.gni b/third_party/openh264/openh264_sources.gni
index 0971e8c..0f9b77b 100644
--- a/third_party/openh264/openh264_sources.gni
+++ b/third_party/openh264/openh264_sources.gni
@@ -7,7 +7,6 @@
 ]
 
 openh264_common_sources = [
-  "//third_party/openh264/src/codec/common/inc/WelsCircleQueue.h",
   "//third_party/openh264/src/codec/common/inc/WelsList.h",
   "//third_party/openh264/src/codec/common/inc/WelsLock.h",
   "//third_party/openh264/src/codec/common/inc/WelsTask.h",
@@ -50,7 +49,6 @@
   "//third_party/openh264/src/codec/common/src/memory_align.cpp",
   "//third_party/openh264/src/codec/common/src/sad_common.cpp",
   "//third_party/openh264/src/codec/common/src/utils.cpp",
-  "//third_party/openh264/src/codec/common/src/utils.h",
   "//third_party/openh264/src/codec/common/src/welsCodecTrace.cpp",
 ]
 
diff --git a/third_party/r8/README.chromium b/third_party/r8/README.chromium
index 2a4d8da..be584395 100644
--- a/third_party/r8/README.chromium
+++ b/third_party/r8/README.chromium
@@ -1,13 +1,14 @@
 Name: R8
 URL: https://r8.googlesource.com/r8
-Version: 1.2.48
+Revision: 97efc6605ceee3e7c12238ae48718d63e5906b4a
+Version: 1.4.4
 License: BSD 3-Clause
 License File: NOT_SHIPPED
 Security Critical: no
 
 Description:
-D8 is a dexer that converts java byte code to dex code.
-It is contained in the R8 repo.
+D8 is a dexer that converts java byte code to dex code. R8 is a proguard-like
+optimizer that also has the ability to dex. D8 is found within R8's repo.
 
 Local Modifications:
 None
diff --git a/third_party/r8/cipd.yaml b/third_party/r8/cipd.yaml
index a498686..e34da20 100644
--- a/third_party/r8/cipd.yaml
+++ b/third_party/r8/cipd.yaml
@@ -1,5 +1,7 @@
 package: chromium/third_party/r8
 description: >
   D8 is a dexer that converts java byte code to dex code (part of the R8 repo).
+  R8 is a proguard-like optimizer that also has the option to dex.
 data:
   - file: lib/d8.jar
+  - file: lib/r8.jar
diff --git a/third_party/s2cellid/BUILD.gn b/third_party/s2cellid/BUILD.gn
index 2d71a80..db13b4c 100644
--- a/third_party/s2cellid/BUILD.gn
+++ b/third_party/s2cellid/BUILD.gn
@@ -25,7 +25,6 @@
     "src/s2/r2rect.h",
     "src/s2/s1angle.cc",
     "src/s2/s1angle.h",
-    "src/s2/s2.h",
     "src/s2/s2cellid.cc",
     "src/s2/s2cellid.h",
     "src/s2/s2coords-internal.h",
diff --git a/tools/gyp b/tools/gyp
new file mode 160000
index 0000000..d61a939
--- /dev/null
+++ b/tools/gyp
@@ -0,0 +1 @@
+Subproject commit d61a9397e668fa9843c4aa7da9e79460fe590bfb
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index fc2a0de..3d9b6398 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -12528,6 +12528,9 @@
   <int value="0" label="Success"/>
   <int value="1" label="UnknownFailure"/>
   <int value="2" label="TemporaryUnavailable"/>
+  <int value="3" label="InvocationFailure"/>
+  <int value="4" label="UnexpectedDisconnect"/>
+  <int value="5" label="Timeout"/>
 </enum>
 
 <enum name="DriveUploadProtocol">
@@ -20607,6 +20610,7 @@
   <int value="2610" label="V8AttemptOverrideReadOnlyOnPrototypeStrict"/>
   <int value="2611" label="HTMLCanvasElementLowLatency"/>
   <int value="2612" label="V8OptimizedFunctionWithOneShotBytecode"/>
+  <int value="2613" label="SVGGeometryPropertyHasNonZeroUnitlessValue"/>
 </enum>
 
 <enum name="FeaturePolicyFeature">
@@ -29459,6 +29463,7 @@
   <int value="-1085492638" label="FetchKeepaliveTimeoutSetting:enabled"/>
   <int value="-1084855234" label="UnfilteredBluetoothDevices:disabled"/>
   <int value="-1084055006" label="disable-web-notification-custom-layouts"/>
+  <int value="-1083547717" label="NotificationExpansionAnimation:disabled"/>
   <int value="-1082302549" label="scan-cards-in-web-payments"/>
   <int value="-1078093206" label="ash-debug-shortcuts"/>
   <int value="-1077752943" label="enable-password-generation"/>
@@ -30291,6 +30296,7 @@
   <int value="588333474" label="OfflineIndicator:disabled"/>
   <int value="592050831" label="disable-slimming-paint"/>
   <int value="593707592" label="disable-network-portal-notification"/>
+  <int value="595168244" label="NotificationExpansionAnimation:enabled"/>
   <int value="595371145" label="OmniboxRichEntitySuggestions:disabled"/>
   <int value="596106994" label="CustomFeedbackUi:enabled"/>
   <int value="598827460" label="enable-roboto-font-ui"/>
@@ -49740,6 +49746,12 @@
   <int value="6" label="Translation error"/>
 </enum>
 
+<enum name="TranslateExplicitAskPromptEventType">
+  <int value="0" label="Shown"/>
+  <int value="1" label="Saved"/>
+  <int value="2" label="Cancelled"/>
+</enum>
+
 <enum name="TranslateInitiationStatus">
   <int value="0" label="Completely disabled by prefs"/>
   <int value="1" label="Completely disabled by switch"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 85add6e..7d55892 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -5395,21 +5395,24 @@
 </histogram>
 
 <histogram name="AsyncDNS.AttemptCountFail">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     Count of DnsAttempts before DnsTransaction completes with failure.
   </summary>
 </histogram>
 
 <histogram name="AsyncDNS.AttemptCountSuccess">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     Count of DnsAttempts before DnsTransaction completes successfully.
   </summary>
 </histogram>
 
 <histogram name="AsyncDNS.ConfigChange" enum="BooleanSuccess">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     Whether DnsConfigService::OnConfigChange actually corresponded to a change
     in DnsConfig.
@@ -5417,19 +5420,22 @@
 </histogram>
 
 <histogram name="AsyncDNS.ConfigNotifyInterval" units="ms">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     Duration of time between calls to DnsConfigService::InvalidateConfig.
   </summary>
 </histogram>
 
 <histogram name="AsyncDNS.ConfigParseDuration" units="ms">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>Duration of time spent parsing DnsConfig.</summary>
 </histogram>
 
 <histogram name="AsyncDNS.ConfigParsePosix" enum="AsyncDNSConfigParsePosix">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     Counts of results of parsing DnsConfig in DnsConfigServicePosix.
   </summary>
@@ -5444,7 +5450,8 @@
 </histogram>
 
 <histogram name="AsyncDNS.ConfigParseWin" enum="AsyncDNSConfigParseWin">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     Counts of results of parsing DnsConfig in DnsConfigServiceWin.
   </summary>
@@ -5461,7 +5468,8 @@
 </histogram>
 
 <histogram name="AsyncDNS.DnsClientDisabledReason" enum="NetErrorCodes">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     Counts of specific error codes returned by DnsTask if a subsequent ProcTask
     succeeded, at the end of a streak of failures after which the DnsClient was
@@ -5470,7 +5478,8 @@
 </histogram>
 
 <histogram name="AsyncDNS.DnsClientEnabled" enum="BooleanSuccess">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     TRUE counts the events when a valid DnsConfig is received and used to enable
     DnsClient, while FALSE counts the events when DnsClient is disabled after a
@@ -5479,21 +5488,24 @@
 </histogram>
 
 <histogram name="AsyncDNS.FallbackFail" units="ms">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     Duration of time spent by ProcTask in failing fallback resolutions.
   </summary>
 </histogram>
 
 <histogram name="AsyncDNS.FallbackSuccess" units="ms">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     Duration of time spent by ProcTask in successful fallback resolutions.
   </summary>
 </histogram>
 
 <histogram name="AsyncDNS.HaveDnsConfig" enum="BooleanSuccess">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     Whether there was a valid DNS configuration at the start of a job which
     eventually completed successfully.
@@ -5501,12 +5513,14 @@
 </histogram>
 
 <histogram name="AsyncDNS.HostParseResult" enum="BooleanSuccess">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>Whether DnsHosts were parsed successfully.</summary>
 </histogram>
 
 <histogram name="AsyncDNS.HostsChange" enum="BooleanSuccess">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     Whether DnsConfigService::OnHostsChange actually corresponded to a change in
     DnsHosts.
@@ -5514,26 +5528,30 @@
 </histogram>
 
 <histogram name="AsyncDNS.HostsNotifyInterval" units="ms">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     Duration of time between calls to DnsConfigService::InvalidateHosts.
   </summary>
 </histogram>
 
 <histogram name="AsyncDNS.HostsParseDuration" units="ms">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>Duration of time spent parsing DnsHosts.</summary>
 </histogram>
 
 <histogram name="AsyncDNS.HostsParseWin" enum="AsyncDNSHostsParseWin">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     Counts of results of parsing DnsHosts in DnsConfigServiceWin.
   </summary>
 </histogram>
 
 <histogram name="AsyncDNS.HostsSize" units="bytes">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     The size of the HOSTS file observed before each attempt to parse it.
   </summary>
@@ -5699,7 +5717,8 @@
 </histogram>
 
 <histogram name="AsyncDNS.ParseToAddressList" enum="AsyncDNSParseResult">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     Counts of results of parsing addresses out of DNS responses in successful
     DnsTransactions.
@@ -5819,7 +5838,8 @@
 </histogram>
 
 <histogram name="AsyncDNS.ServerCount">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     Count of servers in DnsConfig. Recorded on every new DnsSession, which is
     created on DNS change.
@@ -5827,14 +5847,16 @@
 </histogram>
 
 <histogram name="AsyncDNS.ServerFailureIndex">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     Index in DnsConfig of the failing server, recorded at the time of failure.
   </summary>
 </histogram>
 
 <histogram name="AsyncDNS.ServerFailuresAfterNetworkChange">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     Count of server failures after network change before first success in the
     DnsSession. Recorded at the time of first success.
@@ -5842,7 +5864,8 @@
 </histogram>
 
 <histogram name="AsyncDNS.ServerFailuresAfterSuccess">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     Count of server failures after success until the end of the session. Server
     has reported success at some point during the session. Recorded at the end
@@ -5851,7 +5874,8 @@
 </histogram>
 
 <histogram name="AsyncDNS.ServerFailuresBeforeSuccess">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     Count of server failures before success. This is NOT the first success in
     the DnsSession. Recorded at the time of success.
@@ -5859,7 +5883,8 @@
 </histogram>
 
 <histogram name="AsyncDNS.ServerFailuresWithoutSuccess">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     Count of server failures without success until the end of the session.
     Server has never reported success during the DnsSession. Recorded at the end
@@ -5878,7 +5903,8 @@
 </histogram>
 
 <histogram name="AsyncDNS.SortFailure" units="ms">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     Duration of time taken in failing calls to AddressSorter in dual-stack
     resolutions using DnsTask.
@@ -5886,7 +5912,8 @@
 </histogram>
 
 <histogram name="AsyncDNS.SortSuccess" units="ms">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     Duration of time taken in successful calls to AddressSorter in dual-stack
     resolutions using DnsTask.
@@ -5894,7 +5921,8 @@
 </histogram>
 
 <histogram name="AsyncDNS.SuffixSearchDone">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     The number of names from the search name list consumed during a successful
     transaction (QTYPE A only).
@@ -5902,7 +5930,8 @@
 </histogram>
 
 <histogram name="AsyncDNS.SuffixSearchRemain">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     The number of names left on the search name list at the end of a successful
     transaction (QTYPE A only).
@@ -5910,7 +5939,8 @@
 </histogram>
 
 <histogram name="AsyncDNS.SuffixSearchStart">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     The number of names on the search name list at the start of a transaction
     (QTYPE A only).
@@ -5918,7 +5948,8 @@
 </histogram>
 
 <histogram name="AsyncDNS.TCPAttemptFail" units="ms">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     Duration of time taken by DnsTCPAttempt in failed attempts. Excludes
     timeouts.
@@ -5926,42 +5957,48 @@
 </histogram>
 
 <histogram name="AsyncDNS.TCPAttemptSuccess" units="ms">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     Duration of time taken by DnsTCPAttempt in successful attempts.
   </summary>
 </histogram>
 
 <histogram name="AsyncDNS.TimeoutErrorHistogram" units="ms">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     Difference between RTT and timeout calculated using Histogram algorithm.
   </summary>
 </histogram>
 
 <histogram name="AsyncDNS.TimeoutErrorHistogramUnder" units="ms">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     Difference between timeout calculated using Histogram algorithm and RTT.
   </summary>
 </histogram>
 
 <histogram name="AsyncDNS.TimeoutErrorJacobson" units="ms">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     Difference between RTT and timeout calculated using Jacobson algorithm.
   </summary>
 </histogram>
 
 <histogram name="AsyncDNS.TimeoutErrorJacobsonUnder" units="ms">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     Difference between timeout calculated using Jacobson algorithm and RTT.
   </summary>
 </histogram>
 
 <histogram name="AsyncDNS.TimeoutSpentHistogram" units="ms">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     Duration of time that would be spent waiting for lost request using
     Histogram algorithm.
@@ -5969,7 +6006,8 @@
 </histogram>
 
 <histogram name="AsyncDNS.TimeoutSpentJacobson" units="ms">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     Duration of time that would be spent waiting for lost request using Jacobson
     algorithm.
@@ -6001,7 +6039,8 @@
 </histogram>
 
 <histogram name="AsyncDNS.TransactionFailure" units="ms">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     Duration of time taken in failing DnsTransactions. This includes server
     failures, timeouts and NXDOMAIN results.
@@ -6009,7 +6048,8 @@
 </histogram>
 
 <histogram name="AsyncDNS.TransactionSuccess" units="ms">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     Duration of time taken in successful DnsTransactions. This includes all
     NOERROR answers, even if they indicate the name has no addresses or they
@@ -6018,21 +6058,24 @@
 </histogram>
 
 <histogram name="AsyncDNS.TransactionSuccess_A" units="ms">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     Same as AsyncDNS.TransactionSuccess but limited to A query type.
   </summary>
 </histogram>
 
 <histogram name="AsyncDNS.TransactionSuccess_AAAA" units="ms">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     Same as AsyncDNS.TransactionSuccess but limited to AAAA query type.
   </summary>
 </histogram>
 
 <histogram name="AsyncDNS.TTL" units="ms">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     TTL of the resolved addresses, as in the response received from the server.
     For results served from local cache, the TTL is from the original response.
@@ -6040,7 +6083,8 @@
 </histogram>
 
 <histogram name="AsyncDNS.UDPAttemptFail" units="ms">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     Duration of time taken by DnsUDPAttempt in failed attempts. Excludes
     timeouts.
@@ -6048,7 +6092,8 @@
 </histogram>
 
 <histogram name="AsyncDNS.UDPAttemptSuccess" units="ms">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     Duration of time taken by DnsUDPAttempt in successful attempts. Includes
     responses arriving after timeout, if multiple attempts are allowed.
@@ -6056,7 +6101,8 @@
 </histogram>
 
 <histogram name="AsyncDNS.UnchangedConfigInterval" units="ms">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     Duration of time since the last empty config result to the time a non-change
     OnConfigChange is received.
@@ -6064,7 +6110,8 @@
 </histogram>
 
 <histogram name="AsyncDNS.UnchangedHostsInterval" units="ms">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     Duration of time since the last empty config result to the time a non-change
     OnHostsChange is received.
@@ -6072,7 +6119,8 @@
 </histogram>
 
 <histogram name="AsyncDNS.WatchStatus" enum="AsyncDNSWatchStatus">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     The result of DnsConfigService watch. Counts STARTED on every initialization
     and FAILED_* on any failure.
@@ -8719,6 +8767,9 @@
 </histogram>
 
 <histogram name="Blink.Canvas.DrawImage" units="microseconds">
+  <obsolete>
+    Replaced with Blink.Canvas.DrawImage.Duration in 10/2018.
+  </obsolete>
   <owner>junov@chromium.org</owner>
   <summary>
     Time spent on 2D canvas drawImage API call.
@@ -8731,6 +8782,19 @@
   </summary>
 </histogram>
 
+<histogram base="true" name="Blink.Canvas.DrawImage.Duration"
+    units="microseconds">
+  <owner>fserb@chromium.org</owner>
+  <owner>davidqu@chromium.org</owner>
+  <summary>
+    Time spent on the main thread during a 2D canvas drawImage API call.
+
+    Note: This metric drops reports on clients with low-resolution clocks, which
+    means these reports will be biased against a portion of the population on
+    Windows. See Windows.HasHighResolutionTimeTicks for the affected sample.
+  </summary>
+</histogram>
+
 <histogram name="Blink.Canvas.GetImageData" units="microseconds">
   <obsolete>
     Replaced with Blink.Canvas.GetImageDataScaledDuration in 10/2018.
@@ -20668,7 +20732,8 @@
 </histogram>
 
 <histogram name="DNS.AttemptDiscarded">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     The attempt which completed after the job was already cancelled OR the
     attempt that has finished after host resolution was already completed by an
@@ -20677,7 +20742,8 @@
 </histogram>
 
 <histogram name="DNS.AttemptFailDuration" units="ms">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     Duration of time taken in OS resolutions for actual navigations. These
     attempts which completed after the job was already canceled OR after the job
@@ -20687,12 +20753,14 @@
 </histogram>
 
 <histogram name="DNS.AttemptFailure">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>The attempt that has not resolved the host successfully.</summary>
 </histogram>
 
 <histogram name="DNS.AttemptFirstFailure">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     The attempt that resolved the host first and the resolution was not
     successful.
@@ -20700,19 +20768,22 @@
 </histogram>
 
 <histogram name="DNS.AttemptFirstSuccess">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     The attempt that resolved the host first and the resolution was successful.
   </summary>
 </histogram>
 
 <histogram name="DNS.AttemptSuccess">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>The attempt that has resolved the host successfully.</summary>
 </histogram>
 
 <histogram name="DNS.AttemptSuccessDuration" units="ms">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     Duration of time taken in OS resolutions that succeeded and were requested
     for actual navigations. These attempts which completed after the job was
@@ -20777,12 +20848,14 @@
 </histogram>
 
 <histogram name="DNS.HostCache.Erase" enum="DNS.HostCache.EraseReason">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>The reason for erasing a DNS entry from the host cache.</summary>
 </histogram>
 
 <histogram name="DNS.HostCache.EraseStale.ExpiredBy" units="ms">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     When erasing a stale (expired or old-network) DNS entry from the host cache,
     how long past the expiration time it is.
@@ -20790,7 +20863,8 @@
 </histogram>
 
 <histogram name="DNS.HostCache.EraseStale.NetworkChanges" units="changes">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     When erasing a stale (expired or old-network) DNS entry from the host cache
     how many network changes happened between setting and erasing it.
@@ -20798,7 +20872,8 @@
 </histogram>
 
 <histogram name="DNS.HostCache.EraseStale.StaleHits" units="hits">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     When erasing a stale (expired or old-network) DNS entry from the host cache
     how many hits it received while stale.
@@ -20806,7 +20881,8 @@
 </histogram>
 
 <histogram name="DNS.HostCache.EraseValid.ValidFor" units="ms">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     When erasing a valid DNS entry from the host cache, for how much longer it
     would have remained valid.
@@ -20814,12 +20890,14 @@
 </histogram>
 
 <histogram name="DNS.HostCache.Lookup" enum="DNS.HostCache.LookupOutcome">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>The outcome of looking up a DNS entry in the host cache.</summary>
 </histogram>
 
 <histogram name="DNS.HostCache.LookupStale.ExpiredBy" units="ms">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     When looking up a stale DNS entry in the host cache, how long past the
     expiration time it is.
@@ -20827,7 +20905,8 @@
 </histogram>
 
 <histogram name="DNS.HostCache.LookupStale.NetworkChanges" units="changes">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     When looking up a stale DNS entry in the host cache, how many network
     changes happened between setting it and looking it up.
@@ -20835,27 +20914,31 @@
 </histogram>
 
 <histogram name="DNS.HostCache.RestoreSize" units="entries">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     Number of HostCache entries persisted to disk, measured at restore time.
   </summary>
 </histogram>
 
 <histogram name="DNS.HostCache.RestoreSuccess" enum="BooleanSuccess">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     Whether the persisted HostCache entries were restored successfully.
   </summary>
 </histogram>
 
 <histogram name="DNS.HostCache.Set" enum="DNS.HostCache.SetOutcome">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>The outcome of setting a DNS entry in the host cache.</summary>
 </histogram>
 
 <histogram name="DNS.HostCache.UpdateStale.AddressListDelta"
     enum="DNS.AddressListDeltaType">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     When updating a stale (expired or old-network) DNS entry in the host cache,
     and both results are successful, how the address list differs between the
@@ -20864,7 +20947,8 @@
 </histogram>
 
 <histogram name="DNS.HostCache.UpdateStale.ExpiredBy" units="ms">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     When updating a stale (expired or old-network) DNS entry in the host cache,
     how long past the expiration time the old entry was.
@@ -20872,7 +20956,8 @@
 </histogram>
 
 <histogram name="DNS.HostCache.UpdateStale.NetworkChanges" units="changes">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     When updating a stale (expired or old-nework) DNS entry in the host cache,
     how many network changes happened between setting the old entry and setting
@@ -20881,7 +20966,8 @@
 </histogram>
 
 <histogram name="DNS.HostCache.UpdateStale.StaleHits" units="hits">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     The number of hits received to an updated stale DNS entry in the host cache
     while it was stale.
@@ -21369,7 +21455,8 @@
 </histogram>
 
 <histogram name="DNS.StaleHostResolver.NetworkEarly" units="ms">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     When a DNS request made through StaleHostResolver returns, a stale cached
     result was available, and the network responded before or exactly at the
@@ -21378,7 +21465,8 @@
 </histogram>
 
 <histogram name="DNS.StaleHostResolver.NetworkLate" units="ms">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     When a DNS request made through StaleHostResolver returns, a stale cached
     result was available, and the network responded after the stale delay, how
@@ -21388,7 +21476,8 @@
 
 <histogram name="DNS.StaleHostResolver.RequestOutcome"
     enum="DNS.StaleHostResolverRequestOutcome">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     When a DNS request made through StaleHostResolver returns or is canceled,
     the outcome of the request.
@@ -21396,7 +21485,8 @@
 </histogram>
 
 <histogram name="DNS.StaleHostResolver.RestoreSizeOnCacheMiss">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     When a DNS request made through StaleHostResolver has no stale cached result
     available, the number of host cache entries that were restored from prefs.
@@ -21404,7 +21494,8 @@
 </histogram>
 
 <histogram name="DNS.StaleHostResolver.SizeOnCacheMiss">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     When a DNS request made through StaleHostResolver has no stale cached result
     available, the number of entries in the host cache.
@@ -21413,7 +21504,8 @@
 
 <histogram name="DNS.StaleHostResolver.StaleAddressListDelta"
     enum="DNS.AddressListDeltaType">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     When a DNS request made through StaleHostResolver had a stale cached result
     and both the stale and network results were successful, the difference
@@ -21488,7 +21580,8 @@
 </histogram>
 
 <histogram name="DnsProbe.ErrorPageUpdateStatus" enum="DnsProbe.ProbeStatus">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>Status of DNS probe updates sent to a DNS error page.</summary>
 </histogram>
 
@@ -21619,12 +21712,14 @@
 </histogram>
 
 <histogram name="DnsProbe.ProbeDuration" units="ms">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>Time between starting and finishing DNS probe.</summary>
 </histogram>
 
 <histogram name="DnsProbe.ProbeResult" enum="DnsProbe.ProbeStatus">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>Result of DNS probes sent by the probe service.</summary>
 </histogram>
 
@@ -54636,7 +54731,8 @@
 </histogram>
 
 <histogram name="Net.DNS.DnsTask.ErrorBeforeFallback.Fast" enum="NetErrorCodes">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     Counts of specific error codes returned by DnsTask. Only counts failures
     that took less than 10ms, which are probably local failures.
@@ -54644,7 +54740,8 @@
 </histogram>
 
 <histogram name="Net.DNS.DnsTask.ErrorBeforeFallback.Slow" enum="NetErrorCodes">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     Counts of specific error codes returned by DnsTask. Only counts failures
     that took at least 10ms, which are probably remote failures or connectivity
@@ -54653,7 +54750,8 @@
 </histogram>
 
 <histogram name="Net.DNS.DnsTask.Errors" enum="NetErrorCodes">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     Counts of specific error codes returned by DnsTask if a subsequent ProcTask
     succeeded.
@@ -54661,7 +54759,8 @@
 </histogram>
 
 <histogram name="Net.DNS.DnsTask.FailureTime" units="ms">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     Duration of time taken by DnsTask in resolutions that failed. Excludes time
     spent in the subsequent fallback.
@@ -54669,14 +54768,16 @@
 </histogram>
 
 <histogram name="Net.DNS.DnsTask.SuccessTime" units="ms">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     Duration of time taken by DnsTask in resolutions that succeeded.
   </summary>
 </histogram>
 
 <histogram name="Net.DNS.JobQueueTime" units="ms">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     Time elapsed between the time the HostResolverImpl::Job was created and the
     time the Job was started.
@@ -54684,7 +54785,8 @@
 </histogram>
 
 <histogram name="Net.DNS.JobQueueTimeAfterChange" units="ms">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     Time elapsed between the last time the priority of a HostResolverImpl::Job
     changed (when a Request was attached or detached) and the time the Job was
@@ -54693,21 +54795,24 @@
 </histogram>
 
 <histogram name="Net.DNS.ProcTask.FailureTime" units="ms">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     Duration of time taken by ProcTask in resolutions that failed.
   </summary>
 </histogram>
 
 <histogram name="Net.DNS.ProcTask.SuccessTime" units="ms">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     Duration of time taken by ProcTask in resolutions that succeeded.
   </summary>
 </histogram>
 
 <histogram name="Net.DNS.ResolveCategory" enum="ResolutionCategory">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     Whether a DNS resolution (single HostResolverImpl::Job) succeeded or failed,
     and whether it was speculative.
@@ -54715,7 +54820,8 @@
 </histogram>
 
 <histogram name="Net.DNS.ResolveError.Fast" enum="NetErrorCodes">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     For DNS resolutions that failed after less than 10 ms, which are probably
     local failures, what error code the jobs failed with.
@@ -54723,7 +54829,8 @@
 </histogram>
 
 <histogram name="Net.DNS.ResolveError.Slow" enum="NetErrorCodes">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     For DNS resolutions that failed after at least 10 ms, which are probably
     remote failures or connectivity problems, what error code the jobs failed
@@ -54732,7 +54839,8 @@
 </histogram>
 
 <histogram name="Net.DNS.ResolveFailureTime" units="ms">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     Duration of time taken by HostResolverImpl::Job in resolutions that failed.
     This is the time to resolve a hostname from start to finish. The main
@@ -54741,7 +54849,8 @@
 </histogram>
 
 <histogram name="Net.DNS.ResolveSuccessTime" units="ms">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     Duration of time taken by HostResolverImpl::Job in resolutions that
     succeeded. This is the time to resolve a hostname from start to finish. The
@@ -54764,7 +54873,8 @@
 </histogram>
 
 <histogram name="Net.DNS.TotalTime" units="ms">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     Duration of time since a HostResolverImpl::Resolve request to the time a
     result is posted. Excludes canceled, evicted, and aborted requests. Includes
@@ -54773,7 +54883,8 @@
 </histogram>
 
 <histogram name="Net.DNS.TotalTimeNotCached" units="ms">
-  <owner>mgersh@chromium.org</owner>
+  <owner>pauljensen@chromium.org</owner>
+  <owner>mef@chromium.org</owner>
   <summary>
     Duration of time since a HostResolverImpl::Resolve request to the time a
     result is posted. Excludes canceled, evicted, and aborted requests and
@@ -84564,75 +84675,86 @@
   </summary>
 </histogram>
 
-<histogram name="Quickoffice.csvFormattedCellCount">
-  <owner>dskelton@google.com</owner>
+<histogram name="Quickoffice.csvFormattedCellCount" expires_after="2020-02-29">
+  <owner>snopanen@google.com</owner>
+  <owner>sdoerner@google.com</owner>
   <summary>
     Records the number of cells that contain formatting data in the default
     worksheet when a comma separated value spreadsheet is opened.
   </summary>
 </histogram>
 
-<histogram name="Quickoffice.csvNonEmptyCellCount">
-  <owner>dskelton@google.com</owner>
+<histogram name="Quickoffice.csvNonEmptyCellCount" expires_after="2020-02-29">
+  <owner>snopanen@google.com</owner>
+  <owner>sdoerner@google.com</owner>
   <summary>
     Records the number of non-empty cells in the default worksheet when a comma
     separated value spreadsheet is opened.
   </summary>
 </histogram>
 
-<histogram name="Quickoffice.csvSheetCount">
-  <owner>dskelton@google.com</owner>
+<histogram name="Quickoffice.csvSheetCount" expires_after="2020-02-29">
+  <owner>snopanen@google.com</owner>
+  <owner>sdoerner@google.com</owner>
   <summary>
     Records the number of worksheets when a comma separated value spreadsheet is
     opened.
   </summary>
 </histogram>
 
-<histogram name="Quickoffice.docPageCount">
-  <owner>joshwoodward@google.com</owner>
+<histogram name="Quickoffice.docPageCount" expires_after="2020-02-29">
+  <owner>snopanen@google.com</owner>
+  <owner>sdoerner@google.com</owner>
   <summary>
     Records the page count when a compound binary format document is opened.
   </summary>
 </histogram>
 
-<histogram name="Quickoffice.docParagraphCount">
-  <owner>joshwoodward@google.com</owner>
+<histogram name="Quickoffice.docParagraphCount" expires_after="2020-02-29">
+  <owner>snopanen@google.com</owner>
+  <owner>sdoerner@google.com</owner>
   <summary>
     Records the paragraph count when a compound binary format document is
     opened.
   </summary>
 </histogram>
 
-<histogram name="Quickoffice.docSectionCount">
-  <owner>joshwoodward@google.com</owner>
+<histogram name="Quickoffice.docSectionCount" expires_after="2020-02-29">
+  <owner>snopanen@google.com</owner>
+  <owner>sdoerner@google.com</owner>
   <summary>
     Records the section count when a compound binary format document is opened.
   </summary>
 </histogram>
 
-<histogram name="Quickoffice.docxPageCount">
-  <owner>joshwoodward@google.com</owner>
+<histogram name="Quickoffice.docxPageCount" expires_after="2020-02-29">
+  <owner>snopanen@google.com</owner>
+  <owner>sdoerner@google.com</owner>
   <summary>
     Records the page count when an OOXML format document is opened.
   </summary>
 </histogram>
 
-<histogram name="Quickoffice.docxParagraphCount">
-  <owner>joshwoodward@google.com</owner>
+<histogram name="Quickoffice.docxParagraphCount" expires_after="2020-02-29">
+  <owner>snopanen@google.com</owner>
+  <owner>sdoerner@google.com</owner>
   <summary>
     Records the paragraph count when an OOXML format document is opened.
   </summary>
 </histogram>
 
-<histogram name="Quickoffice.docxSectionCount">
-  <owner>joshwoodward@google.com</owner>
+<histogram name="Quickoffice.docxSectionCount" expires_after="2020-02-29">
+  <owner>snopanen@google.com</owner>
+  <owner>sdoerner@google.com</owner>
   <summary>
     Records the section count when an OOXML format document is opened.
   </summary>
 </histogram>
 
-<histogram name="Quickoffice.ErrorTypes" enum="QuickofficeErrorTypes">
-  <owner>joshwoodward@google.com</owner>
+<histogram name="Quickoffice.ErrorTypes" enum="QuickofficeErrorTypes"
+    expires_after="2020-02-29">
+  <owner>snopanen@google.com</owner>
+  <owner>sdoerner@google.com</owner>
   <summary>
     Records the various different error types encountered when opening and
     reading MS Office file formats in the Quickoffice viewer. These range from
@@ -84642,8 +84764,10 @@
   </summary>
 </histogram>
 
-<histogram name="Quickoffice.FileFormat" enum="QuickofficeFileFormat">
-  <owner>joshwoodward@google.com</owner>
+<histogram name="Quickoffice.FileFormat" enum="QuickofficeFileFormat"
+    expires_after="2020-02-29">
+  <owner>snopanen@google.com</owner>
+  <owner>sdoerner@google.com</owner>
   <summary>
     Records the various different file types supported by Quickoffice (like MS
     Word, Excel, Powerpoint files) when they opened in the browser to measure
@@ -84651,79 +84775,89 @@
   </summary>
 </histogram>
 
-<histogram name="Quickoffice.pptMasterCount">
-  <owner>joshwoodward@google.com</owner>
+<histogram name="Quickoffice.pptMasterCount" expires_after="2020-02-29">
+  <owner>snopanen@google.com</owner>
+  <owner>sdoerner@google.com</owner>
   <summary>
     Records the number of slide masters when a compound binary format
     presentation is opened.
   </summary>
 </histogram>
 
-<histogram name="Quickoffice.pptSlideCount">
-  <owner>joshwoodward@google.com</owner>
+<histogram name="Quickoffice.pptSlideCount" expires_after="2020-02-29">
+  <owner>snopanen@google.com</owner>
+  <owner>sdoerner@google.com</owner>
   <summary>
     Records the slide count when a compound binary format presentation is
     opened.
   </summary>
 </histogram>
 
-<histogram name="Quickoffice.pptxMasterCount">
-  <owner>joshwoodward@google.com</owner>
+<histogram name="Quickoffice.pptxMasterCount" expires_after="2020-02-29">
+  <owner>snopanen@google.com</owner>
+  <owner>sdoerner@google.com</owner>
   <summary>
     Records the number of slide masters when an OOXML format presentation is
     opened.
   </summary>
 </histogram>
 
-<histogram name="Quickoffice.pptxSlideCount">
-  <owner>joshwoodward@google.com</owner>
+<histogram name="Quickoffice.pptxSlideCount" expires_after="2020-02-29">
+  <owner>snopanen@google.com</owner>
+  <owner>sdoerner@google.com</owner>
   <summary>
     Records the slide count when an OOXML format presentation is opened.
   </summary>
 </histogram>
 
-<histogram name="Quickoffice.xlsFormattedCellCount">
-  <owner>joshwoodward@google.com</owner>
+<histogram name="Quickoffice.xlsFormattedCellCount" expires_after="2020-02-29">
+  <owner>snopanen@google.com</owner>
+  <owner>sdoerner@google.com</owner>
   <summary>
     Records the number of cells that contain formatting data in the default
     worksheet when a compound binary format spreadsheet is opened.
   </summary>
 </histogram>
 
-<histogram name="Quickoffice.xlsNonEmptyCellCount">
-  <owner>joshwoodward@google.com</owner>
+<histogram name="Quickoffice.xlsNonEmptyCellCount" expires_after="2020-02-29">
+  <owner>snopanen@google.com</owner>
+  <owner>sdoerner@google.com</owner>
   <summary>
     Records the number of non-empty cells in the default worksheet when a
     compound binary format spreadsheet is opened.
   </summary>
 </histogram>
 
-<histogram name="Quickoffice.xlsSheetCount">
-  <owner>joshwoodward@google.com</owner>
+<histogram name="Quickoffice.xlsSheetCount" expires_after="2020-02-29">
+  <owner>snopanen@google.com</owner>
+  <owner>sdoerner@google.com</owner>
   <summary>
     Records the number of worksheets when a compound binary format spreadsheet
     is opened.
   </summary>
 </histogram>
 
-<histogram name="Quickoffice.xlsxFormattedCellCount">
-  <owner>joshwoodward@google.com</owner>
+<histogram name="Quickoffice.xlsxFormattedCellCount" expires_after="2020-02-29">
+  <owner>snopanen@google.com</owner>
+  <owner>sdoerner@google.com</owner>
   <summary>
     Records the number of cells that contain formatting data in the default
     worksheet when an OOXML format spreadsheet is opened.
   </summary>
 </histogram>
 
-<histogram name="Quickoffice.xlsxNonEmptyCellCount">
-  <owner>joshwoodward@google.com</owner>
+<histogram name="Quickoffice.xlsxNonEmptyCellCount" expires_after="2020-02-29">
+  <owner>snopanen@google.com</owner>
+  <owner>sdoerner@google.com</owner>
   <summary>
     Records the number of non-empty cells when an OOXML format spreadsheet is
     opened.
   </summary>
 </histogram>
 
-<histogram name="Quickoffice.xlsxSheetCount">
-  <owner>joshwoodward@google.com</owner>
+<histogram name="Quickoffice.xlsxSheetCount" expires_after="2020-02-29">
+  <owner>snopanen@google.com</owner>
+  <owner>sdoerner@google.com</owner>
   <summary>
     Records the number of worksheets when an OOXML format spreadsheet is opened.
   </summary>
@@ -103679,6 +103813,22 @@
   </summary>
 </histogram>
 
+<histogram name="StackSamplingProfiler.ProfileDeserializationTime" units="ms"
+    expires_after="2019-01-24">
+  <owner>chengx@chromium.org</owner>
+  <owner>wittman@chromium.org</owner>
+  <summary>
+    Amount of time taken to deserialize a call stack profile string.
+  </summary>
+</histogram>
+
+<histogram name="StackSamplingProfiler.ProfileSerializationTime" units="ms"
+    expires_after="2019-01-24">
+  <owner>chengx@chromium.org</owner>
+  <owner>wittman@chromium.org</owner>
+  <summary>Amount of time taken to serialize a call stack profile.</summary>
+</histogram>
+
 <histogram name="Stars.Goog_Related" units="%">
   <owner>yefim@chromium.org</owner>
   <summary>
@@ -111682,6 +111832,16 @@
   </summary>
 </histogram>
 
+<histogram name="Translate.ExplicitLanguageAsk.Event"
+    enum="TranslateExplicitAskPromptEventType">
+  <owner>yyushkina@google.com</owner>
+  <owner>anthonyvd@google.com</owner>
+  <summary>
+    The events (shown, saved, cancelled) happening in the Explicit Language Ask
+    prompt.
+  </summary>
+</histogram>
+
 <histogram name="Translate.ExplicitLanguageAsk.LanguageAdded"
     enum="CLD3LanguageCode">
   <owner>yyushkina@google.com</owner>
@@ -112598,29 +112758,6 @@
   </summary>
 </histogram>
 
-<histogram name="UMA.ExpiredHistogram.BugReportTest" expires_after="2018-07-20">
-  <owner>gayane@chromium.org</owner>
-  <summary>Not logged. Used for testing histogram expiry checker.</summary>
-</histogram>
-
-<histogram name="UMA.ExpiredHistogram.Milestone.BugReportTest"
-    expires_after="M68">
-  <owner>gayane@chromium.org</owner>
-  <summary>Not logged. Used for testing histogram expiry checker.</summary>
-</histogram>
-
-<histogram name="UMA.ExpiredHistogram.Milestone.Soon.BugReportTest"
-    expires_after="M69">
-  <owner>gayane@chromium.org</owner>
-  <summary>Not logged. Used for testing histogram expiry checker.</summary>
-</histogram>
-
-<histogram name="UMA.ExpiredHistogram.Soon.BugReportTest"
-    expires_after="2018-08-01">
-  <owner>gayane@chromium.org</owner>
-  <summary>Not logged. Used for testing histogram expiry checker.</summary>
-</histogram>
-
 <histogram name="UMA.ExternalExperiment.GroupCount" units="groups"
     expires_after="2018-08-30">
   <owner>asvitkine@chromium.org</owner>
@@ -112927,9 +113064,9 @@
 </histogram>
 
 <histogram name="UMA.LogUpload.Canceled.CellularConstraint"
-    enum="BooleanCanceled">
+    enum="BooleanCanceled" expires_after="2019-04-30">
+  <owner>holte@chromium.org</owner>
   <owner>asvitkine@chromium.org</owner>
-  <owner>gayane@chromium.org</owner>
   <summary>
     Logs whether a log was not uploaded due to cellular log throttling logic.
     Android only.
@@ -113254,9 +113391,9 @@
   </details>
 </histogram>
 
-<histogram name="UMA.UnsentLogs.Dropped">
+<histogram name="UMA.UnsentLogs.Dropped" expires_after="2019-04-30">
+  <owner>holte@chromium.org</owner>
   <owner>asvitkine@chromium.org</owner>
-  <owner>gayane@chromium.org</owner>
   <summary>
     Counter for number of UMA unsent logs removed from persistent storage.
   </summary>
@@ -116072,8 +116209,10 @@
   </summary>
 </histogram>
 
-<histogram name="Variations.SeedProcessingTime" units="ms">
-  <owner>gayane@chromium.org</owner>
+<histogram name="Variations.SeedProcessingTime" units="ms"
+    expires_after="2019-04-30">
+  <owner>isherman@chromium.org</owner>
+  <owner>asvitkine@chromium.org</owner>
   <summary>
     Records how long it takes to load and process variations seed. This metric
     is recorded only when loading and processing of the seed is successful.
@@ -123859,13 +123998,20 @@
 </histogram_suffixes>
 
 <histogram_suffixes name="BlinkCanvasDrawImageType" separator=".">
-  <suffix name="Canvas"/>
-  <suffix name="ImageBitmap"/>
-  <suffix name="OffscreenCanvas"/>
-  <suffix name="Others"/>
-  <suffix name="SVG"/>
-  <suffix name="Video"/>
-  <affected-histogram name="Blink.Canvas.DrawImage"/>
+  <suffix base="true" name="Canvas"/>
+  <suffix base="true" name="CssImage"/>
+  <suffix base="true" name="ImageBitmap"/>
+  <suffix base="true" name="ImageElement"/>
+  <suffix base="true" name="OffscreenCanvas"/>
+  <suffix base="true" name="Others">
+    <obsolete>
+      Deprecated 10/2018 with the addition of CssImage and Unknown.
+    </obsolete>
+  </suffix>
+  <suffix base="true" name="SVG"/>
+  <suffix base="true" name="Unknown"/>
+  <suffix base="true" name="Video"/>
+  <affected-histogram name="Blink.Canvas.DrawImage.Duration"/>
 </histogram_suffixes>
 
 <histogram_suffixes name="BlinkCanvasDurationBySource" separator=".">
@@ -123876,14 +124022,16 @@
     </obsolete>
   </suffix>
   <suffix name="GPU"/>
-  <affected-histogram name="Blink.Canvas.DrawImage.Canvas"/>
-  <affected-histogram name="Blink.Canvas.DrawImage.ImageBitmap"/>
-  <affected-histogram name="Blink.Canvas.DrawImage.OffscreenCanvas"/>
-  <affected-histogram name="Blink.Canvas.DrawImage.Others"/>
-  <affected-histogram name="Blink.Canvas.DrawImage.SVG"/>
-  <affected-histogram name="Blink.Canvas.DrawImage.Video"/>
-  <affected-histogram name="Blink.Canvas.GetImageDataScaledDuration"/>
-  <affected-histogram name="Blink.Canvas.PutImageDataScaledDuration"/>
+  <affected-histogram name="Blink.Canvas.DrawImage.Duration.Canvas"/>
+  <affected-histogram name="Blink.Canvas.DrawImage.Duration.CssImage"/>
+  <affected-histogram name="Blink.Canvas.DrawImage.Duration.ImageBitmap"/>
+  <affected-histogram name="Blink.Canvas.DrawImage.Duration.ImageElement"/>
+  <affected-histogram name="Blink.Canvas.DrawImage.Duration.OffscreenCanvas"/>
+  <affected-histogram name="Blink.Canvas.DrawImage.Duration.SVG"/>
+  <affected-histogram name="Blink.Canvas.DrawImage.Duration.Unknown"/>
+  <affected-histogram name="Blink.Canvas.DrawImage.Duration.Video"/>
+  <affected-histogram name="Blink.Canvas.GetImageData"/>
+  <affected-histogram name="Blink.Canvas.PutImageData"/>
 </histogram_suffixes>
 
 <histogram_suffixes name="BlinkCanvasOffscreenCommitType" separator=".">
diff --git a/tools/perf/benchmarks/v8_browsing.py b/tools/perf/benchmarks/v8_browsing.py
index 419c125..6efdacd 100644
--- a/tools/perf/benchmarks/v8_browsing.py
+++ b/tools/perf/benchmarks/v8_browsing.py
@@ -25,8 +25,7 @@
     r'incremental-finalize_|'
     r'incremental-step_|'
     r'latency-mark-compactor_|'
-    r'mark-compactor_|'
-    r'mark-compactor-mmu_|'
+    r'mark-compactor-|'
     r'memory-mark-compactor_|'
     r'scavenger_|'
     r'total_)')
diff --git a/tools/win/DebugVisualizers/webkit.natvis b/tools/win/DebugVisualizers/webkit.natvis
index 6001763b..d800ce25 100644
--- a/tools/win/DebugVisualizers/webkit.natvis
+++ b/tools/win/DebugVisualizers/webkit.natvis
@@ -34,7 +34,7 @@
       <Item Name="Length">length_</Item>
       <Item Name="Hash">hash_</Item>
       <Item Name="AsciiText" Condition="is8_bit_">(this+1),[length_]s</Item>
-      <Item Name="UnicodeText" Condition="!is8_bit_">(wchar_t*)(this+1),[length_]su</Item>
+      <Item Name="UnicodeText" Condition="!is8_bit_">(this+1),[length_]su</Item>
     </Expand>
   </Type>
   <Type Name="WTF::AtomicString">
@@ -197,11 +197,11 @@
       </LinkedListItems>
     </Expand>
   </Type>
-  <Type Name="blink::LineBoxList">
+  <Type Name="blink::InlineBoxList&lt;blink::InlineFlowBox&gt;">
     <Expand>
       <LinkedListItems>
-        <HeadPointer>first_line_box_</HeadPointer>
-        <NextPointer>next_line_box_</NextPointer>
+        <HeadPointer>first_</HeadPointer>
+        <NextPointer>(blink::InlineFlowBox*)next_</NextPointer>
         <ValueNode>this</ValueNode>
       </LinkedListItems>
     </Expand>
@@ -210,14 +210,8 @@
     <DisplayString>{layout_object_}</DisplayString>
   </Type>
   <!-- Layout: LayoutNG -->
-  <Type Name="blink::NGBlockNode">
-    <DisplayString>{*box_}</DisplayString>
-  </Type>
-  <Type Name="blink::NGInlineNode">
-    <DisplayString>{*box_}</DisplayString>
-    <Expand>
-      <Item Name="inline_node_data">*((blink::LayoutNGBlockFlow*)box_)->ng_inline_node_data_</Item>
-    </Expand>
+  <Type Name="blink::NGLayoutInputNode">
+    <DisplayString>{(NGLayoutInputNode::NGLayoutInputNodeType)type_} {box_}</DisplayString>
   </Type>
   <Type Name="blink::NGInlineItem">
     <DisplayString>{(NGInlineItem::NGInlineItemType)type_} {start_offset_}-{end_offset_} {*layout_object_}</DisplayString>
@@ -225,8 +219,26 @@
   <Type Name="blink::NGFragment">
     <DisplayString>{physical_fragment_}</DisplayString>
   </Type>
+  <Type Name="blink::NGPaintFragment">
+    <DisplayString>{*physical_fragment_.ptr_}</DisplayString>
+    <Expand>
+      <Synthetic Name="Children">
+        <DisplayString>{first_child_.ptr_}</DisplayString>
+        <Expand>
+          <LinkedListItems>
+            <HeadPointer>first_child_.ptr_</HeadPointer>
+            <NextPointer>next_sibling_.ptr_</NextPointer>
+            <ValueNode>this</ValueNode>
+          </LinkedListItems>
+        </Expand>
+      </Synthetic>
+    </Expand>
+  </Type>
   <Type Name="blink::NGPhysicalFragment">
-    <DisplayString>{(blink::NGPhysicalFragment::NGFragmentType)type_} {layout_object_} {size_} {offset_}</DisplayString>
+    <DisplayString>{(blink::NGPhysicalFragment::NGFragmentType)type_} {size_} {*layout_object_}</DisplayString>
+    <Expand>
+      <Item Name="children_" Condition="type_ == 0 || type_ == 2">((blink::NGPhysicalContainerFragment*)this)->children_</Item>
+    </Expand>
   </Type>
   <Type Name="blink::NGLogicalOffset">
     <DisplayString>({inline_offset}, {block_offset})</DisplayString>
@@ -274,6 +286,6 @@
     <DisplayString>{platform_data_}</DisplayString>
   </Type>
   <Type Name="blink::FontPlatformData">
-    <DisplayString>{*typeface_.fPtr}, {text_size_}px</DisplayString>
+    <DisplayString>{*typeface_.ptr_}, {text_size_}px</DisplayString>
   </Type>
 </AutoVisualizer>
\ No newline at end of file
diff --git a/ui/android/delegated_frame_host_android.cc b/ui/android/delegated_frame_host_android.cc
index 17fbe66..54251f4 100644
--- a/ui/android/delegated_frame_host_android.cc
+++ b/ui/android/delegated_frame_host_android.cc
@@ -93,14 +93,14 @@
     base::Optional<viz::HitTestRegionList> hit_test_region_list) {
   DCHECK(!enable_viz_);
 
+  bool id_changed = (local_surface_id_ != local_surface_id);
   viz::RenderPass* root_pass = frame.render_pass_list.back().get();
   const bool has_transparent_background = root_pass->has_transparent_background;
   const gfx::Size surface_size_in_pixels = frame.size_in_pixels();
   // Reset |content_layer_| only if surface-sync is not used. When surface-sync
   // is turned on, |content_layer_| is updated with the appropriate states (see
   // in EmbedSurface()) instead of being recreated.
-  if (!enable_surface_synchronization_ && content_layer_ &&
-      local_surface_id_ != local_surface_id) {
+  if (!enable_surface_synchronization_ && content_layer_ && id_changed) {
     EvictDelegatedFrame();
   }
   support_->SubmitCompositorFrame(local_surface_id, std::move(frame),
@@ -131,7 +131,8 @@
   if (content_layer_->bounds() == expected_pixel_size_)
     compositor_pending_resize_lock_.reset();
 
-  frame_evictor_->SwappedFrame(frame_evictor_->visible());
+  if (id_changed)
+    frame_evictor_->OnNewSurfaceEmbedded();
 }
 
 void DelegatedFrameHostAndroid::DidNotProduceFrame(
@@ -197,7 +198,12 @@
   std::vector<viz::SurfaceId> surface_ids = {
       viz::SurfaceId(frame_sink_id_, local_surface_id_)};
   host_frame_sink_manager_->EvictSurfaces(surface_ids);
-  frame_evictor_->DiscardedFrame();
+  frame_evictor_->OnSurfaceDiscarded();
+  // When surface sync is on, this call will force |client_| to allocate a new
+  // LocalSurfaceId which will be embedded the next time the tab is shown. When
+  // surface sync is off, the renderer will always allocate a new LocalSurfaceId
+  // when it becomes visible just in case the previous LocalSurfaceId is evicted
+  // by the browser.
   client_->WasEvicted();
 }
 
@@ -271,7 +277,7 @@
 }
 
 bool DelegatedFrameHostAndroid::HasSavedFrame() const {
-  return frame_evictor_->HasFrame();
+  return frame_evictor_->has_surface();
 }
 
 void DelegatedFrameHostAndroid::WasHidden() {
@@ -320,10 +326,7 @@
     return;
   }
 
-  // TODO(fsamuel): "SwappedFrame" is a bad name. Also, this method doesn't
-  // really need to take in visibility. FrameEvictor already has the latest
-  // visibility state.
-  frame_evictor_->SwappedFrame(true /* visibility */);
+  frame_evictor_->OnNewSurfaceEmbedded();
 
   if (!current_primary_surface_id.is_valid() ||
       current_primary_surface_id.local_surface_id() != local_surface_id_) {
diff --git a/ui/android/java/res/layout/dropdown_item.xml b/ui/android/java/res/layout/dropdown_item.xml
index 7244be0..c689ee6c 100644
--- a/ui/android/java/res/layout/dropdown_item.xml
+++ b/ui/android/java/res/layout/dropdown_item.xml
@@ -24,7 +24,7 @@
     <LinearLayout
         android:id="@+id/dropdown_label_wrapper"
         android:layout_width="0dp"
-        android:layout_height="0dp"
+        android:layout_height="wrap_content"
         android:layout_weight="1"
         android:gravity="center_vertical"
         android:orientation="vertical" >
diff --git a/ui/android/java/src/org/chromium/ui/DropdownPopupWindowJellyBean.java b/ui/android/java/src/org/chromium/ui/DropdownPopupWindowJellyBean.java
index dd0d07a..0bb047f 100644
--- a/ui/android/java/src/org/chromium/ui/DropdownPopupWindowJellyBean.java
+++ b/ui/android/java/src/org/chromium/ui/DropdownPopupWindowJellyBean.java
@@ -199,7 +199,7 @@
         mFooterView = footerView;
         if (footerView != null) {
             footerView.setLayoutParams(new LinearLayout.LayoutParams(
-                    ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
+                    ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
         }
         mListPopupWindow.setPromptPosition(ListPopupWindow.POSITION_PROMPT_BELOW);
         mListPopupWindow.setPromptView(footerView);
diff --git a/ui/aura/test/aura_test_base.cc b/ui/aura/test/aura_test_base.cc
index 0125a31..03db199 100644
--- a/ui/aura/test/aura_test_base.cc
+++ b/ui/aura/test/aura_test_base.cc
@@ -15,7 +15,6 @@
 #include "ui/aura/window.h"
 #include "ui/base/ime/input_method_initializer.h"
 #include "ui/base/material_design/material_design_controller.h"
-#include "ui/base/test/material_design_controller_test_api.h"
 #include "ui/base/ui_base_features.h"
 #include "ui/base/ui_base_switches.h"
 #include "ui/base/ui_base_switches_util.h"
@@ -42,9 +41,6 @@
 void AuraTestBase::SetUp() {
   setup_called_ = true;
   testing::Test::SetUp();
-  // ContentTestSuiteBase might have already initialized
-  // MaterialDesignController in unit_tests suite.
-  ui::test::MaterialDesignControllerTestAPI::Uninitialize();
   ui::MaterialDesignController::Initialize();
   ui::InitializeInputMethodForTesting();
   ui::GestureConfiguration* gesture_config =
diff --git a/ui/base/ime/chromeos/character_composer_data.h b/ui/base/ime/chromeos/character_composer_data.h
index f218273..f27ef43 100644
--- a/ui/base/ime/chromeos/character_composer_data.h
+++ b/ui/base/ime/chromeos/character_composer_data.h
@@ -18053,7 +18053,7 @@
     //   leaf character table
     0x0050,          // number of entries
     0x0020,  // space
-    0x00B2,  // -> superscript two
+    0x005E,  // -> circumflex accent
     0x0028,  // left parenthesis
     0x207D,  // -> superscript left parenthesis
     0x0029,  // right parenthesis
diff --git a/ui/base/ime/chromeos/character_composer_sequences.txt b/ui/base/ime/chromeos/character_composer_sequences.txt
index af29bafa..3cc1825 100644
--- a/ui/base/ime/chromeos/character_composer_sequences.txt
+++ b/ui/base/ime/chromeos/character_composer_sequences.txt
@@ -3525,7 +3525,6 @@
 Dead<combining circumflex accent> Dead<combining dot below> <e> <latin small letter e with circumflex and dot below>
 Dead<combining circumflex accent> Dead<combining dot below> <o> <latin small letter o with circumflex and dot below>
 Dead<combining circumflex accent> <space> <^>
-Dead<combining circumflex accent> <space> <superscript two>
 Dead<combining circumflex accent> <(> <superscript left parenthesis>
 Dead<combining circumflex accent> <)> <superscript right parenthesis>
 Dead<combining circumflex accent> <+> <superscript plus sign>
diff --git a/ui/base/material_design/material_design_controller.cc b/ui/base/material_design/material_design_controller.cc
index 31a1c3a..0daa939 100644
--- a/ui/base/material_design/material_design_controller.cc
+++ b/ui/base/material_design/material_design_controller.cc
@@ -52,15 +52,11 @@
 }  // namespace
 #endif  // defined(OS_WIN)
 
-bool MaterialDesignController::initialized_ = false;
 bool MaterialDesignController::touch_ui_ = false;
 bool MaterialDesignController::automatic_touch_ui_ = false;
 
 // static
 void MaterialDesignController::Initialize() {
-  if (initialized_)
-    return;
-
   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
   const std::string switch_value =
       command_line->GetSwitchValueASCII(switches::kTopChromeTouchUi);
@@ -78,8 +74,9 @@
       // Win 10+ uses dynamic mode by default and checks the current tablet mode
       // state to determine whether to start in touch mode.
       automatic_touch_ui_ = true;
-      if (base::MessageLoopForUI::IsCurrent()) {
-        MaterialDesignController::GetInstance()->singleton_hwnd_observer_ =
+      if (base::MessageLoopForUI::IsCurrent() &&
+          !GetInstance()->singleton_hwnd_observer_) {
+        GetInstance()->singleton_hwnd_observer_ =
             std::make_unique<gfx::SingletonHwndObserver>(
                 base::BindRepeating(TabletModeWatcherWinProc));
         touch = IsTabletMode();
@@ -127,17 +124,11 @@
 MaterialDesignController::MaterialDesignController() = default;
 
 // static
-void MaterialDesignController::Uninitialize() {
-  initialized_ = false;
-}
-
-// static
 void MaterialDesignController::SetTouchUi(bool touch_ui) {
-  if (!initialized_ || touch_ui_ != touch_ui) {
-    initialized_ = true;
+  if (touch_ui_ != touch_ui) {
     touch_ui_ = touch_ui;
     for (auto& observer : GetInstance()->observers_)
-      observer.OnMdModeChanged();
+      observer.OnTouchUiChanged();
   }
 }
 
diff --git a/ui/base/material_design/material_design_controller.h b/ui/base/material_design/material_design_controller.h
index 6f1fc53..1e27b70 100644
--- a/ui/base/material_design/material_design_controller.h
+++ b/ui/base/material_design/material_design_controller.h
@@ -50,17 +50,9 @@
   MaterialDesignController();
   ~MaterialDesignController() = delete;
 
-  // Resets the initialization state to uninitialized. To be used by tests to
-  // allow calling Initialize() more than once.
-  static void Uninitialize();
-
   // Sets the touch UI state and notifies observers of the state change.
   static void SetTouchUi(bool touch_ui);
 
-  // Tracks whether |touch_ui_| has been initialized.
-  // Tests can use it to reset the state back to a clean state during tear down.
-  static bool initialized_;
-
   // Whether the UI layout should be touch-optimized.
   static bool touch_ui_;
 
diff --git a/ui/base/material_design/material_design_controller_observer.h b/ui/base/material_design/material_design_controller_observer.h
index 5b7eba4..0cde0d2 100644
--- a/ui/base/material_design/material_design_controller_observer.h
+++ b/ui/base/material_design/material_design_controller_observer.h
@@ -13,7 +13,7 @@
 class UI_BASE_EXPORT MaterialDesignControllerObserver
     : public base::CheckedObserver {
  public:
-  virtual void OnMdModeChanged() = 0;
+  virtual void OnTouchUiChanged() = 0;
 
  protected:
   ~MaterialDesignControllerObserver() override {}
diff --git a/ui/base/material_design/material_design_controller_unittest.cc b/ui/base/material_design/material_design_controller_unittest.cc
index 80f1aada..41abb82 100644
--- a/ui/base/material_design/material_design_controller_unittest.cc
+++ b/ui/base/material_design/material_design_controller_unittest.cc
@@ -10,7 +10,6 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/material_design/material_design_controller.h"
 #include "ui/base/material_design/material_design_controller_observer.h"
-#include "ui/base/test/material_design_controller_test_api.h"
 #include "ui/base/ui_base_switches.h"
 
 namespace ui {
@@ -25,13 +24,13 @@
   TestObserver() = default;
   ~TestObserver() override = default;
 
-  int md_mode_changes() const { return md_mode_changes_; }
+  int touch_ui_changes() const { return touch_ui_changes_; }
 
  private:
   // MDObserver:
-  void OnMdModeChanged() override { ++md_mode_changes_; }
+  void OnTouchUiChanged() override { ++touch_ui_changes_; }
 
-  int md_mode_changes_ = 0;
+  int touch_ui_changes_ = 0;
 
   DISALLOW_COPY_AND_ASSIGN(TestObserver);
 };
@@ -50,7 +49,6 @@
   }
 
   void TearDown() override {
-    test::MaterialDesignControllerTestAPI::Uninitialize();
     testing::Test::TearDown();
   }
 
@@ -124,60 +122,38 @@
   EXPECT_FALSE(MD::touch_ui());
 }
 
-// Verifies that the observer gets called back when the mode changes at
-// startup.
-TEST(MaterialDesignControllerObserver, InitializationOnMdModeChanged) {
-  TestObserver observer;
-  ScopedObserver<MD, MDObserver> scoped_observer(&observer);
-  scoped_observer.Add(MD::GetInstance());
-
-  // Trigger a mode change by setting it for the first time.
-  MD::Initialize();
-  EXPECT_EQ(1, observer.md_mode_changes());
-
-  test::MaterialDesignControllerTestAPI::Uninitialize();
-}
-
 // Verifies that when the mode is set to non-touch and the tablet mode toggles,
 // the touch UI state does not change.
 TEST_F(MaterialDesignControllerTestCommandLineTouchUiDisabled,
-       TabletOnMdModeChanged) {
-  MD::Initialize();
-
+       TabletOnTouchUiChanged) {
   TestObserver observer;
   ScopedObserver<MD, MDObserver> scoped_observer(&observer);
   scoped_observer.Add(MD::GetInstance());
 
   MD::OnTabletModeToggled(true);
   EXPECT_FALSE(MD::touch_ui());
-  EXPECT_EQ(0, observer.md_mode_changes());
+  EXPECT_EQ(0, observer.touch_ui_changes());
 
   MD::OnTabletModeToggled(false);
   EXPECT_FALSE(MD::touch_ui());
-  EXPECT_EQ(0, observer.md_mode_changes());
-
-  test::MaterialDesignControllerTestAPI::Uninitialize();
+  EXPECT_EQ(0, observer.touch_ui_changes());
 }
 
 // Verifies that when the mode is set to auto and the tablet mode toggles, the
 // touch UI state changes and the observer gets called back.
 TEST_F(MaterialDesignControllerTestCommandLineTouchUiAuto,
-       TabletOnMdModeChanged) {
-  MD::Initialize();
-
+       TabletOnTouchUiChanged) {
   TestObserver observer;
   ScopedObserver<MD, MDObserver> scoped_observer(&observer);
   scoped_observer.Add(MD::GetInstance());
 
   MD::OnTabletModeToggled(true);
   EXPECT_TRUE(MD::touch_ui());
-  EXPECT_EQ(1, observer.md_mode_changes());
+  EXPECT_EQ(1, observer.touch_ui_changes());
 
   MD::OnTabletModeToggled(false);
   EXPECT_FALSE(MD::touch_ui());
-  EXPECT_EQ(2, observer.md_mode_changes());
-
-  test::MaterialDesignControllerTestAPI::Uninitialize();
+  EXPECT_EQ(2, observer.touch_ui_changes());
 }
 
 }  // namespace ui
diff --git a/ui/base/test/material_design_controller_test_api.cc b/ui/base/test/material_design_controller_test_api.cc
index 69e28b0..f3122448 100644
--- a/ui/base/test/material_design_controller_test_api.cc
+++ b/ui/base/test/material_design_controller_test_api.cc
@@ -8,19 +8,13 @@
 namespace test {
 
 MaterialDesignControllerTestAPI::MaterialDesignControllerTestAPI(bool touch_ui)
-    : previous_initialized_(MaterialDesignController::initialized_),
-      previous_touch_ui_(MaterialDesignController::touch_ui_) {
+    : previous_touch_ui_(MaterialDesignController::touch_ui_) {
   MaterialDesignController::SetTouchUi(touch_ui);
 }
 
 MaterialDesignControllerTestAPI::~MaterialDesignControllerTestAPI() {
-  MaterialDesignController::initialized_ = previous_initialized_;
   MaterialDesignController::touch_ui_ = previous_touch_ui_;
 }
 
-void MaterialDesignControllerTestAPI::Uninitialize() {
-  MaterialDesignController::Uninitialize();
-}
-
 }  // namespace test
 }  // namespace ui
diff --git a/ui/base/test/material_design_controller_test_api.h b/ui/base/test/material_design_controller_test_api.h
index b9aeb296..9e560a8 100644
--- a/ui/base/test/material_design_controller_test_api.h
+++ b/ui/base/test/material_design_controller_test_api.h
@@ -19,11 +19,7 @@
   explicit MaterialDesignControllerTestAPI(bool touch_ui);
   ~MaterialDesignControllerTestAPI();
 
-  // Wrapper for MaterialDesignController internal function.
-  static void Uninitialize();
-
  private:
-  const bool previous_initialized_;
   const bool previous_touch_ui_;
 
   DISALLOW_COPY_AND_ASSIGN(MaterialDesignControllerTestAPI);
diff --git a/ui/base/x/BUILD.gn b/ui/base/x/BUILD.gn
index eb77c5f..440a5cd 100644
--- a/ui/base/x/BUILD.gn
+++ b/ui/base/x/BUILD.gn
@@ -38,4 +38,15 @@
     "//ui/gfx",
     "//ui/gfx/x",
   ]
+
+  if (!is_chromeos) {
+    sources += [
+      "x11_display_util.cc",
+      "x11_display_util.h",
+    ]
+
+    configs += [ "//build/config/linux:xrandr" ]
+
+    deps += [ "//ui/display/util" ]
+  }
 }
diff --git a/ui/base/x/x11_display_util.cc b/ui/base/x/x11_display_util.cc
new file mode 100644
index 0000000..c130674
--- /dev/null
+++ b/ui/base/x/x11_display_util.cc
@@ -0,0 +1,221 @@
+// 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 "ui/base/x/x11_display_util.h"
+
+#include <dlfcn.h>
+
+#include "base/logging.h"
+#include "base/memory/protected_memory_cfi.h"
+#include "ui/base/x/x11_util.h"
+#include "ui/display/util/display_util.h"
+#include "ui/display/util/x11/edid_parser_x11.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/x/x11.h"
+
+namespace ui {
+
+namespace {
+
+constexpr int kMinVersionXrandr = 103;  // Need at least xrandr version 1.3.
+
+typedef XRRMonitorInfo* (*XRRGetMonitors)(::Display*, Window, bool, int*);
+typedef void (*XRRFreeMonitors)(XRRMonitorInfo*);
+
+PROTECTED_MEMORY_SECTION base::ProtectedMemory<XRRGetMonitors>
+    g_XRRGetMonitors_ptr;
+PROTECTED_MEMORY_SECTION base::ProtectedMemory<XRRFreeMonitors>
+    g_XRRFreeMonitors_ptr;
+
+std::map<RROutput, int> GetMonitors(int version,
+                                    XDisplay* xdisplay,
+                                    GLXWindow window) {
+  std::map<RROutput, int> output_to_monitor;
+  if (version >= 105) {
+    void* xrandr_lib = dlopen(nullptr, RTLD_NOW);
+    if (xrandr_lib) {
+      static base::ProtectedMemory<XRRGetMonitors>::Initializer get_init(
+          &g_XRRGetMonitors_ptr, reinterpret_cast<XRRGetMonitors>(
+                                     dlsym(xrandr_lib, "XRRGetMonitors")));
+      static base::ProtectedMemory<XRRFreeMonitors>::Initializer free_init(
+          &g_XRRFreeMonitors_ptr, reinterpret_cast<XRRFreeMonitors>(
+                                      dlsym(xrandr_lib, "XRRFreeMonitors")));
+      if (*g_XRRGetMonitors_ptr && *g_XRRFreeMonitors_ptr) {
+        int nmonitors = 0;
+        XRRMonitorInfo* monitors = base::UnsanitizedCfiCall(
+            g_XRRGetMonitors_ptr)(xdisplay, window, false, &nmonitors);
+        for (int monitor = 0; monitor < nmonitors; monitor++) {
+          for (int j = 0; j < monitors[monitor].noutput; j++) {
+            output_to_monitor[monitors[monitor].outputs[j]] = monitor;
+          }
+        }
+        base::UnsanitizedCfiCall(g_XRRFreeMonitors_ptr)(monitors);
+      }
+    }
+  }
+  return output_to_monitor;
+}
+
+}  // namespace
+
+int GetXrandrVersion(XDisplay* xdisplay) {
+  int xrandr_version = 0;
+  // We only support 1.3+. There were library changes before this and we should
+  // use the new interface instead of the 1.2 one.
+  int randr_version_major = 0;
+  int randr_version_minor = 0;
+  if (XRRQueryVersion(xdisplay, &randr_version_major, &randr_version_minor)) {
+    xrandr_version = randr_version_major * 100 + randr_version_minor;
+  }
+  return xrandr_version;
+}
+
+std::vector<display::Display> GetFallbackDisplayList(float scale) {
+  XDisplay* display = gfx::GetXDisplay();
+  ::Screen* screen = DefaultScreenOfDisplay(display);
+  gfx::Size physical_size(WidthMMOfScreen(screen), HeightMMOfScreen(screen));
+
+  int width = WidthOfScreen(screen);
+  int height = HeightOfScreen(screen);
+  gfx::Rect bounds_in_pixels(0, 0, width, height);
+  display::Display gfx_display(0, bounds_in_pixels);
+
+  if (!display::Display::HasForceDeviceScaleFactor() &&
+      !display::IsDisplaySizeBlackListed(physical_size)) {
+    DCHECK_LE(1.0f, scale);
+    gfx_display.SetScaleAndBounds(scale, bounds_in_pixels);
+  }
+
+  return {gfx_display};
+}
+
+std::vector<display::Display> BuildDisplaysFromXRandRInfo(
+    int version,
+    float scale,
+    int64_t* primary_display_index_out) {
+  DCHECK(primary_display_index_out);
+  DCHECK_GE(version, kMinVersionXrandr);
+  XDisplay* xdisplay = gfx::GetXDisplay();
+  GLXWindow x_root_window = DefaultRootWindow(xdisplay);
+  std::vector<display::Display> displays;
+  gfx::XScopedPtr<
+      XRRScreenResources,
+      gfx::XObjectDeleter<XRRScreenResources, void, XRRFreeScreenResources>>
+      resources(XRRGetScreenResourcesCurrent(xdisplay, x_root_window));
+  if (!resources) {
+    LOG(ERROR) << "XRandR returned no displays; falling back to root window";
+    return GetFallbackDisplayList(scale);
+  }
+
+  std::map<RROutput, int> output_to_monitor =
+      GetMonitors(version, xdisplay, x_root_window);
+  *primary_display_index_out = 0;
+  RROutput primary_display_id = XRRGetOutputPrimary(xdisplay, x_root_window);
+
+  int explicit_primary_display_index = -1;
+  int monitor_order_primary_display_index = -1;
+
+  bool has_work_area = false;
+  gfx::Rect work_area_in_pixels;
+  std::vector<int> value;
+  if (ui::GetIntArrayProperty(x_root_window, "_NET_WORKAREA", &value) &&
+      value.size() >= 4) {
+    work_area_in_pixels = gfx::Rect(value[0], value[1], value[2], value[3]);
+    has_work_area = true;
+  }
+
+  // As per-display scale factor is not supported right now,
+  // the X11 root window's scale factor is always used.
+  for (int i = 0; i < resources->noutput; ++i) {
+    RROutput output_id = resources->outputs[i];
+    gfx::XScopedPtr<XRROutputInfo,
+                    gfx::XObjectDeleter<XRROutputInfo, void, XRRFreeOutputInfo>>
+        output_info(XRRGetOutputInfo(xdisplay, resources.get(), output_id));
+
+    bool is_connected = (output_info->connection == RR_Connected);
+    if (!is_connected)
+      continue;
+
+    bool is_primary_display = (output_id == primary_display_id);
+
+    if (output_info->crtc) {
+      gfx::XScopedPtr<XRRCrtcInfo,
+                      gfx::XObjectDeleter<XRRCrtcInfo, void, XRRFreeCrtcInfo>>
+          crtc(XRRGetCrtcInfo(xdisplay, resources.get(), output_info->crtc));
+
+      int64_t display_id = -1;
+      if (!display::EDIDParserX11(output_id).GetDisplayId(
+              static_cast<uint8_t>(i), &display_id)) {
+        // It isn't ideal, but if we can't parse the EDID data, fall back on the
+        // display number.
+        display_id = i;
+      }
+
+      gfx::Rect crtc_bounds(crtc->x, crtc->y, crtc->width, crtc->height);
+      display::Display display(display_id, crtc_bounds);
+
+      if (!display::Display::HasForceDeviceScaleFactor()) {
+        display.SetScaleAndBounds(scale, crtc_bounds);
+      }
+
+      if (has_work_area) {
+        gfx::Rect intersection_in_pixels = crtc_bounds;
+        if (is_primary_display) {
+          intersection_in_pixels.Intersect(work_area_in_pixels);
+        }
+        // SetScaleAndBounds() above does the conversion from pixels to DIP for
+        // us, but set_work_area does not, so we need to do it here.
+        display.set_work_area(gfx::Rect(
+            gfx::ScaleToFlooredPoint(intersection_in_pixels.origin(),
+                                     1.0f / display.device_scale_factor()),
+            gfx::ScaleToFlooredSize(intersection_in_pixels.size(),
+                                    1.0f / display.device_scale_factor())));
+      }
+
+      switch (crtc->rotation) {
+        case RR_Rotate_0:
+          display.set_rotation(display::Display::ROTATE_0);
+          break;
+        case RR_Rotate_90:
+          display.set_rotation(display::Display::ROTATE_90);
+          break;
+        case RR_Rotate_180:
+          display.set_rotation(display::Display::ROTATE_180);
+          break;
+        case RR_Rotate_270:
+          display.set_rotation(display::Display::ROTATE_270);
+          break;
+      }
+
+      if (is_primary_display)
+        explicit_primary_display_index = displays.size();
+
+      auto monitor_iter = output_to_monitor.find(output_id);
+      if (monitor_iter != output_to_monitor.end() && monitor_iter->second == 0)
+        monitor_order_primary_display_index = displays.size();
+
+      if (!display::Display::HasForceDisplayColorProfile()) {
+        gfx::ICCProfile icc_profile = ui::GetICCProfileForMonitor(
+            monitor_iter == output_to_monitor.end() ? 0 : monitor_iter->second);
+        icc_profile.HistogramDisplay(display.id());
+        display.set_color_space(icc_profile.GetColorSpace());
+      }
+
+      displays.push_back(display);
+    }
+  }
+
+  if (explicit_primary_display_index != -1) {
+    *primary_display_index_out = explicit_primary_display_index;
+  } else if (monitor_order_primary_display_index != -1) {
+    *primary_display_index_out = monitor_order_primary_display_index;
+  }
+
+  if (displays.empty())
+    return GetFallbackDisplayList(scale);
+
+  return displays;
+}
+
+}  // namespace ui
diff --git a/ui/base/x/x11_display_util.h b/ui/base/x/x11_display_util.h
new file mode 100644
index 0000000..8d16263c
--- /dev/null
+++ b/ui/base/x/x11_display_util.h
@@ -0,0 +1,32 @@
+// 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 UI_BASE_X_X11_DISPLAY_UTIL_H_
+#define UI_BASE_X_X11_DISPLAY_UTIL_H_
+
+#include "ui/base/x/ui_base_x_export.h"
+#include "ui/display/display.h"
+#include "ui/gfx/x/x11_types.h"
+
+namespace ui {
+
+// Return the version for xrandr. It multiplies the major number by 100 and
+// adds the minor like MAJOR * 100 + MINOR. It returns zero if no xrandr is
+// present.
+UI_BASE_X_EXPORT int GetXrandrVersion(XDisplay* xdisplay);
+
+// Builds a list of displays for fallback.
+UI_BASE_X_EXPORT std::vector<display::Display> GetFallbackDisplayList(
+    float scale);
+
+// Builds a list of displays from the current screen information offered by
+// the X server.
+UI_BASE_X_EXPORT std::vector<display::Display> BuildDisplaysFromXRandRInfo(
+    int version,
+    float scale,
+    int64_t* primary_display_index_out);
+
+}  // namespace ui
+
+#endif  // UI_BASE_X_X11_DISPLAY_UTIL_H_
diff --git a/ui/base/x/x11_util.cc b/ui/base/x/x11_util.cc
index 311b10e..9d79f93 100644
--- a/ui/base/x/x11_util.cc
+++ b/ui/base/x/x11_util.cc
@@ -19,6 +19,7 @@
 #include <vector>
 
 #include "base/bind.h"
+#include "base/command_line.h"
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/macros.h"
@@ -55,6 +56,7 @@
 #include "ui/gfx/image/image_skia.h"
 #include "ui/gfx/image/image_skia_rep.h"
 #include "ui/gfx/skia_util.h"
+#include "ui/gfx/switches.h"
 #include "ui/gfx/x/x11.h"
 #include "ui/gfx/x/x11_atom_cache.h"
 #include "ui/gfx/x/x11_error_tracker.h"
@@ -79,6 +81,10 @@
 constexpr int kNetWMStateAdd = 1;
 constexpr int kNetWMStateRemove = 0;
 
+// Length in 32-bit multiples of the data to be retrieved for
+// XGetWindowProperty.
+constexpr int kLongLength = 0x1FFFFFFF; /* MAXINT32 / 4 */
+
 int DefaultX11ErrorHandler(XDisplay* d, XErrorEvent* e) {
   // This callback can be invoked by drivers very late in thread destruction,
   // when Chrome TLS is no longer usable. https://crbug.com/849225.
@@ -680,10 +686,9 @@
   XAtom prop_type = x11::None;
   int prop_format = 0;
   unsigned char* property_data = NULL;
-  if (XGetWindowProperty(gfx::GetXDisplay(), window, property, 0,
-                         0x1FFFFFFF /* MAXINT32 / 4 */, x11::False,
-                         AnyPropertyType, &prop_type, &prop_format, &nitems,
-                         &nbytes, &property_data) != x11::Success) {
+  if (XGetWindowProperty(gfx::GetXDisplay(), window, property, 0, kLongLength,
+                         x11::False, AnyPropertyType, &prop_type, &prop_format,
+                         &nitems, &nbytes, &property_data) != x11::Success) {
     return false;
   }
   gfx::XScopedPtr<unsigned char> scoped_property(property_data);
@@ -1269,6 +1274,35 @@
   return base::ContainsValue(supported_atoms, atom);
 }
 
+gfx::ICCProfile GetICCProfileForMonitor(int monitor) {
+  gfx::ICCProfile icc_profile;
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kHeadless))
+    return icc_profile;
+  std::string atom_name;
+  if (monitor == 0) {
+    atom_name = "_ICC_PROFILE";
+  } else {
+    atom_name = base::StringPrintf("_ICC_PROFILE_%d", monitor);
+  }
+  Atom property = gfx::GetAtom(atom_name.c_str());
+  if (property != x11::None) {
+    Atom prop_type = x11::None;
+    int prop_format = 0;
+    unsigned long nitems = 0;
+    unsigned long nbytes = 0;
+    char* property_data = nullptr;
+    int result = XGetWindowProperty(
+        gfx::GetXDisplay(), DefaultRootWindow(gfx::GetXDisplay()), property, 0,
+        kLongLength, x11::False, AnyPropertyType, &prop_type, &prop_format,
+        &nitems, &nbytes, reinterpret_cast<unsigned char**>(&property_data));
+    if (result == x11::Success) {
+      icc_profile = gfx::ICCProfile::FromData(property_data, nitems);
+      XFree(property_data);
+    }
+  }
+  return icc_profile;
+}
+
 XRefcountedMemory::XRefcountedMemory(unsigned char* x11_data, size_t length)
     : x11_data_(length ? x11_data : nullptr), length_(length) {
 }
diff --git a/ui/base/x/x11_util.h b/ui/base/x/x11_util.h
index e7942b9..ee36758 100644
--- a/ui/base/x/x11_util.h
+++ b/ui/base/x/x11_util.h
@@ -23,6 +23,7 @@
 #include "ui/events/event_constants.h"
 #include "ui/events/keycodes/keyboard_codes.h"
 #include "ui/events/platform_event.h"
+#include "ui/gfx/icc_profile.h"
 #include "ui/gfx/x/x11_types.h"
 
 typedef unsigned long XSharedMemoryId;  // ShmSeg in the X headers.
@@ -297,6 +298,9 @@
 // Returns true if the window manager supports the given hint.
 UI_BASE_X_EXPORT bool WmSupportsHint(XAtom atom);
 
+// Returns the ICCProfile corresponding to |monitor| using XGetWindowProperty.
+UI_BASE_X_EXPORT gfx::ICCProfile GetICCProfileForMonitor(int monitor);
+
 // Manages a piece of X11 allocated memory as a RefCountedMemory segment. This
 // object takes ownership over the passed in memory and will free it with the
 // X11 allocator when done.
diff --git a/ui/display/util/BUILD.gn b/ui/display/util/BUILD.gn
index ebf6b16..347e673 100644
--- a/ui/display/util/BUILD.gn
+++ b/ui/display/util/BUILD.gn
@@ -5,6 +5,7 @@
 import("//build/config/jumbo.gni")
 import("//build/config/ui.gni")
 import("//testing/libfuzzer/fuzzer_test.gni")
+import("//ui/ozone/ozone.gni")
 
 jumbo_component("util") {
   output_name = "display_util"
@@ -27,7 +28,7 @@
     "//ui/gfx/geometry",
   ]
 
-  if (use_x11) {
+  if (use_x11 || (ozone_platform_x11 && !is_chromeos)) {
     sources += [
       "x11/edid_parser_x11.cc",
       "x11/edid_parser_x11.h",
diff --git a/ui/file_manager/file_manager/common/js/mock_entry.js b/ui/file_manager/file_manager/common/js/mock_entry.js
index f9e6dd42..5ebc0c44 100644
--- a/ui/file_manager/file_manager/common/js/mock_entry.js
+++ b/ui/file_manager/file_manager/common/js/mock_entry.js
@@ -296,14 +296,19 @@
  * @param {FileSystem} filesystem File system where the entry is localed.
  * @param {string} fullPath Full path for the entry.
  * @param {Metadata=} opt_metadata Metadata.
- * @extends {MockEntry}
+ * @extends {DirectoryEntry} MockDirectoryEntry is used to mock the implement
+ *   DirectoryEntry for testing.
+ * @implements {MockEntryInterface}
  * @constructor
  */
 function MockDirectoryEntry(filesystem, fullPath, opt_metadata) {
-  var metadata = opt_metadata || /** @type {!Metadata} */ ({});
-  metadata.size = metadata.size || 0;
-  metadata.modificationTime = metadata.modificationTime || new Date();
-  MockEntry.call(this, filesystem, fullPath, metadata);
+  filesystem.entries[fullPath] = this;
+  this.filesystem = filesystem;
+  this.fullPath = fullPath;
+  this.metadata = opt_metadata || /** @type {!Metadata} */ ({});
+  this.metadata.size = this.metadata.size || 0;
+  this.metadata.modificationTime = this.metadata.modificationTime || new Date();
+  this.removed_ = false;
   this.isFile = false;
   this.isDirectory = true;
 }
@@ -329,12 +334,16 @@
  * Returns a file under the directory.
  *
  * @param {string} path Path.
- * @param {Object} option Option.
- * @param {function(!FileEntry)} onSuccess Success callback.
- * @param {function(!FileError)} onError Failure callback;
+ * @param {!FileSystemFlags=} option Options
+ * @param {function(!FileEntry)=} onSuccess Success callback.
+ * @param {function(!FileError)=} onError Failure callback;
  */
 MockDirectoryEntry.prototype.getFile = function(
     path, option, onSuccess, onError) {
+  // As onSuccess and onError are optional, if they are not supplied we default
+  // them to be no-ops to save on checking their validity later.
+  onSuccess = onSuccess || (entry => {});  // no-op
+  onError = onError || (error => {});      // no-op
   var fullPath = path[0] === '/' ? path : joinPath(this.fullPath, path);
   if (!this.filesystem.entries[fullPath])
     onError(/** @type {!FileError} */ ({name: util.FileError.NOT_FOUND_ERR}));
@@ -349,24 +358,30 @@
  * Returns a directory under the directory.
  *
  * @param {string} path Path.
- * @param {Object} option Option.
- * @param {function(!MockDirectoryEntry)} onSuccess Success callback.
- * @param {function(Object)} onError Failure callback;
+ * @param {!FileSystemFlags=} option Options
+ * @param {function(!DirectoryEntry)=} onSuccess Success callback.
+ * @param {function(!FileError)=} onError Failure callback;
  */
-MockDirectoryEntry.prototype.getDirectory =
-    function(path, option, onSuccess, onError) {
+MockDirectoryEntry.prototype.getDirectory = function(
+    path, option, onSuccess, onError) {
+  // As onSuccess and onError are optional, if they are not supplied we default
+  // them to be no-ops to save on checking their validity later.
+  onSuccess = onSuccess || (entry => {});  // no-op
+  onError = onError || (error => {});      // no-op
   var fullPath = path[0] === '/' ? path : joinPath(this.fullPath, path);
   var result = this.filesystem.entries[fullPath];
   if (result) {
     if (!(result instanceof MockDirectoryEntry))
-      onError({name: util.FileError.TYPE_MISMATCH_ERR});
+      onError(
+          /** @type {!FileError} */ ({name: util.FileError.TYPE_MISMATCH_ERR}));
     else if (option['create'] && option['exclusive'])
-      onError({name: util.FileError.PATH_EXISTS_ERR});
+      onError(
+          /** @type {!FileError} */ ({name: util.FileError.PATH_EXISTS_ERR}));
     else
       onSuccess(result);
   } else {
     if (!option['create']) {
-      onError({name: util.FileError.NOT_FOUND_ERR});
+      onError(/** @type {!FileError} */ ({name: util.FileError.NOT_FOUND_ERR}));
     } else {
       var newEntry = new MockDirectoryEntry(this.filesystem, fullPath);
       this.filesystem.entries[fullPath] = newEntry;
diff --git a/ui/file_manager/file_manager/foreground/js/BUILD.gn b/ui/file_manager/file_manager/foreground/js/BUILD.gn
index a3321a8..19e4e4d3 100644
--- a/ui/file_manager/file_manager/foreground/js/BUILD.gn
+++ b/ui/file_manager/file_manager/foreground/js/BUILD.gn
@@ -111,6 +111,10 @@
   testonly = true
   deps = [
     ":mock_actions_model",
+    ":mock_directory_model",
+    ":mock_folder_shortcut_data_model",
+    ":mock_navigation_list_model",
+    ":mock_thumbnail_loader",
   ]
 }
 
@@ -147,6 +151,37 @@
   ]
 }
 
+js_library("mock_directory_model") {
+  testonly = true
+  deps = [
+    ":directory_contents",
+    ":directory_model",
+    "//ui/file_manager/file_manager/common/js:mock_entry",
+    "//ui/file_manager/file_manager/common/js:util",
+  ]
+}
+
+js_library("mock_folder_shortcut_data_model") {
+  testonly = true
+  deps = [
+    "//ui/file_manager/file_manager/common/js:mock_entry",
+  ]
+}
+
+js_library("mock_navigation_list_model") {
+  testonly = true
+  deps = [
+    ":navigation_list_model",
+  ]
+}
+
+js_library("mock_thumbnail_loader") {
+  testonly = true
+  deps = [
+    ":thumbnail_loader",
+  ]
+}
+
 js_library("app_state_controller") {
   deps = [
     ":dialog_type",
diff --git a/ui/file_manager/file_manager/foreground/js/crostini.js b/ui/file_manager/file_manager/foreground/js/crostini.js
index b0f412f..f9c3ee45 100644
--- a/ui/file_manager/file_manager/foreground/js/crostini.js
+++ b/ui/file_manager/file_manager/foreground/js/crostini.js
@@ -132,3 +132,15 @@
       (loadTimeData.getBoolean('DRIVE_FS_ENABLED') &&
        Crostini.VALID_ROOT_TYPES_FOR_SHARE.has(rootType));
 };
+
+/**
+ * Returns true if task requires entries to be shared before executing task.
+ * @param {!chrome.fileManagerPrivate.FileTask} task Task to run.
+ * @return {boolean} true if task requires entries to be shared.
+ */
+Crostini.taskRequiresSharing = function(task) {
+  const taskParts = task.taskId.split('|');
+  const taskType = taskParts[1];
+  const actionId = taskParts[2];
+  return taskType === 'crostini' || actionId === 'install-linux-package';
+};
diff --git a/ui/file_manager/file_manager/foreground/js/crostini_unittest.js b/ui/file_manager/file_manager/foreground/js/crostini_unittest.js
index 2bc29768..a22fa6ca 100644
--- a/ui/file_manager/file_manager/foreground/js/crostini_unittest.js
+++ b/ui/file_manager/file_manager/foreground/js/crostini_unittest.js
@@ -78,3 +78,10 @@
     assertTrue(Crostini.canSharePath(fooFolder, false, volumeManager));
   }
 }
+
+function testTaskRequiresSharing() {
+  assertTrue(Crostini.taskRequiresSharing({taskId: 'app|crostini|open-with'}));
+  assertTrue(
+      Crostini.taskRequiresSharing({taskId: 'appId|x|install-linux-package'}));
+  assertFalse(Crostini.taskRequiresSharing({taskId: 'appId|x|open-with'}));
+}
diff --git a/ui/file_manager/file_manager/foreground/js/file_tasks.js b/ui/file_manager/file_manager/foreground/js/file_tasks.js
index 5f9ec981..1a0fd3f 100644
--- a/ui/file_manager/file_manager/foreground/js/file_tasks.js
+++ b/ui/file_manager/file_manager/foreground/js/file_tasks.js
@@ -176,12 +176,14 @@
       }
 
       // Linux package installation is currently only supported for a single
-      // file already inside the Linux container.
+      // file which is inside the Linux container, or in a sharable volume.
       // TODO(timloh): Instead of filtering these out, we probably should show
       // a dialog with an error message, similar to when attempting to run
       // Crostini tasks with non-Crostini entries.
       if (entries.length !== 1 ||
-          !Crostini.isCrostiniEntry(entries[0], volumeManager)) {
+          !(Crostini.isCrostiniEntry(entries[0], volumeManager) ||
+            Crostini.canSharePath(
+                entries[0], false /* persist */, volumeManager))) {
         taskItems = taskItems.filter(function(item) {
           var taskParts = item.taskId.split('|');
           var appId = taskParts[0];
@@ -558,7 +560,7 @@
 FileTasks.prototype.maybeShareWithCrostiniOrShowDialog_ = function(
     task, callback) {
   // Check if this is a crostini task.
-  if (task.taskId.split('|', 2)[1] !== 'crostini' || this.entries_.length < 1)
+  if (!Crostini.taskRequiresSharing(task))
     return callback();
 
   let showUnableToOpen = false;
diff --git a/ui/file_manager/file_manager/foreground/js/mock_directory_model.js b/ui/file_manager/file_manager/foreground/js/mock_directory_model.js
index 4875e70..b4f3b6a 100644
--- a/ui/file_manager/file_manager/foreground/js/mock_directory_model.js
+++ b/ui/file_manager/file_manager/foreground/js/mock_directory_model.js
@@ -5,7 +5,7 @@
 /**
  * Mock class for DirectoryModel.
  * @constructor
- * @extends {cr.EventTarget}
+ * @extends {DirectoryModel}
  */
 function MockDirectoryModel() {
   /**
@@ -48,8 +48,8 @@
     var event = new Event('directory-changed');
     event.previousDirEntry = this.currentEntry_;
     event.newDirEntry = entry;
-    event.volumeChanged = this.currentEntry_ &&
-        util.isSameFileSystem(this.currentEntry_, entry);
+    event.volumeChanged =
+        this.currentEntry_ && util.isSameEntry(this.currentEntry_, entry);
     this.currentEntry_ = entry;
     this.dispatchEvent(event);
     resolve();
@@ -59,7 +59,7 @@
 /**
  * Mock class for FileFilter.
  * @constructor
- * @extends {cr.EventTarget}
+ * @extends {FileFilter}
  */
 function MockFileFilter() {}
 
diff --git a/ui/file_manager/file_manager/foreground/js/mock_thumbnail_loader.js b/ui/file_manager/file_manager/foreground/js/mock_thumbnail_loader.js
index d2b4414..b4602cf 100644
--- a/ui/file_manager/file_manager/foreground/js/mock_thumbnail_loader.js
+++ b/ui/file_manager/file_manager/foreground/js/mock_thumbnail_loader.js
@@ -11,6 +11,7 @@
  * @param {string=} opt_mediaType Media type.
  * @param {Array<ThumbnailLoader.LoadTarget>=} opt_loadTargets Load targets.
  * @param {number=} opt_priority Priority.
+ * @constructor
  */
 function MockThumbnailLoader(entry, opt_loaderType, opt_metadata, opt_mediaType,
     opt_loadTargets, opt_priority) {
@@ -19,7 +20,7 @@
 
 /**
  * Data url of test image.
- * @private {string}
+ * @private {?string}
  */
 MockThumbnailLoader.testImageDataUrl = null;
 
@@ -44,8 +45,8 @@
 /**
  * Loads thumbnail as data url.
  *
- * @return {!Promise<{data:string, width:number, height:number}>} A promise
- *     which is resolved with data url.
+ * @return {!Promise<{data:?string, width:number, height:number}>} A
+ *     promise which is resolved with data url.
  */
 MockThumbnailLoader.prototype.loadAsDataUrl = function() {
   if (MockThumbnailLoader.errorUrls.indexOf(this.entry_.toURL()) !== -1)
diff --git a/ui/gfx/font_fallback_win.cc b/ui/gfx/font_fallback_win.cc
index 86dc4bc5..4d64f62c 100644
--- a/ui/gfx/font_fallback_win.cc
+++ b/ui/gfx/font_fallback_win.cc
@@ -19,7 +19,9 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/trace_event/trace_event.h"
 #include "base/win/registry.h"
 #include "ui/gfx/font.h"
 #include "ui/gfx/font_fallback.h"
@@ -77,6 +79,7 @@
 void QueryLinkedFontsFromRegistry(const Font& font,
                                   std::map<std::string, std::string>* font_map,
                                   std::vector<Font>* linked_fonts) {
+  std::string logging_str;
   const wchar_t* kSystemLink =
       L"Software\\Microsoft\\Windows NT\\CurrentVersion\\FontLink\\SystemLink";
 
@@ -91,11 +94,18 @@
     return;
   }
 
+  base::StringAppendF(&logging_str, "Original font: %s\n",
+                      font.GetFontName().c_str());
+
   std::string filename;
   std::string font_name;
   for (size_t i = 0; i < values.size(); ++i) {
     internal::ParseFontLinkEntry(
         base::WideToUTF8(values[i]), &filename, &font_name);
+
+    base::StringAppendF(&logging_str, "fallback: '%s' '%s'\n",
+                        font_name.c_str(), filename.c_str());
+
     // If the font name is present, add that directly, otherwise add the
     // font names corresponding to the filename.
     if (!font_name.empty()) {
@@ -109,6 +119,13 @@
   }
 
   key.Close();
+
+  for (const auto& resolved_font : *linked_fonts) {
+    base::StringAppendF(&logging_str, "resolved: '%s'\n",
+                        resolved_font.GetFontName().c_str());
+  }
+
+  TRACE_EVENT1("ui", "QueryLinkedFontsFromRegistry", "results", logging_str);
 }
 
 // CachedFontLinkSettings is a singleton cache of the Windows font settings
@@ -153,6 +170,9 @@
   if (it != cached_linked_fonts_.end())
     return &it->second;
 
+  TRACE_EVENT1("ui", "CachedFontLinkSettings::GetLinkedFonts", "font_name",
+               font_name);
+
   SCOPED_UMA_HISTOGRAM_LONG_TIMER(
       "FontFallback.GetLinkedFonts.CacheMissTiming");
   std::vector<Font>* linked_fonts = &cached_linked_fonts_[font_name];
diff --git a/ui/gfx/linux/client_native_pixmap_factory_dmabuf.cc b/ui/gfx/linux/client_native_pixmap_factory_dmabuf.cc
index 0fdb9cb3..70c287b 100644
--- a/ui/gfx/linux/client_native_pixmap_factory_dmabuf.cc
+++ b/ui/gfx/linux/client_native_pixmap_factory_dmabuf.cc
@@ -12,12 +12,10 @@
 #include "build/build_config.h"
 #include "ui/gfx/native_pixmap_handle.h"
 
-#if defined(OS_CHROMEOS)
-// This can be enabled on all linux but it is not a requirement to support
-// glCreateImageChromium+Dmabuf since it uses gfx::BufferUsage::SCANOUT and
-// the pixmap does not need to be mappable on the client side.
+// Although, it's compiled for all linux platforms, it does not mean dmabuf
+// will work there. Check the comment below in the
+// ClientNativePixmapFactoryDmabuf for more details.
 #include "ui/gfx/linux/client_native_pixmap_dmabuf.h"
-#endif
 
 namespace gfx {
 
@@ -47,7 +45,10 @@
 
 class ClientNativePixmapFactoryDmabuf : public ClientNativePixmapFactory {
  public:
-  ClientNativePixmapFactoryDmabuf() {}
+  explicit ClientNativePixmapFactoryDmabuf(
+      bool supports_native_pixmap_import_from_dmabuf)
+      : supports_native_pixmap_import_from_dmabuf_(
+            supports_native_pixmap_import_from_dmabuf) {}
   ~ClientNativePixmapFactoryDmabuf() override {}
 
   // ClientNativePixmapFactory:
@@ -85,39 +86,34 @@
         return false;
       case gfx::BufferUsage::GPU_READ_CPU_READ_WRITE:
       case gfx::BufferUsage::GPU_READ_CPU_READ_WRITE_PERSISTENT: {
-#if defined(OS_CHROMEOS)
+        if (!supports_native_pixmap_import_from_dmabuf_)
+          return false;
         return
 #if defined(ARCH_CPU_X86_FAMILY)
-            // Currently only Intel driver (i.e. minigbm and Mesa) supports R_8
-            // RG_88 and NV12. https://crbug.com/356871
+            // Currently only Intel driver (i.e. minigbm and
+            // Mesa) supports R_8 RG_88 and NV12.
+            // https://crbug.com/356871
             format == gfx::BufferFormat::R_8 ||
             format == gfx::BufferFormat::RG_88 ||
             format == gfx::BufferFormat::YUV_420_BIPLANAR ||
 #endif
             format == gfx::BufferFormat::BGRA_8888;
-#else
-        return false;
-#endif
       }
       case gfx::BufferUsage::SCANOUT_CAMERA_READ_WRITE: {
-#if defined(OS_CHROMEOS)
+        if (!supports_native_pixmap_import_from_dmabuf_)
+          return false;
         // Each platform only supports one camera buffer type. We list the
         // supported buffer formats on all platforms here. When allocating a
         // camera buffer the caller is responsible for making sure a buffer is
         // successfully allocated. For example, allocating YUV420_BIPLANAR
         // for SCANOUT_CAMERA_READ_WRITE may only work on Intel boards.
         return format == gfx::BufferFormat::YUV_420_BIPLANAR;
-#else
-        return false;
-#endif
       }
       case gfx::BufferUsage::CAMERA_AND_CPU_READ_WRITE: {
-#if defined(OS_CHROMEOS)
+        if (!supports_native_pixmap_import_from_dmabuf_)
+          return false;
         // R_8 is used as the underlying pixel format for BLOB buffers.
         return format == gfx::BufferFormat::R_8;
-#else
-        return false;
-#endif
       }
     }
     NOTREACHED();
@@ -134,12 +130,11 @@
       case gfx::BufferUsage::GPU_READ_CPU_READ_WRITE_PERSISTENT:
       case gfx::BufferUsage::SCANOUT_CAMERA_READ_WRITE:
       case gfx::BufferUsage::CAMERA_AND_CPU_READ_WRITE:
-#if defined(OS_CHROMEOS)
-        return ClientNativePixmapDmaBuf::ImportFromDmabuf(handle, size);
-#else
-        NOTREACHED();
+        if (supports_native_pixmap_import_from_dmabuf_)
+          return ClientNativePixmapDmaBuf::ImportFromDmabuf(handle, size);
+        NOTREACHED()
+            << "Native GpuMemoryBuffers are not supported on this platform";
         return nullptr;
-#endif
       case gfx::BufferUsage::GPU_READ:
       case gfx::BufferUsage::SCANOUT:
       case gfx::BufferUsage::SCANOUT_VDA_WRITE:
@@ -152,11 +147,31 @@
     return nullptr;
   }
 
+ private:
+  // Says if ClientNativePixmapDmaBuf can be used to import handle from dmabuf.
+  const bool supports_native_pixmap_import_from_dmabuf_ = false;
+
   DISALLOW_COPY_AND_ASSIGN(ClientNativePixmapFactoryDmabuf);
 };
 
-ClientNativePixmapFactory* CreateClientNativePixmapFactoryDmabuf() {
-  return new ClientNativePixmapFactoryDmabuf();
+ClientNativePixmapFactory* CreateClientNativePixmapFactoryDmabuf(
+    bool supports_native_pixmap_import_from_dmabuf) {
+// |supports_native_pixmap_import_from_dmabuf| can be enabled on all linux but
+// it is not a requirement to support glCreateImageChromium+Dmabuf since it uses
+// gfx::BufferUsage::SCANOUT and the pixmap does not need to be mappable on the
+// client side.
+//
+// At the moment, only Ozone/Wayland platform running on Linux is able to import
+// handle from dmabuf in addition to the ChromeOS. This is set in the ozone
+// level in the ClientNativePixmapFactoryWayland class.
+//
+// This is not ideal. The ozone platform should probably set this.
+// TODO(rjkroege): do something better here.
+#if defined(OS_CHROMEOS)
+  supports_native_pixmap_import_from_dmabuf = true;
+#endif
+  return new ClientNativePixmapFactoryDmabuf(
+      supports_native_pixmap_import_from_dmabuf);
 }
 
 }  // namespace gfx
diff --git a/ui/gfx/linux/client_native_pixmap_factory_dmabuf.h b/ui/gfx/linux/client_native_pixmap_factory_dmabuf.h
index 7f802a6..730b28d 100644
--- a/ui/gfx/linux/client_native_pixmap_factory_dmabuf.h
+++ b/ui/gfx/linux/client_native_pixmap_factory_dmabuf.h
@@ -10,7 +10,8 @@
 
 namespace gfx {
 
-GFX_EXPORT ClientNativePixmapFactory* CreateClientNativePixmapFactoryDmabuf();
+GFX_EXPORT ClientNativePixmapFactory* CreateClientNativePixmapFactoryDmabuf(
+    bool supports_import_from_dmabuf = false);
 
 }  // namespace gfx
 
diff --git a/ui/keyboard/BUILD.gn b/ui/keyboard/BUILD.gn
index 384a997..3aa3e6c0 100644
--- a/ui/keyboard/BUILD.gn
+++ b/ui/keyboard/BUILD.gn
@@ -13,6 +13,7 @@
 
 jumbo_component("keyboard") {
   sources = [
+    "container_behavior.cc",
     "container_behavior.h",
     "container_floating_behavior.cc",
     "container_floating_behavior.h",
diff --git a/ui/keyboard/container_behavior.cc b/ui/keyboard/container_behavior.cc
new file mode 100644
index 0000000..e5ad95f
--- /dev/null
+++ b/ui/keyboard/container_behavior.cc
@@ -0,0 +1,14 @@
+// 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 "ui/keyboard/container_behavior.h"
+
+namespace keyboard {
+
+ContainerBehavior::ContainerBehavior(Delegate* delegate)
+    : delegate_(delegate) {}
+
+ContainerBehavior::~ContainerBehavior() = default;
+
+}  // namespace keyboard
diff --git a/ui/keyboard/container_behavior.h b/ui/keyboard/container_behavior.h
index 3d5eee9..fe94ce9d 100644
--- a/ui/keyboard/container_behavior.h
+++ b/ui/keyboard/container_behavior.h
@@ -5,12 +5,24 @@
 #ifndef UI_KEYBOARD_CONTAINER_BEHAVIOR_H_
 #define UI_KEYBOARD_CONTAINER_BEHAVIOR_H_
 
-#include "ui/aura/window.h"
-#include "ui/compositor/scoped_layer_animation_settings.h"
-#include "ui/events/event.h"
+#include "ui/display/display.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/vector2d.h"
 #include "ui/keyboard/container_type.h"
 #include "ui/keyboard/keyboard_export.h"
-#include "ui/wm/core/window_animations.h"
+
+namespace aura {
+class Window;
+}
+
+namespace ui {
+class LocatedEvent;
+class ScopedLayerAnimationSettings;
+}  // namespace ui
+
+namespace wm {
+class ScopedHidingAnimationSettings;
+}
 
 namespace keyboard {
 
@@ -18,7 +30,18 @@
 // within the workspace window.
 class KEYBOARD_EXPORT ContainerBehavior {
  public:
-  virtual ~ContainerBehavior() {}
+  class Delegate {
+   public:
+    virtual ~Delegate() {}
+    virtual gfx::Rect GetBoundsInScreen() const = 0;
+    virtual bool IsKeyboardLocked() const = 0;
+    virtual void MoveKeyboardWindow(const gfx::Rect& new_bounds) = 0;
+    virtual void MoveKeyboardWindowToDisplay(const display::Display& display,
+                                             const gfx::Rect& new_bounds) = 0;
+  };
+
+  explicit ContainerBehavior(Delegate* delegate);
+  virtual ~ContainerBehavior();
 
   // Apply changes to the animation settings to animate the keyboard container
   // showing.
@@ -30,7 +53,7 @@
   // hiding.
   virtual void DoHidingAnimation(
       aura::Window* window,
-      ::wm::ScopedHidingAnimationSettings* animation_settings) = 0;
+      wm::ScopedHidingAnimationSettings* animation_settings) = 0;
 
   // Initialize the starting state of the keyboard container for the showing
   // animation.
@@ -95,6 +118,8 @@
   virtual bool SetDraggableArea(const gfx::Rect& rect) = 0;
 
  protected:
+  Delegate* delegate_;
+
   // The opacity of virtual keyboard container when show animation
   // starts or hide animation finishes. This cannot be zero because we
   // call Show() on the keyboard window before setting the opacity
diff --git a/ui/keyboard/container_floating_behavior.cc b/ui/keyboard/container_floating_behavior.cc
index 91815b8..6204872d 100644
--- a/ui/keyboard/container_floating_behavior.cc
+++ b/ui/keyboard/container_floating_behavior.cc
@@ -4,14 +4,15 @@
 
 #include "ui/keyboard/container_floating_behavior.h"
 
+#include "ui/aura/window.h"
+#include "ui/compositor/scoped_layer_animation_settings.h"
+#include "ui/display/display.h"
 #include "ui/events/event.h"
 #include "ui/gfx/geometry/point.h"
-#include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/size.h"
-#include "ui/keyboard/container_type.h"
+#include "ui/keyboard/display_util.h"
 #include "ui/keyboard/drag_descriptor.h"
-#include "ui/keyboard/keyboard_controller.h"
-#include "ui/keyboard/keyboard_ui.h"
+#include "ui/wm/core/window_animations.h"
 
 namespace keyboard {
 
@@ -21,11 +22,10 @@
 // Distance the keyboard moves during the animation
 constexpr int kAnimationDistance = 30;
 
-ContainerFloatingBehavior::ContainerFloatingBehavior(
-    KeyboardController* controller) {
-  controller_ = controller;
-}
-ContainerFloatingBehavior::~ContainerFloatingBehavior() {}
+ContainerFloatingBehavior::ContainerFloatingBehavior(Delegate* delegate)
+    : ContainerBehavior(delegate) {}
+
+ContainerFloatingBehavior::~ContainerFloatingBehavior() = default;
 
 ContainerType ContainerFloatingBehavior::GetType() const {
   return ContainerType::FLOATING;
@@ -186,13 +186,9 @@
 bool ContainerFloatingBehavior::HandlePointerEvent(
     const ui::LocatedEvent& event,
     const display::Display& current_display) {
-  // Cannot call UI-backed operations without a KeyboardController
-  DCHECK(controller_);
   auto kb_offset = gfx::Vector2d(event.x(), event.y());
 
-  aura::Window* contents = controller_->GetKeyboardWindow();
-
-  const gfx::Rect& keyboard_bounds_in_screen = contents->GetBoundsInScreen();
+  const gfx::Rect& keyboard_bounds_in_screen = delegate_->GetBoundsInScreen();
 
   // Don't handle events if this runs in a partially initialized state.
   if (keyboard_bounds_in_screen.height() <= 0)
@@ -257,7 +253,7 @@
                 current_display, current_drag_location);
 
         if (current_display.id() == new_display.id()) {
-          controller_->MoveKeyboard(new_bounds_in_local);
+          delegate_->MoveKeyboardWindow(new_bounds_in_local);
         } else {
           // Since the keyboard has jumped across screens, cancel the current
           // drag descriptor as though the user has lifted their finger.
@@ -274,10 +270,10 @@
           new_bounds_in_local =
               contained_new_bounds_in_screen -
               new_display.bounds().origin().OffsetFromOrigin();
-          controller_->MoveToDisplayWithTransition(new_display,
-                                                   new_bounds_in_local);
+          delegate_->MoveKeyboardWindowToDisplay(new_display,
+                                                 new_bounds_in_local);
         }
-        SavePosition(contents->GetBoundsInScreen(), new_display.size());
+        SavePosition(delegate_->GetBoundsInScreen(), new_display.size());
         return true;
       }
       break;
diff --git a/ui/keyboard/container_floating_behavior.h b/ui/keyboard/container_floating_behavior.h
index ada21722..e19579d 100644
--- a/ui/keyboard/container_floating_behavior.h
+++ b/ui/keyboard/container_floating_behavior.h
@@ -5,16 +5,11 @@
 #ifndef UI_KEYBOARD_CONTAINER_FLOATING_BEHAVIOR_H_
 #define UI_KEYBOARD_CONTAINER_FLOATING_BEHAVIOR_H_
 
-#include "ui/aura/window.h"
-#include "ui/compositor/scoped_layer_animation_settings.h"
-#include "ui/events/event.h"
 #include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/rect.h"
 #include "ui/keyboard/container_behavior.h"
-#include "ui/keyboard/container_type.h"
 #include "ui/keyboard/drag_descriptor.h"
-#include "ui/keyboard/keyboard_controller.h"
 #include "ui/keyboard/keyboard_export.h"
-#include "ui/wm/core/window_animations.h"
 
 namespace keyboard {
 
@@ -23,14 +18,9 @@
 constexpr int kDefaultDistanceFromScreenBottom = 20;
 constexpr int kDefaultDistanceFromScreenRight = 20;
 
-struct KeyboardPosition {
-  double left_padding_allotment_ratio;
-  double top_padding_allotment_ratio;
-};
-
 class KEYBOARD_EXPORT ContainerFloatingBehavior : public ContainerBehavior {
  public:
-  ContainerFloatingBehavior(KeyboardController* controller);
+  explicit ContainerFloatingBehavior(Delegate* delegate);
   ~ContainerFloatingBehavior() override;
 
   // ContainerBehavior overrides
@@ -66,6 +56,11 @@
       const gfx::Rect& display_bounds) const;
 
  private:
+  struct KeyboardPosition {
+    double left_padding_allotment_ratio;
+    double top_padding_allotment_ratio;
+  };
+
   // Ensures that the keyboard is neither off the screen nor overlapping an
   // edge.
   gfx::Rect ContainKeyboardToScreenBounds(
@@ -75,15 +70,12 @@
   // Saves the current keyboard location for use the next time it is displayed.
   void UpdateLastPoint(const gfx::Point& position);
 
-  KeyboardController* controller_;
-
   // TODO(blakeo): cache the default_position_ on a per-display basis.
-  std::unique_ptr<struct keyboard::KeyboardPosition>
-      default_position_in_screen_ = nullptr;
+  std::unique_ptr<KeyboardPosition> default_position_in_screen_;
 
   // Current state of a cursor drag to move the keyboard, if one exists.
   // Otherwise nullptr.
-  std::unique_ptr<const DragDescriptor> drag_descriptor_ = nullptr;
+  std::unique_ptr<const DragDescriptor> drag_descriptor_;
 
   gfx::Rect draggable_area_ = gfx::Rect();
 };
diff --git a/ui/keyboard/container_full_width_behavior.cc b/ui/keyboard/container_full_width_behavior.cc
index 63e42bf..61a21e18 100644
--- a/ui/keyboard/container_full_width_behavior.cc
+++ b/ui/keyboard/container_full_width_behavior.cc
@@ -6,8 +6,7 @@
 
 #include "ui/aura/window.h"
 #include "ui/compositor/scoped_layer_animation_settings.h"
-#include "ui/keyboard/container_type.h"
-#include "ui/keyboard/keyboard_controller.h"
+#include "ui/gfx/transform.h"
 #include "ui/wm/core/window_animations.h"
 
 namespace keyboard {
@@ -15,10 +14,9 @@
 // The virtual keyboard show/hide animation duration.
 constexpr int kFullWidthKeyboardAnimationDurationMs = 100;
 
-ContainerFullWidthBehavior::ContainerFullWidthBehavior(
-    KeyboardController* controller) {
-  controller_ = controller;
-}
+ContainerFullWidthBehavior::ContainerFullWidthBehavior(Delegate* delegate)
+    : ContainerBehavior(delegate) {}
+
 ContainerFullWidthBehavior::~ContainerFullWidthBehavior() {}
 
 ContainerType ContainerFullWidthBehavior::GetType() const {
@@ -79,7 +77,7 @@
 bool ContainerFullWidthBehavior::IsOverscrollAllowed() const {
   // TODO(blakeo): The locked keyboard is essentially its own behavior type and
   // should be refactored as such. Then this will simply return 'true'.
-  return controller_ && !controller_->keyboard_locked();
+  return delegate_ && !delegate_->IsKeyboardLocked();
 }
 
 void ContainerFullWidthBehavior::SavePosition(const gfx::Rect& keyboard_bounds,
@@ -109,7 +107,7 @@
 }
 
 bool ContainerFullWidthBehavior::TextBlurHidesKeyboard() const {
-  return !controller_->keyboard_locked();
+  return !delegate_->IsKeyboardLocked();
 }
 
 void ContainerFullWidthBehavior::SetOccludedBounds(
@@ -125,7 +123,7 @@
 }
 
 bool ContainerFullWidthBehavior::OccludedBoundsAffectWorkspaceLayout() const {
-  return controller_->keyboard_locked();
+  return delegate_->IsKeyboardLocked();
 }
 
 bool ContainerFullWidthBehavior::SetDraggableArea(const gfx::Rect& rect) {
diff --git a/ui/keyboard/container_full_width_behavior.h b/ui/keyboard/container_full_width_behavior.h
index b11e487..bbc96e7 100644
--- a/ui/keyboard/container_full_width_behavior.h
+++ b/ui/keyboard/container_full_width_behavior.h
@@ -5,14 +5,8 @@
 #ifndef UI_KEYBOARD_CONTAINER_FULL_WIDTH_BEHAVIOR_H_
 #define UI_KEYBOARD_CONTAINER_FULL_WIDTH_BEHAVIOR_H_
 
-#include "ui/aura/window.h"
-#include "ui/compositor/scoped_layer_animation_settings.h"
-#include "ui/events/event.h"
+#include "ui/gfx/geometry/rect.h"
 #include "ui/keyboard/container_behavior.h"
-#include "ui/keyboard/container_type.h"
-#include "ui/keyboard/keyboard_controller.h"
-#include "ui/keyboard/keyboard_export.h"
-#include "ui/wm/core/window_animations.h"
 
 namespace keyboard {
 
@@ -22,7 +16,7 @@
 
 class KEYBOARD_EXPORT ContainerFullWidthBehavior : public ContainerBehavior {
  public:
-  ContainerFullWidthBehavior(KeyboardController* controller);
+  explicit ContainerFullWidthBehavior(Delegate* delegate);
   ~ContainerFullWidthBehavior() override;
 
   // ContainerBehavior overrides
@@ -55,7 +49,6 @@
 
  private:
   gfx::Rect occluded_bounds_in_window_;
-  KeyboardController* controller_;
 };
 
 }  // namespace keyboard
diff --git a/ui/keyboard/container_fullscreen_behavior.cc b/ui/keyboard/container_fullscreen_behavior.cc
index 33935515..525ccf8b 100644
--- a/ui/keyboard/container_fullscreen_behavior.cc
+++ b/ui/keyboard/container_fullscreen_behavior.cc
@@ -4,11 +4,12 @@
 
 #include "ui/keyboard/container_fullscreen_behavior.h"
 
+#include "ui/aura/window.h"
+
 namespace keyboard {
 
-ContainerFullscreenBehavior::ContainerFullscreenBehavior(
-    KeyboardController* controller)
-    : ContainerFullWidthBehavior(controller) {}
+ContainerFullscreenBehavior::ContainerFullscreenBehavior(Delegate* delegate)
+    : ContainerFullWidthBehavior(delegate) {}
 
 ContainerFullscreenBehavior::~ContainerFullscreenBehavior() {}
 
diff --git a/ui/keyboard/container_fullscreen_behavior.h b/ui/keyboard/container_fullscreen_behavior.h
index 7383043..8fc9f5c 100644
--- a/ui/keyboard/container_fullscreen_behavior.h
+++ b/ui/keyboard/container_fullscreen_behavior.h
@@ -5,9 +5,7 @@
 #ifndef UI_KEYBOARD_CONTAINER_FULLSCREEN_BEHAVIOR_H_
 #define UI_KEYBOARD_CONTAINER_FULLSCREEN_BEHAVIOR_H_
 
-#include "ui/aura/window.h"
 #include "ui/keyboard/container_full_width_behavior.h"
-#include "ui/keyboard/keyboard_controller.h"
 #include "ui/keyboard/keyboard_export.h"
 
 namespace keyboard {
@@ -15,7 +13,7 @@
 class KEYBOARD_EXPORT ContainerFullscreenBehavior
     : public ContainerFullWidthBehavior {
  public:
-  ContainerFullscreenBehavior(KeyboardController* controller);
+  explicit ContainerFullscreenBehavior(Delegate* controller);
   ~ContainerFullscreenBehavior() override;
 
   // ContainerFullWidthBehavior overrides
diff --git a/ui/keyboard/keyboard_controller.cc b/ui/keyboard/keyboard_controller.cc
index 0f9ab6d..c213d9b 100644
--- a/ui/keyboard/keyboard_controller.cc
+++ b/ui/keyboard/keyboard_controller.cc
@@ -316,11 +316,6 @@
   EnsureCaretInWorkArea(GetWorkspaceOccludedBounds());
 }
 
-void KeyboardController::MoveKeyboard(const gfx::Rect& new_bounds) {
-  DCHECK(IsKeyboardVisible());
-  SetKeyboardWindowBounds(new_bounds);
-}
-
 void KeyboardController::SetKeyboardWindowBounds(const gfx::Rect& new_bounds) {
   ui::LayerAnimator* animator = GetKeyboardWindow()->layer()->GetAnimator();
   // Stops previous animation if a window resize is requested during animation.
@@ -338,7 +333,7 @@
     // The window height is set to 0 initially or before switch to an IME in a
     // different extension. Virtual keyboard window may wait for this bounds
     // change to correctly animate in.
-    if (keyboard_locked()) {
+    if (keyboard_locked_) {
       // Do not move the keyboard to another display after switch to an IME in
       // a different extension.
       ShowKeyboardInDisplay(
@@ -465,14 +460,6 @@
       switches::kDisableVirtualKeyboardOverscroll);
 }
 
-void KeyboardController::MoveToDisplayWithTransition(
-    display::Display display,
-    gfx::Rect new_bounds_in_local) {
-  queued_display_change_ =
-      std::make_unique<QueuedDisplayChange>(display, new_bounds_in_local);
-  HideKeyboardTemporarilyForTransition();
-}
-
 // private
 void KeyboardController::HideKeyboard(HideReason reason) {
   TRACE_EVENT0("vk", "HideKeyboard");
@@ -556,7 +543,7 @@
 }
 
 void KeyboardController::HideKeyboardImplicitlyByUser() {
-  if (!keyboard_locked())
+  if (!keyboard_locked_)
     HideKeyboard(HIDE_REASON_USER_IMPLICIT);
 }
 
@@ -569,7 +556,7 @@
 }
 
 void KeyboardController::HideKeyboardImplicitlyBySystem() {
-  if (state_ != KeyboardControllerState::SHOWN || keyboard_locked())
+  if (state_ != KeyboardControllerState::SHOWN || keyboard_locked_)
     return;
 
   ChangeState(KeyboardControllerState::WILL_HIDE);
@@ -661,6 +648,40 @@
   PopulateKeyboardContent(display::Display(), false);
 }
 
+ui::InputMethod* KeyboardController::GetInputMethodForTest() {
+  return ui_->GetInputMethod();
+}
+
+void KeyboardController::EnsureCaretInWorkAreaForTest(
+    const gfx::Rect& occluded_bounds) {
+  EnsureCaretInWorkArea(occluded_bounds);
+}
+
+// ContainerBehavior::Delegate overrides
+
+bool KeyboardController::IsKeyboardLocked() const {
+  return keyboard_locked_;
+}
+
+gfx::Rect KeyboardController::GetBoundsInScreen() const {
+  return GetKeyboardWindow()->GetBoundsInScreen();
+}
+
+void KeyboardController::MoveKeyboardWindow(const gfx::Rect& new_bounds) {
+  DCHECK(IsKeyboardVisible());
+  SetKeyboardWindowBounds(new_bounds);
+}
+
+void KeyboardController::MoveKeyboardWindowToDisplay(
+    const display::Display& display,
+    const gfx::Rect& new_bounds) {
+  queued_display_change_ =
+      std::make_unique<QueuedDisplayChange>(display, new_bounds);
+  HideKeyboardTemporarilyForTransition();
+}
+
+// aura::WindowObserver overrides
+
 void KeyboardController::OnWindowAddedToRootWindow(aura::Window* window) {
   container_behavior_->SetCanonicalBounds(GetKeyboardWindow(),
                                           GetRootWindow()->bounds());
@@ -682,6 +703,8 @@
     NotifyKeyboardBoundsChanging(new_bounds);
 }
 
+// InputMethodObserver overrides
+
 void KeyboardController::OnInputMethodDestroyed(
     const ui::InputMethod* input_method) {
   ime_observer_.RemoveAll();
@@ -743,7 +766,7 @@
 
 void KeyboardController::OnShowVirtualKeyboardIfEnabled() {
   // Calling |ShowKeyboardInternal| may move the keyboard to another display.
-  if (keyboard::IsKeyboardEnabled() && !keyboard_locked())
+  if (keyboard::IsKeyboardEnabled() && !keyboard_locked_)
     ShowKeyboardInternal(display::Display());
 }
 
@@ -997,15 +1020,6 @@
   }
 }
 
-ui::InputMethod* KeyboardController::GetInputMethodForTest() {
-  return ui_->GetInputMethod();
-}
-
-void KeyboardController::EnsureCaretInWorkAreaForTest(
-    const gfx::Rect& occluded_bounds) {
-  EnsureCaretInWorkArea(occluded_bounds);
-}
-
 void KeyboardController::RecordUkmKeyboardShown() {
   ui::TextInputClient* text_input_client = GetTextInputClient();
   if (!text_input_client)
@@ -1020,9 +1034,11 @@
   return container_behavior_->SetDraggableArea(rect);
 }
 
+// InputMethodKeyboardController overrides:
+
 bool KeyboardController::DisplayVirtualKeyboard() {
   // Calling |ShowKeyboardInternal| may move the keyboard to another display.
-  if (keyboard::IsKeyboardEnabled() && !keyboard_locked()) {
+  if (keyboard::IsKeyboardEnabled() && !keyboard_locked_) {
     ShowKeyboardInternal(display::Display());
     return true;
   }
diff --git a/ui/keyboard/keyboard_controller.h b/ui/keyboard/keyboard_controller.h
index 7e1f9942..9daa7086 100644
--- a/ui/keyboard/keyboard_controller.h
+++ b/ui/keyboard/keyboard_controller.h
@@ -73,7 +73,8 @@
 class KEYBOARD_EXPORT KeyboardController
     : public ui::InputMethodObserver,
       public aura::WindowObserver,
-      public ui::InputMethodKeyboardController {
+      public ui::InputMethodKeyboardController,
+      public ContainerBehavior::Delegate {
  public:
   KeyboardController();
   ~KeyboardController() override;
@@ -116,9 +117,6 @@
   // null if the keyboard has not been attached to any root window.
   aura::Window* GetRootWindow();
 
-  // Moves an already loaded keyboard.
-  void MoveKeyboard(const gfx::Rect& new_bounds);
-
   // Sets the bounds of the keyboard window.
   void SetKeyboardWindowBounds(const gfx::Rect& new_bounds);
 
@@ -154,13 +152,6 @@
   // Returns true if keyboard overscroll is enabled.
   bool IsKeyboardOverscrollEnabled() const;
 
-  void set_keyboard_locked(bool lock) { keyboard_locked_ = lock; }
-
-  bool keyboard_locked() const { return keyboard_locked_; }
-
-  void MoveToDisplayWithTransition(display::Display display,
-                                   gfx::Rect new_bounds_in_local);
-
   // Hide the keyboard because the user has chosen to specifically hide the
   // keyboard, such as pressing the dismiss button.
   // TODO(https://crbug.com/845780): Rename this to
@@ -251,7 +242,7 @@
   // Sets floating keyboard draggable rect.
   bool SetDraggableArea(const gfx::Rect& rect);
 
-  // InputMethodKeyboardController overrides.
+  // InputMethodKeyboardController overrides:
   bool DisplayVirtualKeyboard() override;
   void DismissVirtualKeyboard() override;
   void AddObserver(
@@ -260,6 +251,9 @@
       ui::InputMethodKeyboardControllerObserver* observer) override;
   bool IsKeyboardVisible() override;
 
+  bool keyboard_locked() const { return keyboard_locked_; }
+  void set_keyboard_locked(bool lock) { keyboard_locked_ = lock; }
+
   KeyboardControllerState GetStateForTest() const { return state_; }
   ui::InputMethod* GetInputMethodForTest();
   void EnsureCaretInWorkAreaForTest(const gfx::Rect& occluded_bounds);
@@ -298,6 +292,13 @@
     HIDE_REASON_USER_IMPLICIT,
   };
 
+  // ContainerBehavior::Delegate overrides
+  bool IsKeyboardLocked() const override;
+  gfx::Rect GetBoundsInScreen() const override;
+  void MoveKeyboardWindow(const gfx::Rect& new_bounds) override;
+  void MoveKeyboardWindowToDisplay(const display::Display& display,
+                                   const gfx::Rect& new_bounds) override;
+
   // aura::WindowObserver overrides
   void OnWindowAddedToRootWindow(aura::Window* window) override;
   void OnWindowBoundsChanged(aura::Window* window,
diff --git a/ui/message_center/public/cpp/message_center_constants.h b/ui/message_center/public/cpp/message_center_constants.h
index 6af58c7..90b8bdf 100644
--- a/ui/message_center/public/cpp/message_center_constants.h
+++ b/ui/message_center/public/cpp/message_center_constants.h
@@ -142,14 +142,6 @@
 // The corners are only rounded in Chrome OS.
 constexpr int kNotificationCornerRadius = 2;
 
-// Layout parameters for swipe control of notifications in message center.
-constexpr int kSwipeControlButtonImageSize = 20;
-constexpr int kSwipeControlButtonSize = 36;
-constexpr int kSwipeControlButtonVerticalMargin = 24;
-constexpr int kSwipeControlButtonHorizontalMargin = 8;
-constexpr SkColor kSwipeControlBackgroundColor =
-    SkColorSetRGB(0xee, 0xee, 0xee);
-
 // Close if notification is slided more than this amount in addition to the
 // width of the buttons and their margins.
 constexpr int kSwipeCloseMargin = 64;
diff --git a/ui/message_center/views/message_view.cc b/ui/message_center/views/message_view.cc
index 0652bc73..a4081c1 100644
--- a/ui/message_center/views/message_view.cc
+++ b/ui/message_center/views/message_view.cc
@@ -118,6 +118,7 @@
   is_nested_ = true;
   // Update enability since it might be changed by "is_nested" flag.
   slide_out_controller_.set_slide_mode(CalculateSlideMode());
+  slide_out_controller_.set_update_opacity(false);
 
   SetBorder(views::CreateRoundedRectBorder(
       kNotificationBorderThickness, kNotificationCornerRadius, kBorderColor));
diff --git a/ui/message_center/views/notification_view_md_unittest.cc b/ui/message_center/views/notification_view_md_unittest.cc
index b08d43f..f3dc9c4 100644
--- a/ui/message_center/views/notification_view_md_unittest.cc
+++ b/ui/message_center/views/notification_view_md_unittest.cc
@@ -260,7 +260,6 @@
     // created by the method.
     notification_view_ = std::make_unique<NotificationViewMD>(notification);
     notification_view_->AddObserver(this);
-    notification_view_->SetIsNested();
     notification_view_->set_owned_by_client();
 
     views::Widget::InitParams init_params(
@@ -659,6 +658,7 @@
 }
 
 TEST_F(NotificationViewMDTest, SlideOutNested) {
+  notification_view()->SetIsNested();
   ui::ScopedAnimationDurationScaleMode zero_duration_scope(
       ui::ScopedAnimationDurationScaleMode::ZERO_DURATION);
 
@@ -706,6 +706,7 @@
 #if defined(OS_CHROMEOS)
 
 TEST_F(NotificationViewMDTest, SlideOutPinned) {
+  notification_view()->SetIsNested();
   ui::ScopedAnimationDurationScaleMode zero_duration_scope(
       ui::ScopedAnimationDurationScaleMode::ZERO_DURATION);
 
@@ -722,6 +723,7 @@
 }
 
 TEST_F(NotificationViewMDTest, Pinned) {
+  notification_view()->SetIsNested();
   std::unique_ptr<Notification> notification = CreateSimpleNotification();
 
   // Visible at the initial state.
diff --git a/ui/message_center/views/slide_out_controller.cc b/ui/message_center/views/slide_out_controller.cc
index 18134bd..2f76731 100644
--- a/ui/message_center/views/slide_out_controller.cc
+++ b/ui/message_center/views/slide_out_controller.cc
@@ -98,7 +98,7 @@
         break;
     }
 
-    layer->SetOpacity(opacity);
+    SetOpacityIfNecessary(opacity);
     gfx::Transform transform;
     transform.Translate(scroll_amount, 0.0);
     layer->SetTransform(transform);
@@ -139,7 +139,7 @@
       break;
   }
 
-  if (layer->transform() == transform && layer->opacity() == 1.f) {
+  if (layer->transform() == transform && opacity_ == 1.f) {
     // Here, nothing are changed and no animation starts. In this case, just
     // calls OnSlideChanged(in_progress = false) to notify end of horizontal
     // slide (including animations) to observers.
@@ -150,14 +150,14 @@
   // In this case, animation starts. OnImplicitAnimationsCompleted will be
   // called just after the animation finishes.
   layer->SetTransform(transform);
-  layer->SetOpacity(1.f);
+  SetOpacityIfNecessary(1.f);
   delegate_->OnSlideChanged(true);
 }
 
 void SlideOutController::SlideOutAndClose(int direction) {
   ui::Layer* layer = delegate_->GetSlideOutLayer();
   const int kSwipeOutTotalDurationMS = 150;
-  int swipe_out_duration = kSwipeOutTotalDurationMS * layer->opacity();
+  int swipe_out_duration = kSwipeOutTotalDurationMS * opacity_;
   ui::ScopedLayerAnimationSettings settings(layer->GetAnimator());
   settings.SetTransitionDuration(
       base::TimeDelta::FromMilliseconds(swipe_out_duration));
@@ -170,17 +170,21 @@
   // An animation starts. OnImplicitAnimationsCompleted will be called just
   // after the animation finishes.
   layer->SetTransform(transform);
-  layer->SetOpacity(0.f);
+  SetOpacityIfNecessary(0.f);
   delegate_->OnSlideChanged(true);
 }
 
+void SlideOutController::SetOpacityIfNecessary(float opacity) {
+  if (update_opacity_)
+    delegate_->GetSlideOutLayer()->SetOpacity(opacity);
+  opacity_ = opacity;
+}
+
 void SlideOutController::OnImplicitAnimationsCompleted() {
   delegate_->OnSlideChanged(false);
 
-  // Call Delegate::OnSlideOut() if this animation came from
-  // SlideOutAndClose().
-  ui::Layer* layer = delegate_->GetSlideOutLayer();
-  if (layer->opacity() == 0)
+  // Call Delegate::OnSlideOut() if this animation came from SlideOutAndClose().
+  if (opacity_ == 0)
     delegate_->OnSlideOut();
 }
 
diff --git a/ui/message_center/views/slide_out_controller.h b/ui/message_center/views/slide_out_controller.h
index 1cd86926..100cbfb 100644
--- a/ui/message_center/views/slide_out_controller.h
+++ b/ui/message_center/views/slide_out_controller.h
@@ -42,6 +42,9 @@
   SlideOutController(ui::EventTarget* target, Delegate* delegate);
   ~SlideOutController() override;
 
+  void set_update_opacity(bool update_opacity) {
+    update_opacity_ = update_opacity;
+  }
   void set_slide_mode(SlideMode mode) {
     // TODO(yoshiki): Close the slide when the slide mode sets to NO_SLIDE.
     mode_ = mode;
@@ -79,6 +82,9 @@
   // |direction| indicates which way the slide occurs.
   void SlideOutAndClose(int direction);
 
+  // Sets the opacity of the slide out layer if |update_opacity_| is true.
+  void SetOpacityIfNecessary(float opacity);
+
   ui::ScopedTargetHandler target_handling_;
   Delegate* delegate_;
 
@@ -101,6 +107,12 @@
   // Changed only when |mode_| is FULL and |has_swipe_control_| is true.
   SwipeControlOpenState control_open_state_ = SwipeControlOpenState::CLOSED;
 
+  // If false, it doesn't update the opacity.
+  bool update_opacity_ = true;
+
+  // Last opacity set by SetOpacityIfNecessary.
+  float opacity_ = 1.0;
+
   DISALLOW_COPY_AND_ASSIGN(SlideOutController);
 };
 
diff --git a/ui/ozone/platform/drm/gpu/crtc_controller.cc b/ui/ozone/platform/drm/gpu/crtc_controller.cc
index 537688b..aea5c91 100644
--- a/ui/ozone/platform/drm/gpu/crtc_controller.cc
+++ b/ui/ozone/platform/drm/gpu/crtc_controller.cc
@@ -53,6 +53,12 @@
   mode_ = mode;
   is_disabled_ = false;
 
+  // Hold modeset buffer until page flip. This fixes a crash on entering
+  // hardware mirror mode in some circumstances (bug 888553).
+  // TODO(spang): Fix this better by changing how mirrors are set up (bug
+  // 899352).
+  modeset_framebuffer_ = plane.buffer;
+
   return true;
 }
 
@@ -107,6 +113,10 @@
   drm_->MoveCursor(crtc_, location);
 }
 
+void CrtcController::OnPageFlipComplete() {
+  modeset_framebuffer_ = nullptr;
+}
+
 void CrtcController::DisableCursor() {
   if (!drm_->SetCursor(crtc_, 0, gfx::Size())) {
     PLOG(ERROR) << "drmModeSetCursor: device " << drm_->device_path().value()
diff --git a/ui/ozone/platform/drm/gpu/crtc_controller.h b/ui/ozone/platform/drm/gpu/crtc_controller.h
index 1804ad5..670ed0dd 100644
--- a/ui/ozone/platform/drm/gpu/crtc_controller.h
+++ b/ui/ozone/platform/drm/gpu/crtc_controller.h
@@ -63,6 +63,8 @@
   void SetCursor(uint32_t handle, const gfx::Size& size);
   void MoveCursor(const gfx::Point& location);
 
+  void OnPageFlipComplete();
+
  private:
   void DisableCursor();
 
@@ -75,6 +77,8 @@
 
   drmModeModeInfo mode_ = {};
 
+  scoped_refptr<DrmFramebuffer> modeset_framebuffer_;
+
   // Keeps track of the CRTC state. If a surface has been bound, then the value
   // is set to false. Otherwise it is true.
   bool is_disabled_ = true;
diff --git a/ui/ozone/platform/drm/gpu/hardware_display_controller.cc b/ui/ozone/platform/drm/gpu/hardware_display_controller.cc
index c165b0b..771e6c8 100644
--- a/ui/ozone/platform/drm/gpu/hardware_display_controller.cc
+++ b/ui/ozone/platform/drm/gpu/hardware_display_controller.cc
@@ -338,6 +338,8 @@
     return;  // Modeset occured during this page flip.
   time_of_last_flip_ = presentation_feedback.timestamp;
   current_planes_ = std::move(pending_planes);
+  for (const auto& controller : crtc_controllers_)
+    controller->OnPageFlipComplete();
   page_flip_request_ = nullptr;
 }
 
diff --git a/ui/ozone/platform/drm/gpu/mock_drm_device.cc b/ui/ozone/platform/drm/gpu/mock_drm_device.cc
index e10c43f3..e9dfffb 100644
--- a/ui/ozone/platform/drm/gpu/mock_drm_device.cc
+++ b/ui/ozone/platform/drm/gpu/mock_drm_device.cc
@@ -197,6 +197,7 @@
                             uint32_t framebuffer,
                             std::vector<uint32_t> connectors,
                             drmModeModeInfo* mode) {
+  crtc_fb_[crtc_id] = framebuffer;
   current_framebuffer_ = framebuffer;
   set_crtc_call_count_++;
   return set_crtc_expectation_;
@@ -228,11 +229,24 @@
                                     uint32_t flags) {
   add_framebuffer_call_count_++;
   *framebuffer = add_framebuffer_call_count_;
+  framebuffer_ids_.insert(*framebuffer);
   return add_framebuffer_expectation_;
 }
 
 bool MockDrmDevice::RemoveFramebuffer(uint32_t framebuffer) {
+  {
+    auto it = framebuffer_ids_.find(framebuffer);
+    CHECK(it != framebuffer_ids_.end());
+    framebuffer_ids_.erase(it);
+  }
   remove_framebuffer_call_count_++;
+  std::vector<uint32_t> crtcs_to_clear;
+  for (auto crtc_fb : crtc_fb_) {
+    if (crtc_fb.second == framebuffer)
+      crtcs_to_clear.push_back(crtc_fb.first);
+  }
+  for (auto crtc : crtcs_to_clear)
+    crtc_fb_[crtc] = 0;
   return true;
 }
 
@@ -245,6 +259,7 @@
                              scoped_refptr<PageFlipRequest> page_flip_request) {
   page_flip_call_count_++;
   DCHECK(page_flip_request);
+  crtc_fb_[crtc_id] = framebuffer;
   current_framebuffer_ = framebuffer;
   if (page_flip_expectation_)
     callbacks_.push(page_flip_request->AddPageFlip());
@@ -422,6 +437,11 @@
   return true;
 }
 
+uint32_t MockDrmDevice::GetFramebufferForCrtc(uint32_t crtc_id) const {
+  auto it = crtc_fb_.find(crtc_id);
+  return it != crtc_fb_.end() ? it->second : 0u;
+}
+
 void MockDrmDevice::RunCallbacks() {
   while (!callbacks_.empty()) {
     PageFlipCallback callback = std::move(callbacks_.front());
diff --git a/ui/ozone/platform/drm/gpu/mock_drm_device.h b/ui/ozone/platform/drm/gpu/mock_drm_device.h
index a421d68..64279da 100644
--- a/ui/ozone/platform/drm/gpu/mock_drm_device.h
+++ b/ui/ozone/platform/drm/gpu/mock_drm_device.h
@@ -166,6 +166,7 @@
       uint32_t crtc_id,
       const std::vector<display::GammaRampRGBEntry>& lut) override;
   bool SetCapability(uint64_t capability, uint64_t value) override;
+  uint32_t GetFramebufferForCrtc(uint32_t crtc_id) const;
 
  private:
   ~MockDrmDevice() override;
@@ -205,6 +206,9 @@
 
   std::map<uint32_t, ScopedDrmPropertyBlobPtr> blob_property_map_;
 
+  std::set<uint32_t> framebuffer_ids_;
+  std::map<uint32_t, uint32_t> crtc_fb_;
+
   base::queue<PageFlipCallback> callbacks_;
 
   std::vector<CrtcProperties> crtc_properties_;
diff --git a/ui/ozone/platform/drm/gpu/screen_manager_unittest.cc b/ui/ozone/platform/drm/gpu/screen_manager_unittest.cc
index 01944a2..e8cae25 100644
--- a/ui/ozone/platform/drm/gpu/screen_manager_unittest.cc
+++ b/ui/ozone/platform/drm/gpu/screen_manager_unittest.cc
@@ -701,4 +701,56 @@
   screen_manager.RemoveWindow(3)->Shutdown();
 }
 
+// crbug.com/888553
+TEST(ScreenManagerTest2, ShouldNotUnbindFramebufferOnJoiningMirror) {
+  auto gbm_device = std::make_unique<MockGbmDevice>();
+  auto drm_device = base::MakeRefCounted<MockDrmDevice>(std::move(gbm_device));
+  DrmDeviceManager drm_device_manager(nullptr);
+  ScreenManager screen_manager;
+
+  constexpr uint32_t kCrtc39 = 39;
+  constexpr uint32_t kConnector43 = 43;
+  constexpr uint32_t kCrtc41 = 41;
+  constexpr uint32_t kConnector46 = 46;
+
+  constexpr drmModeModeInfo kMode1080p60 = {
+      /* clock= */ 148500,
+      /* hdisplay= */ 1920,
+      /* hsync_start= */ 2008,
+      /* hsync_end= */ 2052,
+      /* htotal= */ 2200,
+      /* hskew= */ 0,
+      /* vdisplay= */ 1080,
+      /* vsync_start= */ 1084,
+      /* vsync_end= */ 1089,
+      /* vtotal= */ 1125,
+      /* vscan= */ 0,
+      /* vrefresh= */ 60,
+      /* flags= */ 0xa,
+      /* type= */ 64,
+      /* name= */ "1920x1080",
+  };
+
+  // Both displays connect at startup.
+  {
+    auto window1 =
+        std::make_unique<DrmWindow>(1, &drm_device_manager, &screen_manager);
+    window1->Initialize();
+    screen_manager.AddWindow(1, std::move(window1));
+    screen_manager.GetWindow(1)->SetBounds(gfx::Rect(0, 0, 1920, 1080));
+    screen_manager.AddDisplayController(drm_device, kCrtc39, kConnector43);
+    screen_manager.AddDisplayController(drm_device, kCrtc41, kConnector46);
+    screen_manager.ConfigureDisplayController(drm_device, kCrtc39, kConnector43,
+                                              gfx::Point(0, 0), kMode1080p60);
+    screen_manager.ConfigureDisplayController(drm_device, kCrtc41, kConnector46,
+                                              gfx::Point(0, 0), kMode1080p60);
+  }
+
+  EXPECT_NE(0u, drm_device->GetFramebufferForCrtc(kCrtc39));
+  EXPECT_NE(0u, drm_device->GetFramebufferForCrtc(kCrtc41));
+
+  // Cleanup.
+  screen_manager.RemoveWindow(1)->Shutdown();
+}
+
 }  // namespace ui
diff --git a/ui/ozone/platform/wayland/client_native_pixmap_factory_wayland.cc b/ui/ozone/platform/wayland/client_native_pixmap_factory_wayland.cc
index 110dc9f..a57bfb8 100644
--- a/ui/ozone/platform/wayland/client_native_pixmap_factory_wayland.cc
+++ b/ui/ozone/platform/wayland/client_native_pixmap_factory_wayland.cc
@@ -16,7 +16,8 @@
 class ClientNativePixmapFactoryWayland : public gfx::ClientNativePixmapFactory {
  public:
   ClientNativePixmapFactoryWayland() {
-    dmabuf_factory_.reset(gfx::CreateClientNativePixmapFactoryDmabuf());
+    dmabuf_factory_.reset(gfx::CreateClientNativePixmapFactoryDmabuf(
+        true /* supports_native_pixmap_import_from_dmabuf */));
   }
   ~ClientNativePixmapFactoryWayland() override {}
 
diff --git a/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.cc b/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.cc
index c08798ab..62d42fc 100644
--- a/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.cc
+++ b/ui/ozone/platform/wayland/gpu/gbm_pixmap_wayland.cc
@@ -58,13 +58,7 @@
       break;
     case gfx::BufferUsage::GPU_READ_CPU_READ_WRITE:
     case gfx::BufferUsage::GPU_READ_CPU_READ_WRITE_PERSISTENT:
-      // mmap cannot be used with gbm buffers on a different process. That is,
-      // Linux disallows this and "permission denied" is returned. To overcome
-      // this and make software rasterization working, buffers must be created
-      // on the browser process and gbm_bo_map must be used.
-      // TODO(msisov): add support fir these two buffer usage cases.
-      // https://crbug.com/864914
-      LOG(FATAL) << "This scenario is not supported in Wayland now";
+      flags = GBM_BO_USE_LINEAR;
       break;
     default:
       NOTREACHED() << "Not supported buffer format";
diff --git a/ui/ozone/platform/wayland/wayland_buffer_manager.cc b/ui/ozone/platform/wayland/wayland_buffer_manager.cc
index e322f42..393336d 100644
--- a/ui/ozone/platform/wayland/wayland_buffer_manager.cc
+++ b/ui/ozone/platform/wayland/wayland_buffer_manager.cc
@@ -313,7 +313,11 @@
     }
   }
 
-  DCHECK(buffer);
+  // It can happen that buffer was destroyed by a client while the Wayland
+  // compositor was processing a request to create a wl_buffer.
+  if (!buffer)
+    return;
+
   buffer->wl_buffer.reset(new_buffer);
   buffer->params = nullptr;
   zwp_linux_buffer_params_v1_destroy(params);
@@ -370,7 +374,6 @@
     struct zwp_linux_buffer_params_v1* params,
     struct wl_buffer* new_buffer) {
   WaylandBufferManager* self = static_cast<WaylandBufferManager*>(data);
-
   DCHECK(self);
   self->CreateSucceededInternal(params, new_buffer);
 }
diff --git a/ui/strings/ui_strings.grd b/ui/strings/ui_strings.grd
index d82bf2f..146d3fe 100644
--- a/ui/strings/ui_strings.grd
+++ b/ui/strings/ui_strings.grd
@@ -840,6 +840,23 @@
       <message name="IDS_DISPLAY_NAME_INTERNAL" desc="The name used for internal displays, which is shown in the display settings.">
         Internal Display
       </message>
+
+      <!-- Crostini app context menu item names, dialog message and button strings -->
+      <message name="IDS_CROSTINI_USE_LOW_DENSITY" desc="The Crostini app Shelf item context menu item to use low display density for app windows.">
+        Use low density
+      </message>
+      <message name="IDS_CROSTINI_USE_HIGH_DENSITY" desc="The Crostini app Shelf item context menu item to use high display density for app windows.">
+        Use high density
+      </message>
+      <message name="IDS_CROSTINI_APP_RESTART_BODY" desc="Description for the Crostini app restart dialog.">
+        To adjust the window display density, restart the app.
+      </message>
+      <message name="IDS_CROSTINI_APP_RESTART_BUTTON" desc="Label for the button in the Crostini app restart dialog to restart an app.">
+        Restart
+      </message>
+      <message name="IDS_CROSTINI_NOT_NOW_BUTTON" desc="Label for the button in the Crostini app restart dialog to dismiss the dialog.">
+        Not now
+      </message>
     </messages>
   </release>
 </grit>
diff --git a/ui/views/cocoa/bridged_native_widget_unittest.mm b/ui/views/cocoa/bridged_native_widget_unittest.mm
index 99d357d..00df4d7 100644
--- a/ui/views/cocoa/bridged_native_widget_unittest.mm
+++ b/ui/views/cocoa/bridged_native_widget_unittest.mm
@@ -23,7 +23,6 @@
 #include "ui/base/ime/input_method.h"
 #include "ui/base/material_design/material_design_controller.h"
 #import "ui/base/test/cocoa_helper.h"
-#include "ui/base/test/material_design_controller_test_api.h"
 #include "ui/events/test/cocoa_test_event_utils.h"
 #import "ui/gfx/mac/coordinate_conversion.h"
 #import "ui/views/cocoa/bridged_native_widget_host_impl.h"
@@ -373,9 +372,6 @@
   void SetUp() override {
     ui::CocoaTest::SetUp();
 
-    // MaterialDesignController leaks state across tests. See
-    // http://crbug.com/656871.
-    ui::test::MaterialDesignControllerTestAPI::Uninitialize();
     ui::MaterialDesignController::Initialize();
 
     init_params_.native_widget = native_widget_mac_;
@@ -402,7 +398,6 @@
     // be sure to destroy the widget (which will destroy its NSWindow)
     // beforehand.
     widget_.reset();
-    ui::test::MaterialDesignControllerTestAPI::Uninitialize();
     ui::CocoaTest::TearDown();
   }
 
diff --git a/ui/views/controls/animated_image_view.cc b/ui/views/controls/animated_image_view.cc
index 05b1d6c0..bb379bc3 100644
--- a/ui/views/controls/animated_image_view.cc
+++ b/ui/views/controls/animated_image_view.cc
@@ -52,13 +52,7 @@
 
   state_ = State::kPlaying;
 
-  // We cannot play the animation unless we have a valid compositor.
-  if (!compositor_)
-    return;
-
-  // Ensure the class is added as an observer to receive clock ticks.
-  if (!compositor_->HasAnimationObserver(this))
-    compositor_->AddAnimationObserver(this);
+  SetCompositorFromWidget();
 
   animated_image_->Start();
 }
@@ -68,8 +62,7 @@
     return;
 
   DCHECK(animated_image_);
-  if (compositor_)
-    compositor_->RemoveAnimationObserver(this);
+  ClearCurrentCompositor();
 
   animated_image_->Stop();
   state_ = State::kStopped;
@@ -102,27 +95,21 @@
 }
 
 void AnimatedImageView::NativeViewHierarchyChanged() {
-  // When switching a window from one display to another, the compositor
-  // associated with the widget changes.
-  AddedToWidget();
-}
-
-void AnimatedImageView::AddedToWidget() {
   ui::Compositor* compositor = GetWidget()->GetCompositor();
   DCHECK(compositor);
   if (compositor_ != compositor) {
-    if (compositor_ && compositor_->HasAnimationObserver(this))
-      compositor_->RemoveAnimationObserver(this);
-    compositor_ = compositor;
+    ClearCurrentCompositor();
+
+    // Restore the Play() state with the new compositor.
+    if (state_ == State::kPlaying)
+      SetCompositorFromWidget();
   }
 }
 
 void AnimatedImageView::RemovedFromWidget() {
   if (compositor_) {
     Stop();
-    if (compositor_->HasAnimationObserver(this))
-      compositor_->RemoveAnimationObserver(this);
-    compositor_ = nullptr;
+    ClearCurrentCompositor();
   }
 }
 
@@ -134,6 +121,22 @@
 void AnimatedImageView::OnCompositingShuttingDown(ui::Compositor* compositor) {
   if (compositor_ == compositor) {
     Stop();
+    ClearCurrentCompositor();
+  }
+}
+
+void AnimatedImageView::SetCompositorFromWidget() {
+  DCHECK(!compositor_);
+  auto* widget = GetWidget();
+  DCHECK(widget);
+  compositor_ = widget->GetCompositor();
+  DCHECK(!compositor_->HasAnimationObserver(this));
+  compositor_->AddAnimationObserver(this);
+}
+
+void AnimatedImageView::ClearCurrentCompositor() {
+  if (compositor_) {
+    DCHECK(compositor_->HasAnimationObserver(this));
     compositor_->RemoveAnimationObserver(this);
     compositor_ = nullptr;
   }
diff --git a/ui/views/controls/animated_image_view.h b/ui/views/controls/animated_image_view.h
index c62fe5c..f3868c2 100644
--- a/ui/views/controls/animated_image_view.h
+++ b/ui/views/controls/animated_image_view.h
@@ -48,7 +48,8 @@
   void SetAnimatedImage(
       std::unique_ptr<gfx::SkiaVectorAnimation> animated_image);
 
-  // Plays the animation in loop.
+  // Plays the animation in loop and must only be called when this view has
+  // access to a widget.
   void Play();
 
   // Stops any animation and resets it to the start frame.
@@ -61,13 +62,15 @@
   void OnPaint(gfx::Canvas* canvas) override;
   const char* GetClassName() const override;
   void NativeViewHierarchyChanged() override;
-  void AddedToWidget() override;
   void RemovedFromWidget() override;
 
   // Overridden from ui::CompositorAnimationObserver:
   void OnAnimationStep(base::TimeTicks timestamp) override;
   void OnCompositingShuttingDown(ui::Compositor* compositor) override;
 
+  void SetCompositorFromWidget();
+  void ClearCurrentCompositor();
+
   // Overridden from ImageViewBase:
   gfx::Size GetImageSize() const override;
 
diff --git a/ui/views/test/views_test_base.cc b/ui/views/test/views_test_base.cc
index 8855b1c..7f0542d 100644
--- a/ui/views/test/views_test_base.cc
+++ b/ui/views/test/views_test_base.cc
@@ -10,7 +10,6 @@
 #include "base/run_loop.h"
 #include "ui/base/clipboard/clipboard.h"
 #include "ui/base/material_design/material_design_controller.h"
-#include "ui/base/test/material_design_controller_test_api.h"
 #include "ui/views/test/platform_test_helper.h"
 
 #if defined(USE_X11)
@@ -68,9 +67,6 @@
 
 void ViewsTestBase::SetUp() {
   testing::Test::SetUp();
-  // ContentTestSuiteBase might have already initialized
-  // MaterialDesignController in unit_tests suite.
-  ui::test::MaterialDesignControllerTestAPI::Uninitialize();
   ui::MaterialDesignController::Initialize();
   setup_called_ = true;
   if (!views_delegate_for_setup_)
diff --git a/ui/views/widget/desktop_aura/desktop_screen_x11.cc b/ui/views/widget/desktop_aura/desktop_screen_x11.cc
index 0951d2fb..ae784d5 100644
--- a/ui/views/widget/desktop_aura/desktop_screen_x11.cc
+++ b/ui/views/widget/desktop_aura/desktop_screen_x11.cc
@@ -6,7 +6,6 @@
 
 #include "base/command_line.h"
 #include "base/logging.h"
-#include "base/memory/protected_memory_cfi.h"
 #include "base/strings/stringprintf.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/trace_event/trace_event.h"
@@ -14,17 +13,17 @@
 #include "ui/aura/window_event_dispatcher.h"
 #include "ui/aura/window_tree_host.h"
 #include "ui/base/layout.h"
+#include "ui/base/x/x11_display_util.h"
+#include "ui/base/x/x11_util.h"
 #include "ui/display/display.h"
 #include "ui/display/display_finder.h"
 #include "ui/display/screen.h"
 #include "ui/display/util/display_util.h"
-#include "ui/display/util/x11/edid_parser_x11.h"
 #include "ui/events/platform/platform_event_source.h"
 #include "ui/events/platform/x11/x11_event_source.h"
 #include "ui/gfx/font_render_params.h"
 #include "ui/gfx/geometry/point_conversions.h"
 #include "ui/gfx/geometry/size_conversions.h"
-#include "ui/gfx/icc_profile.h"
 #include "ui/gfx/native_widget_types.h"
 #include "ui/gfx/switches.h"
 #include "ui/gfx/x/x11.h"
@@ -35,42 +34,11 @@
 #include "ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h"
 #include "ui/views/widget/desktop_aura/x11_topmost_window_finder.h"
 
-#include <dlfcn.h>
-
 namespace {
 
-// static
-gfx::ICCProfile GetICCProfileForMonitor(int monitor) {
-  gfx::ICCProfile icc_profile;
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kHeadless))
-    return icc_profile;
-  std::string atom_name;
-  if (monitor == 0) {
-    atom_name = "_ICC_PROFILE";
-  } else {
-    atom_name = base::StringPrintf("_ICC_PROFILE_%d", monitor);
-  }
-  Atom property = gfx::GetAtom(atom_name.c_str());
-  if (property != x11::None) {
-    Atom prop_type = x11::None;
-    int prop_format = 0;
-    unsigned long nitems = 0;
-    unsigned long nbytes = 0;
-    char* property_data = NULL;
-    if (XGetWindowProperty(
-            gfx::GetXDisplay(), DefaultRootWindow(gfx::GetXDisplay()), property,
-            0, 0x1FFFFFFF /* MAXINT32 / 4 */, x11::False, AnyPropertyType,
-            &prop_type, &prop_format, &nitems, &nbytes,
-            reinterpret_cast<unsigned char**>(&property_data)) ==
-        x11::Success) {
-      icc_profile = gfx::ICCProfile::FromData(property_data, nitems);
-      XFree(property_data);
-    }
-  }
-  return icc_profile;
-}
+constexpr int kMinVersionXrandr = 103;  // Need at least xrandr version 1.3.
 
-double GetDeviceScaleFactor() {
+float GetDeviceScaleFactor() {
   float device_scale_factor = 1.0f;
   if (views::LinuxUI::instance()) {
     device_scale_factor =
@@ -89,25 +57,6 @@
   return gfx::ScaleToFlooredPoint(dip_point, GetDeviceScaleFactor());
 }
 
-std::vector<display::Display> GetFallbackDisplayList() {
-  ::XDisplay* display = gfx::GetXDisplay();
-  ::Screen* screen = DefaultScreenOfDisplay(display);
-  int width = WidthOfScreen(screen);
-  int height = HeightOfScreen(screen);
-  gfx::Size physical_size(WidthMMOfScreen(screen), HeightMMOfScreen(screen));
-
-  gfx::Rect bounds_in_pixels(0, 0, width, height);
-  display::Display gfx_display(0, bounds_in_pixels);
-  if (!display::Display::HasForceDeviceScaleFactor() &&
-      !display::IsDisplaySizeBlackListed(physical_size)) {
-    const float device_scale_factor = GetDeviceScaleFactor();
-    DCHECK_LE(1.0f, device_scale_factor);
-    gfx_display.SetScaleAndBounds(device_scale_factor, bounds_in_pixels);
-  }
-
-  return std::vector<display::Display>(1, gfx_display);
-}
-
 }  // namespace
 
 namespace views {
@@ -118,21 +67,13 @@
 DesktopScreenX11::DesktopScreenX11()
     : xdisplay_(gfx::GetXDisplay()),
       x_root_window_(DefaultRootWindow(xdisplay_)),
-      xrandr_version_(0),
-      xrandr_event_base_(0),
-      primary_display_index_(0),
+      xrandr_version_(ui::GetXrandrVersion(xdisplay_)),
       weak_factory_(this) {
   if (views::LinuxUI::instance())
     views::LinuxUI::instance()->AddDeviceScaleFactorObserver(this);
-  // We only support 1.3+. There were library changes before this and we should
-  // use the new interface instead of the 1.2 one.
-  int randr_version_major = 0;
-  int randr_version_minor = 0;
-  if (XRRQueryVersion(xdisplay_, &randr_version_major, &randr_version_minor)) {
-    xrandr_version_ = randr_version_major * 100 + randr_version_minor;
-  }
+  float scale = GetDeviceScaleFactor();
   // Need at least xrandr version 1.3.
-  if (xrandr_version_ >= 103) {
+  if (xrandr_version_ >= kMinVersionXrandr) {
     int error_base_ignored = 0;
     XRRQueryExtension(xdisplay_, &xrandr_event_base_, &error_base_ignored);
 
@@ -144,16 +85,18 @@
                    RROutputChangeNotifyMask |
                    RRCrtcChangeNotifyMask);
 
-    SetDisplaysInternal(BuildDisplaysFromXRandRInfo());
+    SetDisplaysInternal(ui::BuildDisplaysFromXRandRInfo(
+        xrandr_version_, scale, &primary_display_index_));
   } else {
-    SetDisplaysInternal(GetFallbackDisplayList());
+    SetDisplaysInternal(ui::GetFallbackDisplayList(scale));
   }
 }
 
 DesktopScreenX11::~DesktopScreenX11() {
   if (views::LinuxUI::instance())
     views::LinuxUI::instance()->AddDeviceScaleFactorObserver(this);
-  if (xrandr_version_ >= 103 && ui::PlatformEventSource::GetInstance())
+  if (xrandr_version_ >= kMinVersionXrandr &&
+      ui::PlatformEventSource::GetInstance())
     ui::PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this);
 }
 
@@ -309,168 +252,13 @@
     const std::vector<display::Display>& test_displays)
     : xdisplay_(gfx::GetXDisplay()),
       x_root_window_(DefaultRootWindow(xdisplay_)),
-      xrandr_version_(0),
-      xrandr_event_base_(0),
+      xrandr_version_(ui::GetXrandrVersion(xdisplay_)),
       displays_(test_displays),
-      primary_display_index_(0),
       weak_factory_(this) {
   if (views::LinuxUI::instance())
     views::LinuxUI::instance()->AddDeviceScaleFactorObserver(this);
 }
 
-typedef XRRMonitorInfo* (*XRRGetMonitors)(::Display*, Window, bool, int*);
-typedef void (*XRRFreeMonitors)(XRRMonitorInfo*);
-
-PROTECTED_MEMORY_SECTION base::ProtectedMemory<XRRGetMonitors>
-    g_XRRGetMonitors_ptr;
-PROTECTED_MEMORY_SECTION base::ProtectedMemory<XRRFreeMonitors>
-    g_XRRFreeMonitors_ptr;
-
-std::vector<display::Display> DesktopScreenX11::BuildDisplaysFromXRandRInfo() {
-  DCHECK(xrandr_version_ >= 103);
-  std::vector<display::Display> displays;
-  gfx::XScopedPtr<
-      XRRScreenResources,
-      gfx::XObjectDeleter<XRRScreenResources, void, XRRFreeScreenResources>>
-      resources(XRRGetScreenResourcesCurrent(xdisplay_, x_root_window_));
-  if (!resources) {
-    LOG(ERROR) << "XRandR returned no displays. Falling back to Root Window.";
-    return GetFallbackDisplayList();
-  }
-
-  std::map<RROutput, int> output_to_monitor;
-  if (xrandr_version_ >= 105) {
-    void* xrandr_lib = dlopen(NULL, RTLD_NOW);
-    if (xrandr_lib) {
-      static base::ProtectedMemory<XRRGetMonitors>::Initializer get_init(
-          &g_XRRGetMonitors_ptr, reinterpret_cast<XRRGetMonitors>(
-                                     dlsym(xrandr_lib, "XRRGetMonitors")));
-      static base::ProtectedMemory<XRRFreeMonitors>::Initializer free_init(
-          &g_XRRFreeMonitors_ptr, reinterpret_cast<XRRFreeMonitors>(
-                                      dlsym(xrandr_lib, "XRRFreeMonitors")));
-      if (*g_XRRGetMonitors_ptr && *g_XRRFreeMonitors_ptr) {
-        int nmonitors = 0;
-        XRRMonitorInfo* monitors = base::UnsanitizedCfiCall(
-            g_XRRGetMonitors_ptr)(xdisplay_, x_root_window_, false, &nmonitors);
-        for (int monitor = 0; monitor < nmonitors; monitor++) {
-          for (int j = 0; j < monitors[monitor].noutput; j++) {
-            output_to_monitor[monitors[monitor].outputs[j]] = monitor;
-          }
-        }
-        base::UnsanitizedCfiCall(g_XRRFreeMonitors_ptr)(monitors);
-      }
-    }
-  }
-
-  primary_display_index_ = 0;
-  RROutput primary_display_id = XRRGetOutputPrimary(xdisplay_, x_root_window_);
-
-  int explicit_primary_display_index = -1;
-  int monitor_order_primary_display_index = -1;
-
-  bool has_work_area = false;
-  gfx::Rect work_area_in_pixels;
-  std::vector<int> value;
-  if (ui::GetIntArrayProperty(x_root_window_, "_NET_WORKAREA", &value) &&
-      value.size() >= 4) {
-    work_area_in_pixels = gfx::Rect(value[0], value[1], value[2], value[3]);
-    has_work_area = true;
-  }
-
-  // As per-display scale factor is not supported right now,
-  // the X11 root window's scale factor is always used.
-  const float device_scale_factor = GetDeviceScaleFactor();
-  for (int i = 0; i < resources->noutput; ++i) {
-    RROutput output_id = resources->outputs[i];
-    gfx::XScopedPtr<XRROutputInfo,
-                    gfx::XObjectDeleter<XRROutputInfo, void, XRRFreeOutputInfo>>
-        output_info(XRRGetOutputInfo(xdisplay_, resources.get(), output_id));
-
-    bool is_connected = (output_info->connection == RR_Connected);
-    if (!is_connected)
-      continue;
-
-    bool is_primary_display = output_id == primary_display_id;
-
-    if (output_info->crtc) {
-      gfx::XScopedPtr<XRRCrtcInfo,
-                      gfx::XObjectDeleter<XRRCrtcInfo, void, XRRFreeCrtcInfo>>
-          crtc(XRRGetCrtcInfo(xdisplay_, resources.get(), output_info->crtc));
-
-      int64_t display_id = -1;
-      if (!display::EDIDParserX11(output_id).GetDisplayId(
-              static_cast<uint8_t>(i), &display_id)) {
-        // It isn't ideal, but if we can't parse the EDID data, fallback on the
-        // display number.
-        display_id = i;
-      }
-
-      gfx::Rect crtc_bounds(crtc->x, crtc->y, crtc->width, crtc->height);
-      display::Display display(display_id, crtc_bounds);
-
-      if (!display::Display::HasForceDeviceScaleFactor()) {
-        display.SetScaleAndBounds(device_scale_factor, crtc_bounds);
-      }
-
-      if (has_work_area) {
-        gfx::Rect intersection_in_pixels = crtc_bounds;
-        if (is_primary_display) {
-          intersection_in_pixels.Intersect(work_area_in_pixels);
-        }
-        // SetScaleAndBounds() above does the conversion from pixels to DIP for
-        // us, but set_work_area does not, so we need to do it here.
-        display.set_work_area(gfx::Rect(
-            gfx::ScaleToFlooredPoint(intersection_in_pixels.origin(),
-                                     1.0f / display.device_scale_factor()),
-            gfx::ScaleToFlooredSize(intersection_in_pixels.size(),
-                                    1.0f / display.device_scale_factor())));
-      }
-
-      switch (crtc->rotation) {
-        case RR_Rotate_0:
-          display.set_rotation(display::Display::ROTATE_0);
-          break;
-        case RR_Rotate_90:
-          display.set_rotation(display::Display::ROTATE_90);
-          break;
-        case RR_Rotate_180:
-          display.set_rotation(display::Display::ROTATE_180);
-          break;
-        case RR_Rotate_270:
-          display.set_rotation(display::Display::ROTATE_270);
-          break;
-      }
-
-      if (is_primary_display)
-        explicit_primary_display_index = displays.size();
-
-      auto monitor_iter = output_to_monitor.find(output_id);
-      if (monitor_iter != output_to_monitor.end() && monitor_iter->second == 0)
-        monitor_order_primary_display_index = displays.size();
-
-      if (!display::Display::HasForceDisplayColorProfile()) {
-        gfx::ICCProfile icc_profile = GetICCProfileForMonitor(
-            monitor_iter == output_to_monitor.end() ? 0 : monitor_iter->second);
-        icc_profile.HistogramDisplay(display.id());
-        display.set_color_space(icc_profile.GetColorSpace());
-      }
-
-      displays.push_back(display);
-    }
-  }
-
-  if (explicit_primary_display_index != -1) {
-    primary_display_index_ = explicit_primary_display_index;
-  } else if (monitor_order_primary_display_index != -1) {
-    primary_display_index_ = monitor_order_primary_display_index;
-  }
-
-  if (displays.empty())
-    return GetFallbackDisplayList();
-
-  return displays;
-}
-
 void DesktopScreenX11::RestartDelayedConfigurationTask() {
   delayed_configuration_task_.Reset(base::Bind(
       &DesktopScreenX11::UpdateDisplays, weak_factory_.GetWeakPtr()));
@@ -480,10 +268,13 @@
 
 void DesktopScreenX11::UpdateDisplays() {
   std::vector<display::Display> old_displays = displays_;
-  if (xrandr_version_ > 103)
-    SetDisplaysInternal(BuildDisplaysFromXRandRInfo());
-  else
-    SetDisplaysInternal(GetFallbackDisplayList());
+  float scale = GetDeviceScaleFactor();
+  if (xrandr_version_ > kMinVersionXrandr) {
+    SetDisplaysInternal(ui::BuildDisplaysFromXRandRInfo(
+        xrandr_version_, scale, &primary_display_index_));
+  } else {
+    SetDisplaysInternal(ui::GetFallbackDisplayList(scale));
+  }
   change_notifier_.NotifyDisplaysChanged(old_displays, displays_);
 }
 
diff --git a/ui/views/widget/desktop_aura/desktop_screen_x11.h b/ui/views/widget/desktop_aura/desktop_screen_x11.h
index 6b7cb73..164ad57 100644
--- a/ui/views/widget/desktop_aura/desktop_screen_x11.h
+++ b/ui/views/widget/desktop_aura/desktop_screen_x11.h
@@ -69,10 +69,6 @@
   // Constructor used in tests.
   DesktopScreenX11(const std::vector<display::Display>& test_displays);
 
-  // Builds a list of displays from the current screen information offered by
-  // the X server.
-  std::vector<display::Display> BuildDisplaysFromXRandRInfo();
-
   // Removes |delayed_configuration_task_| from the task queue (if
   // it's in the queue) and adds it back at the end of the queue.
   void RestartDelayedConfigurationTask();
@@ -88,17 +84,17 @@
   ::Window x_root_window_;
 
   // XRandR version. MAJOR * 100 + MINOR. Zero if no xrandr is present.
-  int xrandr_version_;
+  const int xrandr_version_;
 
   // The base of the event numbers used to represent XRandr events used in
   // decoding events regarding output add/remove.
-  int xrandr_event_base_;
+  int xrandr_event_base_ = 0;
 
   // The display objects we present to chrome.
   std::vector<display::Display> displays_;
 
   // The index into displays_ that represents the primary display.
-  size_t primary_display_index_;
+  int64_t primary_display_index_ = 0;
 
   // The task to delay configuring outputs.  We delay updating the
   // display so we can coalesce events.
diff --git a/ui/webui/resources/cr_elements/cr_scrollable_behavior.js b/ui/webui/resources/cr_elements/cr_scrollable_behavior.js
index 9535c1a9..ffc2878 100644
--- a/ui/webui/resources/cr_elements/cr_scrollable_behavior.js
+++ b/ui/webui/resources/cr_elements/cr_scrollable_behavior.js
@@ -41,14 +41,24 @@
   intervalId_: null,
 
   ready: function() {
-    this.requestUpdateScroll();
+    const readyAsync = () => {
+      this.requestUpdateScroll();
 
-    // Listen to the 'scroll' event for each scrollable container.
-    var scrollableElements = this.root.querySelectorAll('[scrollable]');
-    for (var i = 0; i < scrollableElements.length; i++) {
-      scrollableElements[i].addEventListener(
-          'scroll', this.updateScrollEvent_.bind(this));
+      // Listen to the 'scroll' event for each scrollable container.
+      var scrollableElements = this.root.querySelectorAll('[scrollable]');
+      for (var i = 0; i < scrollableElements.length; i++) {
+        scrollableElements[i].addEventListener(
+            'scroll', this.updateScrollEvent_.bind(this));
+      }
+    };
+
+    // TODO(dpapad): Remove Polymer 1 codepath when Polymer 2 migration has
+    // completed.
+    if (Polymer.DomIf) {
+      Polymer.RenderStatus.beforeNextRender(this, readyAsync);
+      return;
     }
+    readyAsync();
   },
 
   detached: function() {
diff --git a/ui/webui/resources/js/cr/ui/menu.js b/ui/webui/resources/js/cr/ui/menu.js
index ed00ed8..5589cd6 100644
--- a/ui/webui/resources/js/cr/ui/menu.js
+++ b/ui/webui/resources/js/cr/ui/menu.js
@@ -202,16 +202,26 @@
     },
 
     /**
-     * Returns if the menu has any visible item.
+     * Returns whether the menu has any visible items.  Hides any separators
+     * where all items below it until the next separator are hidden.
      * @return {boolean} True if the menu has visible item. Otherwise, false.
      */
     hasVisibleItems: function() {
       var menuItems = this.menuItems;  // Cache.
-      for (var i = 0, menuItem; menuItem = menuItems[i]; i++) {
-        if (!menuItem.isSeparator() && this.isItemVisible_(menuItem))
-          return true;
+      var result = false;
+      var separatorRequired = false;
+      // Inspect items in reverse order to determine if the separator above each
+      // set of items is required.
+      for (var i = menuItems.length - 1; i >= 0; i--) {
+        var menuItem = menuItems[i];
+        if (menuItem.isSeparator()) {
+          menuItem.hidden = !separatorRequired;
+          separatorRequired = false;
+        }
+        if (this.isItemVisible_(menuItem))
+          result = separatorRequired = true;
       }
-      return false;
+      return result;
     },
 
     /**
diff --git a/webrunner/app/sandbox_policy b/webrunner/app/sandbox_policy
index aa36caa..9f8cb63 100644
--- a/webrunner/app/sandbox_policy
+++ b/webrunner/app/sandbox_policy
@@ -4,6 +4,7 @@
       "chromium.web.ContextProvider",
       "fuchsia.fonts.Provider",
       "fuchsia.media.Audio",
+      "fuchsia.mediacodec.CodecFactory",
       "fuchsia.net.LegacySocketProvider",
       "fuchsia.netstack.Netstack",
       "fuchsia.process.Launcher",