diff --git a/BUILD.gn b/BUILD.gn
index 94fddb4e..a0f5f57e 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -341,6 +341,7 @@
         "//android_webview/test",
         "//android_webview/tools/automated_ui_tests:webview_ui_test_app",
         "//android_webview/tools/system_webview_shell",
+        "//android_webview/tools/webview_log_verbosifier:webview_log_verbosifier_apk",
         "//chrome/android:chrome_junit_tests",
         "//chrome/android:chrome_public_apk",
         "//chrome/android:chrome_public_test_apk",
diff --git a/DEPS b/DEPS
index 09a13c8..7ecbc31 100644
--- a/DEPS
+++ b/DEPS
@@ -111,7 +111,7 @@
   # 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': '52a715455181a491d895dc4f3bf700c93dda3851',
+  'skia_revision': 'f5973509ec681e3cc6d498dc31e549c6285e4a61',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # 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': '7cba6be85a1468b113f64c5a8beff4dde4ae8217',
+  'angle_revision': 'af9dd60801883fb385eb825fb972ab62b2781db2',
   # 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': '05e43638cd377444b88def5c02562e771e25a158',
+  'pdfium_revision': '98bc0ce5c15f7405bd0d4906b3522e2cc4140634',
   # 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.
@@ -219,7 +219,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'spv_tools_revision': '1c1e749f0b51603032ed573acb5ee4cd6fee8d01',
+  'spv_tools_revision': '6647884a130d026294bad97d2575ff21560d74ec',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # 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' + '@' + '5a5616f3bb3bc706fbd30d3b4fc6eee710ea2d7a',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '761322d458eaa3e6dde21e5739accfa03884a26e',
       'condition': 'checkout_linux',
   },
 
@@ -1004,7 +1004,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' +  'dfe69cae695eee13453b8a30b0b88ed24f86bb83',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' +  '1b114f20625d03bcf9b53b6ba67e5418c2671909',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + 'ac0d98b5cee6c024b0cffeb4f8f45b6fc5ccdb78',
@@ -1156,7 +1156,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '0d55c887e92b645f6effe753528323ab2ffd94c2',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '3b149e4be88059c853cdfc1940d006e5fe456b32',
+    Var('webrtc_git') + '/src.git' + '@' + '1a92cd7312cad7d312f5bd40cebf3e7499ab141b',
 
   '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@15a8883b4d7ddc424fba989c7b8c4c5d34c94131',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@f8b5a7154479fc394241e1bbfc3d78141c0dc64c',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/WATCHLISTS b/WATCHLISTS
index 6c33209..c1e56fc5 100644
--- a/WATCHLISTS
+++ b/WATCHLISTS
@@ -1191,7 +1191,6 @@
                   '|chromeos/services/multidevice_setup/'\
                   '|chromeos/services/secure_channel/'\
                   '|components/cryptauth/'\
-                  '|components/proximity_auth/logging'\
                   '|ui/webui/resources/cr_components/chromeos/multidevice_setup/'
     },
     'mus': {
@@ -2277,6 +2276,7 @@
     'midi': ['toyoshim+midi@chromium.org'],
     'mojo': ['darin@chromium.org'],
     'multidevice': ['hansberry+watch-multidevice@chromium.org',
+                    'hsuregan+watch-multidevice@chromium.org',
                     'jhawkins+watch-multidevice@chromium.org',
                     'jlklein+watch-multidevice@chromium.org',
                     'jordynass+watch-multidevice@chromium.org',
@@ -2385,6 +2385,7 @@
                       'creis+watch@chromium.org',
                       'nasko+codewatch@chromium.org'],
     'smartlock': ['hansberry+watch-smartlock@chromium.org',
+                  'hsuregan+watch-multidevice@chromium.org',
                   'jhawkins+watch-smartlock@chromium.org',
                   'jlklein+watch-smartlock@chromium.org',
                   'jordynass+watch-smartlock@chromium.org',
@@ -2423,6 +2424,7 @@
                     'einbinder+watch-test-runner@chromium.org'],
     'tests': [],
     'tether': ['hansberry+watch-tether@chromium.org',
+               'hsuregan+watch-multidevice@chromium.org',
                'jhawkins+watch-tether@chromium.org',
                'jlklein+watch-tether@chromium.org',
                'jordynass+watch-tether@chromium.org',
diff --git a/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumAwInit.java b/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumAwInit.java
index 678171e..0b141d6 100644
--- a/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumAwInit.java
+++ b/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumAwInit.java
@@ -38,6 +38,7 @@
 import org.chromium.android_webview.command_line.CommandLineUtil;
 import org.chromium.base.BuildConfig;
 import org.chromium.base.ContextUtils;
+import org.chromium.base.FieldTrialList;
 import org.chromium.base.PathService;
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.TraceEvent;
@@ -47,6 +48,7 @@
 import org.chromium.base.library_loader.ProcessInitException;
 import org.chromium.base.metrics.CachedMetrics;
 import org.chromium.base.metrics.RecordHistogram;
+import org.chromium.base.task.AsyncTask;
 import org.chromium.net.NetworkChangeNotifier;
 
 /**
@@ -199,6 +201,8 @@
             }
 
             mFactory.getRunQueue().drainQueue();
+
+            maybeLogActiveTrials(context);
         }
     }
 
@@ -452,6 +456,23 @@
         }
     }
 
+    // If a certain app is installed, log field trials as they become active, for debugging
+    // purposes. Check for the app asyncronously because PackageManager is slow.
+    private static void maybeLogActiveTrials(final Context ctx) {
+        AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
+            try {
+                // This must match the package name in:
+                // android_webview/tools/webview_log_verbosifier/AndroidManifest.xml
+                ctx.getPackageManager().getPackageInfo(
+                        "org.chromium.webview_log_verbosifier", /*flags=*/0);
+            } catch (PackageManager.NameNotFoundException e) {
+                return;
+            }
+
+            ThreadUtils.postOnUiThread(() -> FieldTrialList.logActiveTrials());
+        });
+    }
+
     public WebViewChromiumRunQueue getRunQueue() {
         return mFactory.getRunQueue();
     }
diff --git a/android_webview/tools/webview_log_verbosifier/AndroidManifest.xml b/android_webview/tools/webview_log_verbosifier/AndroidManifest.xml
new file mode 100644
index 0000000..ed9188b
--- /dev/null
+++ b/android_webview/tools/webview_log_verbosifier/AndroidManifest.xml
@@ -0,0 +1,15 @@
+<!-- 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 package name must match the one in WebViewChromiumAwInit.maybeLogActiveTrials() -->
+<manifest
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    package="org.chromium.webview_log_verbosifier"
+    android:versionCode="1"
+    android:versionName="1.0" >
+
+    <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="28" />
+
+    <application android:label="WebView Log Verbosifier" />
+</manifest>
diff --git a/android_webview/tools/webview_log_verbosifier/BUILD.gn b/android_webview/tools/webview_log_verbosifier/BUILD.gn
new file mode 100644
index 0000000..b746e44
--- /dev/null
+++ b/android_webview/tools/webview_log_verbosifier/BUILD.gn
@@ -0,0 +1,10 @@
+# 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.
+
+import("//build/config/android/rules.gni")
+
+android_apk("webview_log_verbosifier_apk") {
+  apk_name = "WebViewLogVerbosifier"
+  android_manifest = "AndroidManifest.xml"
+}
diff --git a/android_webview/tools/webview_log_verbosifier/README b/android_webview/tools/webview_log_verbosifier/README
new file mode 100644
index 0000000..e374472
--- /dev/null
+++ b/android_webview/tools/webview_log_verbosifier/README
@@ -0,0 +1,3 @@
+WebView Log Verbosifier is an empty dummy app. If this app is installed, WebView
+will log the active field trials, for debugging/QA purposes. A dummy app is used
+because it can be installed on any device, unlike command-line flags.
diff --git a/ash/app_list/views/app_list_view.cc b/ash/app_list/views/app_list_view.cc
index 3f31b4f1..88ff037 100644
--- a/ash/app_list/views/app_list_view.cc
+++ b/ash/app_list/views/app_list_view.cc
@@ -96,6 +96,9 @@
 // home launcher gestures, if they can be processed.
 constexpr int kAppListHomeLaucherGesturesThreshold = 32;
 
+// Quality of the shield background blur.
+constexpr float kAppListBlurQuality = 0.25f;
+
 // Set animation durations to 0 for testing.
 static bool short_animations_for_testing;
 
@@ -507,6 +510,8 @@
         app_list_background_shield_mask_->layer());
     app_list_background_shield_->layer()->SetBackgroundBlur(
         AppListConfig::instance().blur_radius());
+    app_list_background_shield_->layer()->SetBackdropFilterQuality(
+        kAppListBlurQuality);
   }
   AddChildView(app_list_background_shield_);
   app_list_main_view_ = new AppListMainView(delegate_, this);
diff --git a/ash/assistant/ui/assistant_container_view_animator_legacy_impl.cc b/ash/assistant/ui/assistant_container_view_animator_legacy_impl.cc
index f4d6fa6..3a97c9af 100644
--- a/ash/assistant/ui/assistant_container_view_animator_legacy_impl.cc
+++ b/ash/assistant/ui/assistant_container_view_animator_legacy_impl.cc
@@ -4,6 +4,8 @@
 
 #include "ash/assistant/ui/assistant_container_view_animator_legacy_impl.h"
 
+#include <algorithm>
+
 #include "ash/assistant/assistant_controller.h"
 #include "ash/assistant/assistant_ui_controller.h"
 #include "ash/assistant/ui/assistant_container_view.h"
@@ -126,7 +128,7 @@
   bounds.set_size(gfx::Size(size.width(), size.height()));
 
   // Maintain original |center_x| and |bottom| positions.
-  bounds.set_x(center_x - (bounds.width() / 2));
+  bounds.set_x(std::max(center_x - (bounds.width() / 2), 0));
   bounds.set_y(bottom - bounds.height());
 
   // Interpolate the correct corner radius.
diff --git a/ash/components/shortcut_viewer/keyboard_shortcut_viewer_metadata.cc b/ash/components/shortcut_viewer/keyboard_shortcut_viewer_metadata.cc
index 069867d6..0a67ac7 100644
--- a/ash/components/shortcut_viewer/keyboard_shortcut_viewer_metadata.cc
+++ b/ash/components/shortcut_viewer/keyboard_shortcut_viewer_metadata.cc
@@ -937,7 +937,7 @@
 
       {// |categories|
        {ShortcutCategory::kTextEditing},
-       IDS_KSV_DESCRIPTION_GO_TO_END_OF_DOCUMENT,
+       IDS_KSV_DESCRIPTION_GO_TO_END_OF_LINE,
        IDS_KSV_SHORTCUT_ONE_MODIFIER_ONE_KEY,
        // |accelerator_ids|
        {},
@@ -956,7 +956,7 @@
 
       {// |categories|
        {ShortcutCategory::kTextEditing},
-       IDS_KSV_DESCRIPTION_GO_TO_BEGINNING_OF_DOCUMENT,
+       IDS_KSV_DESCRIPTION_GO_TO_BEGINNING_OF_LINE,
        IDS_KSV_SHORTCUT_ONE_MODIFIER_ONE_KEY,
        // |accelerator_ids|
        {},
diff --git a/ash/components/shortcut_viewer_strings.grdp b/ash/components/shortcut_viewer_strings.grdp
index a9706372..9e0a5e9 100644
--- a/ash/components/shortcut_viewer_strings.grdp
+++ b/ash/components/shortcut_viewer_strings.grdp
@@ -459,6 +459,12 @@
   <message name="IDS_KSV_DESCRIPTION_GO_TO_BEGINNING_OF_DOCUMENT" desc="Description of the command in keyboard shortcut viewer.">
     Go to beginning of document
   </message>
+  <message name="IDS_KSV_DESCRIPTION_GO_TO_END_OF_LINE" desc="Description of the command in keyboard shortcut viewer.">
+    Go to end of line
+  </message>
+  <message name="IDS_KSV_DESCRIPTION_GO_TO_BEGINNING_OF_LINE" desc="Description of the command in keyboard shortcut viewer.">
+    Go to beginning of line
+  </message>
   <message name="IDS_KSV_DESCRIPTION_PASTE_CONTENT_AS_TEXT" desc="Description of the command in keyboard shortcut viewer.">
     Paste content from the clipboard as plain text
   </message>
diff --git a/ash/shelf/shelf_layout_manager.cc b/ash/shelf/shelf_layout_manager.cc
index 79a81bc..ce9db3e2e 100644
--- a/ash/shelf/shelf_layout_manager.cc
+++ b/ash/shelf/shelf_layout_manager.cc
@@ -1182,6 +1182,26 @@
 ////////////////////////////////////////////////////////////////////////////////
 // ShelfLayoutManager, Gesture functions:
 
+bool ShelfLayoutManager::ShouldHomeGestureHandleEvent(float scroll_y) const {
+  HomeLauncherGestureHandler* home_launcher_handler =
+      Shell::Get()->app_list_controller()->home_launcher_gesture_handler();
+
+  // If there is no |home_launcher_handler|, return early.
+  if (!home_launcher_handler)
+    return false;
+
+  // If the shelf is not visible, home gesture shouldn't trigger.
+  if (!IsVisible())
+    return false;
+
+  // Scroll down events should never be handled, unless they are currently being
+  // handled
+  if (scroll_y >= 0 && gesture_drag_status_ != GESTURE_DRAG_APPLIST_IN_PROGRESS)
+    return false;
+
+  return true;
+}
+
 bool ShelfLayoutManager::StartGestureDrag(
     const ui::GestureEvent& gesture_in_screen) {
   if (CanStartFullscreenAppListDrag(
@@ -1201,14 +1221,16 @@
     return true;
   }
 
-  HomeLauncherGestureHandler* home_launcher_handler =
-      Shell::Get()->app_list_controller()->home_launcher_gesture_handler();
-  if (home_launcher_handler && IsVisible() &&
-      home_launcher_handler->OnPressEvent(
-          HomeLauncherGestureHandler::Mode::kSlideUpToShow,
-          gesture_in_screen.location())) {
-    gesture_drag_status_ = GESTURE_DRAG_APPLIST_IN_PROGRESS;
-    return true;
+  if (ShouldHomeGestureHandleEvent(
+          gesture_in_screen.details().scroll_y_hint())) {
+    HomeLauncherGestureHandler* home_launcher_handler =
+        Shell::Get()->app_list_controller()->home_launcher_gesture_handler();
+    if (home_launcher_handler->OnPressEvent(
+            HomeLauncherGestureHandler::Mode::kSlideUpToShow,
+            gesture_in_screen.location())) {
+      gesture_drag_status_ = GESTURE_DRAG_APPLIST_IN_PROGRESS;
+      return true;
+    }
   }
 
   // Disable the shelf dragging if the fullscreen app list is opened.
@@ -1226,13 +1248,14 @@
 
 void ShelfLayoutManager::UpdateGestureDrag(
     const ui::GestureEvent& gesture_in_screen) {
-  HomeLauncherGestureHandler* home_launcher_handler =
-      Shell::Get()->app_list_controller()->home_launcher_gesture_handler();
-  if (home_launcher_handler && IsVisible() &&
-      home_launcher_handler->OnScrollEvent(
-          gesture_in_screen.location(),
-          gesture_in_screen.details().scroll_y())) {
-    return;
+  if (ShouldHomeGestureHandleEvent(gesture_in_screen.details().scroll_y())) {
+    HomeLauncherGestureHandler* home_launcher_handler =
+        Shell::Get()->app_list_controller()->home_launcher_gesture_handler();
+    if (home_launcher_handler->OnScrollEvent(
+            gesture_in_screen.location(),
+            gesture_in_screen.details().scroll_y())) {
+      return;
+    }
   }
 
   if (gesture_drag_status_ == GESTURE_DRAG_APPLIST_IN_PROGRESS) {
diff --git a/ash/shelf/shelf_layout_manager.h b/ash/shelf/shelf_layout_manager.h
index 29b4d46..327d873 100644
--- a/ash/shelf/shelf_layout_manager.h
+++ b/ash/shelf/shelf_layout_manager.h
@@ -342,6 +342,9 @@
   // the shelf to be autohidden.
   bool IsShelfAutoHideForFullscreenMaximized() const;
 
+  // Returns true if the home gesture handler should handle the event.
+  bool ShouldHomeGestureHandleEvent(float scroll_y) const;
+
   // Gesture related functions:
   bool StartGestureDrag(const ui::GestureEvent& gesture_in_screen);
   void UpdateGestureDrag(const ui::GestureEvent& gesture_in_screen);
diff --git a/ash/shelf/shelf_layout_manager_unittest.cc b/ash/shelf/shelf_layout_manager_unittest.cc
index 8210c891..55b08d83 100644
--- a/ash/shelf/shelf_layout_manager_unittest.cc
+++ b/ash/shelf/shelf_layout_manager_unittest.cc
@@ -15,6 +15,7 @@
 #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"
+#include "ash/public/cpp/window_properties.h"
 #include "ash/root_window_controller.h"
 #include "ash/session/session_controller.h"
 #include "ash/shelf/shelf.h"
@@ -339,14 +340,14 @@
   void LockScreen() {
     mojom::SessionInfoPtr info = mojom::SessionInfo::New();
     info->state = session_manager::SessionState::LOCKED;
-    ash::Shell::Get()->session_controller()->SetSessionInfo(std::move(info));
+    Shell::Get()->session_controller()->SetSessionInfo(std::move(info));
   }
 
   // Turn off the lock screen.
   void UnlockScreen() {
     mojom::SessionInfoPtr info = mojom::SessionInfo::New();
     info->state = session_manager::SessionState::ACTIVE;
-    ash::Shell::Get()->session_controller()->SetSessionInfo(std::move(info));
+    Shell::Get()->session_controller()->SetSessionInfo(std::move(info));
   }
 
   int64_t GetPrimaryDisplayId() {
@@ -460,7 +461,7 @@
   widget->SetFullscreen(true);
   wm::WindowState* window_state = wm::GetWindowState(window);
   window_state->SetHideShelfWhenFullscreen(false);
-  window_state->SetInImmersiveFullscreen(true);
+  window->SetProperty(kImmersiveIsActive, true);
   layout_manager->UpdateVisibilityState();
   EXPECT_EQ(SHELF_AUTO_HIDE, shelf->GetVisibilityState());
   EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->GetAutoHideState());
@@ -1749,7 +1750,7 @@
   const wm::WMEvent event(wm::WM_EVENT_TOGGLE_FULLSCREEN);
   window_state->OnWMEvent(&event);
   window_state->SetHideShelfWhenFullscreen(false);
-  window_state->SetInImmersiveFullscreen(true);
+  window->SetProperty(kImmersiveIsActive, true);
   GetShelfLayoutManager()->UpdateVisibilityState();
   EXPECT_EQ(SHELF_AUTO_HIDE, shelf->GetVisibilityState());
   EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->GetAutoHideState());
diff --git a/ash/shelf/shelf_widget.cc b/ash/shelf/shelf_widget.cc
index 563ad7d..2e20fe9 100644
--- a/ash/shelf/shelf_widget.cc
+++ b/ash/shelf/shelf_widget.cc
@@ -45,6 +45,7 @@
 
 constexpr int kShelfRoundedCornerRadius = 28;
 constexpr int kShelfBlurRadius = 10;
+constexpr float kShelfBlurQuality = 0.25f;
 
 // Return the first or last focusable child of |root|.
 views::View* FindFirstOrLastFocusableChild(views::View* root,
@@ -198,6 +199,7 @@
 
   opaque_background_.SetBackgroundBlur(should_blur_background ? kShelfBlurRadius
                                                               : 0);
+  opaque_background_.SetBackdropFilterQuality(kShelfBlurQuality);
 
   background_is_currently_blurred_ = should_blur_background;
 }
diff --git a/ash/wm/immersive_context_ash.cc b/ash/wm/immersive_context_ash.cc
index 88a07c1..ea4ff00 100644
--- a/ash/wm/immersive_context_ash.cc
+++ b/ash/wm/immersive_context_ash.cc
@@ -27,8 +27,6 @@
   wm::WindowState* window_state = wm::GetWindowState(window);
   // Auto hide the shelf in immersive fullscreen instead of hiding it.
   window_state->SetHideShelfWhenFullscreen(!entering);
-  // Update the window's immersive mode state for the window manager.
-  window_state->SetInImmersiveFullscreen(entering);
 
   for (aura::Window* root_window : Shell::GetAllRootWindows())
     Shelf::ForWindow(root_window)->UpdateVisibilityState();
diff --git a/ash/wm/overview/OWNERS b/ash/wm/overview/OWNERS
index 73f88e8..a4a1e6c 100644
--- a/ash/wm/overview/OWNERS
+++ b/ash/wm/overview/OWNERS
@@ -1,3 +1,4 @@
+sammiequon@chromium.org
 xdai@chromium.org
 
 # COMPONENT: UI>Shell>OverviewMode
diff --git a/ash/wm/splitview/split_view_controller_unittest.cc b/ash/wm/splitview/split_view_controller_unittest.cc
index 5f1a528..7e61c57e 100644
--- a/ash/wm/splitview/split_view_controller_unittest.cc
+++ b/ash/wm/splitview/split_view_controller_unittest.cc
@@ -2095,7 +2095,7 @@
   DragWindowTo(resizer.get(), gfx::Point(0, 300));
   EXPECT_EQ(GetIndicatorState(resizer.get()), IndicatorState::kPreviewAreaLeft);
   resizer->CompleteDrag();
-  EXPECT_EQ(window1->GetProperty(ash::kTabDroppedWindowStateTypeKey),
+  EXPECT_EQ(window1->GetProperty(kTabDroppedWindowStateTypeKey),
             mojom::WindowStateType::LEFT_SNAPPED);
   EXPECT_NE(split_view_controller()->left_window(), window1.get());
   SetIsInTabDragging(window1.get(), false);
@@ -2123,7 +2123,7 @@
           ->GetDisplayNearestWindow(window1.get())
           .work_area();
   EXPECT_EQ(window2->GetBoundsInScreen(), work_area_bounds);
-  EXPECT_TRUE(window1->GetProperty(ash::kCanAttachToAnotherWindowKey));
+  EXPECT_TRUE(window1->GetProperty(kCanAttachToAnotherWindowKey));
 
   // 2.a. Drag the window a small amount of distance and release will maximize
   // the window.
@@ -2135,13 +2135,13 @@
   EXPECT_EQ(GetIndicatorState(resizer.get()), IndicatorState::kDragArea);
   // The source window should also have been scaled.
   EXPECT_NE(window2->GetBoundsInScreen(), work_area_bounds);
-  EXPECT_FALSE(window1->GetProperty(ash::kCanAttachToAnotherWindowKey));
+  EXPECT_FALSE(window1->GetProperty(kCanAttachToAnotherWindowKey));
   CompleteDrag(std::move(resizer));
   EXPECT_TRUE(wm::GetWindowState(window1.get())->IsMaximized());
   EXPECT_TRUE(wm::GetWindowState(window2.get())->IsMaximized());
   // The source window should have restored its bounds.
   EXPECT_EQ(window2->GetBoundsInScreen(), work_area_bounds);
-  EXPECT_TRUE(window1->GetProperty(ash::kCanAttachToAnotherWindowKey));
+  EXPECT_TRUE(window1->GetProperty(kCanAttachToAnotherWindowKey));
 
   // 2.b. Drag the window long enough to snap the window. The source window will
   // snap to the other side of the splitscreen.
@@ -2155,7 +2155,7 @@
   EXPECT_EQ(window2->GetBoundsInScreen(),
             split_view_controller()->GetSnappedWindowBoundsInScreen(
                 window2.get(), SplitViewController::LEFT));
-  EXPECT_FALSE(window1->GetProperty(ash::kCanAttachToAnotherWindowKey));
+  EXPECT_FALSE(window1->GetProperty(kCanAttachToAnotherWindowKey));
   DragWindowTo(resizer.get(), gfx::Point(0, 300));
   EXPECT_EQ(GetIndicatorState(resizer.get()), IndicatorState::kPreviewAreaLeft);
   // The source window's bounds should be the same as the right snapped window
@@ -2163,7 +2163,7 @@
   EXPECT_EQ(window2->GetBoundsInScreen(),
             split_view_controller()->GetSnappedWindowBoundsInScreen(
                 window2.get(), SplitViewController::RIGHT));
-  EXPECT_FALSE(window1->GetProperty(ash::kCanAttachToAnotherWindowKey));
+  EXPECT_FALSE(window1->GetProperty(kCanAttachToAnotherWindowKey));
 
   resizer->CompleteDrag();
   EXPECT_EQ(window1->GetProperty(kTabDroppedWindowStateTypeKey),
@@ -2177,7 +2177,7 @@
   EXPECT_EQ(split_view_controller()->state(),
             SplitViewController::BOTH_SNAPPED);
   EXPECT_FALSE(Shell::Get()->window_selector_controller()->IsSelecting());
-  EXPECT_TRUE(window1->GetProperty(ash::kCanAttachToAnotherWindowKey));
+  EXPECT_TRUE(window1->GetProperty(kCanAttachToAnotherWindowKey));
 
   EndSplitView();
   EXPECT_FALSE(split_view_controller()->IsSplitViewModeActive());
@@ -3082,46 +3082,46 @@
       StartDrag(dragged_window.get(), source_window.get());
   ASSERT_TRUE(resizer.get());
   EXPECT_FALSE(
-      source_window->GetProperty(ash::kIsDeferredTabDraggingTargetWindowKey));
+      source_window->GetProperty(kIsDeferredTabDraggingTargetWindowKey));
   DragWindowTo(resizer.get(), gfx::Point(300, 200));
   CompleteDrag(std::move(resizer));
   EXPECT_TRUE(
-      source_window->GetProperty(ash::kIsDeferredTabDraggingTargetWindowKey));
-  source_window->ClearProperty(ash::kIsDeferredTabDraggingTargetWindowKey);
+      source_window->GetProperty(kIsDeferredTabDraggingTargetWindowKey));
+  source_window->ClearProperty(kIsDeferredTabDraggingTargetWindowKey);
 
   // b. Drag the window to more than half of the display height and not in the
   // snap preview area.
   resizer = StartDrag(dragged_window.get(), source_window.get());
   ASSERT_TRUE(resizer.get());
   EXPECT_FALSE(
-      source_window->GetProperty(ash::kIsDeferredTabDraggingTargetWindowKey));
+      source_window->GetProperty(kIsDeferredTabDraggingTargetWindowKey));
   DragWindowTo(resizer.get(), gfx::Point(300, 500));
   CompleteDrag(std::move(resizer));
   EXPECT_FALSE(
-      source_window->GetProperty(ash::kIsDeferredTabDraggingTargetWindowKey));
+      source_window->GetProperty(kIsDeferredTabDraggingTargetWindowKey));
 
   // c. Drag the window to the snap preview area.
   resizer = StartDrag(dragged_window.get(), source_window.get());
   ASSERT_TRUE(resizer.get());
   EXPECT_FALSE(
-      source_window->GetProperty(ash::kIsDeferredTabDraggingTargetWindowKey));
+      source_window->GetProperty(kIsDeferredTabDraggingTargetWindowKey));
   DragWindowTo(resizer.get(), gfx::Point(0, 200));
   CompleteDrag(std::move(resizer));
   EXPECT_FALSE(
-      source_window->GetProperty(ash::kIsDeferredTabDraggingTargetWindowKey));
+      source_window->GetProperty(kIsDeferredTabDraggingTargetWindowKey));
   EndSplitView();
 
   // d. The dragged window is already added into overview before drag ends:
   resizer = StartDrag(dragged_window.get(), source_window.get());
   ASSERT_TRUE(resizer.get());
   EXPECT_FALSE(
-      source_window->GetProperty(ash::kIsDeferredTabDraggingTargetWindowKey));
+      source_window->GetProperty(kIsDeferredTabDraggingTargetWindowKey));
   DragWindowTo(resizer.get(), gfx::Point(300, 200));
-  dragged_window->SetProperty(ash::kIsShowingInOverviewKey, true);
+  dragged_window->SetProperty(kIsShowingInOverviewKey, true);
   CompleteDrag(std::move(resizer));
   EXPECT_FALSE(
-      source_window->GetProperty(ash::kIsDeferredTabDraggingTargetWindowKey));
-  dragged_window->ClearProperty(ash::kIsShowingInOverviewKey);
+      source_window->GetProperty(kIsDeferredTabDraggingTargetWindowKey));
+  dragged_window->ClearProperty(kIsShowingInOverviewKey);
 
   // 2. If splitview is active and the dragged window is not the source window.
   // a. Drag the window to less than half of the display height, in the same
@@ -3130,13 +3130,13 @@
                                       SplitViewController::LEFT);
   resizer = StartDrag(dragged_window.get(), source_window.get());
   EXPECT_FALSE(
-      source_window->GetProperty(ash::kIsDeferredTabDraggingTargetWindowKey));
+      source_window->GetProperty(kIsDeferredTabDraggingTargetWindowKey));
   DragWindowTo(resizer.get(), gfx::Point(0, 200));
   CompleteDrag(std::move(resizer));
   EXPECT_TRUE(
-      source_window->GetProperty(ash::kIsDeferredTabDraggingTargetWindowKey));
+      source_window->GetProperty(kIsDeferredTabDraggingTargetWindowKey));
   EndSplitView();
-  source_window->ClearProperty(ash::kIsDeferredTabDraggingTargetWindowKey);
+  source_window->ClearProperty(kIsDeferredTabDraggingTargetWindowKey);
 
   // b. Drag the window to less than half of the display height, in the
   // different split of the source window, and not in the snap preview area.
@@ -3144,11 +3144,11 @@
                                       SplitViewController::LEFT);
   resizer = StartDrag(dragged_window.get(), source_window.get());
   EXPECT_FALSE(
-      source_window->GetProperty(ash::kIsDeferredTabDraggingTargetWindowKey));
+      source_window->GetProperty(kIsDeferredTabDraggingTargetWindowKey));
   DragWindowTo(resizer.get(), gfx::Point(500, 200));
   CompleteDrag(std::move(resizer));
   EXPECT_FALSE(
-      source_window->GetProperty(ash::kIsDeferredTabDraggingTargetWindowKey));
+      source_window->GetProperty(kIsDeferredTabDraggingTargetWindowKey));
   EndSplitView();
 
   // c. Drag the window to move a small distance, but is still in the different
@@ -3157,11 +3157,11 @@
                                       SplitViewController::LEFT);
   resizer = StartDrag(dragged_window.get(), source_window.get());
   EXPECT_FALSE(
-      source_window->GetProperty(ash::kIsDeferredTabDraggingTargetWindowKey));
+      source_window->GetProperty(kIsDeferredTabDraggingTargetWindowKey));
   DragWindowTo(resizer.get(), gfx::Point(500, 20));
   CompleteDrag(std::move(resizer));
   EXPECT_FALSE(
-      source_window->GetProperty(ash::kIsDeferredTabDraggingTargetWindowKey));
+      source_window->GetProperty(kIsDeferredTabDraggingTargetWindowKey));
   EndSplitView();
 
   // d. The dragged window was added to overview before the drag ends.
@@ -3169,13 +3169,13 @@
                                       SplitViewController::LEFT);
   resizer = StartDrag(dragged_window.get(), source_window.get());
   EXPECT_FALSE(
-      source_window->GetProperty(ash::kIsDeferredTabDraggingTargetWindowKey));
+      source_window->GetProperty(kIsDeferredTabDraggingTargetWindowKey));
   DragWindowTo(resizer.get(), gfx::Point(0, 200));
-  dragged_window->SetProperty(ash::kIsShowingInOverviewKey, true);
+  dragged_window->SetProperty(kIsShowingInOverviewKey, true);
   CompleteDrag(std::move(resizer));
   EXPECT_FALSE(
-      source_window->GetProperty(ash::kIsDeferredTabDraggingTargetWindowKey));
-  dragged_window->ClearProperty(ash::kIsShowingInOverviewKey);
+      source_window->GetProperty(kIsDeferredTabDraggingTargetWindowKey));
+  dragged_window->ClearProperty(kIsShowingInOverviewKey);
 }
 
 // Tests that if window being dragged into drop target when preview area is
@@ -3213,13 +3213,13 @@
   ASSERT_TRUE(resizer.get());
   Fling(std::move(resizer), /*velocity_y=*/3000.f);
   EXPECT_FALSE(
-      source_window->GetProperty(ash::kIsDeferredTabDraggingTargetWindowKey));
+      source_window->GetProperty(kIsDeferredTabDraggingTargetWindowKey));
 
   resizer = StartDrag(dragged_window.get(), source_window.get());
   ASSERT_TRUE(resizer.get());
   Fling(std::move(resizer), /*velocity_y=*/1000.f);
   EXPECT_TRUE(
-      source_window->GetProperty(ash::kIsDeferredTabDraggingTargetWindowKey));
+      source_window->GetProperty(kIsDeferredTabDraggingTargetWindowKey));
 }
 
 // Tests that in various cases, after the tab drag ends, the dragged window and
@@ -3263,9 +3263,9 @@
   // As in this case the dragged window should merge back to source window,
   // which we can't test here. We only test the source window's bounds restore
   // to its maximized window size.
-  EXPECT_TRUE(window2->GetProperty(ash::kIsDeferredTabDraggingTargetWindowKey));
+  EXPECT_TRUE(window2->GetProperty(kIsDeferredTabDraggingTargetWindowKey));
   EXPECT_EQ(window2->bounds(), bounds2);
-  window2->ClearProperty(ash::kIsDeferredTabDraggingTargetWindowKey);
+  window2->ClearProperty(kIsDeferredTabDraggingTargetWindowKey);
 
   // b) Drag the window far enough so that the dragged window doesn't merge back
   // into the source window.
@@ -3274,8 +3274,7 @@
   EXPECT_NE(window1->bounds(), bounds1);
   EXPECT_NE(window2->bounds(), bounds2);
   CompleteDrag(std::move(resizer));
-  EXPECT_FALSE(
-      window2->GetProperty(ash::kIsDeferredTabDraggingTargetWindowKey));
+  EXPECT_FALSE(window2->GetProperty(kIsDeferredTabDraggingTargetWindowKey));
   EXPECT_EQ(window1->bounds(), bounds1);
   EXPECT_EQ(window2->bounds(), bounds2);
 
@@ -3312,8 +3311,8 @@
   // |window1|, so we only test the source window's bounds here.
   EXPECT_EQ(window1->bounds(), snapped_bounds1);
   EXPECT_EQ(window2->bounds(), snapped_bounds2);
-  EXPECT_TRUE(window1->GetProperty(ash::kIsDeferredTabDraggingTargetWindowKey));
-  window1->ClearProperty(ash::kIsDeferredTabDraggingTargetWindowKey);
+  EXPECT_TRUE(window1->GetProperty(kIsDeferredTabDraggingTargetWindowKey));
+  window1->ClearProperty(kIsDeferredTabDraggingTargetWindowKey);
   EXPECT_EQ(split_view_controller()->state(),
             SplitViewController::BOTH_SNAPPED);
 
@@ -3324,8 +3323,7 @@
   EXPECT_EQ(window1->bounds(), snapped_bounds1);
   EXPECT_EQ(window2->bounds(), snapped_bounds2);
   CompleteDrag(std::move(resizer));
-  EXPECT_FALSE(
-      window1->GetProperty(ash::kIsDeferredTabDraggingTargetWindowKey));
+  EXPECT_FALSE(window1->GetProperty(kIsDeferredTabDraggingTargetWindowKey));
   // |window3| replaced |window1| as the left snapped window.
   EXPECT_EQ(window3->bounds(), snapped_bounds1);
   EXPECT_EQ(window2->bounds(), snapped_bounds2);
@@ -3555,7 +3553,7 @@
   const wm::WMEvent fullscreen_event(wm::WM_EVENT_TOGGLE_FULLSCREEN);
   window_state->OnWMEvent(&fullscreen_event);
   window_state->SetHideShelfWhenFullscreen(false);
-  window_state->SetInImmersiveFullscreen(true);
+  window->SetProperty(kImmersiveIsActive, true);
   shelf_layout_manager->UpdateVisibilityState();
   EXPECT_TRUE(window_state->IsFullscreen());
   EXPECT_FALSE(shelf_layout_manager->IsVisible());
diff --git a/ash/wm/tablet_mode/tablet_mode_window_manager_unittest.cc b/ash/wm/tablet_mode/tablet_mode_window_manager_unittest.cc
index 307cd53..e9ad613 100644
--- a/ash/wm/tablet_mode/tablet_mode_window_manager_unittest.cc
+++ b/ash/wm/tablet_mode/tablet_mode_window_manager_unittest.cc
@@ -1522,7 +1522,7 @@
   EXPECT_FALSE(window_state->IsInImmersiveFullscreen());
   EXPECT_EQ(window.get(), wm::GetActiveWindow());
 
-  window_state->SetInImmersiveFullscreen(true);
+  window->SetProperty(kImmersiveIsActive, true);
 
   // Do an edge swipe top into screen.
   ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
@@ -1551,7 +1551,7 @@
   EXPECT_TRUE(window_state->IsFullscreen());
   EXPECT_FALSE(window_state->IsInImmersiveFullscreen());
   EXPECT_EQ(window.get(), wm::GetActiveWindow());
-  window_state->SetInImmersiveFullscreen(true);
+  window->SetProperty(kImmersiveIsActive, true);
   EXPECT_TRUE(window_state->IsInImmersiveFullscreen());
 
   // Do an edge swipe bottom into screen.
@@ -1819,7 +1819,7 @@
   std::unique_ptr<aura::Window> window(
       CreateWindow(aura::client::WINDOW_TYPE_NORMAL, rect));
   // Now put the window in tab-dragging process.
-  window->SetProperty(ash::kIsDraggingTabsKey, true);
+  window->SetProperty(kIsDraggingTabsKey, true);
 
   TabletModeWindowManager* manager = CreateTabletModeWindowManager();
   ASSERT_TRUE(manager);
diff --git a/ash/wm/window_state.cc b/ash/wm/window_state.cc
index 9b5e1bc..df0a86c 100644
--- a/ash/wm/window_state.cc
+++ b/ash/wm/window_state.cc
@@ -451,12 +451,7 @@
 }
 
 bool WindowState::IsInImmersiveFullscreen() const {
-  return window_->GetProperty(aura::client::kImmersiveFullscreenKey);
-}
-
-void WindowState::SetInImmersiveFullscreen(bool enabled) {
-  base::AutoReset<bool> resetter(&ignore_property_change_, true);
-  window_->SetProperty(aura::client::kImmersiveFullscreenKey, enabled);
+  return window_->GetProperty(ash::kImmersiveIsActive);
 }
 
 void WindowState::set_bounds_changed_by_user(bool bounds_changed_by_user) {
@@ -754,8 +749,7 @@
     }
     return;
   }
-  if (key == kHideShelfWhenFullscreenKey ||
-      key == aura::client::kImmersiveFullscreenKey) {
+  if (key == kHideShelfWhenFullscreenKey || key == ash::kImmersiveIsActive) {
     if (!ignore_property_change_) {
       // This change came from outside ash. Update our shelf visibility based
       // on our changed state.
diff --git a/ash/wm/window_state.h b/ash/wm/window_state.h
index d4f8044a..5e95404 100644
--- a/ash/wm/window_state.h
+++ b/ash/wm/window_state.h
@@ -295,7 +295,6 @@
   // the top portion of the window through a touch / mouse gesture. It might
   // also allow the shelf to be shown in some situations.
   bool IsInImmersiveFullscreen() const;
-  void SetInImmersiveFullscreen(bool enabled);
 
   // True if the window should not adjust the window's bounds when
   // virtual keyboard bounds changes.
diff --git a/base/android/application_status_listener_unittest.cc b/base/android/application_status_listener_unittest.cc
index 1918d95..37e8e1c 100644
--- a/base/android/application_status_listener_unittest.cc
+++ b/base/android/application_status_listener_unittest.cc
@@ -73,7 +73,7 @@
 
  private:
   void ExpectOnThread() {
-    EXPECT_TRUE(thread_.message_loop()->IsBoundToCurrentThread());
+    EXPECT_TRUE(thread_.task_runner()->BelongsToCurrentThread());
   }
 
   void RegisterThreadForEvents() {
diff --git a/base/android/field_trial_list.cc b/base/android/field_trial_list.cc
index 1dec5b5..cc66af1 100644
--- a/base/android/field_trial_list.cc
+++ b/base/android/field_trial_list.cc
@@ -8,6 +8,8 @@
 #include <string>
 
 #include "base/android/jni_string.h"
+#include "base/lazy_instance.h"
+#include "base/macros.h"
 #include "base/metrics/field_trial.h"
 #include "base/metrics/field_trial_params.h"
 #include "jni/FieldTrialList_jni.h"
@@ -17,6 +19,36 @@
 using base::android::JavaParamRef;
 using base::android::ScopedJavaLocalRef;
 
+namespace {
+
+// Log trials and their groups on activation, for debugging purposes.
+class TrialLogger : public base::FieldTrialList::Observer {
+ public:
+  TrialLogger() {}
+
+  void OnFieldTrialGroupFinalized(const std::string& trial_name,
+                                  const std::string& group_name) override {
+    Log(trial_name, group_name);
+  }
+
+  static void Log(const std::string& trial_name,
+                  const std::string& group_name) {
+    LOG(INFO) << "Active field trial \"" << trial_name
+              << "\" in group \"" << group_name<< '"';
+  }
+
+ protected:
+  ~TrialLogger() override {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TrialLogger);
+};
+
+base::LazyInstance<TrialLogger>::Leaky g_trial_logger =
+    LAZY_INSTANCE_INITIALIZER;
+
+}  // namespace
+
 static ScopedJavaLocalRef<jstring> JNI_FieldTrialList_FindFullName(
     JNIEnv* env,
     const JavaParamRef<jclass>& clazz,
@@ -45,3 +77,19 @@
   return ConvertUTF8ToJavaString(
       env, parameters[ConvertJavaStringToUTF8(env, jparameter_key)]);
 }
+
+static void JNI_FieldTrialList_LogActiveTrials(
+    JNIEnv* env,
+    const base::android::JavaParamRef<jclass>& clazz) {
+  DCHECK(!g_trial_logger.IsCreated()); // This need only be called once.
+
+  LOG(INFO) << "Logging active field trials...";
+  base::FieldTrialList::AddObserver(&g_trial_logger.Get());
+
+  // Log any trials that were already active before adding the observer.
+  std::vector<base::FieldTrial::ActiveGroup> active_groups;
+  base::FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
+  for (const base::FieldTrial::ActiveGroup& group : active_groups) {
+    TrialLogger::Log(group.trial_name, group.group_name);
+  }
+}
diff --git a/base/android/java/src/org/chromium/base/FieldTrialList.java b/base/android/java/src/org/chromium/base/FieldTrialList.java
index c3468a4..ea93a61 100644
--- a/base/android/java/src/org/chromium/base/FieldTrialList.java
+++ b/base/android/java/src/org/chromium/base/FieldTrialList.java
@@ -40,7 +40,16 @@
         return nativeGetVariationParameter(trialName, parameterKey);
     }
 
+    /**
+     * Print active trials and their group assignments to logcat, for debugging purposes. Continue
+     * prtinting new trials as they become active. This should be called at most once.
+     */
+    public static void logActiveTrials() {
+        nativeLogActiveTrials();
+    }
+
     private static native String nativeFindFullName(String trialName);
     private static native boolean nativeTrialExists(String trialName);
     private static native String nativeGetVariationParameter(String trialName, String parameterKey);
+    private static native void nativeLogActiveTrials();
 }
diff --git a/base/android/jni_generator/jni_generator.py b/base/android/jni_generator/jni_generator.py
index 2f210bb5..aa69ead 100755
--- a/base/android/jni_generator/jni_generator.py
+++ b/base/android/jni_generator/jni_generator.py
@@ -72,8 +72,6 @@
     r'@JniStaticNatives\s*interface\s*'
     r'(?P<interface_name>\w*)\s*(?P<interface_body>{(\s*.*)+?\s*})')
 
-
-
 # Use 100 columns rather than 80 because it makes many lines more readable.
 _WRAP_LINE_LENGTH = 100
 # WrapOutput() is fairly slow. Pre-creating TextWrappers helps a bit.
diff --git a/base/android/jni_generator/jni_generator_tests.py b/base/android/jni_generator/jni_generator_tests.py
index ad77bbd..0dde1f9 100755
--- a/base/android/jni_generator/jni_generator_tests.py
+++ b/base/android/jni_generator/jni_generator_tests.py
@@ -97,6 +97,21 @@
     print 'REBASELINE=1', sys.argv[0]
     print 'to regenerate the data files.'
 
+  @staticmethod
+  def _MergeRegistrationForTests(results,
+                                 header_guard='HEADER_GUARD',
+                                 namespace='test'):
+
+    results.sort(key=lambda d: d['FULL_CLASS_NAME'])
+
+    combined_dict = {}
+    for key in jni_registration_generator.MERGEABLE_KEYS:
+      combined_dict[key] = ''.join(d.get(key, '') for d in results)
+
+    combined_dict['HEADER_GUARD'] = header_guard
+    combined_dict['NAMESPACE'] = namespace
+    return combined_dict
+
   def _ReadGoldenFile(self, golden_file):
     if not os.path.exists(golden_file):
       return None
@@ -172,6 +187,72 @@
 
     self.assertListEquals(natives, golden_natives)
 
+  def testProxyNativesMainDex(self):
+    test_data = """
+    @MainDex
+    class Foo() {
+      @JniStaticNatives
+      interface Natives {
+        void thisismaindex();
+      }
+      void dontmatchme();
+      public static void metoo();
+      public static native void this_is_a_non_proxy_native();
+    }
+    """
+
+    non_main_dex_test_data = """
+    class Bar() {
+      @JniStaticNatives
+      interface Natives {
+        void foo();
+        void bar();
+      }
+    }
+    """
+    qualified_clazz = 'test/foo/Foo'
+    jni_params = TestOptions()
+
+    natives = jni_generator.NativeProxyHelpers.ExtractStaticProxyNatives(
+        qualified_clazz, test_data, 'long')
+
+    golden_natives = [
+        NativeMethod(
+            return_type='void',
+            static=True,
+            name='thisismaindex',
+            params=[],
+            java_class_name=None,
+            is_proxy=True,
+            proxy_name='test_foo_Foo_thisismaindex',
+            type='function'),
+    ]
+
+    self.assertListEquals(natives, golden_natives)
+
+    jni_params = jni_generator.JniParams(qualified_clazz)
+    main_dex_header = jni_registration_generator.HeaderGenerator(
+        '', qualified_clazz, natives, jni_params, main_dex=True).Generate()
+    content = TestGenerator._MergeRegistrationForTests([main_dex_header])
+
+    self.assertGoldenTextEquals(
+        jni_registration_generator.CreateFromDict(content))
+
+    other_qualified_clazz = 'test/foo/Bar'
+    other_natives = jni_generator.NativeProxyHelpers.ExtractStaticProxyNatives(
+        other_qualified_clazz, non_main_dex_test_data, 'long')
+
+    jni_params = jni_generator.JniParams(other_qualified_clazz)
+    non_main_dex_header = jni_registration_generator.HeaderGenerator(
+        '', other_qualified_clazz, other_natives, jni_params,
+        main_dex=False).Generate()
+
+    content = TestGenerator._MergeRegistrationForTests([main_dex_header] +
+                                                       [non_main_dex_header])
+
+    self.assertGoldenTextEquals(
+        jni_registration_generator.CreateFromDict(content), 'AndNonMainDex')
+
   def testProxyNatives(self):
     test_data = """
     class SampleProxyJni {
@@ -252,12 +333,8 @@
                                               [], jni_params, TestOptions())
     self.assertGoldenTextEquals(h1.GetContent())
     h2 = jni_registration_generator.HeaderGenerator('', qualified_clazz,
-                                                    natives, jni_params, True)
-    content = h2.Generate()
-    for k in jni_registration_generator.MERGEABLE_KEYS:
-      content[k] = content.get(k, '')
-    content['HEADER_GUARD'] = 'HEADER_GUARD'
-    content['NAMESPACE'] = 'test'
+                                                    natives, jni_params, False)
+    content = TestGenerator._MergeRegistrationForTests([h2.Generate()])
 
     self.assertGoldenTextEquals(
         jni_registration_generator.CreateFromDict(content),
@@ -431,11 +508,7 @@
     self.assertGoldenTextEquals(h1.GetContent())
     h2 = jni_registration_generator.HeaderGenerator(
         '', 'org/chromium/TestJni', natives, jni_params, True)
-    content = h2.Generate()
-    for k in jni_registration_generator.MERGEABLE_KEYS:
-      content[k] = content.get(k, '')
-    content['HEADER_GUARD'] = 'HEADER_GUARD'
-    content['NAMESPACE'] = 'test'
+    content = TestGenerator._MergeRegistrationForTests([h2.Generate()])
 
     self.assertGoldenTextEquals(
         jni_registration_generator.CreateFromDict(content),
@@ -522,11 +595,7 @@
 
     h2 = jni_registration_generator.HeaderGenerator(
         '', 'org/chromium/TestJni', natives, jni_params, True)
-    content = h2.Generate()
-    for k in jni_registration_generator.MERGEABLE_KEYS:
-      content[k] = content.get(k, '')
-    content['HEADER_GUARD'] = 'HEADER_GUARD'
-    content['NAMESPACE'] = 'test'
+    content = TestGenerator._MergeRegistrationForTests([h2.Generate()])
 
     self.assertGoldenTextEquals(
         jni_registration_generator.CreateFromDict(content),
@@ -1034,21 +1103,21 @@
         'org/chromium/example/jni_generator/SampleForAnnotationProcessor', opts)
     self.assertGoldenTextEquals(
         generated_text,
-        golden_file="HashedSampleForAnnotationProcessor_jni.golden")
+        golden_file='HashedSampleForAnnotationProcessor_jni.golden')
 
   def testJniProxyExample(self):
     generated_text = self._createJniHeaderFromFile(
         'java/src/org/chromium/example/jni_generator/SampleForAnnotationProcessor.java',
         'org/chromium/example/jni_generator/SampleForAnnotationProcessor')
     self.assertGoldenTextEquals(
-        generated_text, golden_file="SampleForAnnotationProcessor_jni.golden")
+        generated_text, golden_file='SampleForAnnotationProcessor_jni.golden')
 
   def testJniSelfDocumentingExample(self):
     generated_text = self._createJniHeaderFromFile(
         'java/src/org/chromium/example/jni_generator/SampleForTests.java',
         'org/chromium/example/jni_generator/SampleForTests')
     self.assertGoldenTextEquals(
-        generated_text, golden_file="SampleForTests_jni.golden")
+        generated_text, golden_file='SampleForTests_jni.golden')
 
   def testNoWrappingPreprocessorLines(self):
     test_data = """
@@ -1358,7 +1427,7 @@
 def main(argv):
   parser = optparse.OptionParser()
   parser.add_option('--stamp', help='Path to touch on success.')
-  parser.add_option('--verbose', action="store_true",
+  parser.add_option('--verbose', action='store_true',
                     help='Whether to output details.')
   options, _ = parser.parse_args(argv[1:])
 
diff --git a/base/android/jni_generator/jni_registration_generator.py b/base/android/jni_generator/jni_registration_generator.py
index f498a1786..e6d91e2 100755
--- a/base/android/jni_generator/jni_registration_generator.py
+++ b/base/android/jni_generator/jni_registration_generator.py
@@ -25,6 +25,7 @@
     'JNI_NATIVE_METHOD',
     'JNI_NATIVE_METHOD_ARRAY',
     'PROXY_NATIVE_METHOD_ARRAY',
+    'PROXY_NATIVE_METHOD_ARRAY_MAIN_DEX',
     'REGISTER_MAIN_DEX_NATIVES',
     'REGISTER_NON_MAIN_DEX_NATIVES',
 ]
@@ -73,24 +74,23 @@
   fully_qualified_class = jni_generator.ExtractFullyQualifiedJavaClassName(
       path, contents)
   natives = jni_generator.ExtractNatives(contents, 'long')
+
   natives += jni_generator.NativeProxyHelpers.ExtractStaticProxyNatives(
-      fully_qualified_class, contents, 'long')
+      fully_qualified_class=fully_qualified_class,
+      contents=contents,
+      ptr_type='long')
   if len(natives) == 0:
     return None
   namespace = jni_generator.ExtractJNINamespace(contents)
   jni_params = jni_generator.JniParams(fully_qualified_class)
   jni_params.ExtractImportsAndInnerClasses(contents)
-  main_dex = jni_generator.IsMainDexJavaClass(contents)
-  header_generator = HeaderGenerator(
-      namespace, fully_qualified_class, natives, jni_params, main_dex)
+  is_main_dex = jni_generator.IsMainDexJavaClass(contents)
+  header_generator = HeaderGenerator(namespace, fully_qualified_class, natives,
+                                     jni_params, is_main_dex)
   return header_generator.Generate()
 
-
 def _SetProxyRegistrationFields(registration_dict):
-  if registration_dict['PROXY_NATIVE_METHOD_ARRAY']:
-    registration_name = jni_generator.GetRegistrationFunctionName(
-        jni_generator.NATIVE_PROXY_QUALIFIED_NAME)
-    proxy_native_array = string.Template("""\
+  registration_template = string.Template("""\
 
 static const JNINativeMethod kMethods_${ESCAPED_PROXY_CLASS}[] = {
 ${KMETHODS}
@@ -111,33 +111,48 @@
 
   return true;
 }
-    """).substitute({
-        'ESCAPED_PROXY_CLASS':
-            jni_generator.NativeProxyHelpers.ESCAPED_NATIVE_PROXY_CLASS,
-        'PROXY_CLASS':
-            jni_generator.NATIVE_PROXY_QUALIFIED_NAME,
-        'KMETHODS':
-            registration_dict['PROXY_NATIVE_METHOD_ARRAY'],
-        'REGISTRATION_NAME':
-            registration_name
-    })
+""")
 
-    proxy_natives_registration = string.Template("""\
+  registration_call = string.Template("""\
 
-// Register natives in a proxy.
-if (!${REGISTRATION_NAME}(env)) {
-  return false;
-}
-    """).substitute({
-        'REGISTRATION_NAME': registration_name
-    })
+  // Register natives in a proxy.
+  if (!${REGISTRATION_NAME}(env)) {
+    return false;
+  }
+""")
 
+  sub_dict = {
+      'ESCAPED_PROXY_CLASS':
+          jni_generator.NativeProxyHelpers.ESCAPED_NATIVE_PROXY_CLASS,
+      'PROXY_CLASS':
+          jni_generator.NATIVE_PROXY_QUALIFIED_NAME,
+      'KMETHODS':
+          registration_dict['PROXY_NATIVE_METHOD_ARRAY'],
+      'REGISTRATION_NAME':
+          jni_generator.GetRegistrationFunctionName(
+              jni_generator.NATIVE_PROXY_QUALIFIED_NAME)
+  }
+
+  if registration_dict['PROXY_NATIVE_METHOD_ARRAY']:
+    proxy_native_array = registration_template.substitute(sub_dict)
+    proxy_natives_registration = registration_call.substitute(sub_dict)
   else:
     proxy_native_array = ''
     proxy_natives_registration = ''
 
+  if registration_dict['PROXY_NATIVE_METHOD_ARRAY_MAIN_DEX']:
+    sub_dict['REGISTRATION_NAME'] += 'MAIN_DEX'
+    sub_dict['ESCAPED_PROXY_CLASS'] += 'MAIN_DEX'
+    sub_dict['KMETHODS'] = (
+        registration_dict['PROXY_NATIVE_METHOD_ARRAY_MAIN_DEX'])
+    proxy_native_array += registration_template.substitute(sub_dict)
+    main_dex_call = registration_call.substitute(sub_dict)
+  else:
+    main_dex_call = ''
+
   registration_dict['PROXY_NATIVE_METHOD_ARRAY'] = proxy_native_array
   registration_dict['REGISTER_PROXY_NATIVES'] = proxy_natives_registration
+  registration_dict['REGISTER_MAIN_DEX_PROXY_NATIVES'] = main_dex_call
 
 
 def CreateFromDict(registration_dict):
@@ -179,7 +194,8 @@
 
 namespace ${NAMESPACE} {
 
-bool RegisterMainDexNatives(JNIEnv* env) {
+bool RegisterMainDexNatives(JNIEnv* env) {\
+${REGISTER_MAIN_DEX_PROXY_NATIVES}
 ${REGISTER_MAIN_DEX_NATIVES}
   return true;
 }
@@ -209,6 +225,8 @@
                main_dex):
     self.namespace = namespace
     self.natives = natives
+    self.proxy_natives = [n for n in natives if n.is_proxy]
+    self.non_proxy_natives = [n for n in natives if not n.is_proxy]
     self.fully_qualified_class = fully_qualified_class
     self.jni_params = jni_params
     self.class_name = self.fully_qualified_class.split('/')[-1]
@@ -256,7 +274,7 @@
     """Add the body of the RegisterNativesImpl method to the dictionary."""
 
     # Only register if there is at least 1 non-proxy native
-    if all(native.is_proxy for native in self.natives):
+    if len(self.non_proxy_natives) == 0:
       return ''
 
     template = string.Template("""\
@@ -298,12 +316,7 @@
 
   def _GetKMethodsString(self, clazz):
     ret = []
-    for native in self.natives:
-      if native.is_proxy:
-        # Proxy natives are registered for the native proxy class.
-        if clazz == jni_generator.NATIVE_PROXY_CLASS_NAME:
-          ret += [self._GetKMethodArrayEntry(native)]
-        continue
+    for native in self.non_proxy_natives:
       if (native.java_class_name == clazz or
           (not native.java_class_name and clazz == self.class_name)):
         ret += [self._GetKMethodArrayEntry(native)]
@@ -331,17 +344,15 @@
   def _AddProxyNativeMethodKStrings(self):
     """Returns KMethodString for wrapped native methods in all_classes """
 
-    all_classes = self.helper.GetUniqueClasses(self.natives)
-    all_classes[self.class_name] = self.fully_qualified_class
+    if self.main_dex:
+      key = 'PROXY_NATIVE_METHOD_ARRAY_MAIN_DEX'
+    else:
+      key = 'PROXY_NATIVE_METHOD_ARRAY'
 
-    wrapped_native_methods = ''
+    proxy_k_strings = ('\n'.join(
+        [self._GetKMethodArrayEntry(p) for p in self.proxy_natives]))
 
-    for clazz in all_classes:
-      if clazz != jni_generator.NATIVE_PROXY_CLASS_NAME:
-        continue
-      wrapped_native_methods += self._GetKMethodsString(clazz)
-
-    self._SetDictValue('PROXY_NATIVE_METHOD_ARRAY', wrapped_native_methods)
+    self._SetDictValue(key, proxy_k_strings)
 
   def _SubstituteNativeMethods(self, template, sub_proxy=False):
     """Substitutes NAMESPACE, JAVA_CLASS and KMETHODS in the provided
@@ -416,9 +427,8 @@
 """)
     # Only register if there is a native method not in a proxy,
     # since all the proxies will be registered together.
-    for n in self.natives:
-      if not n.is_proxy:
-        return self._SubstituteNativeMethods(template)
+    if len(self.non_proxy_natives) != 0:
+      return self._SubstituteNativeMethods(template)
     return ''
 
 
diff --git a/base/android/jni_generator/testProxyNativesMainDex.golden b/base/android/jni_generator/testProxyNativesMainDex.golden
new file mode 100644
index 0000000..f093270
--- /dev/null
+++ b/base/android/jni_generator/testProxyNativesMainDex.golden
@@ -0,0 +1,77 @@
+// 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.
+
+
+// This file is autogenerated by
+//     base/android/jni_generator/jni_registration_generator.py
+// Please do not change its content.
+
+#ifndef HEADER_GUARD
+#define HEADER_GUARD
+
+#include <jni.h>
+
+#include "base/android/jni_generator/jni_generator_helper.h"
+#include "base/android/jni_int_wrapper.h"
+
+
+// Step 1: Forward declarations (classes).
+
+
+// Step 2: Forward declarations (methods).
+
+JNI_GENERATOR_EXPORT void Java_org_chromium_base_natives_GEN_1JNI_test_1foo_1Foo_1thisismaindex(
+    JNIEnv* env,
+    jclass jcaller);
+
+
+// Step 3: Method declarations.
+
+
+static const JNINativeMethod kMethods_org_chromium_base_natives_GEN_1JNIMAIN_DEX[] = {
+    { "test_foo_Foo_thisismaindex", "()V",
+        reinterpret_cast<void*>(Java_org_chromium_base_natives_GEN_1JNI_test_1foo_1Foo_1thisismaindex)
+        },
+
+};
+
+JNI_REGISTRATION_EXPORT bool RegisterNative_org_chromium_base_natives_GEN_1JNIMAIN_DEX(JNIEnv* env) {
+  const int number_of_methods = arraysize(kMethods_org_chromium_base_natives_GEN_1JNIMAIN_DEX);
+
+  base::android::ScopedJavaLocalRef<jclass> native_clazz = base::android::GetClass(env, "org/chromium/base/natives/GEN_JNI");
+  if (env->RegisterNatives(
+      native_clazz.obj(),
+      kMethods_org_chromium_base_natives_GEN_1JNIMAIN_DEX,
+      number_of_methods) < 0) {
+
+    jni_generator::HandleRegistrationError(env, native_clazz.obj(), __FILE__);
+    return false;
+  }
+
+  return true;
+}
+
+
+// Step 4: Main dex and non-main dex registration functions.
+
+namespace test {
+
+bool RegisterMainDexNatives(JNIEnv* env) {
+  // Register natives in a proxy.
+  if (!RegisterNative_org_chromium_base_natives_GEN_1JNIMAIN_DEX(env)) {
+    return false;
+  }
+
+
+  return true;
+}
+
+bool RegisterNonMainDexNatives(JNIEnv* env) {
+
+  return true;
+}
+
+}  // namespace test
+
+#endif  // HEADER_GUARD
diff --git a/base/android/jni_generator/testProxyNativesMainDexAndNonMainDex.golden b/base/android/jni_generator/testProxyNativesMainDexAndNonMainDex.golden
new file mode 100644
index 0000000..6b909a7
--- /dev/null
+++ b/base/android/jni_generator/testProxyNativesMainDexAndNonMainDex.golden
@@ -0,0 +1,112 @@
+// 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.
+
+
+// This file is autogenerated by
+//     base/android/jni_generator/jni_registration_generator.py
+// Please do not change its content.
+
+#ifndef HEADER_GUARD
+#define HEADER_GUARD
+
+#include <jni.h>
+
+#include "base/android/jni_generator/jni_generator_helper.h"
+#include "base/android/jni_int_wrapper.h"
+
+
+// Step 1: Forward declarations (classes).
+
+
+// Step 2: Forward declarations (methods).
+
+JNI_GENERATOR_EXPORT void Java_org_chromium_base_natives_GEN_1JNI_test_1foo_1Bar_1foo(
+    JNIEnv* env,
+    jclass jcaller);
+JNI_GENERATOR_EXPORT void Java_org_chromium_base_natives_GEN_1JNI_test_1foo_1Bar_1bar(
+    JNIEnv* env,
+    jclass jcaller);
+JNI_GENERATOR_EXPORT void Java_org_chromium_base_natives_GEN_1JNI_test_1foo_1Foo_1thisismaindex(
+    JNIEnv* env,
+    jclass jcaller);
+
+
+// Step 3: Method declarations.
+
+
+static const JNINativeMethod kMethods_org_chromium_base_natives_GEN_1JNI[] = {
+    { "test_foo_Bar_foo", "()V",
+        reinterpret_cast<void*>(Java_org_chromium_base_natives_GEN_1JNI_test_1foo_1Bar_1foo) },
+    { "test_foo_Bar_bar", "()V",
+        reinterpret_cast<void*>(Java_org_chromium_base_natives_GEN_1JNI_test_1foo_1Bar_1bar) },
+
+};
+
+JNI_REGISTRATION_EXPORT bool RegisterNative_org_chromium_base_natives_GEN_1JNI(JNIEnv* env) {
+  const int number_of_methods = arraysize(kMethods_org_chromium_base_natives_GEN_1JNI);
+
+  base::android::ScopedJavaLocalRef<jclass> native_clazz = base::android::GetClass(env, "org/chromium/base/natives/GEN_JNI");
+  if (env->RegisterNatives(
+      native_clazz.obj(),
+      kMethods_org_chromium_base_natives_GEN_1JNI,
+      number_of_methods) < 0) {
+
+    jni_generator::HandleRegistrationError(env, native_clazz.obj(), __FILE__);
+    return false;
+  }
+
+  return true;
+}
+
+static const JNINativeMethod kMethods_org_chromium_base_natives_GEN_1JNIMAIN_DEX[] = {
+    { "test_foo_Foo_thisismaindex", "()V",
+        reinterpret_cast<void*>(Java_org_chromium_base_natives_GEN_1JNI_test_1foo_1Foo_1thisismaindex)
+        },
+
+};
+
+JNI_REGISTRATION_EXPORT bool RegisterNative_org_chromium_base_natives_GEN_1JNIMAIN_DEX(JNIEnv* env) {
+  const int number_of_methods = arraysize(kMethods_org_chromium_base_natives_GEN_1JNIMAIN_DEX);
+
+  base::android::ScopedJavaLocalRef<jclass> native_clazz = base::android::GetClass(env, "org/chromium/base/natives/GEN_JNI");
+  if (env->RegisterNatives(
+      native_clazz.obj(),
+      kMethods_org_chromium_base_natives_GEN_1JNIMAIN_DEX,
+      number_of_methods) < 0) {
+
+    jni_generator::HandleRegistrationError(env, native_clazz.obj(), __FILE__);
+    return false;
+  }
+
+  return true;
+}
+
+
+// Step 4: Main dex and non-main dex registration functions.
+
+namespace test {
+
+bool RegisterMainDexNatives(JNIEnv* env) {
+  // Register natives in a proxy.
+  if (!RegisterNative_org_chromium_base_natives_GEN_1JNIMAIN_DEX(env)) {
+    return false;
+  }
+
+
+  return true;
+}
+
+bool RegisterNonMainDexNatives(JNIEnv* env) {
+  // Register natives in a proxy.
+  if (!RegisterNative_org_chromium_base_natives_GEN_1JNI(env)) {
+    return false;
+  }
+
+
+  return true;
+}
+
+}  // namespace test
+
+#endif  // HEADER_GUARD
diff --git a/base/android/jni_generator/testProxyNativesRegistrations.golden b/base/android/jni_generator/testProxyNativesRegistrations.golden
index f705c17c..13b5cc2 100644
--- a/base/android/jni_generator/testProxyNativesRegistrations.golden
+++ b/base/android/jni_generator/testProxyNativesRegistrations.golden
@@ -71,7 +71,7 @@
 
   return true;
 }
-    
+
 
 // Step 4: Main dex and non-main dex registration functions.
 
@@ -83,11 +83,11 @@
 }
 
 bool RegisterNonMainDexNatives(JNIEnv* env) {
-// Register natives in a proxy.
-if (!RegisterNative_org_chromium_base_natives_GEN_1JNI(env)) {
-  return false;
-}
-    
+  // Register natives in a proxy.
+  if (!RegisterNative_org_chromium_base_natives_GEN_1JNI(env)) {
+    return false;
+  }
+
 
   return true;
 }
diff --git a/base/at_exit.cc b/base/at_exit.cc
index 52c21513..b9d41d54 100644
--- a/base/at_exit.cc
+++ b/base/at_exit.cc
@@ -24,8 +24,7 @@
 
 static bool g_disable_managers = false;
 
-AtExitManager::AtExitManager()
-    : processing_callbacks_(false), next_manager_(g_top_manager) {
+AtExitManager::AtExitManager() : next_manager_(g_top_manager) {
 // If multiple modules instantiate AtExitManagers they'll end up living in this
 // module... they have to coexist.
 #if !defined(COMPONENT_BUILD)
@@ -60,7 +59,9 @@
   }
 
   AutoLock lock(g_top_manager->lock_);
+#if DCHECK_IS_ON()
   DCHECK(!g_top_manager->processing_callbacks_);
+#endif
   g_top_manager->stack_.push(std::move(task));
 }
 
@@ -78,7 +79,9 @@
   {
     AutoLock lock(g_top_manager->lock_);
     tasks.swap(g_top_manager->stack_);
+#if DCHECK_IS_ON()
     g_top_manager->processing_callbacks_ = true;
+#endif
   }
 
   // Relax the cross-thread access restriction to non-thread-safe RefCount.
@@ -91,8 +94,12 @@
     tasks.pop();
   }
 
+#if DCHECK_IS_ON()
+  AutoLock lock(g_top_manager->lock_);
   // Expect that all callbacks have been run.
   DCHECK(g_top_manager->stack_.empty());
+  g_top_manager->processing_callbacks_ = false;
+#endif
 }
 
 void AtExitManager::DisableAllAtExitManagers() {
@@ -100,8 +107,7 @@
   g_disable_managers = true;
 }
 
-AtExitManager::AtExitManager(bool shadow)
-    : processing_callbacks_(false), next_manager_(g_top_manager) {
+AtExitManager::AtExitManager(bool shadow) : next_manager_(g_top_manager) {
   DCHECK(shadow || !g_top_manager);
   g_top_manager = this;
 }
diff --git a/base/at_exit.h b/base/at_exit.h
index e74de8d..6ace3125 100644
--- a/base/at_exit.h
+++ b/base/at_exit.h
@@ -10,6 +10,7 @@
 #include "base/containers/stack.h"
 #include "base/macros.h"
 #include "base/synchronization/lock.h"
+#include "base/thread_annotations.h"
 
 namespace base {
 
@@ -61,9 +62,15 @@
 
  private:
   base::Lock lock_;
-  base::stack<base::Closure> stack_;
-  bool processing_callbacks_;
-  AtExitManager* next_manager_;  // Stack of managers to allow shadowing.
+
+  base::stack<base::Closure> stack_ GUARDED_BY(lock_);
+
+#if DCHECK_IS_ON()
+  bool processing_callbacks_ GUARDED_BY(lock_) = false;
+#endif
+
+  // Stack of managers to allow shadowing.
+  AtExitManager* const next_manager_;
 
   DISALLOW_COPY_AND_ASSIGN(AtExitManager);
 };
diff --git a/base/files/file_descriptor_watcher_posix_unittest.cc b/base/files/file_descriptor_watcher_posix_unittest.cc
index 8e6dd2be..fb0f5a0 100644
--- a/base/files/file_descriptor_watcher_posix_unittest.cc
+++ b/base/files/file_descriptor_watcher_posix_unittest.cc
@@ -57,20 +57,19 @@
   void SetUp() override {
     ASSERT_EQ(0, pipe(pipe_fds_));
 
-    MessageLoop* message_loop_for_io;
+    scoped_refptr<SingleThreadTaskRunner> io_thread_task_runner;
     if (GetParam() ==
         FileDescriptorWatcherTestType::MESSAGE_LOOP_FOR_IO_ON_OTHER_THREAD) {
       Thread::Options options;
       options.message_loop_type = MessageLoop::TYPE_IO;
       ASSERT_TRUE(other_thread_.StartWithOptions(options));
-      message_loop_for_io = other_thread_.message_loop();
+      io_thread_task_runner = other_thread_.task_runner();
     } else {
-      message_loop_for_io = message_loop_.get();
+      io_thread_task_runner = message_loop_->task_runner();
     }
 
-    ASSERT_TRUE(message_loop_for_io->IsType(MessageLoop::TYPE_IO));
     file_descriptor_watcher_ = std::make_unique<FileDescriptorWatcher>(
-        message_loop_for_io->task_runner());
+        std::move(io_thread_task_runner));
   }
 
   void TearDown() override {
@@ -144,6 +143,8 @@
   testing::StrictMock<Mock> mock_;
 
   // MessageLoop bound to the main thread.
+  // Use MessageLoop instead of ScopedTaskEnvironment here to keep a minimal
+  // and controlled task environment.
   std::unique_ptr<MessageLoop> message_loop_;
 
   // Thread running a MessageLoopForIO. Used when the test type is
diff --git a/base/files/file_path_watcher_fsevents.h b/base/files/file_path_watcher_fsevents.h
index dcdf2fb..2bd979c8 100644
--- a/base/files/file_path_watcher_fsevents.h
+++ b/base/files/file_path_watcher_fsevents.h
@@ -46,7 +46,7 @@
   // Called from FSEventsCallback whenever there is a change to the paths.
   void OnFilePathsChanged(const std::vector<FilePath>& paths);
 
-  // Called on the message_loop() thread to dispatch path events. Can't access
+  // Called on the task_runner() thread to dispatch path events. Can't access
   // target_ and resolved_target_ directly as those are modified on the
   // libdispatch thread.
   void DispatchEvents(const std::vector<FilePath>& paths,
@@ -71,7 +71,7 @@
   void StartEventStream(FSEventStreamEventId start_event, const FilePath& path);
 
   // Callback to notify upon changes.
-  // (Only accessed from the message_loop() thread.)
+  // (Only accessed from the task_runner() thread.)
   FilePathWatcher::Callback callback_;
 
   // The dispatch queue on which the the event stream is scheduled.
diff --git a/base/files/file_win.cc b/base/files/file_win.cc
index b33c6d1..b8a7e0ba 100644
--- a/base/files/file_win.cc
+++ b/base/files/file_win.cc
@@ -273,7 +273,7 @@
 }
 
 bool File::DeleteOnClose(bool delete_on_close) {
-  FILE_DISPOSITION_INFO disposition = {delete_on_close ? TRUE : FALSE};
+  FILE_DISPOSITION_INFO disposition = {delete_on_close};
   return ::SetFileInformationByHandle(GetPlatformFile(), FileDispositionInfo,
                                       &disposition, sizeof(disposition)) != 0;
 }
diff --git a/base/json/json_writer.cc b/base/json/json_writer.cc
index e4f1e3c..376a459f 100644
--- a/base/json/json_writer.cc
+++ b/base/json/json_writer.cc
@@ -57,47 +57,37 @@
 
 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:
+      // Note: We are explicitly invoking the std::string constructor in order
+      // to avoid ASAN errors on Windows: https://crbug.com/900041
+      json_string_->append(node.GetBool() ? std::string("true")
+                                          : std::string("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 +97,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 +138,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 +155,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 +180,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/message_loop/message_loop_task_runner_unittest.cc b/base/message_loop/message_loop_task_runner_unittest.cc
index be7a7a87..dc0e965 100644
--- a/base/message_loop/message_loop_task_runner_unittest.cc
+++ b/base/message_loop/message_loop_task_runner_unittest.cc
@@ -24,12 +24,16 @@
  public:
   MessageLoopTaskRunnerTest()
       : current_loop_(new MessageLoop()),
-        task_thread_("task_thread"),
+        task_thread_("test thread"),
         thread_sync_(WaitableEvent::ResetPolicy::MANUAL,
                      WaitableEvent::InitialState::NOT_SIGNALED) {}
 
   void DeleteCurrentMessageLoop() { current_loop_.reset(); }
 
+  MessageLoop* MessageLoopForThread(base::Thread* thread) {
+    return thread->message_loop();
+  }
+
  protected:
   void SetUp() override {
     // Use SetUp() instead of the constructor to avoid posting a task to a
@@ -126,8 +130,8 @@
   UnblockTaskThread();
   RunLoop().Run();
 
-  EXPECT_EQ(task_thread_.message_loop(), task_run_on);
-  EXPECT_EQ(task_thread_.message_loop(), task_deleted_on);
+  EXPECT_EQ(MessageLoopForThread(&task_thread_), task_run_on);
+  EXPECT_EQ(MessageLoopForThread(&task_thread_), task_deleted_on);
   EXPECT_EQ(current_loop_.get(), reply_run_on);
   EXPECT_EQ(current_loop_.get(), reply_deleted_on);
   EXPECT_LT(task_delete_order, reply_delete_order);
@@ -236,7 +240,7 @@
   // This should ensure the relay has been run.  We need to record the
   // MessageLoop pointer before stopping the thread because Thread::Stop() will
   // NULL out its own pointer.
-  MessageLoop* task_loop = task_thread_.message_loop();
+  MessageLoop* task_loop = MessageLoopForThread(&task_thread_);
   task_thread_.Stop();
 
   // Even if the reply task runner is already gone, the original task should
diff --git a/base/message_loop/message_loop_unittest.cc b/base/message_loop/message_loop_unittest.cc
index 1f549a0..721049c8b 100644
--- a/base/message_loop/message_loop_unittest.cc
+++ b/base/message_loop/message_loop_unittest.cc
@@ -2224,7 +2224,7 @@
     std::string kThreadName("bar");
     base::Thread thread(kThreadName);
     ASSERT_TRUE(thread.StartAndWaitForTesting());
-    EXPECT_EQ(kThreadName, thread.message_loop()->GetThreadName());
+    EXPECT_EQ(kThreadName, thread.thread_name());
   }
 }
 
diff --git a/base/message_loop/message_pump_libevent_unittest.cc b/base/message_loop/message_pump_libevent_unittest.cc
index 55eb0b4d..0abbf6e 100644
--- a/base/message_loop/message_pump_libevent_unittest.cc
+++ b/base/message_loop/message_pump_libevent_unittest.cc
@@ -39,7 +39,6 @@
   void SetUp() override {
     Thread::Options options(MessageLoop::TYPE_IO, 0);
     ASSERT_TRUE(io_thread_.StartWithOptions(options));
-    ASSERT_EQ(MessageLoop::TYPE_IO, io_thread_.message_loop()->type());
     int ret = pipe(pipefds_);
     ASSERT_EQ(0, ret);
   }
diff --git a/base/message_loop/message_pump_perftest.cc b/base/message_loop/message_pump_perftest.cc
index 71ed491..d78d069 100644
--- a/base/message_loop/message_pump_perftest.cc
+++ b/base/message_loop/message_pump_perftest.cc
@@ -27,6 +27,13 @@
 
 namespace base {
 
+class ThreadForTest : public Thread {
+ public:
+  ThreadForTest() : Thread("test") {}
+
+  using Thread::message_loop;
+};
+
 class ScheduleWorkTest : public testing::Test {
  public:
   ScheduleWorkTest() : counter_(0) {}
@@ -78,7 +85,7 @@
     } else
 #endif
     {
-      target_.reset(new Thread("target"));
+      target_.reset(new ThreadForTest());
       target_->StartWithOptions(Thread::Options(target_type, 0u));
 
       // Without this, it's possible for the scheduling threads to start and run
@@ -176,7 +183,7 @@
   }
 
  private:
-  std::unique_ptr<Thread> target_;
+  std::unique_ptr<ThreadForTest> target_;
 #if defined(OS_ANDROID)
   std::unique_ptr<android::JavaHandlerThread> java_thread_;
 #endif
diff --git a/base/task/task_scheduler/task_scheduler_impl.cc b/base/task/task_scheduler/task_scheduler_impl.cc
index 1d80f93..8fc31df 100644
--- a/base/task/task_scheduler/task_scheduler_impl.cc
+++ b/base/task/task_scheduler/task_scheduler_impl.cc
@@ -157,9 +157,8 @@
 
 #if defined(OS_POSIX) && !defined(OS_NACL_SFI)
   // Needs to happen after starting the service thread to get its
-  // message_loop().
-  task_tracker_->set_watch_file_descriptor_message_loop(
-      static_cast<MessageLoopForIO*>(service_thread_->message_loop()));
+  // task_runner().
+  task_tracker_->set_io_thread_task_runner(service_thread_->task_runner());
 #endif  // defined(OS_POSIX) && !defined(OS_NACL_SFI)
 
   // Needs to happen after starting the service thread to get its task_runner().
diff --git a/base/task/task_scheduler/task_tracker_posix.cc b/base/task/task_scheduler/task_tracker_posix.cc
index 6cd6185..704e7941 100644
--- a/base/task/task_scheduler/task_tracker_posix.cc
+++ b/base/task/task_scheduler/task_tracker_posix.cc
@@ -18,9 +18,8 @@
 void TaskTrackerPosix::RunOrSkipTask(Task task,
                                      Sequence* sequence,
                                      bool can_run_task) {
-  DCHECK(watch_file_descriptor_message_loop_);
-  FileDescriptorWatcher file_descriptor_watcher(
-      watch_file_descriptor_message_loop_->task_runner());
+  DCHECK(io_thread_task_runner_);
+  FileDescriptorWatcher file_descriptor_watcher(io_thread_task_runner_);
   TaskTracker::RunOrSkipTask(std::move(task), sequence, can_run_task);
 }
 
diff --git a/base/task/task_scheduler/task_tracker_posix.h b/base/task/task_scheduler/task_tracker_posix.h
index 8d04df78..351b40a 100644
--- a/base/task/task_scheduler/task_tracker_posix.h
+++ b/base/task/task_scheduler/task_tracker_posix.h
@@ -14,29 +14,28 @@
 #include "base/threading/platform_thread.h"
 
 namespace base {
-
-class MessageLoopForIO;
-
 namespace internal {
 
 struct Task;
 
 // A TaskTracker that instantiates a FileDescriptorWatcher in the scope in which
 // a task runs. Used on all POSIX platforms except NaCl SFI.
-// set_watch_file_descriptor_message_loop() must be called before the
+// set_io_thread_task_runner() must be called before the
 // TaskTracker can run tasks.
 class BASE_EXPORT TaskTrackerPosix : public TaskTracker {
  public:
   TaskTrackerPosix(StringPiece name);
   ~TaskTrackerPosix() override;
 
-  // Sets the MessageLoopForIO with which to setup FileDescriptorWatcher in the
-  // scope in which tasks run. Must be called before starting to run tasks.
+  // Sets the task runner with which to setup FileDescriptorWatcher in
+  // the scope in which tasks run. |io_thread_task_runner| must refer to
+  // a Thread with MessageLoop::TYPE_IO.
+  // Must be called before starting to run tasks.
   // External synchronization is required between a call to this and a call to
   // RunTask().
-  void set_watch_file_descriptor_message_loop(
-      MessageLoopForIO* watch_file_descriptor_message_loop) {
-    watch_file_descriptor_message_loop_ = watch_file_descriptor_message_loop;
+  void set_io_thread_task_runner(
+      scoped_refptr<SingleThreadTaskRunner> io_thread_task_runner) {
+    io_thread_task_runner_ = std::move(io_thread_task_runner);
   }
 
  protected:
@@ -44,7 +43,7 @@
   void RunOrSkipTask(Task task, Sequence* sequence, bool can_run_task) override;
 
  private:
-  MessageLoopForIO* watch_file_descriptor_message_loop_ = nullptr;
+  scoped_refptr<SingleThreadTaskRunner> io_thread_task_runner_;
 
   DISALLOW_COPY_AND_ASSIGN(TaskTrackerPosix);
 };
diff --git a/base/task/task_scheduler/task_tracker_posix_unittest.cc b/base/task/task_scheduler/task_tracker_posix_unittest.cc
index 2d1cf021..4109a99 100644
--- a/base/task/task_scheduler/task_tracker_posix_unittest.cc
+++ b/base/task/task_scheduler/task_tracker_posix_unittest.cc
@@ -37,8 +37,7 @@
     Thread::Options service_thread_options;
     service_thread_options.message_loop_type = MessageLoop::TYPE_IO;
     service_thread_.StartWithOptions(service_thread_options);
-    tracker_.set_watch_file_descriptor_message_loop(
-        static_cast<MessageLoopForIO*>(service_thread_.message_loop()));
+    tracker_.set_io_thread_task_runner(service_thread_.task_runner());
   }
 
  protected:
diff --git a/base/test/test_io_thread.h b/base/test/test_io_thread.h
index a55a06340..c72d4fa 100644
--- a/base/test/test_io_thread.h
+++ b/base/test/test_io_thread.h
@@ -40,12 +40,8 @@
   // Post |task| to the IO thread.
   void PostTask(const Location& from_here, base::OnceClosure task);
 
-  base::MessageLoopForIO* message_loop() {
-    return static_cast<base::MessageLoopForIO*>(io_thread_.message_loop());
-  }
-
   scoped_refptr<SingleThreadTaskRunner> task_runner() {
-    return message_loop()->task_runner();
+    return io_thread_.task_runner();
   }
 
  private:
diff --git a/base/threading/thread.h b/base/threading/thread.h
index f3de144..2ce6cee 100644
--- a/base/threading/thread.h
+++ b/base/threading/thread.h
@@ -14,6 +14,7 @@
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_loop_current.h"
 #include "base/message_loop/timer_slack.h"
 #include "base/sequence_checker.h"
 #include "base/single_thread_task_runner.h"
@@ -201,34 +202,6 @@
   // relationship with this one.
   void DetachFromSequence();
 
-  // Returns the message loop for this thread.  Use the MessageLoop's
-  // PostTask methods to execute code on the thread.  This only returns
-  // non-null after a successful call to Start.  After Stop has been called,
-  // this will return nullptr.
-  //
-  // NOTE: You must not call this MessageLoop's Quit method directly.  Use
-  // the Thread's Stop method instead.
-  //
-  // In addition to this Thread's owning sequence, this can also safely be
-  // called from the underlying thread itself.
-  MessageLoop* message_loop() const {
-    // This class doesn't provide synchronization around |message_loop_| and as
-    // such only the owner should access it (and the underlying thread which
-    // never sees it before it's set). In practice, many callers are coming from
-    // unrelated threads but provide their own implicit (e.g. memory barriers
-    // from task posting) or explicit (e.g. locks) synchronization making the
-    // access of |message_loop_| safe... Changing all of those callers is
-    // unfeasible; instead verify that they can reliably see
-    // |message_loop_ != nullptr| without synchronization as a proof that their
-    // external synchronization catches the unsynchronized effects of Start().
-    // TODO(gab): Despite all of the above this test has to be disabled for now
-    // per crbug.com/629139#c6.
-    // DCHECK(owning_sequence_checker_.CalledOnValidSequence() ||
-    //        (id_event_.IsSignaled() && id_ == PlatformThread::CurrentId()) ||
-    //        message_loop_);
-    return message_loop_;
-  }
-
   // Returns a TaskRunner for this thread. Use the TaskRunner's PostTask
   // methods to execute code on the thread. Returns nullptr if the thread is not
   // running (e.g. before Start or after Stop have been called). Callers can
@@ -238,7 +211,15 @@
   // In addition to this Thread's owning sequence, this can also safely be
   // called from the underlying thread itself.
   scoped_refptr<SingleThreadTaskRunner> task_runner() const {
-    // Refer to the DCHECK and comment inside |message_loop()|.
+    // This class doesn't provide synchronization around |message_loop_| and as
+    // such only the owner should access it (and the underlying thread which
+    // never sees it before it's set). In practice, many callers are coming from
+    // unrelated threads but provide their own implicit (e.g. memory barriers
+    // from task posting) or explicit (e.g. locks) synchronization making the
+    // access of |message_loop_| safe... Changing all of those callers is
+    // unfeasible; instead verify that they can reliably see
+    // |message_loop_ != nullptr| without synchronization as a proof that their
+    // external synchronization catches the unsynchronized effects of Start().
     DCHECK(owning_sequence_checker_.CalledOnValidSequence() ||
            (id_event_.IsSignaled() && id_ == PlatformThread::CurrentId()) ||
            message_loop_);
@@ -283,7 +264,29 @@
     return using_external_message_loop_;
   }
 
+  // Returns the message loop for this thread.  Use the MessageLoop's
+  // PostTask methods to execute code on the thread.  This only returns
+  // non-null after a successful call to Start.  After Stop has been called,
+  // this will return nullptr.
+  //
+  // NOTE: You must not call this MessageLoop's Quit method directly.  Use
+  // the Thread's Stop method instead.
+  //
+  // In addition to this Thread's owning sequence, this can also safely be
+  // called from the underlying thread itself.
+  MessageLoop* message_loop() const {
+    // See the comment inside |task_runner()|.
+    DCHECK(owning_sequence_checker_.CalledOnValidSequence() ||
+           (id_event_.IsSignaled() && id_ == PlatformThread::CurrentId()) ||
+           message_loop_);
+    return message_loop_;
+  }
+
  private:
+  // Friends for message_loop() access:
+  friend class MessageLoopTaskRunnerTest;
+  friend class ScheduleWorkTest;
+
 #if defined(OS_WIN)
   enum ComStatus {
     NONE,
diff --git a/base/threading/thread_perftest.cc b/base/threading/thread_perftest.cc
index 82701aec..ead2d2b5 100644
--- a/base/threading/thread_perftest.cc
+++ b/base/threading/thread_perftest.cc
@@ -162,10 +162,12 @@
   void Init() override {
     TaskPerfTest::Init();
     for (auto& i : threads_) {
-      i->message_loop()->task_runner()->PostTask(
-          FROM_HERE,
-          BindOnce(&MessageLoop::AddTaskObserver, Unretained(i->message_loop()),
-                   Unretained(&message_loop_observer)));
+      i->task_runner()->PostTask(
+          FROM_HERE, BindOnce(
+                         [](MessageLoopObserver* observer) {
+                           MessageLoopCurrent::Get()->AddTaskObserver(observer);
+                         },
+                         Unretained(&message_loop_observer)));
     }
   }
 };
diff --git a/base/threading/thread_unittest.cc b/base/threading/thread_unittest.cc
index d90b1f9e..4414585 100644
--- a/base/threading/thread_unittest.cc
+++ b/base/threading/thread_unittest.cc
@@ -14,8 +14,6 @@
 #include "base/debug/leak_annotations.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
-#include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_current.h"
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
 #include "base/synchronization/waitable_event.h"
@@ -152,7 +150,7 @@
   options.stack_size = 3072 * sizeof(uintptr_t);
 #endif
   EXPECT_TRUE(a.StartWithOptions(options));
-  EXPECT_TRUE(a.message_loop());
+  EXPECT_TRUE(a.task_runner());
   EXPECT_TRUE(a.IsRunning());
 
   base::WaitableEvent event(base::WaitableEvent::ResetPolicy::AUTOMATIC,
@@ -175,7 +173,7 @@
   Thread::Options options;
   options.joinable = false;
   EXPECT_TRUE(a->StartWithOptions(options));
-  EXPECT_TRUE(a->message_loop());
+  EXPECT_TRUE(a->task_runner());
   EXPECT_TRUE(a->IsRunning());
 
   // Without this call this test is racy. The above IsRunning() succeeds because
@@ -212,7 +210,7 @@
   {
     Thread a("TwoTasksOnJoinableThread");
     EXPECT_TRUE(a.Start());
-    EXPECT_TRUE(a.message_loop());
+    EXPECT_TRUE(a.task_runner());
 
     // Test that all events are dispatched before the Thread object is
     // destroyed.  We do this by dispatching a sleep event before the
@@ -252,18 +250,18 @@
 TEST_F(ThreadTest, StopSoon) {
   Thread a("StopSoon");
   EXPECT_TRUE(a.Start());
-  EXPECT_TRUE(a.message_loop());
+  EXPECT_TRUE(a.task_runner());
   EXPECT_TRUE(a.IsRunning());
   a.StopSoon();
   a.Stop();
-  EXPECT_FALSE(a.message_loop());
+  EXPECT_FALSE(a.task_runner());
   EXPECT_FALSE(a.IsRunning());
 }
 
 TEST_F(ThreadTest, StopTwiceNop) {
   Thread a("StopTwiceNop");
   EXPECT_TRUE(a.Start());
-  EXPECT_TRUE(a.message_loop());
+  EXPECT_TRUE(a.task_runner());
   EXPECT_TRUE(a.IsRunning());
   a.StopSoon();
   // Calling StopSoon() a second time should be a nop.
@@ -271,7 +269,7 @@
   a.Stop();
   // Same with Stop().
   a.Stop();
-  EXPECT_FALSE(a.message_loop());
+  EXPECT_FALSE(a.task_runner());
   EXPECT_FALSE(a.IsRunning());
   // Calling them when not running should also nop.
   a.StopSoon();
@@ -324,23 +322,23 @@
 TEST_F(ThreadTest, StartTwice) {
   Thread a("StartTwice");
 
-  EXPECT_FALSE(a.message_loop());
+  EXPECT_FALSE(a.task_runner());
   EXPECT_FALSE(a.IsRunning());
 
   EXPECT_TRUE(a.Start());
-  EXPECT_TRUE(a.message_loop());
+  EXPECT_TRUE(a.task_runner());
   EXPECT_TRUE(a.IsRunning());
 
   a.Stop();
-  EXPECT_FALSE(a.message_loop());
+  EXPECT_FALSE(a.task_runner());
   EXPECT_FALSE(a.IsRunning());
 
   EXPECT_TRUE(a.Start());
-  EXPECT_TRUE(a.message_loop());
+  EXPECT_TRUE(a.task_runner());
   EXPECT_TRUE(a.IsRunning());
 
   a.Stop();
-  EXPECT_FALSE(a.message_loop());
+  EXPECT_FALSE(a.task_runner());
   EXPECT_FALSE(a.IsRunning());
 }
 
@@ -357,7 +355,7 @@
   Thread::Options options;
   options.joinable = false;
   EXPECT_TRUE(a->StartWithOptions(options));
-  EXPECT_TRUE(a->message_loop());
+  EXPECT_TRUE(a->task_runner());
   EXPECT_TRUE(a->IsRunning());
 
   // Signaled when last task on |a| is processed.
@@ -456,7 +454,7 @@
     // Start a thread which writes its event into |captured_events|.
     CaptureToEventList t(&captured_events);
     EXPECT_TRUE(t.Start());
-    EXPECT_TRUE(t.message_loop());
+    EXPECT_TRUE(t.task_runner());
     EXPECT_TRUE(t.IsRunning());
 
     // Register an observer that writes into |captured_events| once the
@@ -552,12 +550,12 @@
 
 TEST_F(ThreadTest, ExternalMessageLoop) {
   ExternalMessageLoopThread a;
-  EXPECT_FALSE(a.message_loop());
+  EXPECT_FALSE(a.task_runner());
   EXPECT_FALSE(a.IsRunning());
   a.VerifyUsingExternalMessageLoop(false);
 
   a.InstallMessageLoop();
-  EXPECT_TRUE(a.message_loop());
+  EXPECT_TRUE(a.task_runner());
   EXPECT_TRUE(a.IsRunning());
   a.VerifyUsingExternalMessageLoop(true);
 
@@ -568,7 +566,7 @@
   EXPECT_TRUE(ran);
 
   a.Stop();
-  EXPECT_FALSE(a.message_loop());
+  EXPECT_FALSE(a.task_runner());
   EXPECT_FALSE(a.IsRunning());
   a.VerifyUsingExternalMessageLoop(true);
 
diff --git a/build/android/pylib/local/device/local_device_test_run.py b/build/android/pylib/local/device/local_device_test_run.py
index d76e363e..26d6d07a 100644
--- a/build/android/pylib/local/device/local_device_test_run.py
+++ b/build/android/pylib/local/device/local_device_test_run.py
@@ -113,7 +113,7 @@
       raise TestsTerminated()
 
     try:
-      with signal_handler.SignalHandler(signal.SIGTERM, stop_tests):
+      with signal_handler.AddSignalHandler(signal.SIGTERM, stop_tests):
         tries = 0
         while tries < self._env.max_tries and tests:
           logging.info('STARTING TRY #%d/%d', tries + 1, self._env.max_tries)
diff --git a/build/config/chromeos/rules.gni b/build/config/chromeos/rules.gni
index ef0e5060..cdeff167 100644
--- a/build/config/chromeos/rules.gni
+++ b/build/config/chromeos/rules.gni
@@ -33,7 +33,7 @@
   _cache_path_prefix =
       "//build/cros_cache/chrome-sdk/tarballs/${cros_board}+${cros_sdk_version}"
   _vm_image_path = "${_cache_path_prefix}+chromiumos_qemu_image.tar.xz/"
-  _qemu_dir = "${_cache_path_prefix}+qemu/"
+  _qemu_dir = "${_cache_path_prefix}+app-emulation/"
 
   forward_variables_from(invoker,
                          [
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index 2ff94137..b78f400 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-b50dfdfe8d6d893ea58526a56950d904ea0c9a26
\ No newline at end of file
+242ed66dfc5ab2d055fa02add2819868218894c4
\ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index cefe895..3a4fa3e 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-87575d6a191bf4f9e7c13d62f8b283de157aeaf7
\ No newline at end of file
+5f420e42a37265d7e2f2b4aeba299f4753fb20d1
\ No newline at end of file
diff --git a/cc/test/DEPS b/cc/test/DEPS
index 006cc4c6..7be9056 100644
--- a/cc/test/DEPS
+++ b/cc/test/DEPS
@@ -8,6 +8,7 @@
   "+gpu/command_buffer/common/context_creation_attribs.h",
   "+gpu/command_buffer/common/skia_utils.h",
   "+gpu/command_buffer/service/image_factory.h",
+  "+gpu/config/gpu_feature_type.h",
   "+gpu/config/gpu_info.h",
   "+gpu/ipc",
   "+gpu/skia_bindings/grcontext_for_gles2_interface.h",
diff --git a/cc/test/pixel_test.cc b/cc/test/pixel_test.cc
index 9fe3b51..000060d 100644
--- a/cc/test/pixel_test.cc
+++ b/cc/test/pixel_test.cc
@@ -10,6 +10,7 @@
 #include "base/memory/shared_memory.h"
 #include "base/path_service.h"
 #include "base/run_loop.h"
+#include "base/test/scoped_feature_list.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "cc/base/switches.h"
 #include "cc/raster/raster_buffer_provider.h"
@@ -37,6 +38,7 @@
 #include "components/viz/test/test_shared_bitmap_manager.h"
 #include "gpu/command_buffer/client/gles2_interface.h"
 #include "gpu/command_buffer/client/shared_memory_limits.h"
+#include "gpu/config/gpu_feature_type.h"
 #include "gpu/config/gpu_info.h"
 #include "gpu/ipc/gpu_in_process_thread_service.h"
 #include "gpu/ipc/service/gpu_memory_buffer_factory.h"
@@ -246,10 +248,16 @@
 
 void PixelTest::SetUpGpuServiceOnGpuThread(base::WaitableEvent* event) {
   ASSERT_TRUE(gpu_thread_->task_runner()->BelongsToCurrentThread());
+  gpu::GpuFeatureInfo gpu_feature_info;
+  // To test SkiaRenderer with DDL, we need enable OOP-R.
+  gpu_feature_info.status_values[gpu::GPU_FEATURE_TYPE_OOP_RASTERIZATION] =
+      gpu::kGpuFeatureStatusEnabled;
   gpu_service_ = std::make_unique<viz::GpuServiceImpl>(
       gpu::GPUInfo(), nullptr /* watchdog_thread */, io_thread_->task_runner(),
-      gpu::GpuFeatureInfo(), gpu::GpuPreferences(), gpu::GPUInfo(),
-      gpu::GpuFeatureInfo(), nullptr /* vulkan_implementation */,
+      gpu_feature_info, gpu::GpuPreferences(),
+      gpu::GPUInfo() /* gpu_info_for_hardware_gpu */,
+      gpu::GpuFeatureInfo() /* gpu_feature_info_for_hardware_gpu */,
+      nullptr /* vulkan_implementation */,
       base::DoNothing() /* exit_callback */);
 
   // Uses a null gpu_host here, because we don't want to receive any message.
@@ -275,6 +283,12 @@
 
 void PixelTest::SetUpSkiaRendererDDL() {
   // Set up the GPU service.
+  const char enable_features[] =
+      "VizDisplayCompositor,UseSkiaRenderer,UseSkiaDeferredDisplayList";
+  const char disable_features[] = "";
+  scoped_feature_list_ = std::make_unique<base::test::ScopedFeatureList>();
+  scoped_feature_list_->InitFromCommandLine(enable_features, disable_features);
+
   gpu_thread_ = std::make_unique<base::Thread>("GPUMainThread");
   ASSERT_TRUE(gpu_thread_->Start());
   io_thread_ = std::make_unique<base::Thread>("GPUIOThread");
@@ -353,6 +367,7 @@
   }
   io_thread_ = nullptr;
   gpu_thread_ = nullptr;
+  scoped_feature_list_ = nullptr;
 }
 
 void PixelTest::EnableExternalStencilTest() {
diff --git a/cc/test/pixel_test.h b/cc/test/pixel_test.h
index 82bf6af..669173f 100644
--- a/cc/test/pixel_test.h
+++ b/cc/test/pixel_test.h
@@ -24,6 +24,9 @@
 
 namespace base {
 class Thread;
+namespace test {
+class ScopedFeatureList;
+}
 }
 
 namespace viz {
@@ -118,6 +121,7 @@
   void TearDownGpuServiceOnGpuThread(base::WaitableEvent* event);
 
   std::unique_ptr<gl::DisableNullDrawGLBindings> enable_pixel_output_;
+  std::unique_ptr<base::test::ScopedFeatureList> scoped_feature_list_;
 };
 
 template<typename RendererType>
diff --git a/cc/test/test_image_factory.cc b/cc/test/test_image_factory.cc
index 3d4b098..37613c4 100644
--- a/cc/test/test_image_factory.cc
+++ b/cc/test/test_image_factory.cc
@@ -7,6 +7,7 @@
 #include <stddef.h>
 
 #include "base/numerics/safe_conversions.h"
+#include "gpu/command_buffer/common/gpu_memory_buffer_support.h"
 #include "ui/gl/gl_image_shared_memory.h"
 
 namespace cc {
@@ -19,11 +20,11 @@
     gfx::GpuMemoryBufferHandle handle,
     const gfx::Size& size,
     gfx::BufferFormat format,
-    unsigned internalformat,
     int client_id,
     gpu::SurfaceHandle surface_handle) {
   DCHECK_EQ(handle.type, gfx::SHARED_MEMORY_BUFFER);
 
+  unsigned internalformat = gpu::InternalFormatForGpuMemoryBufferFormat(format);
   scoped_refptr<gl::GLImageSharedMemory> image(
       new gl::GLImageSharedMemory(size, internalformat));
   if (!image->Initialize(handle.region, handle.id, format, handle.offset,
diff --git a/cc/test/test_image_factory.h b/cc/test/test_image_factory.h
index 45a1f3a5..749c4c7 100644
--- a/cc/test/test_image_factory.h
+++ b/cc/test/test_image_factory.h
@@ -20,7 +20,6 @@
       gfx::GpuMemoryBufferHandle handle,
       const gfx::Size& size,
       gfx::BufferFormat format,
-      unsigned internalformat,
       int client_id,
       gpu::SurfaceHandle surface_handle) override;
 
diff --git a/chrome/android/java/res/layout/main.xml b/chrome/android/java/res/layout/main.xml
index 65af497..98bd76b 100644
--- a/chrome/android/java/res/layout/main.xml
+++ b/chrome/android/java/res/layout/main.xml
@@ -72,9 +72,7 @@
             android:id="@+id/omnibox_results_container_stub"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:layout_marginTop="@dimen/control_container_height"
             app:layout_anchor="@id/control_container"
-            app:layout_anchorGravity="start|bottom"
             android:inflatedId="@+id/omnibox_results_container"
             android:layout="@layout/omnibox_results_container" />
 
diff --git a/chrome/android/java/res/layout/search_activity.xml b/chrome/android/java/res/layout/search_activity.xml
index b53997be..85c7246 100644
--- a/chrome/android/java/res/layout/search_activity.xml
+++ b/chrome/android/java/res/layout/search_activity.xml
@@ -14,9 +14,7 @@
             android:id="@+id/omnibox_results_container_stub"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:layout_marginTop="@dimen/toolbar_height_no_shadow"
             app:layout_anchor="@id/toolbar"
-            app:layout_anchorGravity="start|bottom"
             android:background="@android:color/white"
             android:layout="@layout/omnibox_results_container" />
 
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 ab58aab9..fa73b8362 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
@@ -140,6 +140,7 @@
 import org.chromium.chrome.browser.util.ColorUtils;
 import org.chromium.chrome.browser.util.FeatureUtilities;
 import org.chromium.chrome.browser.util.MathUtils;
+import org.chromium.chrome.browser.vr.ArDelegate;
 import org.chromium.chrome.browser.vr.VrModuleProvider;
 import org.chromium.chrome.browser.webapps.AddToHomescreenManager;
 import org.chromium.chrome.browser.widget.ControlContainer;
@@ -1426,6 +1427,7 @@
 
         VrModuleProvider.maybeInit();
         VrModuleProvider.getDelegate().onNativeLibraryAvailable();
+        ArDelegate.maybeInit();
         if (getSavedInstanceState() == null && getIntent() != null) {
             VrModuleProvider.getDelegate().onNewIntentWithNative(this, getIntent());
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
index fafbf24..c1e8531 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
@@ -172,8 +172,6 @@
     public static final String CCT_REPORT_PARALLEL_REQUEST_STATUS =
             "CCTReportParallelRequestStatus";
     public static final String CHROME_DUET = "ChromeDuet";
-    // TODO(mdjones): Remove CHROME_HOME_SWIPE_VELOCITY_FEATURE or rename.
-    public static final String CHROME_HOME_SWIPE_VELOCITY_FEATURE = "ChromeHomeSwipeLogicVelocity";
     public static final String CHROME_MEMEX = "ChromeMemex";
     public static final String CHROME_SMART_SELECTION = "ChromeSmartSelection";
     public static final String CLEAR_OLD_BROWSING_DATA = "ClearOldBrowsingData";
@@ -217,6 +215,7 @@
     public static final String EXPERIMENTAL_UI = "ExperimentalUi";
     public static final String EXPLICIT_LANGUAGE_ASK = "ExplicitLanguageAsk";
     public static final String EXPLORE_SITES = "ExploreSites";
+    public static final String FCM_INVALIDATIONS = "FCMInvalidations";
     // When enabled, fullscreen WebContents will be moved to a new Activity. Coming soon...
     public static final String FULLSCREEN_ACTIVITY = "FullscreenActivity";
     public static final String GRANT_NOTIFICATIONS_TO_DSE = "GrantNotificationsToDSE";
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeStrictMode.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeStrictMode.java
index cae7bf07..275e241 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeStrictMode.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeStrictMode.java
@@ -15,7 +15,6 @@
 import org.chromium.base.JavaExceptionReporter;
 import org.chromium.base.Log;
 import org.chromium.base.ThreadUtils;
-import org.chromium.base.TraceEvent;
 import org.chromium.base.library_loader.LibraryLoader;
 
 import java.lang.reflect.Field;
@@ -193,11 +192,8 @@
                 (ChromeVersionInfo.isDevBuild() && Math.random() < UPLOAD_PROBABILITY);
         if ((ChromeVersionInfo.isLocalBuild() && !BuildConfig.DCHECK_IS_ON)
                 || enableStrictModeWatch) {
-            try (TraceEvent e =
-                            TraceEvent.scoped("configureStrictMode.initializeStrictModeWatch")) {
-                turnOnDetection(threadPolicy, vmPolicy);
-                initializeStrictModeWatch();
-            }
+            turnOnDetection(threadPolicy, vmPolicy);
+            initializeStrictModeWatch();
         }
 
         StrictMode.setThreadPolicy(threadPolicy.build());
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java b/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java
index 9ecd8c8..4cebced 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/init/ChromeBrowserInitializer.java
@@ -149,21 +149,14 @@
      */
     public void handlePreNativeStartup(final BrowserParts parts) {
         ThreadUtils.checkUiThread();
-        try (TraceEvent e1 =
-                        TraceEvent.scoped("ChromeBrowserInitializer.handlePreNativeStartup()")) {
-            ProcessInitializationHandler.getInstance().initializePreNative();
-            try (TraceEvent e2 =
-                            TraceEvent.scoped("ChromeBrowserInitializer.preInflationStartup")) {
-                preInflationStartup();
-                parts.preInflationStartup();
-            }
-            if (parts.isActivityFinishing()) return;
-            preInflationStartupDone();
-            try (TraceEvent e3 = TraceEvent.scoped(
-                         "ChromeBrowserInitializer.setContentViewAndLoadLibrary")) {
-                parts.setContentViewAndLoadLibrary(() -> this.onInflationComplete(parts));
-            }
+        ProcessInitializationHandler.getInstance().initializePreNative();
+        try (TraceEvent e = TraceEvent.scoped("ChromeBrowserInitializer.preInflationStartup")) {
+            preInflationStartup();
+            parts.preInflationStartup();
         }
+        if (parts.isActivityFinishing()) return;
+        preInflationStartupDone();
+        parts.setContentViewAndLoadLibrary(() -> this.onInflationComplete(parts));
     }
 
     /**
@@ -196,25 +189,23 @@
      * Running in an AsyncTask as pre-loading itself may cause I/O.
      */
     private void warmUpSharedPrefs() {
-        try (TraceEvent e = TraceEvent.scoped("ChromeBrowserInitializer.warmUpSharedPrefs")) {
-            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
-                new AsyncTask<Void>() {
-                    @Override
-                    protected Void doInBackground() {
-                        ContextUtils.getAppSharedPreferences();
-                        DocumentTabModelImpl.warmUpSharedPrefs(mApplication);
-                        ActivityAssigner.warmUpSharedPrefs(mApplication);
-                        DownloadManagerService.warmUpSharedPrefs();
-                        return null;
-                    }
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+            new AsyncTask<Void>() {
+                @Override
+                protected Void doInBackground() {
+                    ContextUtils.getAppSharedPreferences();
+                    DocumentTabModelImpl.warmUpSharedPrefs(mApplication);
+                    ActivityAssigner.warmUpSharedPrefs(mApplication);
+                    DownloadManagerService.warmUpSharedPrefs();
+                    return null;
                 }
-                        .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
-            } else {
-                ContextUtils.getAppSharedPreferences();
-                DocumentTabModelImpl.warmUpSharedPrefs(mApplication);
-                ActivityAssigner.warmUpSharedPrefs(mApplication);
-                DownloadManagerService.warmUpSharedPrefs();
             }
+                    .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+        } else {
+            ContextUtils.getAppSharedPreferences();
+            DocumentTabModelImpl.warmUpSharedPrefs(mApplication);
+            ActivityAssigner.warmUpSharedPrefs(mApplication);
+            DownloadManagerService.warmUpSharedPrefs();
         }
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/invalidation/ChromeInvalidationClientService.java b/chrome/android/java/src/org/chromium/chrome/browser/invalidation/ChromeInvalidationClientService.java
index b03d5cef..07a0ffe 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/invalidation/ChromeInvalidationClientService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/invalidation/ChromeInvalidationClientService.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser.invalidation;
 
+import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.init.ProcessInitializationHandler;
 import org.chromium.components.invalidation.InvalidationClientService;
 
@@ -15,6 +16,10 @@
     @Override
     public void onCreate() {
         ProcessInitializationHandler.getInstance().initializePreNative();
+        boolean isFCMInvalidationsEnabled = ChromeFeatureList.isInitialized()
+                ? ChromeFeatureList.isEnabled(ChromeFeatureList.FCM_INVALIDATIONS)
+                : false;
+        super.setShouldCreateService(isFCMInvalidationsEnabled);
         super.onCreate();
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omaha/UpdateMenuItemHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/omaha/UpdateMenuItemHelper.java
index 30824b39..8193d73 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omaha/UpdateMenuItemHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omaha/UpdateMenuItemHelper.java
@@ -150,6 +150,8 @@
         switch (getUpdateType()) {
             case UpdateType.UPDATE_AVAILABLE:
                 title.setText(context.getString(R.string.menu_update));
+                // See crbug.com/899695 for why this line is necessary.
+                title.setContentDescription(context.getString(R.string.menu_update));
                 title.setTextColor(Color.RED);
 
                 String customSummary = getStringParamValue(CUSTOM_SUMMARY);
@@ -164,6 +166,8 @@
                 break;
             case UpdateType.UNSUPPORTED_OS_VERSION:
                 title.setText(R.string.menu_update_unsupported);
+                // See crbug.com/899695 for why this line is necessary.
+                title.setContentDescription(context.getString(R.string.menu_update_unsupported));
                 title.setTextColor(ApiCompatibilityUtils.getColor(
                         context.getResources(), R.color.default_text_color));
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/OmniboxSuggestionsList.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/OmniboxSuggestionsList.java
index 6cdd9a66..de6cd72 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/OmniboxSuggestionsList.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/OmniboxSuggestionsList.java
@@ -12,6 +12,9 @@
 import android.support.annotation.Nullable;
 import android.support.v4.view.ViewCompat;
 import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewParent;
+import android.view.ViewTreeObserver.OnGlobalLayoutListener;
 import android.widget.ListView;
 
 import org.chromium.base.VisibleForTesting;
@@ -36,6 +39,9 @@
     private final int[] mTempPosition = new int[2];
     private final Rect mTempRect = new Rect();
 
+    private final OnGlobalLayoutListener mAnchorViewLayoutListener;
+    private final OnLayoutChangeListener mAlignmentViewLayoutListener;
+
     /**
      * Provides the capabilities required to embed the omnibox suggestion list into the UI.
      */
@@ -81,16 +87,40 @@
         refreshPopupBackground();
 
         mAnchorView = mEmbedder.getAnchorView();
+        // Prior to Android M, the contextual actions associated with the omnibox were anchored to
+        // the top of the screen and not a floating copy/paste menu like on newer versions.  As a
+        // result of this, the toolbar is pushed down in these Android versions and we need to
+        // montior those changes to update the positioning of the list.
+        mAnchorViewLayoutListener = new OnGlobalLayoutListener() {
+            private int mOffsetInWindow;
+
+            @Override
+            public void onGlobalLayout() {
+                int offsetInWindow = 0;
+                View currentView = mAnchorView;
+                while (true) {
+                    offsetInWindow += currentView.getTop();
+                    ViewParent parent = currentView.getParent();
+                    if (parent == null || !(parent instanceof View)) break;
+                    currentView = (View) parent;
+                }
+                if (mOffsetInWindow == offsetInWindow) return;
+                mOffsetInWindow = offsetInWindow;
+                requestLayout();
+            }
+        };
+
         mAlignmentView = mEmbedder.getAlignmentView();
         if (mAlignmentView != null) {
-            adjustSidePadding();
-            mAlignmentView.addOnLayoutChangeListener(new OnLayoutChangeListener() {
+            mAlignmentViewLayoutListener = new OnLayoutChangeListener() {
                 @Override
                 public void onLayoutChange(View v, int left, int top, int right, int bottom,
                         int oldLeft, int oldTop, int oldRight, int oldBottom) {
                     adjustSidePadding();
                 }
-            });
+            };
+        } else {
+            mAlignmentViewLayoutListener = null;
         }
     }
 
@@ -163,6 +193,12 @@
         int anchorY = mTempPosition[1];
         int anchorBottomRelativeToContent = anchorY + mAnchorView.getMeasuredHeight();
 
+        // Update the layout params to ensure the parent correctly positions the suggestions under
+        // the anchor view.
+        ViewGroup.LayoutParams layoutParams = getLayoutParams();
+        if (layoutParams != null && layoutParams instanceof MarginLayoutParams) {
+            ((MarginLayoutParams) layoutParams).topMargin = anchorBottomRelativeToContent;
+        }
         mEmbedder.getWindowDelegate().getWindowVisibleDisplayFrame(mTempRect);
         int availableViewportHeight = mTempRect.height() - anchorBottomRelativeToContent;
         super.onMeasure(
@@ -195,10 +231,24 @@
     }
 
     @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        mAnchorView.getViewTreeObserver().addOnGlobalLayoutListener(mAnchorViewLayoutListener);
+        if (mAlignmentView != null) {
+            adjustSidePadding();
+            mAlignmentView.addOnLayoutChangeListener(mAlignmentViewLayoutListener);
+        }
+    }
+
+    @Override
     protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
         // Ensure none of the views are reused when re-attaching as the TextViews in the suggestions
         // do not handle it in all cases.  https://crbug.com/851839
         reclaimViews(new ArrayList<>());
+        mAnchorView.getViewTreeObserver().removeOnGlobalLayoutListener(mAnchorViewLayoutListener);
+        if (mAlignmentView != null) {
+            mAlignmentView.removeOnLayoutChangeListener(mAlignmentViewLayoutListener);
+        }
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
index b8439da..3a2a702f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
@@ -1063,7 +1063,7 @@
     /**
      * @return The current {@link ConnectionSecurityLevel} for the tab.
      */
-    // TODO(tedchoc): Remove this and transition all clients to use ToolbarModel directly.
+    // TODO(tedchoc): Remove this and transition all clients to use LocationBarModel directly.
     public int getSecurityLevel() {
         return SecurityStateModel.getSecurityLevelForWebContents(getWebContents());
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarModel.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/LocationBarModel.java
similarity index 94%
rename from chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarModel.java
rename to chrome/android/java/src/org/chromium/chrome/browser/toolbar/LocationBarModel.java
index 4068d96..5ac5242 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarModel.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/LocationBarModel.java
@@ -44,7 +44,7 @@
 /**
  * Provides a way of accessing toolbar data and state.
  */
-public class ToolbarModel implements ToolbarDataProvider {
+public class LocationBarModel implements ToolbarDataProvider {
     private final Context mContext;
 
     private Tab mTab;
@@ -52,13 +52,13 @@
     private int mPrimaryColor;
     private boolean mIsUsingBrandColor;
 
-    private long mNativeToolbarModelAndroid;
+    private long mNativeLocationBarModelAndroid;
 
     /**
      * Default constructor for this class.
      * @param context The Context used for styling the toolbar visuals.
      */
-    public ToolbarModel(Context context) {
+    public LocationBarModel(Context context) {
         mContext = context;
         mPrimaryColor = ColorUtils.getDefaultThemeColor(context.getResources(), false);
     }
@@ -67,16 +67,16 @@
      * Handle any initialization that must occur after native has been initialized.
      */
     public void initializeWithNative() {
-        mNativeToolbarModelAndroid = nativeInit();
+        mNativeLocationBarModelAndroid = nativeInit();
     }
 
     /**
-     * Destroys the native ToolbarModel.
+     * Destroys the native LocationBarModel.
      */
     public void destroy() {
-        if (mNativeToolbarModelAndroid == 0) return;
-        nativeDestroy(mNativeToolbarModelAndroid);
-        mNativeToolbarModelAndroid = 0;
+        if (mNativeLocationBarModelAndroid == 0) return;
+        nativeDestroy(mNativeLocationBarModelAndroid);
+        mNativeLocationBarModelAndroid = 0;
     }
 
     /**
@@ -205,7 +205,7 @@
     private UrlBarData buildUrlBarData(String url, String displayText, String editingText) {
         SpannableStringBuilder spannableDisplayText = new SpannableStringBuilder(displayText);
 
-        if (mNativeToolbarModelAndroid != 0 && spannableDisplayText.length() > 0
+        if (mNativeLocationBarModelAndroid != 0 && spannableDisplayText.length() > 0
                 && shouldEmphasizeUrl()) {
             boolean isInternalPage = false;
             try {
@@ -456,18 +456,18 @@
 
     /** @return The formatted URL suitable for editing. */
     public String getFormattedFullUrl() {
-        if (mNativeToolbarModelAndroid == 0) return "";
-        return nativeGetFormattedFullURL(mNativeToolbarModelAndroid);
+        if (mNativeLocationBarModelAndroid == 0) return "";
+        return nativeGetFormattedFullURL(mNativeLocationBarModelAndroid);
     }
 
     /** @return The formatted URL suitable for display only. */
     public String getUrlForDisplay() {
-        if (mNativeToolbarModelAndroid == 0) return "";
-        return nativeGetURLForDisplay(mNativeToolbarModelAndroid);
+        if (mNativeLocationBarModelAndroid == 0) return "";
+        return nativeGetURLForDisplay(mNativeLocationBarModelAndroid);
     }
 
     private native long nativeInit();
-    private native void nativeDestroy(long nativeToolbarModelAndroid);
-    private native String nativeGetFormattedFullURL(long nativeToolbarModelAndroid);
-    private native String nativeGetURLForDisplay(long nativeToolbarModelAndroid);
+    private native void nativeDestroy(long nativeLocationBarModelAndroid);
+    private native String nativeGetFormattedFullURL(long nativeLocationBarModelAndroid);
+    private native String nativeGetURLForDisplay(long nativeLocationBarModelAndroid);
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/MenuButton.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/MenuButton.java
index 70d37a76..b92fde65 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/MenuButton.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/MenuButton.java
@@ -70,6 +70,7 @@
             case UpdateMenuItemHelper.UpdateType.UNSUPPORTED_OS_VERSION:
                 mUpdateBadgeView.setVisibility(visible ? View.VISIBLE : View.GONE);
                 updateImageResources();
+                updateContentDescription(visible);
                 break;
             case UpdateMenuItemHelper.UpdateType.NONE:
             // Intentional fall through.
@@ -77,6 +78,7 @@
             // Intentional fall through.
             default:
                 mUpdateBadgeView.setVisibility(View.GONE);
+                updateContentDescription(false);
                 break;
         }
     }
@@ -110,8 +112,12 @@
         return mUpdateBadgeView.getVisibility() == View.VISIBLE;
     }
 
-    void updateContentDescription() {
-        if (isShowingAppMenuUpdateBadge()) {
+    /**
+     * Sets the content description for the menu button.
+     * @param isUpdateBadgeVisible Whether the update menu badge is visible.
+     */
+    void updateContentDescription(boolean isUpdateBadgeVisible) {
+        if (isUpdateBadgeVisible) {
             switch (UpdateMenuItemHelper.getInstance().getUpdateType()) {
                 case UpdateMenuItemHelper.UpdateType.UPDATE_AVAILABLE:
                     setContentDescription(getResources().getString(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarLayout.java
index aaaeeef4..a2595ae 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarLayout.java
@@ -398,7 +398,7 @@
      * {@link org.chromium.chrome.browser.widget.findinpage.FindToolbar} state changes.
      * @param showing Whether or not the {@code FindToolbar} will be showing.
      */
-    protected void handleFindToolbarStateChange(boolean showing) {
+    protected void handleFindLocationBarStateChange(boolean showing) {
         mFindInPageToolbarShowing = showing;
     }
 
@@ -826,7 +826,7 @@
         if (mMenuBadge == null) return;
         boolean wasShowingMenuBadge = mShowMenuBadge;
         mShowMenuBadge = false;
-        setMenuButtonContentDescription();
+        setMenuButtonContentDescription(false);
 
         if (!animate || !wasShowingMenuBadge) {
             mMenuButtonWrapper.setUpdateBadgeVisibilityIfValidState(false);
@@ -890,7 +890,7 @@
      */
     protected void setAppMenuUpdateBadgeToVisible(boolean animate) {
         if (mMenuBadge == null || mMenuButton == null || mMenuButtonWrapper == null) return;
-        setMenuButtonContentDescription();
+        setMenuButtonContentDescription(true);
         if (!animate || mIsMenuBadgeAnimationRunning) {
             mMenuButtonWrapper.setUpdateBadgeVisibilityIfValidState(true);
             return;
@@ -964,10 +964,11 @@
 
     /**
      * Sets the content description for the menu button.
+     * @param isUpdateBadgeVisible Whether the update menu badge is visible
      */
-    protected void setMenuButtonContentDescription() {
+    protected void setMenuButtonContentDescription(boolean isUpdateBadgeVisible) {
         if (mMenuButtonWrapper == null) return;
-        mMenuButtonWrapper.updateContentDescription();
+        mMenuButtonWrapper.updateContentDescription(isUpdateBadgeVisible);
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
index 8c52c16..83cb5232 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
@@ -172,7 +172,7 @@
     private TabModelSelectorObserver mTabModelSelectorObserver;
     private TabModelObserver mTabModelObserver;
     private MenuDelegatePhone mMenuDelegatePhone;
-    private final ToolbarModel mToolbarModel;
+    private final LocationBarModel mLocationBarModel;
     private Profile mCurrentProfile;
     private BookmarkBridge mBookmarkBridge;
     private TemplateUrlServiceObserver mTemplateUrlObserver;
@@ -242,7 +242,7 @@
         mActivity = activity;
         mActionBarDelegate = new ViewShiftingActionBarDelegate(activity, controlContainer);
 
-        mToolbarModel = new ToolbarModel(activity);
+        mLocationBarModel = new LocationBarModel(activity);
         mControlContainer = controlContainer;
         assert mControlContainer != null;
         mUrlFocusChangedCallback = urlFocusChangedCallback;
@@ -275,7 +275,7 @@
         toolbar.setPaintInvalidator(invalidator);
         mActionModeController.setTabStripHeight(toolbar.getTabStripHeight());
         mLocationBar = mToolbar.getLocationBar();
-        mLocationBar.setToolbarDataProvider(mToolbarModel);
+        mLocationBar.setToolbarDataProvider(mLocationBarModel);
         mLocationBar.addUrlFocusChangeListener(this);
         mLocationBar.setDefaultTextEditActionModeCallback(
                 mActionModeController.getActionModeCallback());
@@ -283,7 +283,7 @@
                 new WindowDelegate(mActivity.getWindow()), mActivity.getWindowAndroid());
 
         setMenuHandler(menuHandler);
-        toolbar.initialize(mToolbarModel, this, mAppMenuButtonHelper);
+        toolbar.initialize(mLocationBarModel, this, mAppMenuButtonHelper);
 
         mAppMenuPropertiesDelegate = appMenuPropertiesDelegate;
 
@@ -355,9 +355,9 @@
         mTabObserver = new EmptyTabObserver() {
             @Override
             public void onSSLStateUpdated(Tab tab) {
-                if (mToolbarModel.getTab() == null) return;
+                if (mLocationBarModel.getTab() == null) return;
 
-                assert tab == mToolbarModel.getTab();
+                assert tab == mLocationBarModel.getTab();
                 QueryInOmnibox.setIgnoreSecurityLevelForSearchTerms(tab.getProfile(), false);
                 mLocationBar.updateSecurityIcon();
                 mLocationBar.setUrlToPageUrl();
@@ -481,7 +481,7 @@
 
             @Override
             public void onLoadUrl(Tab tab, LoadUrlParams params, int loadType) {
-                NewTabPage ntp = mToolbarModel.getNewTabPageForCurrentTab();
+                NewTabPage ntp = mLocationBarModel.getNewTabPageForCurrentTab();
                 if (ntp == null) return;
                 if (!NewTabPage.isNTPUrl(params.getUrl())
                         && loadType != TabLoadStatus.PAGE_LOAD_FAILED) {
@@ -571,7 +571,7 @@
                 // If the load failed due to a different navigation, there is no need to reset the
                 // location bar animations.
                 if (errorCode != 0 && isInMainFrame && !hasPendingNonNtpNavigation(tab)) {
-                    NewTabPage ntp = mToolbarModel.getNewTabPageForCurrentTab();
+                    NewTabPage ntp = mLocationBarModel.getNewTabPageForCurrentTab();
                     if (ntp == null) return;
 
                     ntp.setUrlFocusAnimationsDisabled(false);
@@ -582,7 +582,7 @@
 
             @Override
             public void onNavigationEntriesDeleted(Tab tab) {
-                if (tab == mToolbarModel.getTab()) {
+                if (tab == mLocationBarModel.getTab()) {
                     updateButtonStatus();
                 }
             }
@@ -623,7 +623,7 @@
         mFindToolbarObserver = new FindToolbarObserver() {
             @Override
             public void onFindToolbarShown() {
-                mToolbar.handleFindToolbarStateChange(true);
+                mToolbar.handleFindLocationBarStateChange(true);
                 if (mControlsVisibilityDelegate != null) {
                     mFullscreenFindInPageToken =
                             mControlsVisibilityDelegate.showControlsPersistentAndClearOldToken(
@@ -633,7 +633,7 @@
 
             @Override
             public void onFindToolbarHidden() {
-                mToolbar.handleFindToolbarStateChange(false);
+                mToolbar.handleFindLocationBarStateChange(false);
                 if (mControlsVisibilityDelegate != null) {
                     mControlsVisibilityDelegate.releasePersistentShowingToken(
                             mFullscreenFindInPageToken);
@@ -907,7 +907,7 @@
                 }
             });
 
-            mToolbarModel.initializeWithNative();
+            mLocationBarModel.initializeWithNative();
 
             mFindToolbarManager = findToolbarManager;
 
@@ -1029,9 +1029,9 @@
         return mBookmarkBridge;
     }
 
-    /** Return the toolbar model for testing purposes. */
-    public ToolbarModel getToolbarModelForTesting() {
-        return mToolbarModel;
+    /** Return the location bar model for testing purposes. */
+    public LocationBarModel getLocationBarModelForTesting() {
+        return mLocationBarModel;
     }
 
     /**
@@ -1163,11 +1163,11 @@
         }
 
         if (mTabObserver != null) {
-            Tab currentTab = mToolbarModel.getTab();
+            Tab currentTab = mLocationBarModel.getTab();
             if (currentTab != null) currentTab.removeObserver(mTabObserver);
             mTabObserver = null;
         }
-        mToolbarModel.destroy();
+        mLocationBarModel.destroy();
         mHandler.removeCallbacksAndMessages(null); // Cancel delayed tasks.
     }
 
@@ -1326,7 +1326,7 @@
 
     @Override
     public boolean back() {
-        Tab tab = mToolbarModel.getTab();
+        Tab tab = mLocationBarModel.getTab();
         if (tab != null && tab.canGoBack()) {
             tab.goBack();
             updateButtonStatus();
@@ -1337,7 +1337,7 @@
 
     @Override
     public boolean forward() {
-        Tab tab = mToolbarModel.getTab();
+        Tab tab = mLocationBarModel.getTab();
         if (tab != null && tab.canGoForward()) {
             tab.goForward();
             updateButtonStatus();
@@ -1348,7 +1348,7 @@
 
     @Override
     public void stopOrReloadCurrentTab() {
-        Tab currentTab = mToolbarModel.getTab();
+        Tab currentTab = mLocationBarModel.getTab();
         if (currentTab != null) {
             if (currentTab.isLoading()) {
                 currentTab.stopLoading();
@@ -1365,7 +1365,7 @@
     public void openHomepage() {
         RecordUserAction.record("Home");
 
-        Tab currentTab = mToolbarModel.getTab();
+        Tab currentTab = mLocationBarModel.getTab();
         if (currentTab == null) return;
         String homePageUrl = HomepageManager.getHomepageUri();
         boolean isNewTabPageButtonEnabled = FeatureUtilities.isNewTabPageButtonEnabled();
@@ -1434,7 +1434,7 @@
         if (!colorChanged) return;
 
         mCurrentThemeColor = color;
-        mToolbarModel.setPrimaryColor(color);
+        mLocationBarModel.setPrimaryColor(color);
         mToolbarProvider.whenLoaded((toolbar) -> toolbar.onPrimaryColorChanged(shouldAnimate));
     }
 
@@ -1458,7 +1458,7 @@
      * @return The primary toolbar color.
      */
     public int getPrimaryColor() {
-        return mToolbarModel.getPrimaryColor();
+        return mLocationBarModel.getPrimaryColor();
     }
 
     /**
@@ -1571,7 +1571,7 @@
      */
     private void updateButtonStatus() {
         assert mToolbar != null;
-        Tab currentTab = mToolbarModel.getTab();
+        Tab currentTab = mLocationBarModel.getTab();
         boolean tabCrashed = currentTab != null && SadTab.isShowing(currentTab);
 
         mToolbar.updateButtonVisibility();
@@ -1586,7 +1586,7 @@
 
     private void updateBookmarkButtonStatus() {
         assert mToolbar != null;
-        Tab currentTab = mToolbarModel.getTab();
+        Tab currentTab = mLocationBarModel.getTab();
         boolean isBookmarked = currentTab != null
                 && currentTab.getBookmarkId() != Tab.INVALID_BOOKMARK_ID;
         boolean editingAllowed = currentTab == null || mBookmarkBridge == null
@@ -1596,7 +1596,7 @@
 
     private void updateReloadState(boolean tabCrashed) {
         assert mToolbar != null;
-        Tab currentTab = mToolbarModel.getTab();
+        Tab currentTab = mLocationBarModel.getTab();
         boolean isLoading = false;
         if (!tabCrashed) {
             isLoading = (currentTab != null && currentTab.isLoading()) || !mNativeLibraryReady;
@@ -1616,12 +1616,12 @@
         }
         if (tab == null) tab = mTabModelSelector.getCurrentTab();
 
-        boolean wasIncognito = mToolbarModel.isIncognito();
-        Tab previousTab = mToolbarModel.getTab();
+        boolean wasIncognito = mLocationBarModel.isIncognito();
+        Tab previousTab = mLocationBarModel.getTab();
 
         boolean isIncognito =
                 tab != null ? tab.isIncognito() : mTabModelSelector.isIncognitoSelected();
-        mToolbarModel.setTab(tab, isIncognito);
+        mLocationBarModel.setTab(tab, isIncognito);
 
         updateCurrentTabDisplayStatus();
 
@@ -1684,7 +1684,7 @@
     private void updateCurrentTabDisplayStatus() {
         assert mToolbar != null;
 
-        Tab tab = mToolbarModel.getTab();
+        Tab tab = mLocationBarModel.getTab();
         mLocationBar.setUrlToPageUrl();
 
         updateTabLoadingState(true);
@@ -1720,7 +1720,7 @@
         // the value.
         // TODO(kkimlabs): Investigate back/forward navigation with native page & web content and
         //                 figure out the correct progress bar presentation.
-        Tab tab = mToolbarModel.getTab();
+        Tab tab = mLocationBarModel.getTab();
         if (tab == null || NativePageFactory.isNativePageUrl(tab.getUrl(), tab.isIncognito())) {
             return;
         }
@@ -1752,7 +1752,7 @@
     }
 
     private boolean shouldShowCursorInLocationBar() {
-        Tab tab = mToolbarModel.getTab();
+        Tab tab = mLocationBarModel.getTab();
         if (tab == null) return false;
         NativePage nativePage = tab.getNativePage();
         if (!(nativePage instanceof NewTabPage) && !(nativePage instanceof IncognitoNewTabPage)) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java
index 8a39aad5..b9f22a5d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java
@@ -532,7 +532,7 @@
         if (mNewTabButton != null) mNewTabButton.postNativeInitialization();
 
         setTabSwitcherAnimationMenuDrawable();
-        updateVisualsForToolbarState();
+        updateVisualsForLocationBarState();
     }
 
     @Override
@@ -1830,11 +1830,11 @@
             view.setVisibility(browsingViewsVisibility);
         }
         if (mShowMenuBadge) {
-            setMenuButtonContentDescription();
+            setMenuButtonContentDescription(mTabSwitcherState == STATIC_TAB);
         }
 
         updateProgressBarVisibility();
-        updateVisualsForToolbarState();
+        updateVisualsForLocationBarState();
         updateTabSwitcherButtonRipple();
     }
 
@@ -1844,7 +1844,7 @@
 
     @Override
     protected void setContentAttached(boolean attached) {
-        updateVisualsForToolbarState();
+        updateVisualsForLocationBarState();
     }
 
     @Override
@@ -1937,7 +1937,7 @@
         if (mTabSwitcherState == EXITING_TAB_SWITCHER) {
             mLocationBar.setUrlBarFocusable(true);
             mTabSwitcherState = STATIC_TAB;
-            updateVisualsForToolbarState();
+            updateVisualsForLocationBarState();
         }
         if (mTabSwitcherState == ENTERING_TAB_SWITCHER) mTabSwitcherState = TAB_SWITCHER;
 
@@ -1945,7 +1945,7 @@
 
         if (!mAnimateNormalToolbar) {
             finishAnimations();
-            updateVisualsForToolbarState();
+            updateVisualsForLocationBarState();
         }
 
         if (mDelayingTabSwitcherAnimation) {
@@ -2269,14 +2269,14 @@
     protected void onTabContentViewChanged() {
         super.onTabContentViewChanged();
         updateNtpAnimationState();
-        updateVisualsForToolbarState();
+        updateVisualsForLocationBarState();
     }
 
     @Override
     protected void onTabOrModelChanged() {
         super.onTabOrModelChanged();
         updateNtpAnimationState();
-        updateVisualsForToolbarState();
+        updateVisualsForLocationBarState();
     }
 
     private static boolean isVisualStateValidForBrandColorTransition(@VisualState int state) {
@@ -2328,7 +2328,7 @@
             @Override
             public void onAnimationEnd(Animator animation) {
                 mBrandColorTransitionActive = false;
-                updateVisualsForToolbarState();
+                updateVisualsForLocationBarState();
             }
         });
         mBrandColorTransitionAnimation.start();
@@ -2379,14 +2379,14 @@
         post(new Runnable() {
             @Override
             public void run() {
-                updateVisualsForToolbarState();
+                updateVisualsForLocationBarState();
                 updateNtpAnimationState();
             }
         });
     }
 
     @Override
-    protected void handleFindToolbarStateChange(boolean showing) {
+    protected void handleFindLocationBarStateChange(boolean showing) {
         setVisibility(showing ? View.GONE : View.VISIBLE);
     }
 
@@ -2443,7 +2443,7 @@
         return getToolbarDataProvider().getPrimaryColor();
     }
 
-    protected void updateVisualsForToolbarState() {
+    protected void updateVisualsForLocationBarState() {
         final boolean isIncognito = isIncognito();
 
         // These are important for setting visual state while the entering or leaving the tab
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarTablet.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarTablet.java
index 950692c..f3f5f24 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarTablet.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarTablet.java
@@ -517,7 +517,7 @@
             mLocationBar.getContainerView().setVisibility(View.INVISIBLE);
             if (mShowMenuBadge) {
                 getMenuBadge().setVisibility(View.GONE);
-                setMenuButtonContentDescription();
+                setMenuButtonContentDescription(false);
             }
         } else {
             mIsInTabSwitcherMode = false;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java b/chrome/android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java
index 8ec5f81..b309a5a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java
@@ -68,7 +68,6 @@
 
     private static Boolean sHasGoogleAccountAuthenticator;
     private static Boolean sHasRecognitionIntentHandler;
-    private static String sChromeHomeSwipeLogicType;
 
     private static Boolean sIsSoleEnabled;
     private static Boolean sIsHomePageButtonForceEnabled;
@@ -371,20 +370,6 @@
     }
 
     /**
-     * @return The type of swipe logic used for opening the bottom sheet in Chrome Home. Null is
-     *         returned if the command line is not initialized or no experiment is specified.
-     */
-    public static String getChromeHomeSwipeLogicType() {
-        if (sChromeHomeSwipeLogicType == null) {
-            CommandLine instance = CommandLine.getInstance();
-            sChromeHomeSwipeLogicType =
-                    instance.getSwitchValue(ChromeSwitches.CHROME_HOME_SWIPE_LOGIC);
-        }
-
-        return sChromeHomeSwipeLogicType;
-    }
-
-    /**
      * Cache whether or not Sole integration is enabled.
      */
     public static void cacheSoleEnabled() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr/ArCoreJavaUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/vr/ArCoreJavaUtils.java
index f35ac63..7246c90 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/vr/ArCoreJavaUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/vr/ArCoreJavaUtils.java
@@ -21,6 +21,7 @@
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
+import org.chromium.base.annotations.UsedByReflection;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.infobar.InfoBarIdentifier;
 import org.chromium.chrome.browser.infobar.SimpleConfirmInfoBarBuilder;
@@ -35,6 +36,7 @@
  * Provides ARCore classes access to java-related app functionality.
  */
 @JNINamespace("vr")
+@UsedByReflection("ArDelegate.java")
 public class ArCoreJavaUtils {
     private static final int MIN_SDK_VERSION = Build.VERSION_CODES.O;
     private static final String AR_CORE_PACKAGE = "com.google.ar.core";
@@ -63,6 +65,11 @@
     private boolean mAppInfoInitialized;
     private int mAppMinArCoreApkVersionCode = ARCORE_NOT_INSTALLED_VERSION_CODE;
 
+    @UsedByReflection("ArDelegate.java")
+    /* package */ static void installArCoreDeviceProviderFactory() {
+        nativeInstallArCoreDeviceProviderFactory();
+    }
+
     /**
      * Gets the current application context.
      *
@@ -239,6 +246,7 @@
         }
     }
 
+    private static native void nativeInstallArCoreDeviceProviderFactory();
     private native void nativeOnRequestInstallArModuleResult(
             long nativeArCoreJavaUtils, boolean success);
     private native void nativeOnRequestInstallSupportedArCoreCanceled(long nativeArCoreJavaUtils);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr/ArDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/vr/ArDelegate.java
new file mode 100644
index 0000000..55db849
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/vr/ArDelegate.java
@@ -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.
+
+package org.chromium.chrome.browser.vr;
+
+import java.lang.reflect.InvocationTargetException;
+
+/** This class provides methods to call into AR. */
+public class ArDelegate {
+    /**
+     * Needs to be called once native libraries are available. Has no effect if AR is not compiled
+     * into Chrome.
+     **/
+    public static void maybeInit() {
+        try {
+            // AR may not be compiled into Chrome. Thus, use reflection to access it.
+            Class.forName("org.chromium.chrome.browser.vr.ArCoreJavaUtils")
+                    .getDeclaredMethod("installArCoreDeviceProviderFactory")
+                    .invoke(null);
+        } catch (ClassNotFoundException | IllegalAccessException | IllegalArgumentException
+                | NoSuchMethodException | InvocationTargetException e) {
+            // AR not available. No initialization required.
+        }
+    }
+
+    private ArDelegate() {}
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java
index 2631599..cce26575 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java
@@ -29,8 +29,6 @@
 import org.chromium.base.VisibleForTesting;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeActivity;
-import org.chromium.chrome.browser.ChromeFeatureList;
-import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.TabLoadStatus;
 import org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager;
 import org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager.FullscreenListener;
@@ -41,7 +39,6 @@
 import org.chromium.chrome.browser.toolbar.ActionModeController.ActionBarDelegate;
 import org.chromium.chrome.browser.toolbar.ViewShiftingActionBarDelegate;
 import org.chromium.chrome.browser.util.AccessibilityUtil;
-import org.chromium.chrome.browser.util.FeatureUtilities;
 import org.chromium.chrome.browser.util.MathUtils;
 import org.chromium.content_public.browser.LoadUrlParams;
 import org.chromium.content_public.browser.SelectionPopupController;
@@ -261,9 +258,6 @@
     /** Conversion ratio of dp to px. */
     private float mDpToPx;
 
-    /** Whether or not scroll events are currently being blocked for the 'velocity' swipe logic. */
-    private boolean mVelocityLogicBlockSwipe;
-
     /**
      * An interface defining content that can be displayed inside of the bottom sheet for Chrome
      * Home.
@@ -373,43 +367,8 @@
             return true;
         }
 
-        if (currentEvent.getActionMasked() == MotionEvent.ACTION_DOWN) {
-            mVelocityLogicBlockSwipe = false;
-        }
-
-        float scrollDistanceDp = MathUtils.distance(initialEvent.getX(), initialEvent.getY(),
-                                         currentEvent.getX(), currentEvent.getY())
-                / mDpToPx;
-        long timeDeltaMs = currentEvent.getEventTime() - initialEvent.getDownTime();
-
-        String logicType = FeatureUtilities.getChromeHomeSwipeLogicType();
-
-        // By default, the entire toolbar is swipable.
         float startX = mVisibleViewportRect.left;
         float endX = mDefaultToolbarView.getWidth() + mVisibleViewportRect.left;
-
-        if (ChromeSwitches.CHROME_HOME_SWIPE_LOGIC_RESTRICT_AREA.equals(logicType)) {
-            // Determine an area in the middle of the toolbar that is swipable. This will only
-            // trigger if the expand button is disabled.
-            float allowedSwipeWidth = mContainerWidth * SWIPE_ALLOWED_FRACTION;
-            startX = mVisibleViewportRect.left + (mContainerWidth - allowedSwipeWidth) / 2;
-            endX = startX + allowedSwipeWidth;
-        } else if (ChromeSwitches.CHROME_HOME_SWIPE_LOGIC_VELOCITY.equals(logicType)
-                || (ChromeFeatureList.isInitialized()
-                           && ChromeFeatureList.isEnabled(
-                                      ChromeFeatureList.CHROME_HOME_SWIPE_VELOCITY_FEATURE))) {
-            if (mVelocityLogicBlockSwipe) return false;
-
-            double dpPerMs = scrollDistanceDp / (double) timeDeltaMs;
-
-            if (dpPerMs < SHEET_SWIPE_MIN_DP_PER_MS) {
-                mVelocityLogicBlockSwipe = true;
-                return false;
-            }
-
-            return true;
-        }
-
         return currentEvent.getRawX() > startX && currentEvent.getRawX() < endX;
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/findinpage/FindToolbar.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/findinpage/FindToolbar.java
index 933f5c7f..fb83fe1a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/findinpage/FindToolbar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/findinpage/FindToolbar.java
@@ -60,10 +60,10 @@
 
     private static final long ACCESSIBLE_ANNOUNCEMENT_DELAY_MILLIS = 500;
 
-    @IntDef({FindToolbarState.SHOWN, FindToolbarState.SHOWING, FindToolbarState.HIDDEN,
-            FindToolbarState.HIDING})
+    @IntDef({FindLocationBarState.SHOWN, FindLocationBarState.SHOWING, FindLocationBarState.HIDDEN,
+            FindLocationBarState.HIDING})
     @Retention(RetentionPolicy.SOURCE)
-    private @interface FindToolbarState {
+    private @interface FindLocationBarState {
         int SHOWN = 0;
         int SHOWING = 1;
         int HIDDEN = 2;
@@ -97,10 +97,10 @@
     /** Whether the search key should trigger a new search. */
     private boolean mSearchKeyShouldTriggerSearch;
 
-    @FindToolbarState
-    private int mCurrentState = FindToolbarState.HIDDEN;
-    @FindToolbarState
-    private int mDesiredState = FindToolbarState.HIDDEN;
+    @FindLocationBarState
+    private int mCurrentState = FindLocationBarState.HIDDEN;
+    @FindLocationBarState
+    private int mDesiredState = FindLocationBarState.HIDDEN;
 
     private Handler mHandler = new Handler();
     private Runnable mAccessibleAnnouncementRunnable;
@@ -560,14 +560,14 @@
         ThreadUtils.checkUiThread();
         if (!isWebContentAvailable()) return;
 
-        if (mCurrentState == FindToolbarState.SHOWN) {
+        if (mCurrentState == FindLocationBarState.SHOWN) {
             requestQueryFocus();
             return;
         }
 
-        mDesiredState = FindToolbarState.SHOWN;
-        if (mCurrentState != FindToolbarState.HIDDEN) return;
-        setCurrentState(FindToolbarState.SHOWING);
+        mDesiredState = FindLocationBarState.SHOWN;
+        if (mCurrentState != FindLocationBarState.HIDDEN) return;
+        setCurrentState(FindLocationBarState.SHOWING);
         handleActivate();
     }
 
@@ -592,7 +592,7 @@
         setResultsBarVisibility(true);
         updateVisualsForTabModel(mTabModelSelector.isIncognitoSelected());
 
-        setCurrentState(FindToolbarState.SHOWN);
+        setCurrentState(FindLocationBarState.SHOWN);
     }
 
     /**
@@ -609,9 +609,9 @@
     public final void deactivate(boolean clearSelection) {
         ThreadUtils.checkUiThread();
 
-        mDesiredState = FindToolbarState.HIDDEN;
-        if (mCurrentState != FindToolbarState.SHOWN) return;
-        setCurrentState(FindToolbarState.HIDING);
+        mDesiredState = FindLocationBarState.HIDDEN;
+        if (mCurrentState != FindLocationBarState.SHOWN) return;
+        setCurrentState(FindLocationBarState.HIDING);
         handleDeactivation(clearSelection);
     }
 
@@ -644,28 +644,30 @@
         mFindInPageBridge = null;
         mCurrentTab = null;
 
-        setCurrentState(FindToolbarState.HIDDEN);
+        setCurrentState(FindLocationBarState.HIDDEN);
     }
 
-    private void setCurrentState(@FindToolbarState int state) {
+    private void setCurrentState(@FindLocationBarState int state) {
         mCurrentState = state;
 
         // Notify the observers if we hit the transition states.
         if (mObserver != null) {
-            if (mCurrentState == FindToolbarState.HIDDEN) {
+            if (mCurrentState == FindLocationBarState.HIDDEN) {
                 mObserver.onFindToolbarHidden();
-            } else if (mCurrentState == FindToolbarState.SHOWN) {
+            } else if (mCurrentState == FindLocationBarState.SHOWN) {
                 mObserver.onFindToolbarShown();
             }
         }
 
         // Ensure the current state reflects the desired state if the state change happened while
         // processing the previous state change.
-        assert mDesiredState == FindToolbarState.HIDDEN || mDesiredState == FindToolbarState.SHOWN;
-        if (mCurrentState == FindToolbarState.HIDDEN && mDesiredState == FindToolbarState.SHOWN) {
+        assert mDesiredState == FindLocationBarState.HIDDEN
+                || mDesiredState == FindLocationBarState.SHOWN;
+        if (mCurrentState == FindLocationBarState.HIDDEN
+                && mDesiredState == FindLocationBarState.SHOWN) {
             activate();
-        } else if (mCurrentState == FindToolbarState.SHOWN
-                && mDesiredState == FindToolbarState.HIDDEN) {
+        } else if (mCurrentState == FindLocationBarState.SHOWN
+                && mDesiredState == FindLocationBarState.HIDDEN) {
             deactivate();
         }
     }
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd
index 4e6db8e6..d7a99e7 100644
--- a/chrome/android/java/strings/android_chrome_strings.grd
+++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -81,6 +81,7 @@
     <file lang="am" path="translations/android_chrome_strings_am.xtb" />
     <file lang="ar" path="translations/android_chrome_strings_ar.xtb" />
     <file lang="bg" path="translations/android_chrome_strings_bg.xtb" />
+    <file lang="bn" path="translations/android_chrome_strings_bn.xtb" />
     <file lang="ca" path="translations/android_chrome_strings_ca.xtb" />
     <file lang="cs" path="translations/android_chrome_strings_cs.xtb" />
     <file lang="da" path="translations/android_chrome_strings_da.xtb" />
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index bb8bae32..610bed7 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -1541,11 +1541,11 @@
   "java/src/org/chromium/chrome/browser/toolbar/BottomToolbarViewBinder.java",
   "java/src/org/chromium/chrome/browser/toolbar/CustomTabToolbar.java",
   "java/src/org/chromium/chrome/browser/toolbar/CustomTabToolbarAnimationDelegate.java",
-  "java/src/org/chromium/chrome/browser/toolbar/MenuButton.java",
-  "java/src/org/chromium/chrome/browser/toolbar/ToolbarButtonSlotData.java",
   "java/src/org/chromium/chrome/browser/toolbar/HomePageButton.java",
   "java/src/org/chromium/chrome/browser/toolbar/IncognitoToggleTabLayout.java",
   "java/src/org/chromium/chrome/browser/toolbar/KeyboardNavigationListener.java",
+  "java/src/org/chromium/chrome/browser/toolbar/LocationBarModel.java",
+  "java/src/org/chromium/chrome/browser/toolbar/MenuButton.java",
   "java/src/org/chromium/chrome/browser/toolbar/NewTabButton.java",
   "java/src/org/chromium/chrome/browser/toolbar/ScrollingBottomViewResourceFrameLayout.java",
   "java/src/org/chromium/chrome/browser/toolbar/TabSwitcherButtonViewBinder.java",
@@ -1556,11 +1556,11 @@
   "java/src/org/chromium/chrome/browser/toolbar/Toolbar.java",
   "java/src/org/chromium/chrome/browser/toolbar/ToolbarActionModeCallback.java",
   "java/src/org/chromium/chrome/browser/toolbar/ToolbarButtonInProductHelpController.java",
+  "java/src/org/chromium/chrome/browser/toolbar/ToolbarButtonSlotData.java",
   "java/src/org/chromium/chrome/browser/toolbar/ToolbarControlContainer.java",
   "java/src/org/chromium/chrome/browser/toolbar/ToolbarDataProvider.java",
   "java/src/org/chromium/chrome/browser/toolbar/ToolbarLayout.java",
   "java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java",
-  "java/src/org/chromium/chrome/browser/toolbar/ToolbarModel.java",
   "java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java",
   "java/src/org/chromium/chrome/browser/toolbar/ToolbarTabController.java",
   "java/src/org/chromium/chrome/browser/toolbar/ToolbarTablet.java",
@@ -1587,6 +1587,7 @@
   "java/src/org/chromium/chrome/browser/vr/VrDelegate.java",
   "java/src/org/chromium/chrome/browser/vr/VrIntentDelegate.java",
   "java/src/org/chromium/chrome/browser/vr/VrModuleProvider.java",
+  "java/src/org/chromium/chrome/browser/vr/ArDelegate.java",
   "java/src/org/chromium/chrome/browser/vr/VrDelegateFallback.java",
   "java/src/org/chromium/chrome/browser/vr/VrDelegateProvider.java",
   "java/src/org/chromium/chrome/browser/vr/VrDelegateProviderFallback.java",
@@ -2173,7 +2174,7 @@
   "javatests/src/org/chromium/chrome/browser/test/CommandLineInitRule.java",
   "javatests/src/org/chromium/chrome/browser/test/ScreenShooter.java",
   "javatests/src/org/chromium/chrome/browser/toolbar/BrandColorTest.java",
-  "javatests/src/org/chromium/chrome/browser/toolbar/ToolbarModelTest.java",
+  "javatests/src/org/chromium/chrome/browser/toolbar/LocationBarModelTest.java",
   "javatests/src/org/chromium/chrome/browser/toolbar/ToolbarTest.java",
   "javatests/src/org/chromium/chrome/browser/translate/TranslateCompactInfoBarTest.java",
   "javatests/src/org/chromium/chrome/browser/translate/TranslateOptionsTest.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
index e7ea51c..f7d2850 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
@@ -878,7 +878,7 @@
         Assert.assertEquals(expectedColor, toolbar.getBackground().getColor());
         Assert.assertFalse(mCustomTabActivityTestRule.getActivity()
                                    .getToolbarManager()
-                                   .getToolbarModelForTesting()
+                                   .getLocationBarModelForTesting()
                                    .shouldEmphasizeHttpsScheme());
         // TODO(https://crbug.com/871805): Use helper class to determine whether dark status icons
         // are supported.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/LocationBarLayoutTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/LocationBarLayoutTest.java
index 4eea767..6083607 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/LocationBarLayoutTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/LocationBarLayoutTest.java
@@ -24,7 +24,7 @@
 import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.search_engines.TemplateUrlServiceTestUtils;
-import org.chromium.chrome.browser.toolbar.ToolbarModel;
+import org.chromium.chrome.browser.toolbar.LocationBarModel;
 import org.chromium.chrome.test.ChromeActivityTestRule;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.chrome.test.util.browser.Features.DisableFeatures;
@@ -58,15 +58,15 @@
     private static final String VERBOSE_URL = "https://www.suchwowveryyes.edu";
     private static final String TRIMMED_URL = "suchwowveryyes.edu";
 
-    private TestToolbarModel mTestToolbarModel;
+    private TestLocationBarModel mTestLocationBarModel;
 
-    private class TestToolbarModel extends ToolbarModel {
+    private class TestLocationBarModel extends LocationBarModel {
         private String mCurrentUrl;
         private String mEditingText;
         private String mDisplayText;
         private Integer mSecurityLevel;
 
-        public TestToolbarModel() {
+        public TestLocationBarModel() {
             super(ContextUtils.getApplicationContext());
             initializeWithNative();
         }
@@ -104,11 +104,11 @@
     @Before
     public void setUp() throws InterruptedException {
         mActivityTestRule.startMainActivityOnBlankPage();
-        mTestToolbarModel = new TestToolbarModel();
-        mTestToolbarModel.setTab(mActivityTestRule.getActivity().getActivityTab(), false);
+        mTestLocationBarModel = new TestLocationBarModel();
+        mTestLocationBarModel.setTab(mActivityTestRule.getActivity().getActivityTab(), false);
 
         ThreadUtils.runOnUiThreadBlocking(
-                () -> getLocationBar().setToolbarDataProvider(mTestToolbarModel));
+                () -> getLocationBar().setToolbarDataProvider(mTestLocationBarModel));
     }
 
     private void setUrlToPageUrl(LocationBarLayout locationBar) {
@@ -217,8 +217,8 @@
         final UrlBar urlBar = getUrlBar();
         final LocationBarLayout locationBar = getLocationBar();
 
-        mTestToolbarModel.setCurrentUrl(GOOGLE_SRP_URL);
-        mTestToolbarModel.setSecurityLevel(ConnectionSecurityLevel.SECURE);
+        mTestLocationBarModel.setCurrentUrl(GOOGLE_SRP_URL);
+        mTestLocationBarModel.setSecurityLevel(ConnectionSecurityLevel.SECURE);
         setUrlToPageUrl(locationBar);
 
         Assert.assertEquals(SEARCH_TERMS, getUrlText(urlBar));
@@ -234,8 +234,8 @@
         final LocationBarLayout locationBar = getLocationBar();
 
         TemplateUrlServiceTestUtils.setSearchEngine("bing.com");
-        mTestToolbarModel.setCurrentUrl(BING_SRP_URL);
-        mTestToolbarModel.setSecurityLevel(ConnectionSecurityLevel.SECURE);
+        mTestLocationBarModel.setCurrentUrl(BING_SRP_URL);
+        mTestLocationBarModel.setSecurityLevel(ConnectionSecurityLevel.SECURE);
         setUrlToPageUrl(locationBar);
 
         Assert.assertEquals(SEARCH_TERMS, getUrlText(urlBar));
@@ -251,8 +251,8 @@
         final LocationBarLayout locationBar = getLocationBar();
 
         TemplateUrlServiceTestUtils.setSearchEngine("bing.com");
-        mTestToolbarModel.setCurrentUrl(GOOGLE_SRP_URL);
-        mTestToolbarModel.setSecurityLevel(ConnectionSecurityLevel.SECURE);
+        mTestLocationBarModel.setCurrentUrl(GOOGLE_SRP_URL);
+        mTestLocationBarModel.setSecurityLevel(ConnectionSecurityLevel.SECURE);
         setUrlToPageUrl(locationBar);
 
         Assert.assertNotEquals(SEARCH_TERMS, getUrlText(urlBar));
@@ -266,14 +266,14 @@
         final UrlBar urlBar = getUrlBar();
         final LocationBarLayout locationBar = getLocationBar();
 
-        mTestToolbarModel.setCurrentUrl(GOOGLE_SRP_URL);
-        mTestToolbarModel.setSecurityLevel(ConnectionSecurityLevel.NONE);
+        mTestLocationBarModel.setCurrentUrl(GOOGLE_SRP_URL);
+        mTestLocationBarModel.setSecurityLevel(ConnectionSecurityLevel.NONE);
         setUrlToPageUrl(locationBar);
 
         AppCompatImageButton securityButton = getSecurityButton();
         Assert.assertNotEquals(SEARCH_TERMS, urlBar.getText().toString());
         ThreadUtils.runOnUiThreadBlocking(() -> {
-            Assert.assertNotEquals(mTestToolbarModel.getSecurityIconResource(
+            Assert.assertNotEquals(mTestLocationBarModel.getSecurityIconResource(
                                            mActivityTestRule.getActivity().isTablet()),
                     SEARCH_ICON_RESOURCE);
         });
@@ -286,14 +286,14 @@
     public void testIsShowingSearchIconSecureContent() {
         final LocationBarLayout locationBar = getLocationBar();
 
-        mTestToolbarModel.setCurrentUrl(GOOGLE_SRP_URL);
-        mTestToolbarModel.setSecurityLevel(ConnectionSecurityLevel.SECURE);
+        mTestLocationBarModel.setCurrentUrl(GOOGLE_SRP_URL);
+        mTestLocationBarModel.setSecurityLevel(ConnectionSecurityLevel.SECURE);
         setUrlToPageUrl(locationBar);
 
         AppCompatImageButton securityButton = getSecurityButton();
         Assert.assertEquals(securityButton.getVisibility(), View.VISIBLE);
         ThreadUtils.runOnUiThreadBlocking(() -> {
-            Assert.assertEquals(mTestToolbarModel.getSecurityIconResource(
+            Assert.assertEquals(mTestLocationBarModel.getSecurityIconResource(
                                         mActivityTestRule.getActivity().isTablet()),
                     SEARCH_ICON_RESOURCE);
         });
@@ -307,8 +307,8 @@
         final UrlBar urlBar = getUrlBar();
         final LocationBarLayout locationBar = getLocationBar();
 
-        mTestToolbarModel.setCurrentUrl(GOOGLE_SRP_URL_LIKE_URL);
-        mTestToolbarModel.setSecurityLevel(ConnectionSecurityLevel.SECURE);
+        mTestLocationBarModel.setCurrentUrl(GOOGLE_SRP_URL_LIKE_URL);
+        mTestLocationBarModel.setSecurityLevel(ConnectionSecurityLevel.SECURE);
         setUrlToPageUrl(locationBar);
 
         Assert.assertNotEquals(SEARCH_TERMS_URL, getUrlText(urlBar));
@@ -323,8 +323,8 @@
         final UrlBar urlBar = getUrlBar();
         final LocationBarLayout locationBar = getLocationBar();
 
-        mTestToolbarModel.setCurrentUrl(GOOGLE_SRP_URL);
-        mTestToolbarModel.setSecurityLevel(ConnectionSecurityLevel.SECURE);
+        mTestLocationBarModel.setCurrentUrl(GOOGLE_SRP_URL);
+        mTestLocationBarModel.setSecurityLevel(ConnectionSecurityLevel.SECURE);
         setUrlToPageUrl(locationBar);
 
         Assert.assertNotEquals(SEARCH_TERMS, getUrlText(urlBar));
@@ -336,10 +336,10 @@
         final UrlBar urlBar = getUrlBar();
         final LocationBarLayout locationBar = getLocationBar();
 
-        mTestToolbarModel.setCurrentUrl(VERBOSE_URL);
-        mTestToolbarModel.setSecurityLevel(ConnectionSecurityLevel.SECURE);
-        mTestToolbarModel.mDisplayText = TRIMMED_URL;
-        mTestToolbarModel.mEditingText = VERBOSE_URL;
+        mTestLocationBarModel.setCurrentUrl(VERBOSE_URL);
+        mTestLocationBarModel.setSecurityLevel(ConnectionSecurityLevel.SECURE);
+        mTestLocationBarModel.mDisplayText = TRIMMED_URL;
+        mTestLocationBarModel.mEditingText = VERBOSE_URL;
         setUrlToPageUrl(locationBar);
 
         Assert.assertEquals(TRIMMED_URL, getUrlText(urlBar));
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/OmniboxTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/OmniboxTest.java
index bdcf867..902ccec9 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/OmniboxTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/OmniboxTest.java
@@ -730,12 +730,12 @@
             if (mActivityTestRule.getActivity().isTablet()) {
                 Assert.assertTrue(mActivityTestRule.getActivity()
                                           .getToolbarManager()
-                                          .getToolbarModelForTesting()
+                                          .getLocationBarModelForTesting()
                                           .shouldEmphasizeHttpsScheme());
             } else {
                 Assert.assertFalse(mActivityTestRule.getActivity()
                                            .getToolbarManager()
-                                           .getToolbarModelForTesting()
+                                           .getLocationBarModelForTesting()
                                            .shouldEmphasizeHttpsScheme());
             }
         } finally {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/ToolbarModelTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/LocationBarModelTest.java
similarity index 91%
rename from chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/ToolbarModelTest.java
rename to chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/LocationBarModelTest.java
index c95ac3fe..005790d 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/ToolbarModelTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/LocationBarModelTest.java
@@ -30,11 +30,11 @@
 import org.chromium.chrome.test.util.ChromeTabUtils;
 
 /**
- * Tests for ToolbarModel.
+ * Tests for LocationBarModel.
  */
 @RunWith(ChromeJUnit4ClassRunner.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
-public class ToolbarModelTest {
+public class LocationBarModelTest {
     @Rule
     public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();
 
@@ -44,7 +44,7 @@
     }
 
     /**
-     * After closing all {@link Tab}s, the {@link ToolbarModel} should know that it is not
+     * After closing all {@link Tab}s, the {@link LocationBarModel} should know that it is not
      * showing any {@link Tab}.
      * @throws InterruptedException
      */
@@ -59,7 +59,7 @@
                 InstrumentationRegistry.getInstrumentation(), mActivityTestRule.getActivity());
         Assert.assertEquals("Didn't close all tabs.", 0,
                 ChromeTabUtils.getNumOpenTabs(mActivityTestRule.getActivity()));
-        Assert.assertEquals("ToolbarModel is still trying to show a tab.", Tab.INVALID_TAB_ID,
+        Assert.assertEquals("LocationBarModel is still trying to show a tab.", Tab.INVALID_TAB_ID,
                 getCurrentTabId(mActivityTestRule.getActivity()));
     }
 
@@ -67,7 +67,7 @@
     @SmallTest
     public void testDisplayAndEditText() throws Exception {
         ThreadUtils.runOnUiThreadBlocking(() -> {
-            TestToolbarModel model = new TestToolbarModel();
+            TestLocationBarModel model = new TestLocationBarModel();
             model.mUrl = UrlConstants.NTP_URL;
             assertDisplayAndEditText(model, "", null);
 
@@ -101,7 +101,7 @@
     /**
      * @param activity A reference to {@link ChromeTabbedActivity} to pull
      *            {@link android.view.View} data from.
-     * @return The id of the current {@link Tab} as far as the {@link ToolbarModel} sees it.
+     * @return The id of the current {@link Tab} as far as the {@link LocationBarModel} sees it.
      */
     public static int getCurrentTabId(final ChromeTabbedActivity activity) {
         ToolbarLayout toolbar = (ToolbarLayout) activity.findViewById(R.id.toolbar);
@@ -112,12 +112,12 @@
         return tab != null ? tab.getId() : Tab.INVALID_TAB_ID;
     }
 
-    private class TestToolbarModel extends ToolbarModel {
+    private class TestLocationBarModel extends LocationBarModel {
         private String mDisplayUrl;
         private String mFullUrl;
         private String mUrl;
 
-        public TestToolbarModel() {
+        public TestLocationBarModel() {
             super(ContextUtils.getApplicationContext());
             initializeWithNative();
 
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/toolbar/ToolbarSecurityIconTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/toolbar/ToolbarSecurityIconTest.java
index 4edd3b59..d51da68b 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/toolbar/ToolbarSecurityIconTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/toolbar/ToolbarSecurityIconTest.java
@@ -43,30 +43,30 @@
     @Test
     public void testGetSecurityLevel() {
         assertEquals(ConnectionSecurityLevel.NONE,
-                ToolbarModel.getSecurityLevel(null, !IS_OFFLINE_PAGE, null));
+                LocationBarModel.getSecurityLevel(null, !IS_OFFLINE_PAGE, null));
         assertEquals(ConnectionSecurityLevel.NONE,
-                ToolbarModel.getSecurityLevel(null, IS_OFFLINE_PAGE, null));
+                LocationBarModel.getSecurityLevel(null, IS_OFFLINE_PAGE, null));
         assertEquals(ConnectionSecurityLevel.NONE,
-                ToolbarModel.getSecurityLevel(mTab, IS_OFFLINE_PAGE, null));
+                LocationBarModel.getSecurityLevel(mTab, IS_OFFLINE_PAGE, null));
 
         for (int securityLevel : SECURITY_LEVELS) {
             when(mTab.getSecurityLevel()).thenReturn(securityLevel);
             assertEquals("Wrong security level returned for " + securityLevel, securityLevel,
-                    ToolbarModel.getSecurityLevel(mTab, !IS_OFFLINE_PAGE, null));
+                    LocationBarModel.getSecurityLevel(mTab, !IS_OFFLINE_PAGE, null));
         }
 
         when(mTab.getSecurityLevel()).thenReturn(ConnectionSecurityLevel.SECURE);
         assertEquals("Wrong security level returned for HTTPS publisher URL",
                 ConnectionSecurityLevel.SECURE,
-                ToolbarModel.getSecurityLevel(mTab, !IS_OFFLINE_PAGE, "https://example.com"));
+                LocationBarModel.getSecurityLevel(mTab, !IS_OFFLINE_PAGE, "https://example.com"));
         assertEquals("Wrong security level returned for HTTP publisher URL",
                 ConnectionSecurityLevel.HTTP_SHOW_WARNING,
-                ToolbarModel.getSecurityLevel(mTab, !IS_OFFLINE_PAGE, "http://example.com"));
+                LocationBarModel.getSecurityLevel(mTab, !IS_OFFLINE_PAGE, "http://example.com"));
 
         when(mTab.getSecurityLevel()).thenReturn(ConnectionSecurityLevel.DANGEROUS);
         assertEquals("Wrong security level returned for publisher URL on insecure page",
                 ConnectionSecurityLevel.DANGEROUS,
-                ToolbarModel.getSecurityLevel(mTab, !IS_OFFLINE_PAGE, null));
+                LocationBarModel.getSecurityLevel(mTab, !IS_OFFLINE_PAGE, null));
     }
 
     @Test
@@ -74,64 +74,64 @@
         for (int securityLevel : SECURITY_LEVELS) {
             assertEquals("Wrong phone resource for security level " + securityLevel,
                     R.drawable.offline_pin_round,
-                    ToolbarModel.getSecurityIconResource(
+                    LocationBarModel.getSecurityIconResource(
                             securityLevel, IS_SMALL_DEVICE, IS_OFFLINE_PAGE, !IS_PREVIEW));
             assertEquals("Wrong tablet resource for security level " + securityLevel,
                     R.drawable.offline_pin_round,
-                    ToolbarModel.getSecurityIconResource(
+                    LocationBarModel.getSecurityIconResource(
                             securityLevel, !IS_SMALL_DEVICE, IS_OFFLINE_PAGE, !IS_PREVIEW));
             assertEquals("Wrong phone resource for security level " + securityLevel,
                     R.drawable.preview_pin_round,
-                    ToolbarModel.getSecurityIconResource(
+                    LocationBarModel.getSecurityIconResource(
                             securityLevel, IS_SMALL_DEVICE, !IS_OFFLINE_PAGE, IS_PREVIEW));
             assertEquals("Wrong tablet resource for security level " + securityLevel,
                     R.drawable.preview_pin_round,
-                    ToolbarModel.getSecurityIconResource(
+                    LocationBarModel.getSecurityIconResource(
                             securityLevel, !IS_SMALL_DEVICE, !IS_OFFLINE_PAGE, IS_PREVIEW));
         }
 
         assertEquals(0,
-                ToolbarModel.getSecurityIconResource(ConnectionSecurityLevel.NONE, IS_SMALL_DEVICE,
-                        !IS_OFFLINE_PAGE, !IS_PREVIEW));
-        assertEquals(R.drawable.omnibox_info,
-                ToolbarModel.getSecurityIconResource(ConnectionSecurityLevel.NONE, !IS_SMALL_DEVICE,
-                        !IS_OFFLINE_PAGE, !IS_PREVIEW));
-
-        assertEquals(R.drawable.omnibox_info,
-                ToolbarModel.getSecurityIconResource(ConnectionSecurityLevel.HTTP_SHOW_WARNING,
+                LocationBarModel.getSecurityIconResource(ConnectionSecurityLevel.NONE,
                         IS_SMALL_DEVICE, !IS_OFFLINE_PAGE, !IS_PREVIEW));
         assertEquals(R.drawable.omnibox_info,
-                ToolbarModel.getSecurityIconResource(ConnectionSecurityLevel.HTTP_SHOW_WARNING,
+                LocationBarModel.getSecurityIconResource(ConnectionSecurityLevel.NONE,
+                        !IS_SMALL_DEVICE, !IS_OFFLINE_PAGE, !IS_PREVIEW));
+
+        assertEquals(R.drawable.omnibox_info,
+                LocationBarModel.getSecurityIconResource(ConnectionSecurityLevel.HTTP_SHOW_WARNING,
+                        IS_SMALL_DEVICE, !IS_OFFLINE_PAGE, !IS_PREVIEW));
+        assertEquals(R.drawable.omnibox_info,
+                LocationBarModel.getSecurityIconResource(ConnectionSecurityLevel.HTTP_SHOW_WARNING,
                         !IS_SMALL_DEVICE, !IS_OFFLINE_PAGE, !IS_PREVIEW));
 
         assertEquals(R.drawable.omnibox_https_invalid,
-                ToolbarModel.getSecurityIconResource(ConnectionSecurityLevel.DANGEROUS,
+                LocationBarModel.getSecurityIconResource(ConnectionSecurityLevel.DANGEROUS,
                         IS_SMALL_DEVICE, !IS_OFFLINE_PAGE, !IS_PREVIEW));
         assertEquals(R.drawable.omnibox_https_invalid,
-                ToolbarModel.getSecurityIconResource(ConnectionSecurityLevel.DANGEROUS,
+                LocationBarModel.getSecurityIconResource(ConnectionSecurityLevel.DANGEROUS,
                         !IS_SMALL_DEVICE, !IS_OFFLINE_PAGE, !IS_PREVIEW));
 
         assertEquals(R.drawable.omnibox_https_valid,
-                ToolbarModel.getSecurityIconResource(
+                LocationBarModel.getSecurityIconResource(
                         ConnectionSecurityLevel.SECURE_WITH_POLICY_INSTALLED_CERT, IS_SMALL_DEVICE,
                         !IS_OFFLINE_PAGE, !IS_PREVIEW));
         assertEquals(R.drawable.omnibox_https_valid,
-                ToolbarModel.getSecurityIconResource(
+                LocationBarModel.getSecurityIconResource(
                         ConnectionSecurityLevel.SECURE_WITH_POLICY_INSTALLED_CERT, !IS_SMALL_DEVICE,
                         !IS_OFFLINE_PAGE, !IS_PREVIEW));
 
         assertEquals(R.drawable.omnibox_https_valid,
-                ToolbarModel.getSecurityIconResource(ConnectionSecurityLevel.SECURE,
+                LocationBarModel.getSecurityIconResource(ConnectionSecurityLevel.SECURE,
                         IS_SMALL_DEVICE, !IS_OFFLINE_PAGE, !IS_PREVIEW));
         assertEquals(R.drawable.omnibox_https_valid,
-                ToolbarModel.getSecurityIconResource(ConnectionSecurityLevel.SECURE,
+                LocationBarModel.getSecurityIconResource(ConnectionSecurityLevel.SECURE,
                         !IS_SMALL_DEVICE, !IS_OFFLINE_PAGE, !IS_PREVIEW));
 
         assertEquals(R.drawable.omnibox_https_valid,
-                ToolbarModel.getSecurityIconResource(ConnectionSecurityLevel.EV_SECURE,
+                LocationBarModel.getSecurityIconResource(ConnectionSecurityLevel.EV_SECURE,
                         IS_SMALL_DEVICE, !IS_OFFLINE_PAGE, !IS_PREVIEW));
         assertEquals(R.drawable.omnibox_https_valid,
-                ToolbarModel.getSecurityIconResource(ConnectionSecurityLevel.EV_SECURE,
+                LocationBarModel.getSecurityIconResource(ConnectionSecurityLevel.EV_SECURE,
                         !IS_SMALL_DEVICE, !IS_OFFLINE_PAGE, !IS_PREVIEW));
     }
 }
diff --git a/chrome/app/onboarding_welcome_strings.grdp b/chrome/app/onboarding_welcome_strings.grdp
index b0bb772..7c187a21 100644
--- a/chrome/app/onboarding_welcome_strings.grdp
+++ b/chrome/app/onboarding_welcome_strings.grdp
@@ -13,9 +13,15 @@
   <message name="IDS_ONBOARDING_WELCOME_BOOKMARK_ADDED" desc="String read for accessibility to inform the user a bookmark was added.">
     Bookmark added
   </message>
+  <message name="IDS_ONBOARDING_WELCOME_BOOKMARKS_ADDED" desc="String read for accessibility to inform the user that several bookmarks were added.">
+    Bookmarks added
+  </message>
   <message name="IDS_ONBOARDING_WELCOME_BOOKMARK_REMOVED" desc="String read for accessibility to inform the user a bookmark was removed.">
     Bookmark removed
   </message>
+  <message name="IDS_ONBOARDING_WELCOME_BOOKMARKS_REMOVED" desc="String read for accessibility to inform the user that several bookmarks were removed.">
+    Bookmarks removed
+  </message>
   <message name="IDS_ONBOARDING_WELCOME_BOOKMARK_REPLACED" desc="String read for accessibility to inform the user a bookmark was replaced.">
     Bookmark replaced
   </message>
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 28ee98d..2a13db8dd 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -3165,6 +3165,8 @@
       "task_manager/providers/crostini/crostini_process_task.h",
       "task_manager/providers/crostini/crostini_process_task_provider.cc",
       "task_manager/providers/crostini/crostini_process_task_provider.h",
+      "task_manager/sampling/arc_shared_sampler.cc",
+      "task_manager/sampling/arc_shared_sampler.h",
       "upgrade_detector/upgrade_detector_chromeos.cc",
       "upgrade_detector/upgrade_detector_chromeos.h",
     ]
@@ -4831,7 +4833,7 @@
       "../android/java/src/org/chromium/chrome/browser/tabmodel/SingleTabModel.java",
       "../android/java/src/org/chromium/chrome/browser/tabmodel/TabModelJniBridge.java",
       "../android/java/src/org/chromium/chrome/browser/tabmodel/TabModelObserverJniBridge.java",
-      "../android/java/src/org/chromium/chrome/browser/toolbar/ToolbarModel.java",
+      "../android/java/src/org/chromium/chrome/browser/toolbar/LocationBarModel.java",
       "../android/java/src/org/chromium/chrome/browser/translate/TranslateBridge.java",
       "../android/java/src/org/chromium/chrome/browser/util/ChromeContextUtil.java",
       "../android/java/src/org/chromium/chrome/browser/util/FeatureUtilities.java",
diff --git a/chrome/browser/DEPS b/chrome/browser/DEPS
index 1438322..538a8e0c 100644
--- a/chrome/browser/DEPS
+++ b/chrome/browser/DEPS
@@ -8,6 +8,7 @@
   "+chrome/installer/util",
   "+chrome/notification_helper/notification_helper_constants.h",
   "+chrome/services/cups_ipp_parser/public",
+  "+chrome/services/diagnosticsd/public",
   "+chrome/services/file_util/public",
   "+chrome/services/media_gallery_util/public",
   "+chrome/services/printing/public",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 9c36d57..a79f8e4 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -416,14 +416,6 @@
      switches::reader_mode_heuristics::kAllArticles},
 };
 
-const FeatureEntry::Choice kChromeHomeSwipeLogicChoices[] = {
-    {flags_ui::kGenericExperimentChoiceDefault, "", ""},
-    {flag_descriptions::kChromeHomeSwipeLogicRestrictArea,
-     switches::kChromeHomeSwipeLogicType, "restrict-area"},
-    {flag_descriptions::kChromeHomeSwipeLogicVelocity,
-     switches::kChromeHomeSwipeLogicType, "velocity"},
-};
-
 const FeatureEntry::Choice kForceUpdateMenuTypeChoices[] = {
     {flags_ui::kGenericExperimentChoiceDefault, "", ""},
     {flag_descriptions::kUpdateMenuTypeNone, switches::kForceUpdateMenuType,
@@ -2085,9 +2077,6 @@
     {"enable-chrome-duet", flag_descriptions::kChromeDuetName,
      flag_descriptions::kChromeDuetDescription, kOsAndroid,
      FEATURE_VALUE_TYPE(chrome::android::kChromeDuetFeature)},
-    {"chrome-home-swipe-logic", flag_descriptions::kChromeHomeSwipeLogicName,
-     flag_descriptions::kChromeHomeSwipeLogicDescription, kOsAndroid,
-     MULTI_VALUE_TYPE(kChromeHomeSwipeLogicChoices)},
     {"enable-chrome-memex", flag_descriptions::kChromeMemexName,
      flag_descriptions::kChromeMemexDescription, kOsAndroid,
      FEATURE_VALUE_TYPE(chrome::android::kChromeMemexFeature)},
@@ -3710,12 +3699,6 @@
      flag_descriptions::kClipboardContentSettingDescription, kOsAll,
      FEATURE_VALUE_TYPE(features::kClipboardContentSetting)},
 
-#if defined(OS_CHROMEOS)
-    {"native-smb", flag_descriptions::kNativeSmbName,
-     flag_descriptions::kNativeSmbDescription, kOsCrOS,
-     FEATURE_VALUE_TYPE(features::kNativeSmb)},
-#endif  // defined(OS_CHROMEOS)
-
     {"enable-modern-media-controls",
      flag_descriptions::kUseModernMediaControlsName,
      flag_descriptions::kUseModernMediaControlsDescription, kOsAll,
diff --git a/chrome/browser/android/chrome_feature_list.cc b/chrome/browser/android/chrome_feature_list.cc
index 2ae41250..e190da3 100644
--- a/chrome/browser/android/chrome_feature_list.cc
+++ b/chrome/browser/android/chrome_feature_list.cc
@@ -90,8 +90,6 @@
     &kCCTReportParallelRequestStatus,
     &kCCTResourcePrefetch,
     &kChromeDuetFeature,
-    &kChromeHomeSwipeLogic,
-    &kChromeHomeSwipeLogicVelocity,
     &kChromeSmartSelection,
     &kChromeMemexFeature,
     &kCommandLineOnNonRooted,
@@ -245,12 +243,6 @@
 const base::Feature kChromeDuetFeature{"ChromeDuet",
                                        base::FEATURE_DISABLED_BY_DEFAULT};
 
-const base::Feature kChromeHomeSwipeLogic{"ChromeHomeSwipeLogic",
-                                          base::FEATURE_DISABLED_BY_DEFAULT};
-
-const base::Feature kChromeHomeSwipeLogicVelocity{
-    "ChromeHomeSwipeLogicVelocity", base::FEATURE_DISABLED_BY_DEFAULT};
-
 const base::Feature kChromeMemexFeature{"ChromeMemex",
                                         base::FEATURE_DISABLED_BY_DEFAULT};
 
diff --git a/chrome/browser/android/chrome_feature_list.h b/chrome/browser/android/chrome_feature_list.h
index c8e7287..149536d 100644
--- a/chrome/browser/android/chrome_feature_list.h
+++ b/chrome/browser/android/chrome_feature_list.h
@@ -30,8 +30,6 @@
 extern const base::Feature kCCTReportParallelRequestStatus;
 extern const base::Feature kCCTResourcePrefetch;
 extern const base::Feature kChromeDuetFeature;
-extern const base::Feature kChromeHomeSwipeLogic;
-extern const base::Feature kChromeHomeSwipeLogicVelocity;
 extern const base::Feature kChromeMemexFeature;
 extern const base::Feature kChromeSmartSelection;
 extern const base::Feature kCommandLineOnNonRooted;
diff --git a/chrome/browser/android/compositor/compositor_view.cc b/chrome/browser/android/compositor/compositor_view.cc
index ae97d5e5..3426fa40 100644
--- a/chrome/browser/android/compositor/compositor_view.cc
+++ b/chrome/browser/android/compositor/compositor_view.cc
@@ -261,7 +261,7 @@
     const content::ChildProcessData& data,
     const content::ChildProcessTerminationInfo& info) {
   LOG(WARNING) << "Child process died (type=" << data.process_type
-               << ") pid=" << data.GetHandle() << ")";
+               << ") pid=" << data.GetProcess().Pid() << ")";
   if (base::android::BuildInfo::GetInstance()->sdk_int() <=
           base::android::SDK_VERSION_JELLY_BEAN_MR2 &&
       data.process_type == content::PROCESS_TYPE_GPU) {
diff --git a/chrome/browser/android/explore_sites/image_helper_unittest.cc b/chrome/browser/android/explore_sites/image_helper_unittest.cc
index 02de1982..76458f291 100644
--- a/chrome/browser/android/explore_sites/image_helper_unittest.cc
+++ b/chrome/browser/android/explore_sites/image_helper_unittest.cc
@@ -13,6 +13,8 @@
 #include "base/test/scoped_task_environment.h"
 #include "base/test/test_simple_task_runner.h"
 #include "services/data_decoder/public/cpp/test_data_decoder_service.h"
+#include "services/data_decoder/public/mojom/constants.mojom.h"
+#include "services/service_manager/public/cpp/test/test_connector_factory.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "third_party/skia/include/core/SkImageInfo.h"
@@ -45,13 +47,9 @@
 
 class ExploreSitesImageHelperTest : public testing::Test {
  public:
-  ExploreSitesImageHelperTest() {
-    std::unique_ptr<service_manager::Service> service =
-        data_decoder::DataDecoderService::Create();
-    connector_factory_ =
-        service_manager::TestConnectorFactory::CreateForUniqueService(
-            std::move(service));
-  }
+  ExploreSitesImageHelperTest()
+      : data_decoder_(connector_factory_.RegisterInstance(
+            data_decoder::mojom::kServiceName)) {}
 
   ~ExploreSitesImageHelperTest() override{};
 
@@ -70,10 +68,11 @@
   base::test::ScopedTaskEnvironment scoped_task_environment_;
 
   std::unique_ptr<service_manager::Connector> GetConnector() {
-    return connector_factory_->CreateConnector();
+    return connector_factory_.CreateConnector();
   }
 
-  std::unique_ptr<service_manager::TestConnectorFactory> connector_factory_;
+  service_manager::TestConnectorFactory connector_factory_;
+  data_decoder::DataDecoderService data_decoder_;
   base::HistogramTester histogram_tester_;
 };
 
diff --git a/chrome/browser/android/feedback/process_id_feedback_source.cc b/chrome/browser/android/feedback/process_id_feedback_source.cc
index 41258982..6e703bba 100644
--- a/chrome/browser/android/feedback/process_id_feedback_source.cc
+++ b/chrome/browser/android/feedback/process_id_feedback_source.cc
@@ -68,7 +68,7 @@
 
   for (content::BrowserChildProcessHostIterator iter; !iter.Done(); ++iter)
     process_ids_[iter.GetData().process_type].push_back(
-        iter.GetData().GetHandle());
+        iter.GetData().GetProcess().Handle());
 
   base::PostTaskWithTraits(
       FROM_HERE, {BrowserThread::UI},
diff --git a/chrome/browser/android/omnibox/autocomplete_controller_android.cc b/chrome/browser/android/omnibox/autocomplete_controller_android.cc
index 07b4e43..cd211a7 100644
--- a/chrome/browser/android/omnibox/autocomplete_controller_android.cc
+++ b/chrome/browser/android/omnibox/autocomplete_controller_android.cc
@@ -39,11 +39,11 @@
 #include "components/omnibox/browser/autocomplete_input.h"
 #include "components/omnibox/browser/autocomplete_match.h"
 #include "components/omnibox/browser/autocomplete_match_type.h"
+#include "components/omnibox/browser/location_bar_model.h"
 #include "components/omnibox/browser/omnibox_event_global_tracker.h"
 #include "components/omnibox/browser/omnibox_field_trial.h"
 #include "components/omnibox/browser/omnibox_log.h"
 #include "components/omnibox/browser/search_provider.h"
-#include "components/omnibox/browser/toolbar_model.h"
 #include "components/open_from_clipboard/clipboard_recent_content.h"
 #include "components/prefs/pref_service.h"
 #include "components/search_engines/template_url_service.h"
diff --git a/chrome/browser/android/policy/policy_auditor.cc b/chrome/browser/android/policy/policy_auditor.cc
index 4eb18de8..25c4570 100644
--- a/chrome/browser/android/policy/policy_auditor.cc
+++ b/chrome/browser/android/policy/policy_auditor.cc
@@ -16,8 +16,8 @@
     const JavaParamRef<jclass>& obj,
     const JavaParamRef<jobject>& java_web_contents) {
   // This function is similar to
-  // ToolbarModelImpl::GetSecurityLevelForWebContents, but has a custom mapping
-  // for policy auditing
+  // LocationBarModelImpl::GetSecurityLevelForWebContents, but has a custom
+  // mapping for policy auditing.
   // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.policy
   // GENERATED_JAVA_PREFIX_TO_STRIP: CERTIFICATE_FAIL_
   enum CertificateFailure {
diff --git a/chrome/browser/android/tab_android.h b/chrome/browser/android/tab_android.h
index f37a21f7..42c4c06 100644
--- a/chrome/browser/android/tab_android.h
+++ b/chrome/browser/android/tab_android.h
@@ -21,7 +21,7 @@
 #include "chrome/browser/ui/tab_contents/core_tab_helper_delegate.h"
 #include "components/favicon/core/favicon_driver_observer.h"
 #include "components/infobars/core/infobar_manager.h"
-#include "components/omnibox/browser/toolbar_model.h"
+#include "components/omnibox/browser/location_bar_model.h"
 #include "components/sessions/core/session_id.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
diff --git a/chrome/browser/android/vr/arcore_device/arcore_java_utils.cc b/chrome/browser/android/vr/arcore_device/arcore_java_utils.cc
index 39f71a09..f0f5c458 100644
--- a/chrome/browser/android/vr/arcore_device/arcore_java_utils.cc
+++ b/chrome/browser/android/vr/arcore_device/arcore_java_utils.cc
@@ -7,9 +7,11 @@
 #include "base/android/jni_string.h"
 #include "chrome/browser/android/tab_android.h"
 #include "chrome/browser/android/vr/arcore_device/arcore_device.h"
+#include "chrome/browser/android/vr/arcore_device/arcore_device_provider.h"
 #include "chrome/browser/android/vr/arcore_device/arcore_shim.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
+#include "device/vr/android/arcore/arcore_device_provider_factory.h"
 #include "jni/ArCoreJavaUtils_jni.h"
 
 using base::android::AttachCurrentThread;
@@ -17,6 +19,26 @@
 
 namespace vr {
 
+namespace {
+
+class ArCoreDeviceProviderFactoryImpl
+    : public device::ArCoreDeviceProviderFactory {
+ public:
+  ArCoreDeviceProviderFactoryImpl() = default;
+  ~ArCoreDeviceProviderFactoryImpl() override = default;
+  std::unique_ptr<device::VRDeviceProvider> CreateDeviceProvider() override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ArCoreDeviceProviderFactoryImpl);
+};
+
+std::unique_ptr<device::VRDeviceProvider>
+ArCoreDeviceProviderFactoryImpl::CreateDeviceProvider() {
+  return std::make_unique<device::ArCoreDeviceProvider>();
+}
+
+}  // namespace
+
 ArCoreJavaUtils::ArCoreJavaUtils(device::ArCoreDevice* arcore_device)
     : arcore_device_(arcore_device) {
   DCHECK(arcore_device_);
@@ -108,4 +130,11 @@
   return Java_ArCoreJavaUtils_getApplicationContext(env);
 }
 
+static void JNI_ArCoreJavaUtils_InstallArCoreDeviceProviderFactory(
+    JNIEnv* env,
+    const base::android::JavaParamRef<jclass>& clazz) {
+  device::ArCoreDeviceProviderFactory::Install(
+      std::make_unique<ArCoreDeviceProviderFactoryImpl>());
+}
+
 }  // namespace vr
diff --git a/chrome/browser/android/vr/vr_gl_thread.cc b/chrome/browser/android/vr/vr_gl_thread.cc
index 3477047..03d2dbd 100644
--- a/chrome/browser/android/vr/vr_gl_thread.cc
+++ b/chrome/browser/android/vr/vr_gl_thread.cc
@@ -15,8 +15,8 @@
 #include "chrome/browser/vr/browser_renderer.h"
 #include "chrome/browser/vr/browser_ui_interface.h"
 #include "chrome/browser/vr/model/assets.h"
+#include "chrome/browser/vr/model/location_bar_state.h"
 #include "chrome/browser/vr/model/omnibox_suggestions.h"
-#include "chrome/browser/vr/model/toolbar_state.h"
 #include "chrome/browser/vr/sounds_manager_audio_delegate.h"
 #include "chrome/browser/vr/ui_factory.h"
 #include "chrome/browser/vr/ui_test_input.h"
@@ -380,11 +380,11 @@
                                          weak_browser_ui_, loading));
 }
 
-void VrGLThread::SetToolbarState(const ToolbarState& state) {
+void VrGLThread::SetLocationBarState(const LocationBarState& state) {
   DCHECK(OnMainThread());
-  task_runner()->PostTask(FROM_HERE,
-                          base::BindOnce(&BrowserUiInterface::SetToolbarState,
-                                         weak_browser_ui_, state));
+  task_runner()->PostTask(
+      FROM_HERE, base::BindOnce(&BrowserUiInterface::SetLocationBarState,
+                                weak_browser_ui_, state));
 }
 
 void VrGLThread::SetWebVrMode(bool enabled) {
diff --git a/chrome/browser/android/vr/vr_gl_thread.h b/chrome/browser/android/vr/vr_gl_thread.h
index 8267e24..e9d98e4 100644
--- a/chrome/browser/android/vr/vr_gl_thread.h
+++ b/chrome/browser/android/vr/vr_gl_thread.h
@@ -122,7 +122,7 @@
   // BrowserUiInterface implementation (Browser calling to UI).
   void SetWebVrMode(bool enabled) override;
   void SetFullscreen(bool enabled) override;
-  void SetToolbarState(const ToolbarState& state) override;
+  void SetLocationBarState(const LocationBarState& state) override;
   void SetIncognito(bool incognito) override;
   void SetLoading(bool loading) override;
   void SetLoadProgress(float progress) override;
diff --git a/chrome/browser/android/vr/vr_shell.cc b/chrome/browser/android/vr/vr_shell.cc
index 8f112df..88776a2a 100644
--- a/chrome/browser/android/vr/vr_shell.cc
+++ b/chrome/browser/android/vr/vr_shell.cc
@@ -38,12 +38,12 @@
 #include "chrome/browser/ssl/security_state_tab_helper.h"
 #include "chrome/browser/vr/assets_loader.h"
 #include "chrome/browser/vr/browser_renderer.h"
+#include "chrome/browser/vr/location_bar_helper.h"
 #include "chrome/browser/vr/metrics/metrics_helper.h"
 #include "chrome/browser/vr/metrics/session_metrics_helper.h"
 #include "chrome/browser/vr/model/assets.h"
 #include "chrome/browser/vr/model/omnibox_suggestions.h"
 #include "chrome/browser/vr/model/text_input_info.h"
-#include "chrome/browser/vr/toolbar_helper.h"
 #include "chrome/browser/vr/ui_test_input.h"
 #include "chrome/browser/vr/vr_tab_helper.h"
 #include "chrome/browser/vr/vr_web_contents_observer.h"
@@ -174,7 +174,7 @@
       pause_content, low_density, &gl_surface_created_event_,
       std::move(surface_callback));
   ui_ = gl_thread_.get();
-  toolbar_ = std::make_unique<ToolbarHelper>(ui_, this);
+  toolbar_ = std::make_unique<LocationBarHelper>(ui_, this);
   autocomplete_controller_ =
       std::make_unique<AutocompleteController>(base::BindRepeating(
           &BrowserUiInterface::SetOmniboxSuggestions, base::Unretained(ui_)));
@@ -1130,7 +1130,7 @@
 bool VrShell::ShouldDisplayURL() const {
   content::NavigationEntry* entry = GetNavigationEntry();
   if (!entry) {
-    return ChromeToolbarModelDelegate::ShouldDisplayURL();
+    return ChromeLocationBarModelDelegate::ShouldDisplayURL();
   }
   GURL url = entry->GetVirtualURL();
   // URL is of the form chrome-native://.... This is not useful for the user.
@@ -1142,7 +1142,7 @@
   if (url.SchemeIs(content::kChromeUIScheme)) {
     return true;
   }
-  return ChromeToolbarModelDelegate::ShouldDisplayURL();
+  return ChromeLocationBarModelDelegate::ShouldDisplayURL();
 }
 
 void VrShell::OnVoiceResults(const base::string16& result) {
diff --git a/chrome/browser/android/vr/vr_shell.h b/chrome/browser/android/vr/vr_shell.h
index f9aa677a..f49cb7e 100644
--- a/chrome/browser/android/vr/vr_shell.h
+++ b/chrome/browser/android/vr/vr_shell.h
@@ -16,7 +16,7 @@
 #include "base/single_thread_task_runner.h"
 #include "base/strings/string16.h"
 #include "chrome/browser/ui/page_info/page_info_ui.h"
-#include "chrome/browser/ui/toolbar/chrome_toolbar_model_delegate.h"
+#include "chrome/browser/ui/toolbar/chrome_location_bar_model_delegate.h"
 #include "chrome/browser/vr/assets_load_status.h"
 #include "chrome/browser/vr/exit_vr_prompt_choice.h"
 #include "chrome/browser/vr/metrics/session_metrics_helper.h"
@@ -51,7 +51,7 @@
 class BrowserUiInterface;
 class AndroidUiGestureTarget;
 class AutocompleteController;
-class ToolbarHelper;
+class LocationBarHelper;
 class VrGLThread;
 class VrInputConnection;
 class VrShellDelegate;
@@ -66,7 +66,7 @@
 class VrShell : device::GvrGamepadDataProvider,
                 device::CardboardGamepadDataProvider,
                 VoiceResultDelegate,
-                public ChromeToolbarModelDelegate,
+                public ChromeLocationBarModelDelegate,
                 public PageInfoUI {
  public:
   VrShell(JNIEnv* env,
@@ -255,7 +255,7 @@
   void RegisterCardboardGamepadDataFetcher(
       device::CardboardGamepadDataFetcher*) override;
 
-  // ChromeToolbarModelDelegate implementation.
+  // ChromeLocationBarModelDelegate implementation.
   content::WebContents* GetActiveWebContents() const override;
   bool ShouldDisplayURL() const override;
 
@@ -352,7 +352,7 @@
 
   // These instances make use of ui_ (provided by gl_thread_), and hence must be
   // destroyed before gl_thread_;
-  std::unique_ptr<ToolbarHelper> toolbar_;
+  std::unique_ptr<LocationBarHelper> toolbar_;
   std::unique_ptr<vr::AutocompleteController> autocomplete_controller_;
   std::unique_ptr<SpeechRecognizer> speech_recognizer_;
 
diff --git a/chrome/browser/android/vr/vr_shell_delegate.cc b/chrome/browser/android/vr/vr_shell_delegate.cc
index 252e289d..339c514 100644
--- a/chrome/browser/android/vr/vr_shell_delegate.cc
+++ b/chrome/browser/android/vr/vr_shell_delegate.cc
@@ -23,10 +23,6 @@
 #include "jni/VrShellDelegate_jni.h"
 #include "third_party/gvr-android-sdk/src/libraries/headers/vr/gvr/capi/include/gvr.h"
 
-#if BUILDFLAG(ENABLE_ARCORE)
-#include "device/vr/android/arcore/arcore_device_provider_factory.h"
-#endif
-
 using base::android::JavaParamRef;
 using base::android::JavaRef;
 using base::android::AttachCurrentThread;
@@ -52,24 +48,6 @@
   return VrShellDelegate::CreateVrShellDelegate();
 }
 
-#if BUILDFLAG(ENABLE_ARCORE)
-class ArCoreDeviceProviderFactoryImpl
-    : public device::ArCoreDeviceProviderFactory {
- public:
-  ArCoreDeviceProviderFactoryImpl() = default;
-  ~ArCoreDeviceProviderFactoryImpl() override = default;
-  std::unique_ptr<device::VRDeviceProvider> CreateDeviceProvider() override;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(ArCoreDeviceProviderFactoryImpl);
-};
-
-std::unique_ptr<device::VRDeviceProvider>
-ArCoreDeviceProviderFactoryImpl::CreateDeviceProvider() {
-  return std::make_unique<device::ArCoreDeviceProvider>();
-}
-#endif
-
 }  // namespace
 
 VrShellDelegate::VrShellDelegate(JNIEnv* env, jobject obj)
@@ -350,13 +328,6 @@
     const JavaParamRef<jclass>& clazz) {
   device::GvrDelegateProviderFactory::Install(
       std::make_unique<VrShellDelegateProviderFactory>());
-
-#if BUILDFLAG(ENABLE_ARCORE)
-  // TODO(https://crbug.com/837965): Move this to an ARCore-specific location
-  // with similar timing (occurs before XRRuntimeManager is initialized).
-  device::ArCoreDeviceProviderFactory::Install(
-      std::make_unique<ArCoreDeviceProviderFactoryImpl>());
-#endif
 }
 
 static void JNI_VrShellDelegate_RegisterVrAssetsComponent(
diff --git a/chrome/browser/apps/app_shim/app_shim_handler_mac.h b/chrome/browser/apps/app_shim/app_shim_handler_mac.h
index 9baa3f8c..629d6208 100644
--- a/chrome/browser/apps/app_shim/app_shim_handler_mac.h
+++ b/chrome/browser/apps/app_shim/app_shim_handler_mac.h
@@ -5,7 +5,6 @@
 #ifndef CHROME_BROWSER_APPS_APP_SHIM_APP_SHIM_HANDLER_MAC_H_
 #define CHROME_BROWSER_APPS_APP_SHIM_APP_SHIM_HANDLER_MAC_H_
 
-#include <memory>
 #include <string>
 #include <vector>
 
@@ -16,23 +15,14 @@
 class BridgeFactoryHost;
 }  // namespace views
 
-class AppShimHostBootstrap;
-
 namespace apps {
 
 // Registrar, and interface for services that can handle interactions with OSX
 // shim processes.
 class AppShimHandler {
  public:
-  // TODO(ccameron): Remove this virtual interface and always use AppShimHost
-  // directly.
-  // https://crbug.com/896917
   class Host {
    public:
-    // Invoked when the app shim process has finished launching. The |bootstrap|
-    // object owns the lifetime of the app shim process.
-    virtual void OnBootstrapConnected(
-        std::unique_ptr<AppShimHostBootstrap> bootstrap) = 0;
     // Invoked when the app is successfully launched.
     virtual void OnAppLaunchComplete(AppShimLaunchResult result) = 0;
     // Invoked when the app is closed in the browser process.
@@ -85,8 +75,9 @@
   // |launch_type| indicates the type of launch.
   // |files|, if non-empty, holds an array of files paths given as arguments, or
   // dragged onto the app bundle or dock icon.
-  virtual void OnShimLaunch(
-      std::unique_ptr<AppShimHostBootstrap> bootstrap) = 0;
+  virtual void OnShimLaunch(Host* host,
+                            AppShimLaunchType launch_type,
+                            const std::vector<base::FilePath>& files) = 0;
 
   // Invoked by the shim host when the connection to the shim process is closed.
   virtual void OnShimClose(Host* host) = 0;
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
index 831c5d3..bea5124 100644
--- a/chrome/browser/apps/app_shim/app_shim_host_bootstrap_mac.cc
+++ b/chrome/browser/apps/app_shim/app_shim_host_bootstrap_mac.cc
@@ -48,15 +48,24 @@
   delete this;
 }
 
-apps::AppShimHandler* AppShimHostBootstrap::GetHandler() {
-  return apps::AppShimHandler::GetForAppMode(app_id_);
-}
-
 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,
@@ -71,8 +80,6 @@
     return;
 
   app_shim_host_request_ = std::move(app_shim_host_request);
-  profile_path_ = profile_dir;
-  app_id_ = app_id;
   launch_type_ = launch_type;
   files_ = files;
   launch_app_callback_ = std::move(callback);
@@ -83,23 +90,13 @@
   has_received_launch_app_ = true;
   std::unique_ptr<AppShimHostBootstrap> deleter(this);
 
-  // |handler| takes ownership of |this| now.
-  apps::AppShimHandler* handler = GetHandler();
-  if (handler)
-    handler->OnShimLaunch(std::move(deleter));
-  // |handler| can only be NULL after AppShimHostManager is destroyed. Since
-  // this only happens at shutdown, do nothing here.
+  // |connected_host_| takes ownership of itself and |this|.
+  connected_host_ = new AppShimHost(app_id, profile_dir);
+  connected_host_->OnBootstrapConnected(std::move(deleter));
 }
 
-void AppShimHostBootstrap::OnLaunchAppSucceeded(
+void AppShimHostBootstrap::OnLaunchAppComplete(
+    apps::AppShimLaunchResult result,
     chrome::mojom::AppShimRequest app_shim_request) {
-  std::move(launch_app_callback_)
-      .Run(apps::APP_SHIM_LAUNCH_SUCCESS, std::move(app_shim_request));
-}
-
-void AppShimHostBootstrap::OnLaunchAppFailed(apps::AppShimLaunchResult result) {
-  // Because there will be users of the AppShim interface in failure, just
-  // return a dummy request.
-  chrome::mojom::AppShimPtr dummy_ptr;
-  std::move(launch_app_callback_).Run(result, mojo::MakeRequest(&dummy_ptr));
+  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
index e545274..f961ffd 100644
--- a/chrome/browser/apps/app_shim/app_shim_host_bootstrap_mac.h
+++ b/chrome/browser/apps/app_shim/app_shim_host_bootstrap_mac.h
@@ -25,20 +25,19 @@
   static void CreateForChannel(mojo::PlatformChannelEndpoint endpoint);
   ~AppShimHostBootstrap() override;
 
-  void OnLaunchAppSucceeded(chrome::mojom::AppShimRequest app_shim_request);
-  void OnLaunchAppFailed(apps::AppShimLaunchResult result);
+  void OnLaunchAppComplete(apps::AppShimLaunchResult result,
+                           chrome::mojom::AppShimRequest app_shim_request);
 
   chrome::mojom::AppShimHostRequest GetLaunchAppShimHostRequest();
-  const std::string& GetAppId() const { return app_id_; }
-  const base::FilePath& GetProfilePath() const { return profile_path_; }
-  apps::AppShimLaunchType GetLaunchType() const { return launch_type_; }
-  const std::vector<base::FilePath>& GetLaunchFiles() const { return files_; }
+  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);
-  virtual apps::AppShimHandler* GetHandler();
 
   // chrome::mojom::AppShimHostBootstrap.
   void LaunchApp(chrome::mojom::AppShimHostRequest app_shim_host_request,
@@ -55,12 +54,14 @@
   // yet.
   bool has_received_launch_app_ = false;
   chrome::mojom::AppShimHostRequest app_shim_host_request_;
-  base::FilePath profile_path_;
-  std::string app_id_;
   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);
 };
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 08873fd..0f24d8f 100644
--- a/chrome/browser/apps/app_shim/app_shim_host_mac.cc
+++ b/chrome/browser/apps/app_shim/app_shim_host_mac.cc
@@ -58,10 +58,9 @@
 
 AppShimHost::~AppShimHost() {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  // Ensure that we send a response to the bootstrap even if we failed to finish
-  // loading.
-  if (bootstrap_ && !has_sent_on_launch_complete_)
-    bootstrap_->OnLaunchAppFailed(apps::APP_SHIM_LAUNCH_APP_NOT_FOUND);
+  apps::AppShimHandler* handler = apps::AppShimHandler::GetForAppMode(app_id_);
+  if (handler)
+    handler->OnShimClose(this);
 }
 
 void AppShimHost::ChannelError(uint32_t custom_reason,
@@ -73,18 +72,9 @@
 
 void AppShimHost::Close() {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  // Note that we must call GetAppShimHandler here and not in the destructor
-  // because some tests override the method.
-  apps::AppShimHandler* handler = GetAppShimHandler();
-  if (handler)
-    handler->OnShimClose(this);
   delete this;
 }
 
-apps::AppShimHandler* AppShimHost::GetAppShimHandler() const {
-  return apps::AppShimHandler::GetForAppMode(app_id_);
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // AppShimHost, chrome::mojom::AppShimHost
 
@@ -97,26 +87,33 @@
   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, bootstrap_->GetLaunchType(),
+                          bootstrap_->GetLaunchFiles());
+  // |handler| can only be NULL after AppShimHostManager is destroyed. Since
+  // this only happens at shutdown, do nothing here.
 }
 
 void AppShimHost::FocusApp(apps::AppShimFocusType focus_type,
                            const std::vector<base::FilePath>& files) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  apps::AppShimHandler* handler = GetAppShimHandler();
+  apps::AppShimHandler* handler = apps::AppShimHandler::GetForAppMode(app_id_);
   if (handler)
     handler->OnShimFocus(this, focus_type, files);
 }
 
 void AppShimHost::SetAppHidden(bool hidden) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  apps::AppShimHandler* handler = GetAppShimHandler();
+  apps::AppShimHandler* handler = apps::AppShimHandler::GetForAppMode(app_id_);
   if (handler)
     handler->OnShimSetHidden(this, hidden);
 }
 
 void AppShimHost::QuitApp() {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  apps::AppShimHandler* handler = GetAppShimHandler();
+  apps::AppShimHandler* handler = apps::AppShimHandler::GetForAppMode(app_id_);
   if (handler)
     handler->OnShimQuit(this);
 }
@@ -125,13 +122,11 @@
 // AppShimHost, apps::AppShimHandler::Host
 
 void AppShimHost::OnAppLaunchComplete(apps::AppShimLaunchResult result) {
-  DCHECK(!has_sent_on_launch_complete_);
-  DCHECK(bootstrap_);
-  if (result == apps::APP_SHIM_LAUNCH_SUCCESS)
-    bootstrap_->OnLaunchAppSucceeded(std::move(app_shim_request_));
-  else
-    bootstrap_->OnLaunchAppFailed(result);
-  has_sent_on_launch_complete_ = true;
+  if (!has_sent_on_launch_complete_) {
+    DCHECK(bootstrap_);
+    bootstrap_->OnLaunchAppComplete(result, std::move(app_shim_request_));
+    has_sent_on_launch_complete_ = true;
+  }
 }
 
 void AppShimHost::OnAppClosed() {
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 25ca5e25..b89fa994 100644
--- a/chrome/browser/apps/app_shim/app_shim_host_mac.h
+++ b/chrome/browser/apps/app_shim/app_shim_host_mac.h
@@ -33,10 +33,23 @@
                     public apps::AppShimHandler::Host {
  public:
   AppShimHost(const std::string& app_id, const base::FilePath& profile_path);
+  ~AppShimHost() override;
+
+  void OnBootstrapConnected(std::unique_ptr<AppShimHostBootstrap> bootstrap);
+
+ protected:
+  void ChannelError(uint32_t custom_reason, const std::string& description);
+
+  // Closes the channel and destroys the AppShimHost.
+  void Close();
+
+  // chrome::mojom::AppShimHost.
+  void FocusApp(apps::AppShimFocusType focus_type,
+                const std::vector<base::FilePath>& files) override;
+  void SetAppHidden(bool hidden) override;
+  void QuitApp() override;
 
   // apps::AppShimHandler::Host overrides:
-  void OnBootstrapConnected(
-      std::unique_ptr<AppShimHostBootstrap> bootstrap) override;
   void OnAppLaunchComplete(apps::AppShimLaunchResult result) override;
   void OnAppClosed() override;
   void OnAppHide() override;
@@ -46,24 +59,6 @@
   std::string GetAppId() const override;
   views::BridgeFactoryHost* GetViewsBridgeFactoryHost() const override;
 
- protected:
-  // AppShimHost is owned by itself. It will delete itself in Close (called on
-  // channel error and OnAppClosed).
-  ~AppShimHost() override;
-  void ChannelError(uint32_t custom_reason, const std::string& description);
-
-  // Closes the channel and destroys the AppShimHost.
-  void Close();
-
-  // Return the AppShimHandler for this app (virtual for tests).
-  virtual apps::AppShimHandler* GetAppShimHandler() const;
-
-  // chrome::mojom::AppShimHost.
-  void FocusApp(apps::AppShimFocusType focus_type,
-                const std::vector<base::FilePath>& files) override;
-  void SetAppHidden(bool hidden) override;
-  void QuitApp() override;
-
   mojo::Binding<chrome::mojom::AppShimHost> host_binding_;
   chrome::mojom::AppShimPtr app_shim_;
   chrome::mojom::AppShimRequest app_shim_request_;
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 34fd814..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
@@ -10,7 +10,6 @@
 
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
-#include "base/memory/weak_ptr.h"
 #include "base/single_thread_task_runner.h"
 #include "base/test/scoped_task_environment.h"
 #include "base/test/test_simple_task_runner.h"
@@ -63,22 +62,6 @@
   DISALLOW_COPY_AND_ASSIGN(TestingAppShim);
 };
 
-class TestingAppShimHost : public AppShimHost {
- public:
-  TestingAppShimHost(const std::string& app_id,
-                     const base::FilePath& profile_path)
-      : AppShimHost(app_id, profile_path), test_weak_factory_(this) {}
-
-  base::WeakPtr<TestingAppShimHost> GetWeakPtr() {
-    return test_weak_factory_.GetWeakPtr();
-  }
-
- private:
-  ~TestingAppShimHost() override {}
-  base::WeakPtrFactory<TestingAppShimHost> test_weak_factory_;
-  DISALLOW_COPY_AND_ASSIGN(TestingAppShimHost);
-};
-
 class TestingAppShimHostBootstrap : public AppShimHostBootstrap {
  public:
   explicit TestingAppShimHostBootstrap(
@@ -93,8 +76,6 @@
     return test_weak_factory_.GetWeakPtr();
   }
 
-  using AppShimHostBootstrap::LaunchApp;
-
  private:
   base::WeakPtrFactory<TestingAppShimHostBootstrap> test_weak_factory_;
   DISALLOW_COPY_AND_ASSIGN(TestingAppShimHostBootstrap);
@@ -110,7 +91,7 @@
 
   ~AppShimHostTest() override {
     if (host_)
-      host_->OnAppClosed();
+      delete host_.get();
     DCHECK(!host_);
   }
 
@@ -118,16 +99,17 @@
   scoped_refptr<base::SingleThreadTaskRunner> task_runner() {
     return task_runner_;
   }
-  apps::AppShimHandler::Host* host() { return host_.get(); }
+  TestingAppShimHostBootstrap* host() { return host_.get(); }
+  chrome::mojom::AppShimHostBootstrap* GetBootstrapMojoHost() {
+    return host_.get();
+  }
   chrome::mojom::AppShimHost* GetMojoHost() { return host_ptr_.get(); }
 
   void LaunchApp(apps::AppShimLaunchType launch_type) {
-    // Ownership of TestingAppShimHostBootstrap will be transferred to its host.
-    (new TestingAppShimHostBootstrap(shim_->GetHostBootstrapRequest()))
-        ->LaunchApp(mojo::MakeRequest(&host_ptr_),
-                    base::FilePath(kTestProfileDir), kTestAppId, launch_type,
-                    std::vector<base::FilePath>(),
-                    shim_->GetLaunchAppCallback());
+    GetBootstrapMojoHost()->LaunchApp(
+        mojo::MakeRequest(&host_ptr_), base::FilePath(kTestProfileDir),
+        kTestAppId, launch_type, std::vector<base::FilePath>(),
+        shim_->GetLaunchAppCallback());
   }
 
   apps::AppShimLaunchResult GetLaunchResult() {
@@ -138,17 +120,13 @@
   void SimulateDisconnect() { host_ptr_.reset(); }
 
  protected:
-  void OnShimLaunch(std::unique_ptr<AppShimHostBootstrap> bootstrap) override {
+  void OnShimLaunch(Host* host,
+                    apps::AppShimLaunchType launch_type,
+                    const std::vector<base::FilePath>& file) override {
     ++launch_count_;
-    if (bootstrap->GetLaunchType() == apps::APP_SHIM_LAUNCH_NORMAL)
+    if (launch_type == apps::APP_SHIM_LAUNCH_NORMAL)
       ++launch_now_count_;
-    // Maintain only a weak reference to |host_| because it is owned by itself
-    // and will delete itself upon closing.
-    host_ = (new TestingAppShimHost(bootstrap->GetAppId(),
-                                    bootstrap->GetProfilePath()))
-                ->GetWeakPtr();
-    host_->OnBootstrapConnected(std::move(bootstrap));
-    host_->OnAppLaunchComplete(launch_result_);
+    host->OnAppLaunchComplete(launch_result_);
   }
 
   void OnShimClose(Host* host) override { ++close_count_; }
@@ -174,6 +152,9 @@
   void SetUp() override {
     testing::Test::SetUp();
     shim_.reset(new TestingAppShim());
+    TestingAppShimHostBootstrap* host =
+        new TestingAppShimHostBootstrap(shim_->GetHostBootstrapRequest());
+    host_ = host->GetWeakPtr();
   }
 
   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
@@ -181,11 +162,9 @@
 
   std::unique_ptr<TestingAppShim> shim_;
 
-  std::unique_ptr<AppShimHostBootstrap> launched_bootstrap_;
-
   // 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);
@@ -197,13 +176,18 @@
 TEST_F(AppShimHostTest, TestLaunchAppWithHandler) {
   apps::AppShimHandler::RegisterHandler(kTestAppId, this);
   LaunchApp(apps::APP_SHIM_LAUNCH_NORMAL);
-  EXPECT_EQ(kTestAppId, 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_);
   EXPECT_EQ(0, focus_count_);
   EXPECT_EQ(0, close_count_);
 
+  // A second OnAppLaunchComplete is ignored.
+  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,
                           std::vector<base::FilePath>());
   RunUntilIdle();
@@ -223,7 +207,7 @@
 TEST_F(AppShimHostTest, TestNoLaunchNow) {
   apps::AppShimHandler::RegisterHandler(kTestAppId, this);
   LaunchApp(apps::APP_SHIM_LAUNCH_REGISTER_ONLY);
-  EXPECT_EQ(kTestAppId, 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_browsertest_mac.mm b/chrome/browser/apps/app_shim/app_shim_host_manager_browsertest_mac.mm
index b17c6e7..325ca959 100644
--- a/chrome/browser/apps/app_shim/app_shim_host_manager_browsertest_mac.mm
+++ b/chrome/browser/apps/app_shim/app_shim_host_manager_browsertest_mac.mm
@@ -13,7 +13,6 @@
 #include "base/run_loop.h"
 #include "base/threading/thread_restrictions.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 "chrome/browser/apps/app_shim/test/app_shim_host_manager_test_api_mac.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
@@ -100,10 +99,9 @@
 // Browser Test for AppShimHostManager to test IPC interactions across the
 // UNIX domain socket.
 class AppShimHostManagerBrowserTest : public InProcessBrowserTest,
-                                      public apps::AppShimHandler,
-                                      public chrome::mojom::AppShimHost {
+                                      public apps::AppShimHandler {
  public:
-  AppShimHostManagerBrowserTest() : binding_(this) {}
+  AppShimHostManagerBrowserTest() {}
 
  protected:
   // Wait for OnShimLaunch, then send a quit, and wait for the response. Used to
@@ -115,32 +113,23 @@
   void TearDownOnMainThread() override;
 
   // AppShimHandler overrides:
-  void OnShimLaunch(std::unique_ptr<AppShimHostBootstrap> bootstrap) override;
+  void OnShimLaunch(apps::AppShimHandler::Host* host,
+                    apps::AppShimLaunchType launch_type,
+                    const std::vector<base::FilePath>& files) override;
   void OnShimClose(apps::AppShimHandler::Host* host) override {}
   void OnShimFocus(apps::AppShimHandler::Host* host,
                    apps::AppShimFocusType focus_type,
                    const std::vector<base::FilePath>& files) override {}
   void OnShimSetHidden(apps::AppShimHandler::Host* host, bool hidden) override {
   }
-  void OnShimQuit(apps::AppShimHandler::Host* host) override {}
+  void OnShimQuit(apps::AppShimHandler::Host* host) override;
 
   std::unique_ptr<TestShimClient> test_client_;
   std::vector<base::FilePath> last_launch_files_;
   apps::AppShimLaunchType last_launch_type_ = apps::APP_SHIM_LAUNCH_NUM_TYPES;
 
  private:
-  // chrome::mojom::AppShimHost.
-  void FocusApp(apps::AppShimFocusType focus_type,
-                const std::vector<base::FilePath>& files) override {}
-  void SetAppHidden(bool hidden) override {}
-  void QuitApp() override {
-    ++quit_count_;
-    runner_->Quit();
-  }
-
   std::unique_ptr<base::RunLoop> runner_;
-  mojo::Binding<chrome::mojom::AppShimHost> binding_;
-  chrome::mojom::AppShimPtr app_shim_ptr_;
 
   int launch_count_ = 0;
   int quit_count_ = 0;
@@ -157,7 +146,7 @@
   runner_ = std::make_unique<base::RunLoop>();
   test_client_->host()->QuitApp();
   EXPECT_EQ(0, quit_count_);
-  runner_->Run();  // Will stop in QuitApp().
+  runner_->Run();  // Will stop in OnShimQuit().
   EXPECT_EQ(1, quit_count_);
 
   test_client_.reset();
@@ -173,13 +162,19 @@
 }
 
 void AppShimHostManagerBrowserTest::OnShimLaunch(
-    std::unique_ptr<AppShimHostBootstrap> bootstrap) {
+    apps::AppShimHandler::Host* host,
+    apps::AppShimLaunchType launch_type,
+    const std::vector<base::FilePath>& files) {
+  host->OnAppLaunchComplete(apps::APP_SHIM_LAUNCH_SUCCESS);
   ++launch_count_;
-  binding_.Bind(bootstrap->GetLaunchAppShimHostRequest());
-  last_launch_type_ = bootstrap->GetLaunchType();
-  last_launch_files_ = bootstrap->GetLaunchFiles();
+  last_launch_type_ = launch_type;
+  last_launch_files_ = files;
+  runner_->Quit();
+}
 
-  bootstrap->OnLaunchAppSucceeded(mojo::MakeRequest(&app_shim_ptr_));
+void AppShimHostManagerBrowserTest::OnShimQuit(
+    apps::AppShimHandler::Host* host) {
+  ++quit_count_;
   runner_->Quit();
 }
 
diff --git a/chrome/browser/apps/app_shim/app_shim_interactive_uitest_mac.mm b/chrome/browser/apps/app_shim/app_shim_interactive_uitest_mac.mm
index d36e26d..83166ac 100644
--- a/chrome/browser/apps/app_shim/app_shim_interactive_uitest_mac.mm
+++ b/chrome/browser/apps/app_shim/app_shim_interactive_uitest_mac.mm
@@ -3,8 +3,6 @@
 // found in the LICENSE file.
 
 #import <Cocoa/Cocoa.h>
-#include <memory>
-#include <utility>
 #include <vector>
 
 #include "apps/app_lifetime_monitor_factory.h"
@@ -26,7 +24,6 @@
 #include "base/threading/thread_restrictions.h"
 #include "build/build_config.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 "chrome/browser/apps/app_shim/app_shim_host_manager_mac.h"
 #include "chrome/browser/apps/app_shim/extension_app_shim_handler_mac.h"
 #include "chrome/browser/apps/platform_apps/app_browsertest_util.h"
@@ -98,11 +95,13 @@
   }
 
   // AppShimHandler overrides:
-  void OnShimLaunch(std::unique_ptr<AppShimHostBootstrap> bootstrap) override {
+  void OnShimLaunch(Host* host,
+                    apps::AppShimLaunchType launch_type,
+                    const std::vector<base::FilePath>& files) override {
     // Remove self and pass through to the default handler.
     apps::AppShimHandler::RemoveHandler(app_mode_id_);
     apps::AppShimHandler::GetForAppMode(app_mode_id_)
-        ->OnShimLaunch(std::move(bootstrap));
+        ->OnShimLaunch(host, launch_type, files);
     observed_ = true;
     if (run_loop_.get())
       run_loop_->Quit();
diff --git a/chrome/browser/apps/app_shim/app_shim_quit_interactive_uitest_mac.mm b/chrome/browser/apps/app_shim/app_shim_quit_interactive_uitest_mac.mm
index 37f8ad7..d41afb7 100644
--- a/chrome/browser/apps/app_shim/app_shim_quit_interactive_uitest_mac.mm
+++ b/chrome/browser/apps/app_shim/app_shim_quit_interactive_uitest_mac.mm
@@ -8,10 +8,7 @@
 #include <vector>
 
 #include "apps/switches.h"
-#include "base/bind.h"
 #include "base/macros.h"
-#include "chrome/browser/apps/app_shim/app_shim_host_bootstrap_mac.h"
-#include "chrome/browser/apps/app_shim/app_shim_host_mac.h"
 #include "chrome/browser/apps/app_shim/app_shim_host_manager_mac.h"
 #include "chrome/browser/apps/app_shim/extension_app_shim_handler_mac.h"
 #include "chrome/browser/apps/platform_apps/app_browsertest_util.h"
@@ -31,14 +28,32 @@
 
 namespace {
 
-// Test class used to expose protected methods of AppShimHostBootstrap.
-class TestAppShimHostBootstrap : public AppShimHostBootstrap {
+class FakeHost : public apps::AppShimHandler::Host {
  public:
-  TestAppShimHostBootstrap() {}
-  using AppShimHostBootstrap::LaunchApp;
+  FakeHost(const base::FilePath& profile_path,
+           const std::string& app_id,
+           ExtensionAppShimHandler* handler)
+      : profile_path_(profile_path),
+        app_id_(app_id),
+        handler_(handler) {}
+
+  void OnAppLaunchComplete(AppShimLaunchResult result) override {}
+  void OnAppClosed() override { handler_->OnShimClose(this); }
+  void OnAppHide() override {}
+  void OnAppUnhideWithoutActivation() override {}
+  void OnAppRequestUserAttention(AppShimAttentionType type) override {}
+  base::FilePath GetProfilePath() const override { return profile_path_; }
+  std::string GetAppId() const override { return app_id_; }
+  views::BridgeFactoryHost* GetViewsBridgeFactoryHost() const override {
+    return nullptr;
+  }
 
  private:
-  DISALLOW_COPY_AND_ASSIGN(TestAppShimHostBootstrap);
+  base::FilePath profile_path_;
+  std::string app_id_;
+  ExtensionAppShimHandler* handler_;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeHost);
 };
 
 // Starts an app without a browser window using --load_and_launch_app and
@@ -61,14 +76,13 @@
         extensions::ExtensionRegistry::Get(profile());
     extension_id_ =
         GetExtensionByPath(registry->enabled_extensions(), app_path_)->id();
-    chrome::mojom::AppShimHostPtr host_ptr;
-    (new TestAppShimHostBootstrap)
-        ->LaunchApp(mojo::MakeRequest(&host_ptr),
-                    profile()->GetPath().BaseName(), extension_id_,
-                    APP_SHIM_LAUNCH_REGISTER_ONLY,
-                    std::vector<base::FilePath>(),
-                    base::BindOnce(&AppShimQuitTest::DoShimLaunchDone,
-                                   base::Unretained(this)));
+    host_.reset(new FakeHost(profile()->GetPath().BaseName(),
+                             extension_id_,
+                             handler_));
+    handler_->OnShimLaunch(host_.get(),
+                           APP_SHIM_LAUNCH_REGISTER_ONLY,
+                           std::vector<base::FilePath>());
+    EXPECT_EQ(host_.get(), handler_->FindHost(profile(), extension_id_));
 
     // Focus the app window.
     NSWindow* window = [[NSApp windows] objectAtIndex:0];
@@ -76,9 +90,6 @@
     content::RunAllPendingInMessageLoop();
   }
 
-  void DoShimLaunchDone(apps::AppShimLaunchResult result,
-                        chrome::mojom::AppShimRequest app_shim_request) {}
-
   void SetUpCommandLine(base::CommandLine* command_line) override {
     PlatformAppBrowserTest::SetUpCommandLine(command_line);
     // Simulate an app shim initiated launch, i.e. launch app but not browser.
@@ -93,6 +104,7 @@
   base::FilePath app_path_;
   ExtensionAppShimHandler* handler_;
   std::string extension_id_;
+  std::unique_ptr<FakeHost> host_;
 
   DISALLOW_COPY_AND_ASSIGN(AppShimQuitTest);
 };
diff --git a/chrome/browser/apps/app_shim/apps_page_shim_handler.h b/chrome/browser/apps/app_shim/apps_page_shim_handler.h
index 5a7ed3c..68dd13c 100644
--- a/chrome/browser/apps/app_shim/apps_page_shim_handler.h
+++ b/chrome/browser/apps/app_shim/apps_page_shim_handler.h
@@ -17,7 +17,9 @@
   AppsPageShimHandler() {}
 
   // AppShimHandler:
-  void OnShimLaunch(std::unique_ptr<AppShimHostBootstrap> bootstrap) override;
+  void OnShimLaunch(apps::AppShimHandler::Host* host,
+                    apps::AppShimLaunchType launch_type,
+                    const std::vector<base::FilePath>& files) override;
   void OnShimClose(apps::AppShimHandler::Host* host) override;
   void OnShimFocus(apps::AppShimHandler::Host* host,
                    apps::AppShimFocusType focus_type,
diff --git a/chrome/browser/apps/app_shim/apps_page_shim_handler.mm b/chrome/browser/apps/app_shim/apps_page_shim_handler.mm
index 93fadaf..ef1b6c8 100644
--- a/chrome/browser/apps/app_shim/apps_page_shim_handler.mm
+++ b/chrome/browser/apps/app_shim/apps_page_shim_handler.mm
@@ -6,7 +6,6 @@
 
 #import "base/mac/foundation_util.h"
 #import "chrome/browser/app_controller_mac.h"
-#include "chrome/browser/apps/app_shim/app_shim_host_bootstrap_mac.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_attributes_entry.h"
@@ -54,13 +53,15 @@
 }  // namespace
 
 void AppsPageShimHandler::OnShimLaunch(
-    std::unique_ptr<AppShimHostBootstrap> bootstrap) {
+    apps::AppShimHandler::Host* host,
+    apps::AppShimLaunchType launch_type,
+    const std::vector<base::FilePath>& files) {
   AppController* controller =
       base::mac::ObjCCastStrict<AppController>([NSApp delegate]);
   OpenAppsPage([controller lastProfile]);
 
   // Always close the shim process immediately.
-  bootstrap->OnLaunchAppFailed(apps::APP_SHIM_LAUNCH_DUPLICATE_HOST);
+  host->OnAppLaunchComplete(apps::APP_SHIM_LAUNCH_DUPLICATE_HOST);
 }
 
 void AppsPageShimHandler::OnShimClose(apps::AppShimHandler::Host* host) {}
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 885161a0..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
@@ -8,12 +8,9 @@
 
 #include "apps/app_lifetime_monitor_factory.h"
 #include "apps/launcher.h"
-#include "base/callback.h"
 #include "base/files/file_path.h"
 #include "base/logging.h"
 #include "base/macros.h"
-#include "chrome/browser/apps/app_shim/app_shim_host_bootstrap_mac.h"
-#include "chrome/browser/apps/app_shim/app_shim_host_mac.h"
 #include "chrome/browser/apps/app_shim/app_shim_host_manager_mac.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
@@ -61,6 +58,18 @@
 
 typedef AppWindowRegistry::AppWindowList AppWindowList;
 
+void ProfileLoadedCallback(base::Callback<void(Profile*)> callback,
+                           Profile* profile,
+                           Profile::CreateStatus status) {
+  if (status == Profile::CREATE_STATUS_INITIALIZED) {
+    callback.Run(profile);
+    return;
+  }
+
+  // This should never get an error since it only loads existing profiles.
+  DCHECK_EQ(Profile::CREATE_STATUS_CREATED, status);
+}
+
 void SetAppHidden(Profile* profile, const std::string& app_id, bool hidden) {
   AppWindowList windows =
       AppWindowRegistry::Get(profile)->GetAppWindowsForApp(app_id);
@@ -174,10 +183,13 @@
 
 void ExtensionAppShimHandler::Delegate::LoadProfileAsync(
     const base::FilePath& path,
-    base::OnceCallback<void(Profile*)> callback) {
+    base::Callback<void(Profile*)> callback) {
   ProfileManager* profile_manager = g_browser_process->profile_manager();
   base::FilePath full_path = profile_manager->user_data_dir().Append(path);
-  profile_manager->LoadProfileByPath(full_path, false, std::move(callback));
+  profile_manager->CreateProfileAsync(
+      full_path,
+      base::Bind(&ProfileLoadedCallback, callback),
+      base::string16(), std::string());
 }
 
 bool ExtensionAppShimHandler::Delegate::IsProfileLockedForPath(
@@ -199,12 +211,6 @@
   return ExtensionAppShimHandler::MaybeGetAppExtension(context, extension_id);
 }
 
-AppShimHandler::Host* ExtensionAppShimHandler::Delegate::CreateHost(
-    const std::string& app_id,
-    const base::FilePath& profile_path) {
-  return new AppShimHost(app_id, profile_path);
-}
-
 void ExtensionAppShimHandler::Delegate::EnableExtension(
     Profile* profile,
     const std::string& extension_id,
@@ -412,12 +418,13 @@
 }
 
 void ExtensionAppShimHandler::OnShimLaunch(
-    std::unique_ptr<AppShimHostBootstrap> bootstrap) {
-  const std::string& app_id = bootstrap->GetAppId();
-  AppShimLaunchType launch_type = bootstrap->GetLaunchType();
+    Host* host,
+    AppShimLaunchType launch_type,
+    const std::vector<base::FilePath>& files) {
+  const std::string& app_id = host->GetAppId();
   DCHECK(crx_file::id_util::IdIsValid(app_id));
 
-  const base::FilePath& profile_path = bootstrap->GetProfilePath();
+  const base::FilePath& profile_path = host->GetProfilePath();
   DCHECK(!profile_path.empty());
 
   if (!delegate_->ProfileExistsForPath(profile_path)) {
@@ -425,31 +432,34 @@
     // TODO(jackhou): Add some UI for this case and remove the LOG.
     LOG(ERROR) << "Requested directory is not a known profile '"
                << profile_path.value() << "'.";
-    bootstrap->OnLaunchAppFailed(APP_SHIM_LAUNCH_PROFILE_NOT_FOUND);
+    host->OnAppLaunchComplete(APP_SHIM_LAUNCH_PROFILE_NOT_FOUND);
     return;
   }
 
   if (delegate_->IsProfileLockedForPath(profile_path)) {
     LOG(WARNING) << "Requested profile is locked.  Showing User Manager.";
-    bootstrap->OnLaunchAppFailed(APP_SHIM_LAUNCH_PROFILE_LOCKED);
+    host->OnAppLaunchComplete(APP_SHIM_LAUNCH_PROFILE_LOCKED);
     delegate_->LaunchUserManager();
     return;
   }
 
   Profile* profile = delegate_->ProfileForPath(profile_path);
+
   if (profile) {
-    OnProfileLoaded(std::move(bootstrap), profile);
-  } else {
-    // If the profile is not loaded, this must have been a launch by the shim.
-    // Load the profile asynchronously, the host will be registered in
-    // OnProfileLoaded.
-    DCHECK_EQ(APP_SHIM_LAUNCH_NORMAL, launch_type);
-    delegate_->LoadProfileAsync(
-        profile_path,
-        base::BindOnce(&ExtensionAppShimHandler::OnProfileLoaded,
-                       weak_factory_.GetWeakPtr(), std::move(bootstrap)));
+    OnProfileLoaded(host, launch_type, files, profile);
+    return;
   }
 
+  // If the profile is not loaded, this must have been a launch by the shim.
+  // Load the profile asynchronously, the host will be registered in
+  // OnProfileLoaded.
+  DCHECK_EQ(APP_SHIM_LAUNCH_NORMAL, launch_type);
+  delegate_->LoadProfileAsync(
+      profile_path,
+      base::Bind(&ExtensionAppShimHandler::OnProfileLoaded,
+                 weak_factory_.GetWeakPtr(),
+                 host, launch_type, files));
+
   // Return now. OnAppLaunchComplete will be called when the app is activated.
 }
 
@@ -493,26 +503,23 @@
 }
 
 void ExtensionAppShimHandler::OnProfileLoaded(
-    std::unique_ptr<AppShimHostBootstrap> bootstrap,
+    Host* host,
+    AppShimLaunchType launch_type,
+    const std::vector<base::FilePath>& files,
     Profile* profile) {
-  const std::string& app_id = bootstrap->GetAppId();
-  AppShimLaunchType launch_type = bootstrap->GetLaunchType();
-  const std::vector<base::FilePath>& files = bootstrap->GetLaunchFiles();
+  const std::string& app_id = host->GetAppId();
 
   // The first host to claim this (profile, app_id) becomes the main host.
   // For any others, focus or relaunch the app.
-  Host*& host = hosts_[make_pair(profile, app_id)];
-  if (!host) {
-    host = delegate_->CreateHost(app_id, bootstrap->GetProfilePath());
-  } else {
+  if (!hosts_.insert(make_pair(make_pair(profile, app_id), host)).second) {
     OnShimFocus(host,
                 launch_type == APP_SHIM_LAUNCH_NORMAL ?
                     APP_SHIM_FOCUS_REOPEN : APP_SHIM_FOCUS_NORMAL,
                 files);
-    bootstrap->OnLaunchAppFailed(APP_SHIM_LAUNCH_DUPLICATE_HOST);
+    host->OnAppLaunchComplete(APP_SHIM_LAUNCH_DUPLICATE_HOST);
     return;
   }
-  host->OnBootstrapConnected(std::move(bootstrap));
+
   if (launch_type != APP_SHIM_LAUNCH_NORMAL) {
     host->OnAppLaunchComplete(APP_SHIM_LAUNCH_SUCCESS);
     return;
diff --git a/chrome/browser/apps/app_shim/extension_app_shim_handler_mac.h b/chrome/browser/apps/app_shim/extension_app_shim_handler_mac.h
index 02abbd8e..f226456 100644
--- a/chrome/browser/apps/app_shim/extension_app_shim_handler_mac.h
+++ b/chrome/browser/apps/app_shim/extension_app_shim_handler_mac.h
@@ -12,7 +12,6 @@
 #include <vector>
 
 #include "apps/app_lifetime_monitor.h"
-#include "base/callback_forward.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/apps/app_shim/app_shim_handler_mac.h"
@@ -53,7 +52,7 @@
     virtual bool ProfileExistsForPath(const base::FilePath& path);
     virtual Profile* ProfileForPath(const base::FilePath& path);
     virtual void LoadProfileAsync(const base::FilePath& path,
-                                  base::OnceCallback<void(Profile*)> callback);
+                                  base::Callback<void(Profile*)> callback);
     virtual bool IsProfileLockedForPath(const base::FilePath& path);
 
     virtual extensions::AppWindowRegistry::AppWindowList GetWindows(
@@ -63,8 +62,6 @@
     virtual const extensions::Extension* MaybeGetAppExtension(
         content::BrowserContext* context,
         const std::string& extension_id);
-    virtual Host* CreateHost(const std::string& app_id,
-                             const base::FilePath& profile_path);
     virtual void EnableExtension(Profile* profile,
                                  const std::string& extension_id,
                                  const base::Callback<void()>& callback);
@@ -122,7 +119,9 @@
   void OnChromeWillHide();
 
   // AppShimHandler overrides:
-  void OnShimLaunch(std::unique_ptr<AppShimHostBootstrap> bootstrap) override;
+  void OnShimLaunch(Host* host,
+                    AppShimLaunchType launch_type,
+                    const std::vector<base::FilePath>& files) override;
   void OnShimClose(Host* host) override;
   void OnShimFocus(Host* host,
                    AppShimFocusType focus_type,
@@ -174,7 +173,9 @@
 
   // This is passed to Delegate::LoadProfileAsync for shim-initiated launches
   // where the profile was not yet loaded.
-  void OnProfileLoaded(std::unique_ptr<AppShimHostBootstrap> bootstrap,
+  void OnProfileLoaded(Host* host,
+                       AppShimLaunchType launch_type,
+                       const std::vector<base::FilePath>& files,
                        Profile* profile);
 
   // This is passed to Delegate::EnableViaPrompt for shim-initiated launches
diff --git a/chrome/browser/apps/app_shim/extension_app_shim_handler_mac_unittest.cc b/chrome/browser/apps/app_shim/extension_app_shim_handler_mac_unittest.cc
index ed60fc1..d57a6cbd 100644
--- a/chrome/browser/apps/app_shim/extension_app_shim_handler_mac_unittest.cc
+++ b/chrome/browser/apps/app_shim/extension_app_shim_handler_mac_unittest.cc
@@ -4,14 +4,10 @@
 
 #include "chrome/browser/apps/app_shim/extension_app_shim_handler_mac.h"
 
-#include <map>
 #include <memory>
-#include <utility>
 #include <vector>
 
 #include "base/macros.h"
-#include "base/optional.h"
-#include "chrome/browser/apps/app_shim/app_shim_host_bootstrap_mac.h"
 #include "chrome/browser/apps/app_shim/app_shim_host_mac.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/test/base/testing_profile.h"
@@ -38,10 +34,9 @@
 
   MOCK_METHOD1(ProfileExistsForPath, bool(const base::FilePath&));
   MOCK_METHOD1(ProfileForPath, Profile*(const base::FilePath&));
-  void LoadProfileAsync(const base::FilePath& path,
-                        base::OnceCallback<void(Profile*)> callback) override {
-    CaptureLoadProfileCallback(path, std::move(callback));
-  }
+  MOCK_METHOD2(LoadProfileAsync,
+               void(const base::FilePath&,
+                    base::Callback<void(Profile*)>));
   MOCK_METHOD1(IsProfileLockedForPath, bool(const base::FilePath&));
 
   MOCK_METHOD2(GetWindows, AppWindowList(Profile*, const std::string&));
@@ -60,26 +55,16 @@
 
   MOCK_METHOD0(MaybeTerminate, void());
 
-  void SetHostForCreate(AppShimHandler::Host* host_for_create) {
-    host_for_create_ = host_for_create;
-  }
-  AppShimHandler::Host* CreateHost(
-      const std::string& app_id,
-      const base::FilePath& profile_path) override {
-    auto* result = host_for_create_;
-    host_for_create_ = nullptr;
-    return result;
-  }
-
-  void CaptureLoadProfileCallback(const base::FilePath& path,
-                                  base::OnceCallback<void(Profile*)> callback) {
-    callbacks_[path] = std::move(callback);
+  void CaptureLoadProfileCallback(
+      const base::FilePath& path,
+      base::Callback<void(Profile*)> callback) {
+    callbacks_[path] = callback;
   }
 
   bool RunLoadProfileCallback(
       const base::FilePath& path,
       Profile* profile) {
-    std::move(callbacks_[path]).Run(profile);
+    callbacks_[path].Run(profile);
     return callbacks_.erase(path);
   }
 
@@ -88,8 +73,8 @@
   }
 
  private:
-  std::map<base::FilePath, base::OnceCallback<void(Profile*)>> callbacks_;
-  AppShimHandler::Host* host_for_create_ = nullptr;
+  std::map<base::FilePath,
+           base::Callback<void(Profile*)> > callbacks_;
 };
 
 class TestingExtensionAppShimHandler : public ExtensionAppShimHandler {
@@ -122,53 +107,45 @@
   DISALLOW_COPY_AND_ASSIGN(TestingExtensionAppShimHandler);
 };
 
-class TestingAppShimHostBootstrap : public AppShimHostBootstrap {
- public:
-  TestingAppShimHostBootstrap(apps::AppShimHandler* handler)
-      : handler_(handler) {}
-  using AppShimHostBootstrap::LaunchApp;
-  apps::AppShimHandler* GetHandler() override { return handler_; }
-
- private:
-  apps::AppShimHandler* const handler_;
-  DISALLOW_COPY_AND_ASSIGN(TestingAppShimHostBootstrap);
-};
-
 const char kTestAppIdA[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
 const char kTestAppIdB[] = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";
 
-class TestHost : public AppShimHost {
+class FakeHost : public apps::AppShimHandler::Host {
  public:
-  TestHost(const base::FilePath& profile_path,
+  FakeHost(const base::FilePath& profile_path,
            const std::string& app_id,
-           base::Optional<apps::AppShimLaunchResult>* launch_result,
            TestingExtensionAppShimHandler* handler)
-      : AppShimHost(app_id, profile_path),
-        launch_result_(launch_result),
+      : profile_path_(profile_path),
+        app_id_(app_id),
         handler_(handler),
-        weak_factory_(this) {}
+        close_count_(0) {}
 
-  // Override the GetAppShimHandler for testing.
-  apps::AppShimHandler* GetAppShimHandler() const override { return handler_; }
+  MOCK_METHOD1(OnAppLaunchComplete, void(AppShimLaunchResult));
 
-  void SetLaunchResult(apps::AppShimLaunchResult result) {
-    launch_result_->emplace(result);
+  void OnAppClosed() override {
+    handler_->OnShimClose(this);
+    ++close_count_;
   }
-  apps::AppShimLaunchResult GetLaunchResult() {
-    DCHECK(*launch_result_);
-    return *(*launch_result_);
+  void OnAppHide() override {}
+  void OnAppUnhideWithoutActivation() override {}
+  void OnAppRequestUserAttention(AppShimAttentionType type) override {}
+  base::FilePath GetProfilePath() const override {
+    return profile_path_;
   }
-  base::WeakPtr<TestHost> GetWeakPtr() { return weak_factory_.GetWeakPtr(); }
+  std::string GetAppId() const override { return app_id_; }
+  views::BridgeFactoryHost* GetViewsBridgeFactoryHost() const override {
+    return nullptr;
+  }
+
+  int close_count() { return close_count_; }
 
  private:
-  ~TestHost() override {}
-  // Note that |launch_result_| is optional so that we can track whether or not
-  // the callback to set it has arrived.
-  base::Optional<apps::AppShimLaunchResult>* launch_result_;
+  base::FilePath profile_path_;
+  std::string app_id_;
   TestingExtensionAppShimHandler* handler_;
+  int close_count_;
 
-  base::WeakPtrFactory<TestHost> weak_factory_;
-  DISALLOW_COPY_AND_ASSIGN(TestHost);
+  DISALLOW_COPY_AND_ASSIGN(FakeHost);
 };
 
 class ExtensionAppShimHandlerTest : public testing::Test {
@@ -177,21 +154,11 @@
       : delegate_(new MockDelegate),
         handler_(new TestingExtensionAppShimHandler(delegate_)),
         profile_path_a_("Profile A"),
-        profile_path_b_("Profile B") {
-    host_aa_ = (new TestHost(profile_path_a_, kTestAppIdA,
-                             &host_aa_launch_result_, handler_.get()))
-                   ->GetWeakPtr();
-    host_ab_ = (new TestHost(profile_path_a_, kTestAppIdB,
-                             &host_ab_launch_result_, handler_.get()))
-                   ->GetWeakPtr();
-    host_bb_ = (new TestHost(profile_path_b_, kTestAppIdB,
-                             &host_bb_launch_result_, handler_.get()))
-                   ->GetWeakPtr();
-    host_aa_duplicate_ =
-        (new TestHost(profile_path_a_, kTestAppIdA,
-                      &host_aa_duplicate_launch_result_, handler_.get()))
-            ->GetWeakPtr();
-
+        profile_path_b_("Profile B"),
+        host_aa_(profile_path_a_, kTestAppIdA, handler_.get()),
+        host_ab_(profile_path_a_, kTestAppIdB, handler_.get()),
+        host_bb_(profile_path_b_, kTestAppIdB, handler_.get()),
+        host_aa_duplicate_(profile_path_a_, kTestAppIdA, handler_.get()) {
     base::FilePath extension_path("/fake/path");
     extension_a_ = extensions::ExtensionBuilder("Fake Name")
                        .SetLocation(extensions::Manifest::INTERNAL)
@@ -232,56 +199,29 @@
         .WillRepeatedly(Return());
   }
 
-  ~ExtensionAppShimHandlerTest() override {
-    if (host_aa_)
-      host_aa_->OnAppClosed();
-    if (host_ab_)
-      host_ab_->OnAppClosed();
-    if (host_bb_)
-      host_bb_->OnAppClosed();
-    if (host_aa_duplicate_)
-      host_aa_duplicate_->OnAppClosed();
+  void NormalLaunch(AppShimHandler::Host* host) {
+    handler_->OnShimLaunch(host,
+                           APP_SHIM_LAUNCH_NORMAL,
+                           std::vector<base::FilePath>());
   }
 
-  void DoShimLaunch(TestHost* host,
-                    apps::AppShimLaunchType launch_type,
-                    const std::vector<base::FilePath>& files) {
-    delegate_->SetHostForCreate(host);
-    chrome::mojom::AppShimHostPtr host_ptr;
-    (new TestingAppShimHostBootstrap(handler_.get()))
-        ->LaunchApp(
-            mojo::MakeRequest(&host_ptr), host->GetProfilePath(),
-            host->GetAppId(), launch_type, files,
-            base::BindOnce(&ExtensionAppShimHandlerTest::DoShimLaunchDone,
-                           base::Unretained(this), host));
-  }
-
-  void DoShimLaunchDone(TestHost* host,
-                        apps::AppShimLaunchResult result,
-                        chrome::mojom::AppShimRequest app_shim_request) {
-    host->SetLaunchResult(result);
-  }
-
-  void NormalLaunch(TestHost* host) {
-    DoShimLaunch(host, APP_SHIM_LAUNCH_NORMAL, std::vector<base::FilePath>());
-  }
-
-  void RegisterOnlyLaunch(TestHost* host) {
-    DoShimLaunch(host, APP_SHIM_LAUNCH_REGISTER_ONLY,
-                 std::vector<base::FilePath>());
+  void RegisterOnlyLaunch(AppShimHandler::Host* host) {
+    handler_->OnShimLaunch(host,
+                           APP_SHIM_LAUNCH_REGISTER_ONLY,
+                           std::vector<base::FilePath>());
   }
 
   // Completely launch a shim host and leave it running.
-  void LaunchAndActivate(TestHost* host, Profile* profile) {
+  void LaunchAndActivate(FakeHost* host, Profile* profile) {
     NormalLaunch(host);
     EXPECT_EQ(host, handler_->FindHost(profile, host->GetAppId()));
+    EXPECT_CALL(*host, OnAppLaunchComplete(APP_SHIM_LAUNCH_SUCCESS));
     EXPECT_CALL(*handler_, OnShimFocus(host, APP_SHIM_FOCUS_NORMAL, _));
     handler_->OnAppActivated(profile, host->GetAppId());
-    EXPECT_EQ(APP_SHIM_LAUNCH_SUCCESS, host->GetLaunchResult());
   }
 
   // Simulates a focus request coming from a running app shim.
-  void ShimNormalFocus(TestHost* host) {
+  void ShimNormalFocus(FakeHost* host) {
     EXPECT_CALL(*handler_, OnShimFocus(host, APP_SHIM_FOCUS_NORMAL, _))
         .WillOnce(Invoke(handler_.get(),
                          &TestingExtensionAppShimHandler::RealOnShimFocus));
@@ -291,7 +231,7 @@
   }
 
   // Simulates a hide (or unhide) request coming from a running app shim.
-  void ShimSetHidden(TestHost* host, bool hidden) {
+  void ShimSetHidden(FakeHost* host, bool hidden) {
     handler_->OnShimSetHidden(host, hidden);
   }
 
@@ -302,14 +242,10 @@
   base::FilePath profile_path_b_;
   TestingProfile profile_a_;
   TestingProfile profile_b_;
-  base::Optional<apps::AppShimLaunchResult> host_aa_launch_result_;
-  base::Optional<apps::AppShimLaunchResult> host_ab_launch_result_;
-  base::Optional<apps::AppShimLaunchResult> host_bb_launch_result_;
-  base::Optional<apps::AppShimLaunchResult> host_aa_duplicate_launch_result_;
-  base::WeakPtr<TestHost> host_aa_;
-  base::WeakPtr<TestHost> host_ab_;
-  base::WeakPtr<TestHost> host_bb_;
-  base::WeakPtr<TestHost> host_aa_duplicate_;
+  FakeHost host_aa_;
+  FakeHost host_ab_;
+  FakeHost host_bb_;
+  FakeHost host_aa_duplicate_;
   scoped_refptr<const Extension> extension_a_;
   scoped_refptr<const Extension> extension_b_;
 
@@ -322,17 +258,17 @@
   EXPECT_CALL(*delegate_, ProfileExistsForPath(profile_path_a_))
       .WillOnce(Return(false))
       .WillRepeatedly(Return(true));
-  NormalLaunch(host_aa_.get());
-  EXPECT_EQ(APP_SHIM_LAUNCH_PROFILE_NOT_FOUND, *host_aa_launch_result_);
+  EXPECT_CALL(host_aa_, OnAppLaunchComplete(APP_SHIM_LAUNCH_PROFILE_NOT_FOUND));
+  NormalLaunch(&host_aa_);
 }
 
 TEST_F(ExtensionAppShimHandlerTest, LaunchProfileIsLocked) {
   // Profile is locked.
   EXPECT_CALL(*delegate_, IsProfileLockedForPath(profile_path_a_))
       .WillOnce(Return(true));
+  EXPECT_CALL(host_aa_, OnAppLaunchComplete(APP_SHIM_LAUNCH_PROFILE_LOCKED));
   EXPECT_CALL(*delegate_, LaunchUserManager());
-  NormalLaunch(host_aa_.get());
-  EXPECT_EQ(APP_SHIM_LAUNCH_PROFILE_LOCKED, *host_aa_launch_result_);
+  NormalLaunch(&host_aa_);
 }
 
 TEST_F(ExtensionAppShimHandlerTest, LaunchAppNotFound) {
@@ -341,8 +277,8 @@
       .WillRepeatedly(Return(static_cast<const Extension*>(NULL)));
   EXPECT_CALL(*delegate_, EnableExtension(&profile_a_, kTestAppIdA, _))
       .WillOnce(WithArgs<2>(Invoke(delegate_, &MockDelegate::RunCallback)));
-  NormalLaunch(host_aa_.get());
-  EXPECT_EQ(APP_SHIM_LAUNCH_APP_NOT_FOUND, *host_aa_launch_result_);
+  EXPECT_CALL(host_aa_, OnAppLaunchComplete(APP_SHIM_LAUNCH_APP_NOT_FOUND));
+  NormalLaunch(&host_aa_);
 }
 
 TEST_F(ExtensionAppShimHandlerTest, LaunchAppNotEnabled) {
@@ -352,47 +288,48 @@
       .WillRepeatedly(Return(extension_a_.get()));
   EXPECT_CALL(*delegate_, EnableExtension(&profile_a_, kTestAppIdA, _))
       .WillOnce(WithArgs<2>(Invoke(delegate_, &MockDelegate::RunCallback)));
-  NormalLaunch(host_aa_.get());
+  NormalLaunch(&host_aa_);
 }
 
 TEST_F(ExtensionAppShimHandlerTest, LaunchAndCloseShim) {
   // Normal startup.
-  NormalLaunch(host_aa_.get());
-  EXPECT_EQ(host_aa_.get(), handler_->FindHost(&profile_a_, kTestAppIdA));
+  NormalLaunch(&host_aa_);
+  EXPECT_EQ(&host_aa_, handler_->FindHost(&profile_a_, kTestAppIdA));
 
-  NormalLaunch(host_ab_.get());
-  EXPECT_EQ(host_ab_.get(), handler_->FindHost(&profile_a_, kTestAppIdB));
+  NormalLaunch(&host_ab_);
+  EXPECT_EQ(&host_ab_, handler_->FindHost(&profile_a_, kTestAppIdB));
 
   std::vector<base::FilePath> some_file(1, base::FilePath("some_file"));
   EXPECT_CALL(*delegate_,
               LaunchApp(&profile_b_, extension_b_.get(), some_file));
-  DoShimLaunch(host_bb_.get(), APP_SHIM_LAUNCH_NORMAL, some_file);
-  EXPECT_EQ(host_bb_.get(), handler_->FindHost(&profile_b_, kTestAppIdB));
+  handler_->OnShimLaunch(&host_bb_, APP_SHIM_LAUNCH_NORMAL, some_file);
+  EXPECT_EQ(&host_bb_, handler_->FindHost(&profile_b_, kTestAppIdB));
 
   // Activation when there is a registered shim finishes launch with success and
   // focuses the app.
-  EXPECT_CALL(*handler_, OnShimFocus(host_aa_.get(), APP_SHIM_FOCUS_NORMAL, _));
+  EXPECT_CALL(host_aa_, OnAppLaunchComplete(APP_SHIM_LAUNCH_SUCCESS));
+  EXPECT_CALL(*handler_, OnShimFocus(&host_aa_, APP_SHIM_FOCUS_NORMAL, _));
   handler_->OnAppActivated(&profile_a_, kTestAppIdA);
-  EXPECT_EQ(APP_SHIM_LAUNCH_SUCCESS, *host_aa_launch_result_);
 
-  // Starting and closing a second host just focuses the original host of the
-  // app.
-  EXPECT_CALL(*handler_,
-              OnShimFocus(host_aa_.get(), APP_SHIM_FOCUS_REOPEN, some_file));
-
-  DoShimLaunch(host_aa_duplicate_.get(), APP_SHIM_LAUNCH_NORMAL, some_file);
-  EXPECT_EQ(APP_SHIM_LAUNCH_DUPLICATE_HOST, *host_aa_duplicate_launch_result_);
-
-  EXPECT_EQ(host_aa_.get(), handler_->FindHost(&profile_a_, kTestAppIdA));
-  handler_->OnShimClose(host_aa_duplicate_.get());
-  EXPECT_EQ(host_aa_.get(), handler_->FindHost(&profile_a_, kTestAppIdA));
+  // Starting and closing a second host just focuses the app.
+  EXPECT_CALL(*handler_, OnShimFocus(&host_aa_duplicate_,
+                                     APP_SHIM_FOCUS_REOPEN,
+                                     some_file));
+  EXPECT_CALL(host_aa_duplicate_,
+              OnAppLaunchComplete(APP_SHIM_LAUNCH_DUPLICATE_HOST));
+  handler_->OnShimLaunch(&host_aa_duplicate_,
+                         APP_SHIM_LAUNCH_NORMAL,
+                         some_file);
+  EXPECT_EQ(&host_aa_, handler_->FindHost(&profile_a_, kTestAppIdA));
+  handler_->OnShimClose(&host_aa_duplicate_);
+  EXPECT_EQ(&host_aa_, handler_->FindHost(&profile_a_, kTestAppIdA));
 
   // Normal close.
-  handler_->OnShimClose(host_aa_.get());
+  handler_->OnShimClose(&host_aa_);
   EXPECT_FALSE(handler_->FindHost(&profile_a_, kTestAppIdA));
 
   // Closing the second host afterward does nothing.
-  handler_->OnShimClose(host_aa_duplicate_.get());
+  handler_->OnShimClose(&host_aa_duplicate_);
   EXPECT_FALSE(handler_->FindHost(&profile_a_, kTestAppIdA));
 }
 
@@ -406,9 +343,9 @@
   EXPECT_CALL(*delegate_,
               LaunchApp(&profile_a_, extension_a_.get(), _))
       .Times(0);
-  RegisterOnlyLaunch(host_aa_.get());
-  EXPECT_EQ(APP_SHIM_LAUNCH_SUCCESS, *host_aa_launch_result_);
-  EXPECT_EQ(host_aa_.get(), handler_->FindHost(&profile_a_, kTestAppIdA));
+  EXPECT_CALL(host_aa_, OnAppLaunchComplete(APP_SHIM_LAUNCH_SUCCESS));
+  RegisterOnlyLaunch(&host_aa_);
+  EXPECT_EQ(&host_aa_, handler_->FindHost(&profile_a_, kTestAppIdA));
 
   // Return no app windows for OnShimFocus and OnShimQuit.
   AppWindowList app_window_list;
@@ -419,40 +356,39 @@
   EXPECT_CALL(*delegate_,
               LaunchApp(&profile_a_, extension_a_.get(), _))
       .Times(0);
-  ShimNormalFocus(host_aa_.get());
+  ShimNormalFocus(&host_aa_);
 
   // Reopen focus launches the app.
-  EXPECT_CALL(*handler_, OnShimFocus(host_aa_.get(), APP_SHIM_FOCUS_REOPEN, _))
+  EXPECT_CALL(*handler_, OnShimFocus(&host_aa_, APP_SHIM_FOCUS_REOPEN, _))
       .WillOnce(Invoke(handler_.get(),
                        &TestingExtensionAppShimHandler::RealOnShimFocus));
   std::vector<base::FilePath> some_file(1, base::FilePath("some_file"));
   EXPECT_CALL(*delegate_,
               LaunchApp(&profile_a_, extension_a_.get(), some_file));
-  handler_->OnShimFocus(host_aa_.get(), APP_SHIM_FOCUS_REOPEN, some_file);
+  handler_->OnShimFocus(&host_aa_, APP_SHIM_FOCUS_REOPEN, some_file);
 
   // Quit just closes all the windows. This tests that it doesn't terminate,
   // but we expect closing all windows triggers a OnAppDeactivated from
   // AppLifetimeMonitor.
-  handler_->OnShimQuit(host_aa_.get());
+  handler_->OnShimQuit(&host_aa_);
 
   // Closing all windows closes the shim and checks if Chrome should be
   // terminated.
   EXPECT_CALL(*delegate_, MaybeTerminate())
       .WillOnce(Return());
-  EXPECT_NE(nullptr, host_aa_.get());
   handler_->OnAppDeactivated(&profile_a_, kTestAppIdA);
-  EXPECT_EQ(nullptr, host_aa_.get());
+  EXPECT_EQ(1, host_aa_.close_count());
 }
 
 TEST_F(ExtensionAppShimHandlerTest, MaybeTerminate) {
   // Launch shims, adding entries in the map.
-  RegisterOnlyLaunch(host_aa_.get());
-  EXPECT_EQ(APP_SHIM_LAUNCH_SUCCESS, *host_aa_launch_result_);
-  EXPECT_EQ(host_aa_.get(), handler_->FindHost(&profile_a_, kTestAppIdA));
+  EXPECT_CALL(host_aa_, OnAppLaunchComplete(APP_SHIM_LAUNCH_SUCCESS));
+  RegisterOnlyLaunch(&host_aa_);
+  EXPECT_EQ(&host_aa_, handler_->FindHost(&profile_a_, kTestAppIdA));
 
-  RegisterOnlyLaunch(host_ab_.get());
-  EXPECT_EQ(APP_SHIM_LAUNCH_SUCCESS, *host_ab_launch_result_);
-  EXPECT_EQ(host_ab_.get(), handler_->FindHost(&profile_a_, kTestAppIdB));
+  EXPECT_CALL(host_ab_, OnAppLaunchComplete(APP_SHIM_LAUNCH_SUCCESS));
+  RegisterOnlyLaunch(&host_ab_);
+  EXPECT_EQ(&host_ab_, handler_->FindHost(&profile_a_, kTestAppIdB));
 
   // Return empty window list.
   AppWindowList app_window_list;
@@ -473,12 +409,12 @@
   // For an APP_SHIM_LAUNCH_REGISTER_ONLY, don't launch the app.
   EXPECT_CALL(*delegate_, LaunchApp(_, _, _))
       .Times(0);
-  RegisterOnlyLaunch(host_aa_.get());
-  EXPECT_EQ(APP_SHIM_LAUNCH_SUCCESS, *host_aa_launch_result_);
+  EXPECT_CALL(host_aa_, OnAppLaunchComplete(APP_SHIM_LAUNCH_SUCCESS));
+  RegisterOnlyLaunch(&host_aa_);
   EXPECT_TRUE(handler_->FindHost(&profile_a_, kTestAppIdA));
 
   // Close the shim, removing the entry in the map.
-  handler_->OnShimClose(host_aa_.get());
+  handler_->OnShimClose(&host_aa_);
   EXPECT_FALSE(handler_->FindHost(&profile_a_, kTestAppIdA));
 }
 
@@ -489,7 +425,9 @@
   EXPECT_CALL(*delegate_, ProfileForPath(profile_path_a_))
       .WillOnce(Return(static_cast<Profile*>(NULL)))
       .WillRepeatedly(Return(&profile_a_));
-  NormalLaunch(host_aa_.get());
+  EXPECT_CALL(*delegate_, LoadProfileAsync(profile_path_a_, _))
+      .WillOnce(Invoke(delegate_, &MockDelegate::CaptureLoadProfileCallback));
+  NormalLaunch(&host_aa_);
   EXPECT_FALSE(handler_->FindHost(&profile_a_, kTestAppIdA));
   delegate_->RunLoadProfileCallback(profile_path_a_, &profile_a_);
   EXPECT_TRUE(handler_->FindHost(&profile_a_, kTestAppIdA));
@@ -498,15 +436,15 @@
 // Tests that calls to OnShimFocus, OnShimHide correctly handle a null extension
 // being provided by the extension system.
 TEST_F(ExtensionAppShimHandlerTest, ExtensionUninstalled) {
-  LaunchAndActivate(host_aa_.get(), &profile_a_);
+  LaunchAndActivate(&host_aa_, &profile_a_);
 
   // Have GetWindows() return an empty window list for focus (otherwise, it
   // will contain a single nullptr, which can't be focused). Expect 1 call only.
   AppWindowList empty_window_list;
   EXPECT_CALL(*delegate_, GetWindows(_, _)).WillOnce(Return(empty_window_list));
 
-  ShimNormalFocus(host_aa_.get());
-  EXPECT_NE(nullptr, host_aa_.get());
+  ShimNormalFocus(&host_aa_);
+  EXPECT_EQ(0, host_aa_.close_count());
 
   // Set up the mock to return a null extension, as if it were uninstalled.
   EXPECT_CALL(*delegate_, MaybeGetAppExtension(&profile_a_, kTestAppIdA))
@@ -514,18 +452,18 @@
 
   // Now trying to focus should automatically close the shim, and not try to
   // get the window list.
-  ShimNormalFocus(host_aa_.get());
-  EXPECT_EQ(nullptr, host_aa_.get());
+  ShimNormalFocus(&host_aa_);
+  EXPECT_EQ(1, host_aa_.close_count());
 
   // Do the same for SetHidden on host_bb.
-  LaunchAndActivate(host_bb_.get(), &profile_b_);
-  ShimSetHidden(host_bb_.get(), true);
-  EXPECT_NE(nullptr, host_bb_.get());
+  LaunchAndActivate(&host_bb_, &profile_b_);
+  ShimSetHidden(&host_bb_, true);
+  EXPECT_EQ(0, host_bb_.close_count());
 
   EXPECT_CALL(*delegate_, MaybeGetAppExtension(&profile_b_, kTestAppIdB))
       .WillRepeatedly(Return(nullptr));
-  ShimSetHidden(host_bb_.get(), true);
-  EXPECT_EQ(nullptr, host_bb_.get());
+  ShimSetHidden(&host_bb_, true);
+  EXPECT_EQ(1, host_bb_.close_count());
 }
 
 }  // namespace apps
diff --git a/chrome/browser/browser_process.h b/chrome/browser/browser_process.h
index ff026bb3..9b52c66 100644
--- a/chrome/browser/browser_process.h
+++ b/chrome/browser/browser_process.h
@@ -61,10 +61,6 @@
 class SupervisedUserWhitelistInstaller;
 }
 
-namespace data_use_measurement {
-class ChromeDataUseMeasurement;
-}
-
 namespace extensions {
 class EventRouterForwarder;
 }
@@ -293,9 +289,6 @@
 
   virtual prefs::InProcessPrefServiceFactory* pref_service_factory() const = 0;
 
-  virtual data_use_measurement::ChromeDataUseMeasurement*
-  data_use_measurement() = 0;
-
  private:
   DISALLOW_COPY_AND_ASSIGN(BrowserProcess);
 };
diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc
index bf3b591..a97daaa 100644
--- a/chrome/browser/browser_process_impl.cc
+++ b/chrome/browser/browser_process_impl.cc
@@ -41,7 +41,6 @@
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/component_updater/chrome_component_updater_configurator.h"
 #include "chrome/browser/component_updater/supervised_user_whitelist_installer.h"
-#include "chrome/browser/data_use_measurement/chrome_data_use_measurement.h"
 #include "chrome/browser/defaults.h"
 #include "chrome/browser/devtools/devtools_auto_opener.h"
 #include "chrome/browser/devtools/remote_debugging_server.h"
@@ -923,16 +922,6 @@
   return pref_service_factory_.get();
 }
 
-data_use_measurement::ChromeDataUseMeasurement*
-BrowserProcessImpl::data_use_measurement() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  if (!data_use_measurement_) {
-    data_use_measurement_ = data_use_measurement::ChromeDataUseMeasurement::
-        CreateForNetworkService();
-  }
-  return data_use_measurement_.get();
-}
-
 // static
 void BrowserProcessImpl::RegisterPrefs(PrefRegistrySimple* registry) {
   registry->RegisterBooleanPref(prefs::kDefaultBrowserSettingEnabled,
diff --git a/chrome/browser/browser_process_impl.h b/chrome/browser/browser_process_impl.h
index b62ec6f..ab192b4 100644
--- a/chrome/browser/browser_process_impl.h
+++ b/chrome/browser/browser_process_impl.h
@@ -199,8 +199,6 @@
   shell_integration::DefaultWebClientState CachedDefaultWebClientState()
       override;
   prefs::InProcessPrefServiceFactory* pref_service_factory() const override;
-  data_use_measurement::ChromeDataUseMeasurement* data_use_measurement()
-      override;
 
   static void RegisterPrefs(PrefRegistrySimple* registry);
 
@@ -431,9 +429,6 @@
   base::OnceClosure quit_closure_;
 #endif
 
-  std::unique_ptr<data_use_measurement::ChromeDataUseMeasurement>
-      data_use_measurement_;
-
   SEQUENCE_CHECKER(sequence_checker_);
 
   DISALLOW_COPY_AND_ASSIGN(BrowserProcessImpl);
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 95c24e9..9376b8d 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -4951,9 +4951,10 @@
     int32_t network_traffic_annotation_id_hash,
     int64_t recv_bytes,
     int64_t sent_bytes) {
-  if (g_browser_process->data_use_measurement()) {
-    g_browser_process->data_use_measurement()->ReportNetworkServiceDataUse(
-        network_traffic_annotation_id_hash, recv_bytes, sent_bytes);
+  if (data_use_measurement::ChromeDataUseMeasurement::GetInstance()) {
+    data_use_measurement::ChromeDataUseMeasurement::GetInstance()
+        ->ReportNetworkServiceDataUse(network_traffic_annotation_id_hash,
+                                      recv_bytes, sent_bytes);
   }
 }
 
diff --git a/chrome/browser/chrome_content_browser_client_browsertest_chromeos.cc b/chrome/browser/chrome_content_browser_client_browsertest_chromeos.cc
index ffc46440..bf2e10b7 100644
--- a/chrome/browser/chrome_content_browser_client_browsertest_chromeos.cc
+++ b/chrome/browser/chrome_content_browser_client_browsertest_chromeos.cc
@@ -28,7 +28,7 @@
 void GetUtilityProcessPidsOnIOThread(std::vector<pid_t>* pids) {
   for (BrowserChildProcessHostIterator it(content::PROCESS_TYPE_UTILITY);
        !it.Done(); ++it) {
-    pid_t pid = it.GetData().GetHandle();
+    pid_t pid = it.GetData().GetProcess().Pid();
     pids->push_back(pid);
   }
 }
diff --git a/chrome/browser/chrome_plugin_browsertest.cc b/chrome/browser/chrome_plugin_browsertest.cc
index 8294f832..1311d3a 100644
--- a/chrome/browser/chrome_plugin_browsertest.cc
+++ b/chrome/browser/chrome_plugin_browsertest.cc
@@ -155,9 +155,7 @@
     for (content::BrowserChildProcessHostIterator iter; !iter.Done(); ++iter) {
       if (iter.GetData().process_type != content::PROCESS_TYPE_PPAPI_PLUGIN)
         continue;
-      base::Process process = base::Process::DeprecatedGetProcessFromHandle(
-          iter.GetData().GetHandle());
-      process.Terminate(0, true);
+      iter.GetData().GetProcess().Terminate(0, true);
       found = true;
     }
     ASSERT_TRUE(found) << "Didn't find Flash process!";
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index e037ded..b31f515 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -75,6 +75,7 @@
     "//chrome/common/extensions/api",
     "//chrome/common/net",
     "//chrome/common/safe_browsing:proto",
+    "//chrome/services/diagnosticsd/public/mojom",
     "//chrome/services/file_util/public/cpp",
     "//chromeos",
     "//chromeos:attestation_proto",
@@ -654,6 +655,8 @@
     "dbus/vm_applications_service_provider.h",
     "device_sync/device_sync_client_factory.cc",
     "device_sync/device_sync_client_factory.h",
+    "diagnosticsd/diagnosticsd_bridge.cc",
+    "diagnosticsd/diagnosticsd_bridge.h",
     "display/output_protection_controller_ash.cc",
     "display/output_protection_controller_ash.h",
     "display/output_protection_controller_mus.cc",
@@ -1594,6 +1597,8 @@
     "policy/value_validation/onc_user_policy_value_validator.h",
     "policy/wildcard_login_checker.cc",
     "policy/wildcard_login_checker.h",
+    "power/auto_screen_brightness/adapter.cc",
+    "power/auto_screen_brightness/adapter.h",
     "power/auto_screen_brightness/als_reader.h",
     "power/auto_screen_brightness/als_reader_impl.cc",
     "power/auto_screen_brightness/als_reader_impl.h",
@@ -2289,6 +2294,7 @@
     "policy/upload_job_unittest.cc",
     "policy/user_cloud_policy_manager_chromeos_unittest.cc",
     "policy/user_cloud_policy_store_chromeos_unittest.cc",
+    "power/auto_screen_brightness/adapter_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",
diff --git a/chrome/browser/chromeos/app_mode/app_session.cc b/chrome/browser/chromeos/app_mode/app_session.cc
index d692ca87..037e7ff 100644
--- a/chrome/browser/chromeos/app_mode/app_session.cc
+++ b/chrome/browser/chromeos/app_mode/app_session.cc
@@ -80,12 +80,12 @@
     const content::ChildProcessData& data = iter.GetData();
     if (child_ids.count(data.id) == 1) {
       // Send a signal to dump the plugin process.
-      if (kill(data.GetHandle(), SIGFPE) == 0) {
+      if (kill(data.GetProcess().Handle(), SIGFPE) == 0) {
         dump_requested = true;
       } else {
         LOG(WARNING) << "Failed to send SIGFPE to plugin process"
                      << ", errno=" << errno
-                     << ", pid=" << data.GetHandle()
+                     << ", pid=" << data.GetProcess().Pid()
                      << ", type=" << data.process_type
                      << ", name=" << data.name;
       }
diff --git a/chrome/browser/chromeos/arc/process/arc_process_service.cc b/chrome/browser/chromeos/arc/process/arc_process_service.cc
index da755e2d..143e3187 100644
--- a/chrome/browser/chromeos/arc/process/arc_process_service.cc
+++ b/chrome/browser/chromeos/arc/process/arc_process_service.cc
@@ -10,17 +10,22 @@
 #include "chrome/browser/chromeos/arc/process/arc_process_service.h"
 
 #include <algorithm>
+#include <set>
 #include <string>
 #include <unordered_map>
 #include <unordered_set>
 #include <utility>
 
+#include "base/bind.h"
 #include "base/callback.h"
+#include "base/containers/flat_set.h"
 #include "base/containers/queue.h"
 #include "base/logging.h"
+#include "base/memory/scoped_refptr.h"
 #include "base/memory/singleton.h"
 #include "base/process/process.h"
 #include "base/process/process_iterator.h"
+#include "base/stl_util.h"
 #include "base/task/post_task.h"
 #include "base/task/task_traits.h"
 #include "base/task_runner_util.h"
@@ -28,6 +33,8 @@
 #include "components/arc/arc_bridge_service.h"
 #include "components/arc/arc_browser_context_keyed_service_factory_base.h"
 #include "content/public/browser/browser_thread.h"
+#include "services/resource_coordinator/public/cpp/memory_instrumentation/global_memory_dump.h"
+#include "services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom.h"
 
 namespace arc {
 
@@ -196,6 +203,41 @@
   return FilterProcessList(pid_map, std::move(processes));
 }
 
+std::unique_ptr<memory_instrumentation::GlobalMemoryDump>
+UpdateAndReturnMemoryInfo(
+    scoped_refptr<ArcProcessService::NSPidToPidMap> nspid_map,
+    memory_instrumentation::mojom::GlobalMemoryDumpPtr dump) {
+  ArcProcessService::NSPidToPidMap& pid_map = *nspid_map;
+  // Cleanup dead processes in pid_map
+  // TODO(wvk) should we be cleaning dead processes here too ?
+  base::flat_set<ProcessId> nspid_to_remove;
+  for (const auto& entry : pid_map)
+    nspid_to_remove.insert(entry.first);
+
+  bool unmapped_nspid = false;
+  for (const auto& proc : dump->process_dumps) {
+    // erase() returns 0 if couldn't find the key (new process)
+    if (nspid_to_remove.erase(proc->pid) == 0) {
+      pid_map[proc->pid] = base::kNullProcessId;
+      unmapped_nspid = true;
+    }
+  }
+  for (const auto& old_nspid : nspid_to_remove)
+    pid_map.erase(old_nspid);
+
+  if (unmapped_nspid)
+    UpdateNspidToPidMap(nspid_map);
+
+  // Return memory info only for processes that have a mapping nspid->pid
+  for (auto& proc : dump->process_dumps) {
+    auto it = pid_map.find(proc->pid);
+    proc->pid = it == pid_map.end() ? kNullProcessId : it->second;
+  }
+  base::EraseIf(dump->process_dumps,
+                [](const auto& proc) { return proc->pid == kNullProcessId; });
+  return memory_instrumentation::GlobalMemoryDump::MoveFrom(std::move(dump));
+}
+
 void Reset(scoped_refptr<ArcProcessService::NSPidToPidMap> pid_map) {
   if (pid_map.get())
     pid_map->clear();
@@ -289,11 +331,40 @@
   return true;
 }
 
+bool ArcProcessService::RequestAppMemoryInfo(
+    RequestMemoryInfoCallback callback) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  if (!connection_ready_)
+    return false;
+
+  mojom::ProcessInstance* process_instance = ARC_GET_INSTANCE_FOR_METHOD(
+      arc_bridge_service_->process(), RequestApplicationProcessMemoryInfo);
+  if (!process_instance) {
+    LOG(ERROR) << "could not find method / get ProcessInstance";
+    return false;
+  }
+  process_instance->RequestApplicationProcessMemoryInfo(
+      base::BindOnce(&ArcProcessService::OnReceiveMemoryInfo,
+                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+  return true;
+}
+
+bool ArcProcessService::RequestSystemMemoryInfo(
+    RequestMemoryInfoCallback callback) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  if (!connection_ready_)
+    return false;
+  base::PostTaskAndReplyWithResult(
+      task_runner_.get(), FROM_HERE, base::BindOnce(&GetArcSystemProcessList),
+      base::BindOnce(&ArcProcessService::OnGetSystemProcessList,
+                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+  return true;
+}
+
 void ArcProcessService::OnReceiveProcessList(
     const RequestProcessListCallback& callback,
     std::vector<mojom::RunningAppProcessInfoPtr> processes) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-
   base::PostTaskAndReplyWithResult(
       task_runner_.get(), FROM_HERE,
       base::Bind(&UpdateAndReturnProcessList, nspid_to_pid_,
@@ -301,6 +372,35 @@
       callback);
 }
 
+void ArcProcessService::OnReceiveMemoryInfo(
+    RequestMemoryInfoCallback callback,
+    memory_instrumentation::mojom::GlobalMemoryDumpPtr dump) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  base::PostTaskAndReplyWithResult(
+      task_runner_.get(), FROM_HERE,
+      base::BindOnce(&UpdateAndReturnMemoryInfo, nspid_to_pid_,
+                     std::move(dump)),
+      std::move(callback));
+}
+
+void ArcProcessService::OnGetSystemProcessList(
+    RequestMemoryInfoCallback callback,
+    std::vector<ArcProcess> procs) {
+  mojom::ProcessInstance* process_instance = ARC_GET_INSTANCE_FOR_METHOD(
+      arc_bridge_service_->process(), RequestSystemProcessMemoryInfo);
+  if (!process_instance) {
+    LOG(ERROR) << "could not find method / get ProcessInstance";
+    return;
+  }
+  std::vector<uint32_t> nspids;
+  for (const auto& proc : procs)
+    nspids.push_back(proc.nspid());
+  process_instance->RequestSystemProcessMemoryInfo(
+      nspids,
+      base::BindOnce(&ArcProcessService::OnReceiveMemoryInfo,
+                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+}
+
 void ArcProcessService::OnConnectionReady() {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   task_runner_->PostTask(FROM_HERE, base::BindOnce(&Reset, nspid_to_pid_));
diff --git a/chrome/browser/chromeos/arc/process/arc_process_service.h b/chrome/browser/chromeos/arc/process/arc_process_service.h
index f62d8b7..f2073d5 100644
--- a/chrome/browser/chromeos/arc/process/arc_process_service.h
+++ b/chrome/browser/chromeos/arc/process/arc_process_service.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_CHROMEOS_ARC_PROCESS_ARC_PROCESS_SERVICE_H_
 
 #include <map>
+#include <memory>
 #include <vector>
 
 #include "base/callback.h"
@@ -18,6 +19,8 @@
 #include "components/arc/common/process.mojom.h"
 #include "components/arc/connection_observer.h"
 #include "components/keyed_service/core/keyed_service.h"
+#include "services/resource_coordinator/public/cpp/memory_instrumentation/global_memory_dump.h"
+#include "services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom.h"
 
 namespace content {
 class BrowserContext;
@@ -59,6 +62,8 @@
 
   using RequestProcessListCallback =
       base::Callback<void(std::vector<ArcProcess>)>;
+  using RequestMemoryInfoCallback = base::OnceCallback<void(
+      std::unique_ptr<memory_instrumentation::GlobalMemoryDump>)>;
 
   ArcProcessService(content::BrowserContext* context,
                     ArcBridgeService* bridge_service);
@@ -72,6 +77,9 @@
   bool RequestAppProcessList(RequestProcessListCallback callback);
   void RequestSystemProcessList(RequestProcessListCallback callback);
 
+  bool RequestAppMemoryInfo(RequestMemoryInfoCallback callback);
+  bool RequestSystemMemoryInfo(RequestMemoryInfoCallback callback);
+
   using PidMap = std::map<base::ProcessId, base::ProcessId>;
 
   class NSPidToPidMap : public base::RefCountedThreadSafe<NSPidToPidMap> {
@@ -105,7 +113,11 @@
   void OnReceiveProcessList(
       const RequestProcessListCallback& callback,
       std::vector<mojom::RunningAppProcessInfoPtr> processes);
-
+  void OnReceiveMemoryInfo(
+      RequestMemoryInfoCallback callback,
+      memory_instrumentation::mojom::GlobalMemoryDumpPtr dump);
+  void OnGetSystemProcessList(RequestMemoryInfoCallback callback,
+                              std::vector<ArcProcess> processes);
   // ConnectionObserver<mojom::ProcessInstance> overrides.
   void OnConnectionReady() override;
   void OnConnectionClosed() override;
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
index 7672cfd..3286709 100644
--- a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
+++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
@@ -55,6 +55,7 @@
 #include "chrome/browser/chromeos/dbus/screen_lock_service_provider.h"
 #include "chrome/browser/chromeos/dbus/virtual_file_request_service_provider.h"
 #include "chrome/browser/chromeos/dbus/vm_applications_service_provider.h"
+#include "chrome/browser/chromeos/diagnosticsd/diagnosticsd_bridge.h"
 #include "chrome/browser/chromeos/display/quirks_manager_delegate_impl.h"
 #include "chrome/browser/chromeos/events/event_rewriter_delegate_impl.h"
 #include "chrome/browser/chromeos/extensions/default_app_order.h"
@@ -655,6 +656,8 @@
 
   discover_manager_ = std::make_unique<DiscoverManager>();
 
+  diagnosticsd_bridge_ = std::make_unique<DiagnosticsdBridge>();
+
   ChromeBrowserMainPartsLinux::PreMainMessageLoopRun();
 }
 
@@ -1077,6 +1080,7 @@
   demo_mode_resources_remover_.reset();
   user_activity_controller_.reset();
   adaptive_screen_brightness_manager_.reset();
+  diagnosticsd_bridge_.reset();
 
   // Detach D-Bus clients before DBusThreadManager is shut down.
   idle_action_warning_observer_.reset();
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.h b/chrome/browser/chromeos/chrome_browser_main_chromeos.h
index ff095cb..0aacf1e 100644
--- a/chrome/browser/chromeos/chrome_browser_main_chromeos.h
+++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.h
@@ -35,6 +35,7 @@
 
 class ArcKioskAppManager;
 class DemoModeResourcesRemover;
+class DiagnosticsdBridge;
 class DiscoverManager;
 class EventRewriterDelegateImpl;
 class IdleActionWarningObserver;
@@ -144,6 +145,7 @@
   std::unique_ptr<DemoModeResourcesRemover> demo_mode_resources_remover_;
   std::unique_ptr<crostini::CrosvmMetrics> crosvm_metrics_;
   std::unique_ptr<DiscoverManager> discover_manager_;
+  std::unique_ptr<DiagnosticsdBridge> diagnosticsd_bridge_;
 
   DISALLOW_COPY_AND_ASSIGN(ChromeBrowserMainPartsChromeos);
 };
diff --git a/chrome/browser/chromeos/diagnosticsd/OWNERS b/chrome/browser/chromeos/diagnosticsd/OWNERS
new file mode 100644
index 0000000..8c3eff5
--- /dev/null
+++ b/chrome/browser/chromeos/diagnosticsd/OWNERS
@@ -0,0 +1,2 @@
+emaxx@chromium.org
+pmarko@chromium.org
diff --git a/chrome/browser/chromeos/diagnosticsd/diagnosticsd_bridge.cc b/chrome/browser/chromeos/diagnosticsd/diagnosticsd_bridge.cc
new file mode 100644
index 0000000..2aa0f389
--- /dev/null
+++ b/chrome/browser/chromeos/diagnosticsd/diagnosticsd_bridge.cc
@@ -0,0 +1,163 @@
+// 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 <memory>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/process/process_handle.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/time.h"
+#include "chrome/browser/chromeos/diagnosticsd/diagnosticsd_bridge.h"
+#include "chromeos/dbus/dbus_thread_manager.h"
+#include "chromeos/dbus/diagnosticsd_client.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/platform/platform_channel.h"
+#include "mojo/public/cpp/system/invitation.h"
+#include "mojo/public/cpp/system/message_pipe.h"
+#include "third_party/cros_system_api/dbus/diagnosticsd/dbus-constants.h"
+
+namespace chromeos {
+
+namespace {
+
+// Interval used between successive connection attempts to the diagnosticsd.
+// This is a safety measure for avoiding busy loops when the diagnosticsd is
+// dysfunctional.
+constexpr base::TimeDelta kConnectionAttemptInterval =
+    base::TimeDelta::FromSeconds(1);
+// The maximum number of consecutive connection attempts to the diagnosticsd
+// before giving up. This is to prevent wasting system resources on hopeless
+// attempts to connect in cases when the diagnosticsd is dysfunctional.
+constexpr int kMaxConnectionAttemptCount = 10;
+
+DiagnosticsdBridge* g_diagnosticsd_bridge_instance = nullptr;
+
+}  // namespace
+
+// static
+DiagnosticsdBridge* DiagnosticsdBridge::Get() {
+  return g_diagnosticsd_bridge_instance;
+}
+
+DiagnosticsdBridge::DiagnosticsdBridge() {
+  DCHECK(!g_diagnosticsd_bridge_instance);
+  g_diagnosticsd_bridge_instance = this;
+  WaitForDBusService();
+}
+
+DiagnosticsdBridge::~DiagnosticsdBridge() {
+  DCHECK_EQ(g_diagnosticsd_bridge_instance, this);
+  g_diagnosticsd_bridge_instance = nullptr;
+}
+
+void DiagnosticsdBridge::WaitForDBusService() {
+  if (connection_attempt_ >= kMaxConnectionAttemptCount) {
+    DLOG(WARNING) << "Stopping attempts to connect to diagnosticsd - too many "
+                     "unsuccessful attempts in a row";
+    return;
+  }
+  ++connection_attempt_;
+
+  // Cancel any tasks previously created from WaitForDBusService() or
+  // ScheduleWaitingForDBusService().
+  dbus_waiting_weak_ptr_factory_.InvalidateWeakPtrs();
+
+  DBusThreadManager::Get()
+      ->GetDiagnosticsdClient()
+      ->WaitForServiceToBeAvailable(
+          base::BindOnce(&DiagnosticsdBridge::OnWaitedForDBusService,
+                         dbus_waiting_weak_ptr_factory_.GetWeakPtr()));
+}
+
+void DiagnosticsdBridge::ScheduleWaitingForDBusService() {
+  // Cancel any tasks previously created from WaitForDBusService() or
+  // ScheduleWaitingForDBusService().
+  dbus_waiting_weak_ptr_factory_.InvalidateWeakPtrs();
+
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE,
+      base::BindOnce(&DiagnosticsdBridge::WaitForDBusService,
+                     dbus_waiting_weak_ptr_factory_.GetWeakPtr()),
+      kConnectionAttemptInterval);
+}
+
+void DiagnosticsdBridge::OnWaitedForDBusService(bool service_is_available) {
+  if (!service_is_available) {
+    DLOG(WARNING) << "The diagnosticsd D-Bus service is unavailable";
+    return;
+  }
+
+  // Cancel any tasks previously created from WaitForDBusService() or
+  // ScheduleWaitingForDBusService().
+  dbus_waiting_weak_ptr_factory_.InvalidateWeakPtrs();
+
+  BootstrapMojoConnection();
+}
+
+void DiagnosticsdBridge::BootstrapMojoConnection() {
+  DCHECK(!diagnosticsd_service_factory_mojo_ptr_);
+
+  // Create a Mojo message pipe and attach
+  // |diagnosticsd_service_factory_mojo_ptr_| to its local endpoint.
+  mojo::OutgoingInvitation invitation;
+  mojo::PlatformChannel channel;
+  mojo::ScopedMessagePipeHandle server_pipe = invitation.AttachMessagePipe(
+      diagnostics::kDiagnosticsdMojoConnectionChannelToken);
+  mojo::OutgoingInvitation::Send(std::move(invitation),
+                                 base::kNullProcessHandle,
+                                 channel.TakeLocalEndpoint());
+  diagnosticsd_service_factory_mojo_ptr_.Bind(
+      mojo::InterfacePtrInfo<diagnosticsd::mojom::DiagnosticsdServiceFactory>(
+          std::move(server_pipe), 0 /* version */));
+  diagnosticsd_service_factory_mojo_ptr_.set_connection_error_handler(
+      base::BindOnce(&DiagnosticsdBridge::OnMojoConnectionError,
+                     weak_ptr_factory_.GetWeakPtr()));
+
+  // Queue a call that would establish full-duplex Mojo communication with the
+  // diagnosticsd daemon by sending an interface pointer to the self instance.
+  auto self_binding =
+      std::make_unique<mojo::Binding<diagnosticsd::mojom::DiagnosticsdClient>>(
+          this);
+  diagnosticsd::mojom::DiagnosticsdClientPtr self_proxy;
+  self_binding->Bind(mojo::MakeRequest(&self_proxy));
+  diagnosticsd_service_factory_mojo_ptr_->GetService(
+      mojo::MakeRequest(&diagnosticsd_service_mojo_ptr_), std::move(self_proxy),
+      base::BindOnce(&DiagnosticsdBridge::OnMojoGetServiceCompleted,
+                     weak_ptr_factory_.GetWeakPtr()));
+
+  // Send the file descriptor with the Mojo message pipe's remote endpoint to
+  // the diagnosticsd daemon via the D-Bus.
+  DBusThreadManager::Get()->GetDiagnosticsdClient()->BootstrapMojoConnection(
+      channel.TakeRemoteEndpoint().TakePlatformHandle().TakeFD(),
+      base::BindOnce(&DiagnosticsdBridge::OnBootstrappedMojoConnection,
+                     weak_ptr_factory_.GetWeakPtr()));
+}
+
+void DiagnosticsdBridge::OnBootstrappedMojoConnection(bool success) {
+  if (success)
+    return;
+  DLOG(ERROR) << "Failed to establish Mojo connection to diagnosticsd";
+  diagnosticsd_service_factory_mojo_ptr_.reset();
+  diagnosticsd_service_mojo_ptr_.reset();
+  ScheduleWaitingForDBusService();
+}
+
+void DiagnosticsdBridge::OnMojoGetServiceCompleted() {
+  DVLOG(0) << "Established Mojo communication with diagnosticsd";
+  // Reset the current connection attempt counter, since a successful
+  // initialization of Mojo communication has completed.
+  connection_attempt_ = 0;
+}
+
+void DiagnosticsdBridge::OnMojoConnectionError() {
+  DLOG(WARNING) << "Mojo connection to the diagnosticsd daemon got shut down";
+  diagnosticsd_service_factory_mojo_ptr_.reset();
+  diagnosticsd_service_mojo_ptr_.reset();
+  ScheduleWaitingForDBusService();
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/diagnosticsd/diagnosticsd_bridge.h b/chrome/browser/chromeos/diagnosticsd/diagnosticsd_bridge.h
new file mode 100644
index 0000000..90c37449
--- /dev/null
+++ b/chrome/browser/chromeos/diagnosticsd/diagnosticsd_bridge.h
@@ -0,0 +1,65 @@
+// 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_DIAGNOSTICSD_DIAGNOSTICSD_BRIDGE_H_
+#define CHROME_BROWSER_CHROMEOS_DIAGNOSTICSD_DIAGNOSTICSD_BRIDGE_H_
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "chrome/services/diagnosticsd/public/mojom/diagnosticsd.mojom.h"
+
+namespace chromeos {
+
+// Establishes Mojo communication to the diagnosticsd daemon. The Mojo pipe gets
+// bootstrapped via D-Bus, and the class takes care of waiting until the
+// diagnosticsd D-Bus service gets started and of repeating the bootstrapping
+// after the daemon gets restarted.
+class DiagnosticsdBridge final
+    : public diagnosticsd::mojom::DiagnosticsdClient {
+ public:
+  // Returns the global singleton instance.
+  static DiagnosticsdBridge* Get();
+
+  DiagnosticsdBridge();
+  ~DiagnosticsdBridge() override;
+
+ private:
+  // Starts waiting until the diagnosticsd D-Bus service becomes available (or
+  // until this waiting fails).
+  void WaitForDBusService();
+  // Schedules a postponed execution of WaitForDBusService().
+  void ScheduleWaitingForDBusService();
+  // Called once waiting for the D-Bus service, started by WaitForDBusService(),
+  // finishes.
+  void OnWaitedForDBusService(bool service_is_available);
+  // Triggers Mojo bootstrapping via a D-Bus to the diagnosticsd daemon.
+  void BootstrapMojoConnection();
+  // Called once the result of the D-Bus call, made from
+  // BootstrapMojoConnection(), arrives.
+  void OnBootstrappedMojoConnection(bool success);
+  // Called once the GetService() Mojo request completes.
+  void OnMojoGetServiceCompleted();
+  // Called when Mojo signals a connection error.
+  void OnMojoConnectionError();
+
+  int connection_attempt_ = 0;
+
+  // Interface pointers to the Mojo services exposed by the diagnosticsd daemon.
+  diagnosticsd::mojom::DiagnosticsdServiceFactoryPtr
+      diagnosticsd_service_factory_mojo_ptr_;
+  diagnosticsd::mojom::DiagnosticsdServicePtr diagnosticsd_service_mojo_ptr_;
+
+  // These weak pointer factories must be the last members:
+
+  // Used for cancelling previously posted tasks that wait for the D-Bus service
+  // availability.
+  base::WeakPtrFactory<DiagnosticsdBridge> dbus_waiting_weak_ptr_factory_{this};
+  base::WeakPtrFactory<DiagnosticsdBridge> weak_ptr_factory_{this};
+
+  DISALLOW_COPY_AND_ASSIGN(DiagnosticsdBridge);
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_DIAGNOSTICSD_DIAGNOSTICSD_BRIDGE_H_
diff --git a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service.cc b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service.cc
index d9b8221..5c9d1b6 100644
--- a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service.cc
+++ b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service.cc
@@ -547,11 +547,6 @@
   app_manager_->DisableAppIfLoaded();
 }
 
-void EasyUnlockService::NotifyTurnOffOperationStatusChanged() {
-  for (EasyUnlockServiceObserver& observer : observers_)
-    observer.OnTurnOffOperationStatusChanged();
-}
-
 void EasyUnlockService::ResetScreenlockState() {
   screenlock_state_handler_.reset();
   auth_attempt_.reset();
diff --git a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service.h b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service.h
index f366a617..1efa6dc 100644
--- a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service.h
+++ b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service.h
@@ -57,12 +57,6 @@
 
 class EasyUnlockService : public KeyedService {
  public:
-  enum TurnOffFlowStatus {
-    IDLE,
-    PENDING,
-    FAIL,
-  };
-
   enum Type { TYPE_REGULAR, TYPE_SIGNIN };
 
   // Gets EasyUnlockService instance.
@@ -99,15 +93,6 @@
   virtual const base::ListValue* GetRemoteDevices() const = 0;
   virtual void SetRemoteDevices(const base::ListValue& devices) = 0;
 
-  // Runs the flow for turning Easy unlock off.
-  virtual void RunTurnOffFlow() = 0;
-
-  // Resets the turn off flow if one is in progress.
-  virtual void ResetTurnOffFlow() = 0;
-
-  // Returns the current turn off flow status.
-  virtual TurnOffFlowStatus GetTurnOffFlowStatus() const = 0;
-
   // Gets the challenge bytes for the user currently associated with the
   // service.
   virtual std::string GetChallenge() const = 0;
@@ -233,9 +218,6 @@
   // the lock screen UI should remain unchanged until the screen unlocks.
   void DisableAppWithoutResettingScreenlockState();
 
-  // Notifies observers that the turn off flow status changed.
-  void NotifyTurnOffOperationStatusChanged();
-
   // Resets the screenlock state set by this service.
   void ResetScreenlockState();
 
diff --git a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service_observer.h b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service_observer.h
index 255bb51..b793221 100644
--- a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service_observer.h
+++ b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service_observer.h
@@ -11,9 +11,6 @@
 
 class EasyUnlockServiceObserver {
  public:
-  // Invoked when turn-off operation status changes.
-  virtual void OnTurnOffOperationStatusChanged() {}
-
   // Invoked when screenlock state changes.
   virtual void OnScreenlockStateChanged(proximity_auth::ScreenlockState state) {
   }
diff --git a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service_regular.cc b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service_regular.cc
index 011e411..4d32c60 100644
--- a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service_regular.cc
+++ b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service_regular.cc
@@ -45,7 +45,6 @@
 #include "chromeos/components/proximity_auth/proximity_auth_system.h"
 #include "chromeos/components/proximity_auth/screenlock_bridge.h"
 #include "chromeos/components/proximity_auth/switches.h"
-#include "components/cryptauth/cryptauth_client_impl.h"
 #include "components/cryptauth/cryptauth_enrollment_manager.h"
 #include "components/cryptauth/cryptauth_enrollment_utils.h"
 #include "components/cryptauth/cryptauth_gcm_manager_impl.h"
@@ -88,15 +87,6 @@
   COUNT
 };
 
-void LogToggleFeature(SmartLockToggleFeature toggle) {
-  UMA_HISTOGRAM_BOOLEAN("SmartLock.ToggleFeature", static_cast<bool>(toggle));
-}
-
-void LogToggleFeatureDisableResult(SmartLockResult result) {
-  UMA_HISTOGRAM_BOOLEAN("SmartLock.ToggleFeature.Disable.Result",
-                        static_cast<bool>(result));
-}
-
 void LogSmartLockEnabledState(SmartLockEnabledState state) {
   UMA_HISTOGRAM_ENUMERATION("SmartLock.EnabledState", state,
                             SmartLockEnabledState::COUNT);
@@ -123,7 +113,6 @@
     device_sync::DeviceSyncClient* device_sync_client,
     multidevice_setup::MultiDeviceSetupClient* multidevice_setup_client)
     : EasyUnlockService(profile, secure_channel_client),
-      turn_off_flow_status_(EasyUnlockService::IDLE),
       scoped_crypt_auth_device_manager_observer_(this),
       will_unlock_using_easy_unlock_(false),
       lock_screen_last_shown_timestamp_(base::TimeTicks::Now()),
@@ -424,51 +413,6 @@
   RefreshCryptohomeKeysIfPossible();
 }
 
-void EasyUnlockServiceRegular::RunTurnOffFlow() {
-  if (turn_off_flow_status_ == PENDING)
-    return;
-
-  LogToggleFeature(SmartLockToggleFeature::DISABLE);
-
-  SetTurnOffFlowStatus(PENDING);
-
-  if (base::FeatureList::IsEnabled(chromeos::features::kMultiDeviceApi)) {
-    // Disabling EASY_UNLOCK_HOST is a special case that does not require a
-    // public key to be passed; EASY_UNLOCK_HOST will be disabled for all hosts.
-    device_sync_client_->SetSoftwareFeatureState(
-        std::string() /* public_key */,
-        cryptauth::SoftwareFeature::EASY_UNLOCK_HOST, false /* enabled */,
-        false /* is_exclusive */,
-        base::BindOnce(&EasyUnlockServiceRegular::OnTurnOffEasyUnlockCompleted,
-                       weak_ptr_factory_.GetWeakPtr()));
-  } else {
-    DCHECK(!cryptauth_client_);
-    std::unique_ptr<cryptauth::CryptAuthClientFactory> factory =
-        proximity_auth_client()->CreateCryptAuthClientFactory();
-    cryptauth_client_ = factory->CreateInstance();
-
-    cryptauth::ToggleEasyUnlockRequest request;
-    request.set_enable(false);
-    request.set_apply_to_all(true);
-    cryptauth_client_->ToggleEasyUnlock(
-        request,
-        base::Bind(&EasyUnlockServiceRegular::OnToggleEasyUnlockApiComplete,
-                   weak_ptr_factory_.GetWeakPtr()),
-        base::Bind(&EasyUnlockServiceRegular::OnToggleEasyUnlockApiFailed,
-                   weak_ptr_factory_.GetWeakPtr()));
-  }
-}
-
-void EasyUnlockServiceRegular::ResetTurnOffFlow() {
-  cryptauth_client_.reset();
-  SetTurnOffFlowStatus(IDLE);
-}
-
-EasyUnlockService::TurnOffFlowStatus
-EasyUnlockServiceRegular::GetTurnOffFlowStatus() const {
-  return turn_off_flow_status_;
-}
-
 std::string EasyUnlockServiceRegular::GetChallenge() const {
   return std::string();
 }
@@ -522,7 +466,6 @@
   short_lived_user_context_.reset();
   pref_manager_.reset();
 
-  turn_off_flow_status_ = EasyUnlockService::IDLE;
   proximity_auth::ScreenlockBridge::Get()->RemoveObserver(this);
 
   if (!base::FeatureList::IsEnabled(chromeos::features::kMultiDeviceApi)) {
@@ -846,63 +789,6 @@
   // Nothing to do.
 }
 
-void EasyUnlockServiceRegular::SetTurnOffFlowStatus(TurnOffFlowStatus status) {
-  turn_off_flow_status_ = status;
-  NotifyTurnOffOperationStatusChanged();
-}
-
-void EasyUnlockServiceRegular::OnToggleEasyUnlockApiComplete(
-    const cryptauth::ToggleEasyUnlockResponse& response) {
-  DCHECK(!base::FeatureList::IsEnabled(chromeos::features::kMultiDeviceApi));
-  cryptauth_client_.reset();
-  OnTurnOffEasyUnlockSuccess();
-}
-
-void EasyUnlockServiceRegular::OnToggleEasyUnlockApiFailed(
-    cryptauth::NetworkRequestError error) {
-  PA_LOG(WARNING) << "ToggleEasyUnlock call failed: " << error;
-  DCHECK(!base::FeatureList::IsEnabled(chromeos::features::kMultiDeviceApi));
-  OnTurnOffEasyUnlockFailure();
-}
-
-void EasyUnlockServiceRegular::OnTurnOffEasyUnlockCompleted(
-    device_sync::mojom::NetworkRequestResult result_code) {
-  DCHECK(base::FeatureList::IsEnabled(chromeos::features::kMultiDeviceApi));
-
-  if (result_code != device_sync::mojom::NetworkRequestResult::kSuccess) {
-    PA_LOG(WARNING) << "ToggleEasyUnlock call failed: " << result_code;
-    OnTurnOffEasyUnlockFailure();
-  } else {
-    OnTurnOffEasyUnlockSuccess();
-  }
-}
-
-void EasyUnlockServiceRegular::OnTurnOffEasyUnlockSuccess() {
-  PA_LOG(INFO) << "Successfully turned off Smart Lock.";
-  LogToggleFeatureDisableResult(SmartLockResult::SUCCESS);
-
-  if (base::FeatureList::IsEnabled(chromeos::features::kMultiDeviceApi)) {
-    remote_device_unlock_keys_before_sync_ = GetUnlockKeys();
-  } else {
-    GetCryptAuthDeviceManager()->ForceSyncNow(
-        cryptauth::InvocationReason::INVOCATION_REASON_FEATURE_TOGGLED);
-  }
-
-  EasyUnlockService::ResetLocalStateForUser(GetAccountId());
-  SetRemoteDevices(base::ListValue());
-  SetProximityAuthDevices(GetAccountId(), cryptauth::RemoteDeviceRefList(),
-                          base::nullopt /* local_device */);
-  pref_manager_->SetIsEasyUnlockEnabled(false);
-  SetTurnOffFlowStatus(IDLE);
-  ResetScreenlockState();
-  registrar_.RemoveAll();
-}
-
-void EasyUnlockServiceRegular::OnTurnOffEasyUnlockFailure() {
-  LogToggleFeatureDisableResult(SmartLockResult::FAILURE);
-  SetTurnOffFlowStatus(FAIL);
-}
-
 cryptauth::CryptAuthEnrollmentManager*
 EasyUnlockServiceRegular::GetCryptAuthEnrollmentManager() {
   DCHECK(!base::FeatureList::IsEnabled(chromeos::features::kMultiDeviceApi));
diff --git a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service_regular.h b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service_regular.h
index 45a7f6a..27d21bb4 100644
--- a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service_regular.h
+++ b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service_regular.h
@@ -29,12 +29,10 @@
 }  // namespace base
 
 namespace cryptauth {
-class CryptAuthClient;
 class CryptAuthDeviceManager;
 class CryptAuthEnrollmentManager;
 class LocalDeviceDataProvider;
 class RemoteDeviceLoader;
-class ToggleEasyUnlockResponse;
 }  // namespace cryptauth
 
 namespace proximity_auth {
@@ -95,9 +93,6 @@
   void ClearPermitAccess() override;
   const base::ListValue* GetRemoteDevices() const override;
   void SetRemoteDevices(const base::ListValue& devices) override;
-  void RunTurnOffFlow() override;
-  void ResetTurnOffFlow() override;
-  TurnOffFlowStatus GetTurnOffFlowStatus() const override;
   std::string GetChallenge() const override;
   std::string GetWrappedSecret() const override;
   void RecordEasySignInOutcome(const AccountId& account_id,
@@ -150,20 +145,6 @@
       override;
   void OnFocusedUserChanged(const AccountId& account_id) override;
 
-  // Sets the new turn-off flow status.
-  void SetTurnOffFlowStatus(TurnOffFlowStatus status);
-
-  // Callback for ToggleEasyUnlock CryptAuth API.
-  void OnToggleEasyUnlockApiComplete(
-      const cryptauth::ToggleEasyUnlockResponse& response);
-  void OnToggleEasyUnlockApiFailed(cryptauth::NetworkRequestError error);
-
-  void OnTurnOffEasyUnlockCompleted(
-      device_sync::mojom::NetworkRequestResult result_code);
-
-  void OnTurnOffEasyUnlockSuccess();
-  void OnTurnOffEasyUnlockFailure();
-
   // Called after a cryptohome RemoveKey or RefreshKey operation to set the
   // proper hardlock state if the operation is successful.
   void SetHardlockAfterKeyOperation(
@@ -186,8 +167,6 @@
 
   cryptauth::RemoteDeviceRefList GetUnlockKeys();
 
-  TurnOffFlowStatus turn_off_flow_status_;
-  std::unique_ptr<cryptauth::CryptAuthClient> cryptauth_client_;
   ScopedObserver<cryptauth::CryptAuthDeviceManager, EasyUnlockServiceRegular>
       scoped_crypt_auth_device_manager_observer_;
 
diff --git a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service_signin_chromeos.cc b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service_signin_chromeos.cc
index 42b67d7..f5cd6ed 100644
--- a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service_signin_chromeos.cc
+++ b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service_signin_chromeos.cc
@@ -241,19 +241,6 @@
   NOTREACHED();
 }
 
-void EasyUnlockServiceSignin::RunTurnOffFlow() {
-  NOTREACHED();
-}
-
-void EasyUnlockServiceSignin::ResetTurnOffFlow() {
-  NOTREACHED();
-}
-
-EasyUnlockService::TurnOffFlowStatus
-EasyUnlockServiceSignin::GetTurnOffFlowStatus() const {
-  return EasyUnlockService::IDLE;
-}
-
 std::string EasyUnlockServiceSignin::GetChallenge() const {
   const UserData* data = FindLoadedDataForCurrentUser();
   if (!data)
diff --git a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service_signin_chromeos.h b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service_signin_chromeos.h
index a8d3daf9..4159bd7 100644
--- a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service_signin_chromeos.h
+++ b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_service_signin_chromeos.h
@@ -95,9 +95,6 @@
   void ClearPermitAccess() override;
   const base::ListValue* GetRemoteDevices() const override;
   void SetRemoteDevices(const base::ListValue& devices) override;
-  void RunTurnOffFlow() override;
-  void ResetTurnOffFlow() override;
-  TurnOffFlowStatus GetTurnOffFlowStatus() const override;
   std::string GetChallenge() const override;
   std::string GetWrappedSecret() const override;
   void RecordEasySignInOutcome(const AccountId& account_id,
diff --git a/chrome/browser/chromeos/login/ui/simple_web_view_dialog.cc b/chrome/browser/chromeos/login/ui/simple_web_view_dialog.cc
index 4e8798e..5ed7ede 100644
--- a/chrome/browser/chromeos/login/ui/simple_web_view_dialog.cc
+++ b/chrome/browser/chromeos/login/ui/simple_web_view_dialog.cc
@@ -21,7 +21,7 @@
 #include "chrome/browser/ui/views/toolbar/reload_button.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/grit/theme_resources.h"
-#include "components/omnibox/browser/toolbar_model_impl.h"
+#include "components/omnibox/browser/location_bar_model_impl.h"
 #include "components/password_manager/core/browser/password_manager.h"
 #include "components/strings/grit/components_strings.h"
 #include "content/public/browser/navigation_controller.h"
@@ -156,11 +156,11 @@
 }
 
 void SimpleWebViewDialog::Init() {
-  // Create the security state model that the toolbar model needs.
+  // Create the security state model that the location bar model needs.
   if (web_view_->GetWebContents())
     SecurityStateTabHelper::CreateForWebContents(web_view_->GetWebContents());
-  toolbar_model_.reset(
-      new ToolbarModelImpl(this, content::kMaxURLDisplayChars));
+  location_bar_model_.reset(
+      new LocationBarModelImpl(this, content::kMaxURLDisplayChars));
 
   SetBackground(views::CreateSolidBackground(kDialogColor));
 
@@ -275,12 +275,12 @@
   return nullptr;
 }
 
-ToolbarModel* SimpleWebViewDialog::GetToolbarModel() {
-  return toolbar_model_.get();
+LocationBarModel* SimpleWebViewDialog::GetLocationBarModel() {
+  return location_bar_model_.get();
 }
 
-const ToolbarModel* SimpleWebViewDialog::GetToolbarModel() const {
-  return toolbar_model_.get();
+const LocationBarModel* SimpleWebViewDialog::GetLocationBarModel() const {
+  return location_bar_model_.get();
 }
 
 ContentSettingBubbleModelDelegate*
diff --git a/chrome/browser/chromeos/login/ui/simple_web_view_dialog.h b/chrome/browser/chromeos/login/ui/simple_web_view_dialog.h
index 5177c51..0fad748 100644
--- a/chrome/browser/chromeos/login/ui/simple_web_view_dialog.h
+++ b/chrome/browser/chromeos/login/ui/simple_web_view_dialog.h
@@ -10,7 +10,7 @@
 
 #include "base/macros.h"
 #include "chrome/browser/command_updater_delegate.h"
-#include "chrome/browser/ui/toolbar/chrome_toolbar_model_delegate.h"
+#include "chrome/browser/ui/toolbar/chrome_location_bar_model_delegate.h"
 #include "chrome/browser/ui/views/location_bar/location_bar_view.h"
 #include "content/public/browser/page_navigator.h"
 #include "content/public/browser/web_contents_delegate.h"
@@ -21,7 +21,7 @@
 class CommandUpdaterImpl;
 class Profile;
 class ReloadButton;
-class ToolbarModel;
+class LocationBarModel;
 
 namespace views {
 class WebView;
@@ -40,7 +40,7 @@
 class SimpleWebViewDialog : public views::ButtonListener,
                             public views::WidgetDelegateView,
                             public LocationBarView::Delegate,
-                            public ChromeToolbarModelDelegate,
+                            public ChromeLocationBarModelDelegate,
                             public CommandUpdaterDelegate,
                             public content::PageNavigator,
                             public content::WebContentsDelegate {
@@ -74,12 +74,12 @@
 
   // Implements LocationBarView::Delegate:
   content::WebContents* GetWebContents() override;
-  ToolbarModel* GetToolbarModel() override;
-  const ToolbarModel* GetToolbarModel() const override;
+  LocationBarModel* GetLocationBarModel() override;
+  const LocationBarModel* GetLocationBarModel() const override;
   ContentSettingBubbleModelDelegate* GetContentSettingBubbleModelDelegate()
       override;
 
-  // Implements ChromeToolbarModelDelegate:
+  // Implements ChromeLocationBarModelDelegate:
   content::WebContents* GetActiveWebContents() const override;
 
   // Implements CommandUpdaterDelegate:
@@ -93,7 +93,7 @@
   void UpdateReload(bool is_loading, bool force);
 
   Profile* profile_;
-  std::unique_ptr<ToolbarModel> toolbar_model_;
+  std::unique_ptr<LocationBarModel> location_bar_model_;
   std::unique_ptr<CommandUpdaterImpl> command_updater_;
 
   // Controls
diff --git a/chrome/browser/chromeos/multidevice_setup/android_sms_app_helper_delegate_impl.cc b/chrome/browser/chromeos/multidevice_setup/android_sms_app_helper_delegate_impl.cc
index e9da9457b..466b97c 100644
--- a/chrome/browser/chromeos/multidevice_setup/android_sms_app_helper_delegate_impl.cc
+++ b/chrome/browser/chromeos/multidevice_setup/android_sms_app_helper_delegate_impl.cc
@@ -57,7 +57,7 @@
           true /* override_previous_user_uninstall */,
           // The service worker does not load in time for the installability
           // check so we bypass it as a workaround.
-          true /* bypass_service_worker_check */),
+          true /* bypass_service_worker_check */, true /* require_manifest */),
       base::BindOnce(&AndroidSmsAppHelperDelegateImpl::OnAppInstalled,
                      weak_ptr_factory_.GetWeakPtr(), launch_on_install));
 }
diff --git a/chrome/browser/chromeos/multidevice_setup/android_sms_app_helper_delegate_impl_unittest.cc b/chrome/browser/chromeos/multidevice_setup/android_sms_app_helper_delegate_impl_unittest.cc
index dea9d64..9e0d0bcb 100644
--- a/chrome/browser/chromeos/multidevice_setup/android_sms_app_helper_delegate_impl_unittest.cc
+++ b/chrome/browser/chromeos/multidevice_setup/android_sms_app_helper_delegate_impl_unittest.cc
@@ -84,7 +84,7 @@
       web_app::LaunchContainer::kWindow, web_app::InstallSource::kInternal,
       web_app::PendingAppManager::AppInfo::kDefaultCreateShortcuts,
       true /* override_previous_user_uninstall */,
-      true /* bypass_service_worker_check */);
+      true /* bypass_service_worker_check */, true /* require_manifest */);
   EXPECT_EQ(expected_apps_to_install,
             test_pending_app_manager()->install_requests());
   EXPECT_EQ(ContentSetting::CONTENT_SETTING_ALLOW, GetNotificationSetting());
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/adapter.cc b/chrome/browser/chromeos/power/auto_screen_brightness/adapter.cc
new file mode 100644
index 0000000..49e4e85
--- /dev/null
+++ b/chrome/browser/chromeos/power/auto_screen_brightness/adapter.cc
@@ -0,0 +1,362 @@
+// 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/adapter.h"
+
+#include "ash/public/cpp/ash_pref_names.h"
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "base/metrics/field_trial_params.h"
+#include "base/time/default_tick_clock.h"
+#include "chrome/browser/chromeos/power/auto_screen_brightness/utils.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chromeos/chromeos_features.h"
+#include "chromeos/dbus/power_manager/backlight.pb.h"
+#include "components/prefs/pref_service.h"
+
+namespace chromeos {
+namespace power {
+namespace auto_screen_brightness {
+
+constexpr base::TimeDelta Adapter::kAmbientLightShortHorizon;
+constexpr int Adapter::kNumberAmbientValuesToTrack;
+
+Adapter::Adapter(Profile* profile,
+                 AlsReader* als_reader,
+                 BrightnessMonitor* brightness_monitor,
+                 Modeller* modeller,
+                 chromeos::PowerManagerClient* power_manager_client)
+    : profile_(profile),
+      als_reader_observer_(this),
+      brightness_monitor_observer_(this),
+      modeller_observer_(this),
+      power_manager_client_(power_manager_client),
+      tick_clock_(base::DefaultTickClock::GetInstance()),
+      weak_ptr_factory_(this) {
+  DCHECK(profile);
+  DCHECK(als_reader);
+  DCHECK(brightness_monitor);
+  DCHECK(modeller);
+  DCHECK(power_manager_client);
+
+  als_reader_observer_.Add(als_reader);
+  brightness_monitor_observer_.Add(brightness_monitor);
+  modeller_observer_.Add(modeller);
+
+  power_manager_client_->WaitForServiceToBeAvailable(
+      base::BindOnce(&Adapter::OnPowerManagerServiceAvailable,
+                     weak_ptr_factory_.GetWeakPtr()));
+
+  InitParams();
+}
+
+Adapter::~Adapter() = default;
+
+void Adapter::OnAmbientLightUpdated(int lux) {
+  if (adapter_status_ == Status::kDisabled)
+    return;
+
+  const base::TimeTicks now = tick_clock_->NowTicks();
+
+  if (first_als_time_.is_null())
+    first_als_time_ = now;
+
+  latest_als_time_ = now;
+
+  ambient_light_values_.SaveToBuffer({lux, now});
+
+  MaybeAdjustBrightness();
+}
+
+void Adapter::OnAlsReaderInitialized(AlsReader::AlsInitStatus status) {
+  DCHECK(!als_init_status_);
+
+  als_init_status_ = status;
+  UpdateStatus();
+}
+
+void Adapter::OnBrightnessMonitorInitialized(bool success) {
+  DCHECK(!brightness_monitor_success_.has_value());
+
+  brightness_monitor_success_ = success;
+  UpdateStatus();
+}
+
+void Adapter::OnUserBrightnessChanged(double old_brightness_percent,
+                                      double new_brightness_percent) {}
+
+void Adapter::OnUserBrightnessChangeRequested() {
+  // This will disable |adapter_status_| so that the model will not make any
+  // brightness adjustment.
+  adapter_status_ = Status::kDisabled;
+}
+
+void Adapter::OnModelTrained(const MonotoneCubicSpline& brightness_curve) {
+  if (adapter_status_ == Status::kDisabled)
+    return;
+
+  personal_curve_.emplace(brightness_curve);
+}
+
+void Adapter::OnModelInitialized(
+    const base::Optional<MonotoneCubicSpline>& global_curve,
+    const base::Optional<MonotoneCubicSpline>& personal_curve) {
+  DCHECK(!model_initialized_);
+
+  model_initialized_ = true;
+
+  if (global_curve)
+    global_curve_.emplace(*global_curve);
+  if (personal_curve)
+    personal_curve_.emplace(*personal_curve);
+
+  UpdateStatus();
+}
+
+void Adapter::SetTickClockForTesting(const base::TickClock* test_tick_clock) {
+  tick_clock_ = test_tick_clock;
+}
+
+Adapter::Status Adapter::GetStatusForTesting() const {
+  return adapter_status_;
+}
+
+base::Optional<MonotoneCubicSpline> Adapter::GetGlobalCurveForTesting() const {
+  return global_curve_;
+}
+
+base::Optional<MonotoneCubicSpline> Adapter::GetPersonalCurveForTesting()
+    const {
+  return personal_curve_;
+}
+
+double Adapter::GetAverageAmbientForTesting() const {
+  return AverageAmbient(ambient_light_values_, -1);
+}
+
+double Adapter::GetBrighteningThresholdForTesting() const {
+  return *brightening_lux_threshold_;
+}
+
+double Adapter::GetDarkeningThresholdForTesting() const {
+  return *darkening_lux_threshold_;
+}
+
+// TODO(jiameng): add UMA metrics to record errors.
+void Adapter::InitParams() {
+  params_.brightening_lux_threshold_ratio = GetFieldTrialParamByFeatureAsDouble(
+      features::kAutoScreenBrightness, "brightening_lux_threshold_ratio",
+      params_.brightening_lux_threshold_ratio);
+  if (params_.brightening_lux_threshold_ratio <= 0) {
+    adapter_status_ = Status::kDisabled;
+    return;
+  }
+
+  params_.darkening_lux_threshold_ratio = GetFieldTrialParamByFeatureAsDouble(
+      features::kAutoScreenBrightness, "darkening_lux_threshold_ratio",
+      params_.darkening_lux_threshold_ratio);
+  if (params_.darkening_lux_threshold_ratio <= 0 ||
+      params_.darkening_lux_threshold_ratio > 1) {
+    adapter_status_ = Status::kDisabled;
+    return;
+  }
+
+  params_.immediate_brightening_lux_threshold_ratio =
+      GetFieldTrialParamByFeatureAsDouble(
+          features::kAutoScreenBrightness,
+          "immediate_brightening_lux_threshold_ratio",
+          params_.immediate_brightening_lux_threshold_ratio);
+  if (params_.immediate_brightening_lux_threshold_ratio <
+      params_.brightening_lux_threshold_ratio) {
+    adapter_status_ = Status::kDisabled;
+    return;
+  }
+
+  params_.immediate_darkening_lux_threshold_ratio =
+      GetFieldTrialParamByFeatureAsDouble(
+          features::kAutoScreenBrightness,
+          "immediate_darkening_lux_threshold_ratio",
+          params_.immediate_darkening_lux_threshold_ratio);
+  if (params_.immediate_darkening_lux_threshold_ratio <
+          params_.darkening_lux_threshold_ratio ||
+      params_.immediate_darkening_lux_threshold_ratio > 1) {
+    adapter_status_ = Status::kDisabled;
+    return;
+  }
+
+  params_.update_brightness_on_startup = GetFieldTrialParamByFeatureAsBool(
+      features::kAutoScreenBrightness, "update_brightness_on_startup",
+      params_.update_brightness_on_startup);
+
+  const int min_seconds_between_brightness_changes =
+      GetFieldTrialParamByFeatureAsInt(
+          features::kAutoScreenBrightness,
+          "min_seconds_between_brightness_changes",
+          params_.min_time_between_brightness_changes.InSeconds());
+  if (min_seconds_between_brightness_changes < 0) {
+    adapter_status_ = Status::kDisabled;
+    return;
+  }
+  params_.min_time_between_brightness_changes =
+      base::TimeDelta::FromSeconds(min_seconds_between_brightness_changes);
+
+  const int model_curve = base::GetFieldTrialParamByFeatureAsInt(
+      features::kAutoScreenBrightness, "model_curve", 2);
+  if (model_curve < 0 || model_curve > 2) {
+    adapter_status_ = Status::kDisabled;
+    return;
+  }
+  params_.model_curve = static_cast<ModelCurve>(model_curve);
+}
+
+void Adapter::OnPowerManagerServiceAvailable(bool service_is_ready) {
+  power_manager_service_available_ = service_is_ready;
+  UpdateStatus();
+}
+
+void Adapter::UpdateStatus() {
+  if (adapter_status_ != Status::kInitializing)
+    return;
+
+  if (!als_init_status_)
+    return;
+
+  const bool als_success =
+      *als_init_status_ == AlsReader::AlsInitStatus::kSuccess;
+  if (!als_success) {
+    adapter_status_ = Status::kDisabled;
+    return;
+  }
+
+  if (!brightness_monitor_success_.has_value())
+    return;
+
+  if (!*brightness_monitor_success_) {
+    adapter_status_ = Status::kDisabled;
+    return;
+  }
+
+  if (!model_initialized_)
+    return;
+
+  if (!global_curve_) {
+    adapter_status_ = Status::kDisabled;
+    return;
+  }
+
+  if (!power_manager_service_available_.has_value())
+    return;
+
+  if (!*power_manager_service_available_) {
+    adapter_status_ = Status::kDisabled;
+    return;
+  }
+
+  adapter_status_ = Status::kSuccess;
+}
+
+bool Adapter::CanAdjustBrightness(double current_average_ambient) const {
+  if (adapter_status_ != Status::kSuccess)
+    return false;
+
+  // Do not change brightness if it's set by the policy, but do not completely
+  // disable the model as the policy could change.
+  if (profile_->GetPrefs()->GetInteger(
+          ash::prefs::kPowerAcScreenBrightnessPercent) >= 0 ||
+      profile_->GetPrefs()->GetInteger(
+          ash::prefs::kPowerBatteryScreenBrightnessPercent) >= 0) {
+    return false;
+  }
+
+  if (latest_brightness_change_time_.is_null()) {
+    // Brightness hasn't been changed before.
+    return latest_als_time_ - first_als_time_ >= kAmbientLightShortHorizon ||
+           params_.update_brightness_on_startup;
+  }
+
+  // The following thresholds should have been set last time when brightness was
+  // changed.
+  if (current_average_ambient > *immediate_brightening_lux_threshold_ ||
+      current_average_ambient < *immediate_darkening_lux_threshold_) {
+    return true;
+  }
+
+  if (tick_clock_->NowTicks() - latest_brightness_change_time_ <
+      params_.min_time_between_brightness_changes) {
+    return false;
+  }
+
+  return current_average_ambient > *brightening_lux_threshold_ ||
+         current_average_ambient < *darkening_lux_threshold_;
+}
+
+void Adapter::MaybeAdjustBrightness() {
+  const double average_ambient_lux = AverageAmbient(ambient_light_values_, -1);
+
+  if (!CanAdjustBrightness(average_ambient_lux))
+    return;
+
+  const base::Optional<double> brightness =
+      GetBrightnessBasedOnAmbientLogLux(ConvertToLog(average_ambient_lux));
+
+  // This could occur if curve isn't set up (e.g. when we want to use
+  // personal only that's not yet available).
+  if (!brightness)
+    return;
+
+  power_manager::SetBacklightBrightnessRequest request;
+  request.set_percent(*brightness);
+  request.set_transition(
+      power_manager::SetBacklightBrightnessRequest_Transition_GRADUAL);
+  request.set_cause(power_manager::SetBacklightBrightnessRequest_Cause_MODEL);
+  power_manager_client_->SetScreenBrightness(request);
+
+  latest_brightness_change_time_ = tick_clock_->NowTicks();
+  average_ambient_lux_ = average_ambient_lux;
+
+  UpdateLuxThresholds();
+}
+
+void Adapter::UpdateLuxThresholds() {
+  DCHECK(average_ambient_lux_);
+  DCHECK_GE(*average_ambient_lux_, 0);
+
+  brightening_lux_threshold_ =
+      *average_ambient_lux_ * (1 + params_.brightening_lux_threshold_ratio);
+  darkening_lux_threshold_ =
+      *average_ambient_lux_ * (1 - params_.darkening_lux_threshold_ratio);
+  immediate_brightening_lux_threshold_ =
+      *average_ambient_lux_ *
+      (1 + params_.immediate_brightening_lux_threshold_ratio);
+  immediate_darkening_lux_threshold_ =
+      *average_ambient_lux_ *
+      (1 - params_.immediate_darkening_lux_threshold_ratio);
+
+  DCHECK_GE(*brightening_lux_threshold_, 0);
+  DCHECK_GE(*darkening_lux_threshold_, 0);
+  DCHECK_GE(*immediate_brightening_lux_threshold_, 0);
+  DCHECK_GE(*immediate_darkening_lux_threshold_, 0);
+}
+
+base::Optional<double> Adapter::GetBrightnessBasedOnAmbientLogLux(
+    double ambient_log_lux) const {
+  switch (params_.model_curve) {
+    case ModelCurve::kGlobal:
+      return global_curve_->Interpolate(ambient_log_lux);
+    case ModelCurve::kPersonal:
+      if (personal_curve_)
+        return personal_curve_->Interpolate(ambient_log_lux);
+      return base::nullopt;  // signal brightness shouldn't be changed
+    default:
+      // We use the latest curve available.
+      if (personal_curve_)
+        return personal_curve_->Interpolate(ambient_log_lux);
+      return global_curve_->Interpolate(ambient_log_lux);
+  }
+}
+
+}  // namespace auto_screen_brightness
+}  // namespace power
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/adapter.h b/chrome/browser/chromeos/power/auto_screen_brightness/adapter.h
new file mode 100644
index 0000000..b1839ec6
--- /dev/null
+++ b/chrome/browser/chromeos/power/auto_screen_brightness/adapter.h
@@ -0,0 +1,235 @@
+// 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_ADAPTER_H_
+#define CHROME_BROWSER_CHROMEOS_POWER_AUTO_SCREEN_BRIGHTNESS_ADAPTER_H_
+
+#include "base/containers/ring_buffer.h"
+#include "base/macros.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/optional.h"
+#include "base/scoped_observer.h"
+#include "base/sequenced_task_runner.h"
+#include "base/time/tick_clock.h"
+#include "base/time/time.h"
+#include "chrome/browser/chromeos/power/auto_screen_brightness/als_reader.h"
+#include "chrome/browser/chromeos/power/auto_screen_brightness/brightness_monitor.h"
+#include "chrome/browser/chromeos/power/auto_screen_brightness/modeller.h"
+#include "chrome/browser/chromeos/power/auto_screen_brightness/monotone_cubic_spline.h"
+#include "chrome/browser/chromeos/power/auto_screen_brightness/utils.h"
+#include "chromeos/dbus/power_manager_client.h"
+
+class Profile;
+
+namespace chromeos {
+namespace power {
+namespace auto_screen_brightness {
+
+// Adapter monitors changes in ambient light, selects an optimal screen
+// brightness as predicted by the model and instructs powerd to change it.
+class Adapter : public AlsReader::Observer,
+                public BrightnessMonitor::Observer,
+                public Modeller::Observer {
+ public:
+  // Type of curve to use.
+  // These values are persisted to logs. Entries should not be renumbered and
+  // numeric values should never be reused.
+  enum class ModelCurve {
+    // Always use the global curve.
+    kGlobal = 0,
+    // Always use the personal curve, and make no brightness adjustment until a
+    // personal curve is trained.
+    kPersonal = 1,
+    // Use the personal curve if available, else use the global curve.
+    kLatest = 2,
+    kMaxValue = kLatest
+  };
+
+  // TODO(jiameng): we currently use past 2 seconds of ambient values to
+  // calculate average ambient when we predict optimal brightness. This is
+  // shorter than the duration used for training data (10 seconds), because it's
+  // important that we can quickly adjust the brightness when ambient value
+  // changes. This duration should be revised.
+  static constexpr base::TimeDelta kAmbientLightShortHorizon =
+      base::TimeDelta::FromSeconds(2);
+
+  // Size of |ambient_light_values_|.
+  static constexpr int kNumberAmbientValuesToTrack =
+      kAmbientLightShortHorizon.InSeconds() * AlsReader::kAlsPollFrequency;
+
+  // The values in Params can be overridden by experiment flags.
+  struct Params {
+    // Average ambient value has to go up (resp. down) by
+    // |brightening_lux_threshold_ratio| (resp. |darkening_lux_threshold_ratio|)
+    // from the current value before brightness could be changed: brightness
+    // will actually be changed if |min_time_between_brightness_changes| has
+    // passed from the previous change.
+    double brightening_lux_threshold_ratio = 0.1;
+    double darkening_lux_threshold_ratio = 0.2;
+
+    // If average ambient value changes by more than the "immediate" thresholds
+    // then brightness transition will happen immediately, without waiting for
+    // |min_time_between_brightness_changes| to elapse. This value should be
+    // greater than or equal to the max of brightening/darkening thresholds
+    // above.
+    double immediate_brightening_lux_threshold_ratio = 0.3;
+    double immediate_darkening_lux_threshold_ratio = 0.4;
+
+    // Whether brightness should be set to the predicted value when the first
+    // ambient reading comes in. If false, we'll wait for
+    // |kAmbientLightShortHorizon| of ambient values before setting brightness
+    // for the first time.
+    bool update_brightness_on_startup = true;
+
+    // Once a brightness change occurs, the next one will not occur until at
+    // least |min_time_between_brightness_changes| later, unless ambient change
+    // exceeds |immediate_brightening_lux_threshold_ratio| or
+    // |immediate_darkening_lux_threshold_ratio|.
+    base::TimeDelta min_time_between_brightness_changes =
+        base::TimeDelta::FromSeconds(10);
+
+    ModelCurve model_curve = ModelCurve::kLatest;
+  };
+
+  // These values are persisted to logs. Entries should not be renumbered and
+  // numeric values should never be reused.
+  enum class Status {
+    kInitializing = 0,
+    kSuccess = 1,
+    kDisabled = 2,
+    kMaxValue = kDisabled
+  };
+
+  Adapter(Profile* profile,
+          AlsReader* als_reader,
+          BrightnessMonitor* brightness_monitor,
+          Modeller* modeller,
+          chromeos::PowerManagerClient* power_manager_client);
+  ~Adapter() override;
+
+  // AlsReader::Observer overrides:
+  void OnAmbientLightUpdated(int lux) override;
+  void OnAlsReaderInitialized(AlsReader::AlsInitStatus status) override;
+
+  // BrightnessMonitor::Observer overrides:
+  void OnBrightnessMonitorInitialized(bool success) override;
+  void OnUserBrightnessChanged(double old_brightness_percent,
+                               double new_brightness_percent) override;
+  void OnUserBrightnessChangeRequested() override;
+
+  // Modeller::Observer overrides:
+  void OnModelTrained(const MonotoneCubicSpline& brightness_curve) override;
+  void OnModelInitialized(
+      const base::Optional<MonotoneCubicSpline>& global_curve,
+      const base::Optional<MonotoneCubicSpline>& personal_curve) override;
+
+  void SetTickClockForTesting(const base::TickClock* test_tick_clock);
+
+  Status GetStatusForTesting() const;
+  base::Optional<MonotoneCubicSpline> GetGlobalCurveForTesting() const;
+  base::Optional<MonotoneCubicSpline> GetPersonalCurveForTesting() const;
+
+  // Returns the actual average over |ambient_light_values_|, which is not
+  // necessarily the same as |average_ambient_lux_|.
+  double GetAverageAmbientForTesting() const;
+  double GetBrighteningThresholdForTesting() const;
+  double GetDarkeningThresholdForTesting() const;
+
+ private:
+  // Called by the constructor to initialize |params_| possibly from experiment
+  // flags. It will disable the adapter if any param value is invalid.
+  void InitParams();
+
+  // Called when powerd becomes available.
+  void OnPowerManagerServiceAvailable(bool service_is_ready);
+
+  // Called to update |adapter_status_| when there's some status change from
+  // AlsReader, BrightnessMonitor, Modeller or power manager.
+  void UpdateStatus();
+
+  // Returns true if the adapter can change the brightness.
+  // This is generally the case when the brightness hasn't been manually
+  // set, we've received enough initial ambient light readings, and
+  // the ambient light has changed beyond thresholds for a long enough
+  // period of time.
+  bool CanAdjustBrightness(double current_average_ambient) const;
+
+  // Called when ambient light changes. It only changes screen brightness if
+  // |CanAdjustBrightness| returns true and a required curve is set up:
+  // if the required curve is personal but no personal curve is available, then
+  // brightness won't be changed.
+  // It will call |UpdateLuxThresholds| if brightness is actually changed.
+  void MaybeAdjustBrightness();
+
+  // This is only called when brightness is changed.
+  void UpdateLuxThresholds();
+
+  // Calculates brightness from given |ambient_lux| based on either
+  // |global_curve_| or |personal_curve_| (as specified by the experiment
+  // params). Returns nullopt if a personal curve should be used but it's not
+  // available.
+  base::Optional<double> GetBrightnessBasedOnAmbientLogLux(
+      double ambient_lux) const;
+
+  Profile* const profile_;
+
+  ScopedObserver<AlsReader, AlsReader::Observer> als_reader_observer_;
+  ScopedObserver<BrightnessMonitor, BrightnessMonitor::Observer>
+      brightness_monitor_observer_;
+  ScopedObserver<Modeller, Modeller::Observer> modeller_observer_;
+
+  chromeos::PowerManagerClient* const power_manager_client_;
+
+  Params params_;
+
+  // This will be replaced by a mock tick clock during tests.
+  const base::TickClock* tick_clock_;
+
+  base::RingBuffer<AmbientLightSample, kNumberAmbientValuesToTrack>
+      ambient_light_values_;
+
+  base::Optional<AlsReader::AlsInitStatus> als_init_status_;
+  base::Optional<bool> brightness_monitor_success_;
+  bool model_initialized_ = false;
+
+  base::Optional<bool> power_manager_service_available_;
+
+  Status adapter_status_ = Status::kInitializing;
+
+  // The thresholds are calculated from |average_ambient_lux_|. They are only
+  // updated when brightness should occur (because average ambient value changed
+  // sufficiently).
+  base::Optional<double> brightening_lux_threshold_;
+  base::Optional<double> darkening_lux_threshold_;
+  base::Optional<double> immediate_brightening_lux_threshold_;
+  base::Optional<double> immediate_darkening_lux_threshold_;
+
+  base::Optional<MonotoneCubicSpline> global_curve_;
+  base::Optional<MonotoneCubicSpline> personal_curve_;
+
+  // Average ambient value is only calculated when |CanAdjustBrightness|
+  // returns true. This is the average over all values in
+  // |ambient_light_values_|. The adapter will notify powerd to change
+  // brightness. New thresholds will be calculated from it.
+  base::Optional<double> average_ambient_lux_;
+
+  // First time an ALS value was received.
+  base::TimeTicks first_als_time_;
+  // Latest time an ALS value was received.
+  base::TimeTicks latest_als_time_;
+
+  // Last time brightness change occurred.
+  base::TimeTicks latest_brightness_change_time_;
+
+  base::WeakPtrFactory<Adapter> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(Adapter);
+};
+
+}  // namespace auto_screen_brightness
+}  // namespace power
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_POWER_AUTO_SCREEN_BRIGHTNESS_ADAPTER_H_
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/adapter_unittest.cc b/chrome/browser/chromeos/power/auto_screen_brightness/adapter_unittest.cc
new file mode 100644
index 0000000..dc6c168
--- /dev/null
+++ b/chrome/browser/chromeos/power/auto_screen_brightness/adapter_unittest.cc
@@ -0,0 +1,590 @@
+// 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/adapter.h"
+
+#include "ash/public/cpp/ash_pref_names.h"
+#include "base/memory/ptr_util.h"
+#include "base/task/task_scheduler/task_scheduler.h"
+#include "base/test/scoped_feature_list.h"
+#include "base/test/scoped_task_environment.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "chrome/browser/chromeos/power/auto_screen_brightness/fake_als_reader.h"
+#include "chrome/browser/chromeos/power/auto_screen_brightness/fake_brightness_monitor.h"
+#include "chrome/browser/chromeos/power/auto_screen_brightness/modeller.h"
+#include "chrome/browser/chromeos/power/auto_screen_brightness/monotone_cubic_spline.h"
+#include "chrome/browser/prefs/browser_prefs.h"
+#include "chrome/test/base/testing_browser_process.h"
+#include "chrome/test/base/testing_profile.h"
+#include "chromeos/chromeos_features.h"
+#include "chromeos/dbus/dbus_thread_manager.h"
+#include "chromeos/dbus/fake_power_manager_client.h"
+#include "chromeos/dbus/power_manager/backlight.pb.h"
+#include "components/pref_registry/pref_registry_syncable.h"
+#include "components/prefs/testing_pref_store.h"
+#include "components/sync_preferences/pref_service_mock_factory.h"
+#include "components/sync_preferences/pref_service_syncable.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chromeos {
+namespace power {
+namespace auto_screen_brightness {
+
+namespace {
+
+// Testing modeller.
+class FakeModeller : public Modeller {
+ public:
+  FakeModeller() = default;
+  ~FakeModeller() override = default;
+
+  void InitModellerWithCurves(
+      const base::Optional<MonotoneCubicSpline>& global_curve,
+      const base::Optional<MonotoneCubicSpline>& personal_curve) {
+    DCHECK(!modeller_initialized_);
+    modeller_initialized_ = true;
+    if (global_curve)
+      global_curve_.emplace(*global_curve);
+
+    if (personal_curve)
+      personal_curve_.emplace(*personal_curve);
+  }
+
+  void ReportModelTrained(const MonotoneCubicSpline& personal_curve) {
+    DCHECK(modeller_initialized_);
+    personal_curve_.emplace(personal_curve);
+    for (auto& observer : observers_)
+      observer.OnModelTrained(personal_curve);
+  }
+
+  void ReportModelInitialized() {
+    DCHECK(modeller_initialized_);
+    for (auto& observer : observers_)
+      observer.OnModelInitialized(global_curve_, personal_curve_);
+  }
+
+  // Modeller overrides:
+  void AddObserver(Modeller::Observer* observer) override {
+    DCHECK(observer);
+    observers_.AddObserver(observer);
+    if (modeller_initialized_)
+      observer->OnModelInitialized(global_curve_, personal_curve_);
+  }
+
+  void RemoveObserver(Modeller::Observer* observer) override {
+    DCHECK(observer);
+    observers_.RemoveObserver(observer);
+  }
+
+ private:
+  bool modeller_initialized_ = false;
+  base::Optional<MonotoneCubicSpline> global_curve_;
+  base::Optional<MonotoneCubicSpline> personal_curve_;
+
+  base::ObserverList<Observer> observers_;
+};
+
+class TestObserver : public PowerManagerClient::Observer {
+ public:
+  TestObserver() = default;
+  ~TestObserver() override = default;
+
+  // chromeos::PowerManagerClient::Observer overrides:
+  void ScreenBrightnessChanged(
+      const power_manager::BacklightBrightnessChange& change) override {
+    ++num_changes_;
+    change_ = change;
+  }
+  double GetBrightnessPercent() const { return change_.percent(); }
+
+  int num_changes() const { return num_changes_; }
+
+  power_manager::BacklightBrightnessChange_Cause GetCause() const {
+    return change_.cause();
+  }
+
+ private:
+  int num_changes_ = 0;
+  power_manager::BacklightBrightnessChange change_;
+};
+
+}  // namespace
+
+class AdapterTest : public testing::Test {
+ public:
+  AdapterTest()
+      : scoped_task_environment_(
+            base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME),
+        thread_bundle_(content::TestBrowserThreadBundle::PLAIN_MAINLOOP) {
+    chromeos::DBusThreadManager::GetSetterForTesting()->SetPowerManagerClient(
+        std::make_unique<chromeos::FakePowerManagerClient>());
+    power_manager::SetBacklightBrightnessRequest request;
+    request.set_percent(1);
+    chromeos::DBusThreadManager::Get()
+        ->GetPowerManagerClient()
+        ->SetScreenBrightness(request);
+    scoped_task_environment_.RunUntilIdle();
+
+    chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->AddObserver(
+        &test_observer_);
+
+    global_curve_.emplace(MonotoneCubicSpline({-4, 12, 20}, {30, 80, 100}));
+    personal_curve_.emplace(MonotoneCubicSpline({-4, 12, 20}, {20, 60, 100}));
+  }
+
+  ~AdapterTest() override {
+    base::TaskScheduler::GetInstance()->FlushForTesting();
+  }
+
+  void SetUpAdapter(const std::map<std::string, std::string>& params,
+                    bool brightness_set_by_policy = false) {
+    sync_preferences::PrefServiceMockFactory factory;
+    factory.set_user_prefs(base::WrapRefCounted(new TestingPrefStore()));
+    scoped_refptr<user_prefs::PrefRegistrySyncable> registry(
+        new user_prefs::PrefRegistrySyncable);
+
+    // Same default values as used in the actual pref store.
+    registry->RegisterIntegerPref(ash::prefs::kPowerAcScreenBrightnessPercent,
+                                  -1, PrefRegistry::PUBLIC);
+    registry->RegisterIntegerPref(
+        ash::prefs::kPowerBatteryScreenBrightnessPercent, -1,
+        PrefRegistry::PUBLIC);
+
+    sync_preferences::PrefServiceSyncable* regular_prefs =
+        factory.CreateSyncable(registry.get()).release();
+
+    RegisterUserProfilePrefs(registry.get());
+    if (brightness_set_by_policy) {
+      regular_prefs->SetInteger(ash::prefs::kPowerAcScreenBrightnessPercent,
+                                10);
+      regular_prefs->SetInteger(
+          ash::prefs::kPowerBatteryScreenBrightnessPercent, 10);
+    }
+
+    CHECK(temp_dir_.CreateUniqueTempDir());
+    TestingProfile::Builder profile_builder;
+    profile_builder.SetProfileName("testuser@gmail.com");
+    profile_builder.SetPath(temp_dir_.GetPath().AppendASCII("TestProfile"));
+    profile_builder.SetPrefService(base::WrapUnique(regular_prefs));
+
+    profile_ = profile_builder.Build();
+
+    base::test::ScopedFeatureList scoped_feature_list;
+    scoped_feature_list.InitAndEnableFeatureWithParameters(
+        features::kAutoScreenBrightness, params);
+
+    adapter_ = std::make_unique<Adapter>(
+        profile_.get(), &fake_als_reader_, &fake_brightness_monitor_,
+        &fake_modeller_,
+        chromeos::DBusThreadManager::Get()->GetPowerManagerClient());
+    adapter_->SetTickClockForTesting(
+        scoped_task_environment_.GetMockTickClock());
+  }
+
+  void Init(AlsReader::AlsInitStatus als_reader_status,
+            BrightnessMonitor::Status brightness_monitor_status,
+            const base::Optional<MonotoneCubicSpline>& global_curve,
+            const base::Optional<MonotoneCubicSpline>& personal_curve,
+            const std::map<std::string, std::string>& params,
+            bool brightness_set_by_policy = false) {
+    fake_als_reader_.set_als_init_status(als_reader_status);
+    fake_brightness_monitor_.set_status(brightness_monitor_status);
+    fake_modeller_.InitModellerWithCurves(global_curve, personal_curve);
+    SetUpAdapter(params, brightness_set_by_policy);
+    scoped_task_environment_.RunUntilIdle();
+  }
+
+ protected:
+  base::test::ScopedTaskEnvironment scoped_task_environment_;
+  content::TestBrowserThreadBundle thread_bundle_;
+
+  TestObserver test_observer_;
+
+  base::ScopedTempDir temp_dir_;
+  std::unique_ptr<TestingProfile> profile_;
+
+  base::Optional<MonotoneCubicSpline> global_curve_;
+  base::Optional<MonotoneCubicSpline> personal_curve_;
+
+  FakeAlsReader fake_als_reader_;
+  FakeBrightnessMonitor fake_brightness_monitor_;
+  FakeModeller fake_modeller_;
+
+  const std::map<std::string, std::string> default_params_ = {
+      {"brightening_lux_threshold_ratio", "0.1"},
+      {"darkening_lux_threshold_ratio", "0.2"},
+      {"immediate_brightening_lux_threshold_ratio", "3"},
+      {"immediate_darkening_lux_threshold_ratio", "1"},
+      {"update_brightness_on_startup", "true"},
+      {"min_seconds_between_brightness_changes", "10"},
+      {"model_curve", "2"},
+  };
+
+  std::unique_ptr<Adapter> adapter_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(AdapterTest);
+};
+
+// AlsReader is |kDisabled| when Adapter is created.
+TEST_F(AdapterTest, AlsReaderDisabledOnInit) {
+  Init(AlsReader::AlsInitStatus::kDisabled, BrightnessMonitor::Status::kSuccess,
+       global_curve_, base::nullopt /* personal_curve */, default_params_);
+
+  EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kDisabled);
+}
+
+// BrightnessMonitor is |kDisabled| when Adapter is created.
+TEST_F(AdapterTest, BrightnessMonitorDisabledOnInit) {
+  Init(AlsReader::AlsInitStatus::kSuccess, BrightnessMonitor::Status::kDisabled,
+       global_curve_, base::nullopt /* personal_curve */, default_params_);
+
+  EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kDisabled);
+}
+
+// Modeller is |kDisabled| when Adapter is created.
+TEST_F(AdapterTest, ModellerDisabledOnInit) {
+  Init(AlsReader::AlsInitStatus::kSuccess, BrightnessMonitor::Status::kSuccess,
+       base::nullopt /* global_curve */, base::nullopt /* personal_curve */,
+       default_params_);
+
+  EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kDisabled);
+}
+
+// AlsReader is |kDisabled| on later notification.
+TEST_F(AdapterTest, AlsReaderDisabledOnNotification) {
+  Init(AlsReader::AlsInitStatus::kInProgress,
+       BrightnessMonitor::Status::kSuccess, global_curve_,
+       base::nullopt /* personal_curve */, default_params_);
+
+  EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kInitializing);
+
+  fake_als_reader_.set_als_init_status(AlsReader::AlsInitStatus::kDisabled);
+  fake_als_reader_.ReportReaderInitialized();
+  EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kDisabled);
+}
+
+// AlsReader is |kSuccess| on later notification.
+TEST_F(AdapterTest, AlsReaderEnabledOnNotification) {
+  Init(AlsReader::AlsInitStatus::kInProgress,
+       BrightnessMonitor::Status::kSuccess, global_curve_,
+       base::nullopt /* personal_curve */, default_params_);
+
+  EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kInitializing);
+
+  fake_als_reader_.set_als_init_status(AlsReader::AlsInitStatus::kSuccess);
+  fake_als_reader_.ReportReaderInitialized();
+  scoped_task_environment_.RunUntilIdle();
+  EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kSuccess);
+  EXPECT_TRUE(adapter_->GetGlobalCurveForTesting());
+  EXPECT_EQ(*adapter_->GetGlobalCurveForTesting(), *global_curve_);
+  EXPECT_FALSE(adapter_->GetPersonalCurveForTesting());
+}
+
+// BrightnessMonitor is |kDisabled| on later notification.
+TEST_F(AdapterTest, BrightnessMonitorDisabledOnNotification) {
+  Init(AlsReader::AlsInitStatus::kSuccess,
+       BrightnessMonitor::Status::kInitializing, global_curve_,
+       base::nullopt /* personal_curve */, default_params_);
+
+  EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kInitializing);
+
+  fake_brightness_monitor_.set_status(BrightnessMonitor::Status::kDisabled);
+  fake_brightness_monitor_.ReportBrightnessMonitorInitialized();
+  EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kDisabled);
+}
+
+// BrightnessMonitor is |kSuccess| on later notification.
+TEST_F(AdapterTest, BrightnessMonitorEnabledOnNotification) {
+  Init(AlsReader::AlsInitStatus::kSuccess,
+       BrightnessMonitor::Status::kInitializing, global_curve_,
+       base::nullopt /* personal_curve */, default_params_);
+
+  EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kInitializing);
+
+  fake_brightness_monitor_.set_status(BrightnessMonitor::Status::kSuccess);
+  fake_brightness_monitor_.ReportBrightnessMonitorInitialized();
+  scoped_task_environment_.RunUntilIdle();
+  EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kSuccess);
+  EXPECT_TRUE(adapter_->GetGlobalCurveForTesting());
+  EXPECT_EQ(*adapter_->GetGlobalCurveForTesting(), *global_curve_);
+  EXPECT_FALSE(adapter_->GetPersonalCurveForTesting());
+}
+
+// Modeller is |kDisabled| on later notification.
+TEST_F(AdapterTest, ModellerDisabledOnNotification) {
+  fake_als_reader_.set_als_init_status(AlsReader::AlsInitStatus::kSuccess);
+  fake_brightness_monitor_.set_status(BrightnessMonitor::Status::kSuccess);
+  SetUpAdapter(default_params_);
+  scoped_task_environment_.RunUntilIdle();
+  EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kInitializing);
+
+  fake_modeller_.InitModellerWithCurves(base::nullopt, base::nullopt);
+  fake_modeller_.ReportModelInitialized();
+  EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kDisabled);
+  EXPECT_FALSE(adapter_->GetGlobalCurveForTesting());
+  EXPECT_FALSE(adapter_->GetPersonalCurveForTesting());
+}
+
+// Modeller is |kSuccess| on later notification.
+TEST_F(AdapterTest, ModellerEnabledOnNotification) {
+  fake_als_reader_.set_als_init_status(AlsReader::AlsInitStatus::kSuccess);
+  fake_brightness_monitor_.set_status(BrightnessMonitor::Status::kSuccess);
+  SetUpAdapter(default_params_);
+  scoped_task_environment_.RunUntilIdle();
+  EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kInitializing);
+
+  fake_modeller_.InitModellerWithCurves(global_curve_, personal_curve_);
+  fake_modeller_.ReportModelInitialized();
+  EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kSuccess);
+  EXPECT_TRUE(adapter_->GetGlobalCurveForTesting());
+  EXPECT_EQ(*adapter_->GetGlobalCurveForTesting(), *global_curve_);
+  EXPECT_TRUE(adapter_->GetPersonalCurveForTesting());
+  EXPECT_EQ(*adapter_->GetPersonalCurveForTesting(), *personal_curve_);
+}
+
+TEST_F(AdapterTest, SequenceOfBrightnessUpdatesWithDefaultParams) {
+  Init(AlsReader::AlsInitStatus::kSuccess, BrightnessMonitor::Status::kSuccess,
+       global_curve_, personal_curve_, default_params_);
+
+  EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kSuccess);
+  EXPECT_TRUE(adapter_->GetGlobalCurveForTesting());
+  EXPECT_EQ(*adapter_->GetGlobalCurveForTesting(), *global_curve_);
+  EXPECT_TRUE(adapter_->GetPersonalCurveForTesting());
+  EXPECT_EQ(*adapter_->GetPersonalCurveForTesting(), *personal_curve_);
+
+  // Forward by 1sec because in real implementation, |first_als_time_| is zero
+  // if there's no ALS reading received.
+  scoped_task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(1));
+
+  // Brightness is changed after the 1st ALS reading comes in.
+  fake_als_reader_.ReportAmbientLightUpdate(10);
+  scoped_task_environment_.RunUntilIdle();
+  EXPECT_EQ(test_observer_.num_changes(), 1);
+
+  // Another ALS value is received in 3 sec, but no brightness update is done.
+  scoped_task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(3));
+  fake_als_reader_.ReportAmbientLightUpdate(20);
+  scoped_task_environment_.RunUntilIdle();
+  EXPECT_EQ(test_observer_.num_changes(), 1);
+
+  // |params.min_time_between_brightness_changes| has elapsed since we've made
+  // the change, but there's no new ALS value, hence no brightness change is
+  // triggered.
+  scoped_task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(10));
+  EXPECT_EQ(test_observer_.num_changes(), 1);
+
+  // A new ALS value triggers a brightness change.
+  fake_als_reader_.ReportAmbientLightUpdate(40);
+  scoped_task_environment_.RunUntilIdle();
+  EXPECT_EQ(test_observer_.num_changes(), 2);
+
+  // Adapter is disabled after a user manual adjustment.
+  fake_brightness_monitor_.ReportUserBrightnessChangeRequested();
+  scoped_task_environment_.RunUntilIdle();
+  EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kDisabled);
+}
+
+TEST_F(AdapterTest, BrightnessLuxThresholds) {
+  Init(AlsReader::AlsInitStatus::kSuccess, BrightnessMonitor::Status::kSuccess,
+       global_curve_, personal_curve_, default_params_);
+
+  EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kSuccess);
+  EXPECT_TRUE(adapter_->GetGlobalCurveForTesting());
+  EXPECT_EQ(*adapter_->GetGlobalCurveForTesting(), *global_curve_);
+  EXPECT_TRUE(adapter_->GetPersonalCurveForTesting());
+  EXPECT_EQ(*adapter_->GetPersonalCurveForTesting(), *personal_curve_);
+
+  scoped_task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(1));
+
+  // Brightness is changed after the 1st ALS value, and the thresholds are
+  // changed.
+  fake_als_reader_.ReportAmbientLightUpdate(20);
+  scoped_task_environment_.RunUntilIdle();
+  EXPECT_EQ(test_observer_.num_changes(), 1);
+  EXPECT_DOUBLE_EQ(adapter_->GetBrighteningThresholdForTesting(), 22);
+  EXPECT_DOUBLE_EQ(adapter_->GetDarkeningThresholdForTesting(), 16);
+
+  // A 2nd ALS comes in, but average ambient is within the thresholds, hence
+  // brightness isn't changed and thresholds aren't updated.
+  scoped_task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(20));
+  fake_als_reader_.ReportAmbientLightUpdate(21);
+  EXPECT_EQ(1, test_observer_.num_changes());
+  EXPECT_DOUBLE_EQ(adapter_->GetBrighteningThresholdForTesting(), 22);
+  EXPECT_DOUBLE_EQ(adapter_->GetDarkeningThresholdForTesting(), 16);
+
+  // A 3rd ALS comes in, but still not enough to trigger brightness change.
+  fake_als_reader_.ReportAmbientLightUpdate(15);
+  EXPECT_EQ(test_observer_.num_changes(), 1);
+  EXPECT_DOUBLE_EQ(adapter_->GetBrighteningThresholdForTesting(), 22);
+  EXPECT_DOUBLE_EQ(adapter_->GetDarkeningThresholdForTesting(), 16);
+
+  // A 4th ALS makes average value below the darkening threshold, hence
+  // brightness is changed. Thresholds are also changed.
+  fake_als_reader_.ReportAmbientLightUpdate(7);
+  scoped_task_environment_.RunUntilIdle();
+
+  EXPECT_EQ(test_observer_.num_changes(), 2);
+  const double expected_average_ambient = (20 + 21 + 15 + 7) / 4.0;
+  EXPECT_DOUBLE_EQ(adapter_->GetAverageAmbientForTesting(),
+                   expected_average_ambient);
+  EXPECT_DOUBLE_EQ(adapter_->GetBrighteningThresholdForTesting(),
+                   expected_average_ambient * 1.1);
+  EXPECT_DOUBLE_EQ(adapter_->GetDarkeningThresholdForTesting(),
+                   expected_average_ambient * 0.8);
+}
+
+TEST_F(AdapterTest, ImmediateBrightnessTransitionThresholds) {
+  std::map<std::string, std::string> params = default_params_;
+  params["immediate_brightening_lux_threshold_ratio"] = "0.3";
+  params["immediate_darkening_lux_threshold_ratio"] = "0.3";
+
+  Init(AlsReader::AlsInitStatus::kSuccess, BrightnessMonitor::Status::kSuccess,
+       global_curve_, personal_curve_, params);
+
+  EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kSuccess);
+  EXPECT_TRUE(adapter_->GetGlobalCurveForTesting());
+  EXPECT_EQ(*adapter_->GetGlobalCurveForTesting(), *global_curve_);
+  EXPECT_TRUE(adapter_->GetPersonalCurveForTesting());
+  EXPECT_EQ(*adapter_->GetPersonalCurveForTesting(), *personal_curve_);
+
+  scoped_task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(1));
+
+  // Brightness is changed after the 1st ALS reading comes in.
+  fake_als_reader_.ReportAmbientLightUpdate(10);
+  scoped_task_environment_.RunUntilIdle();
+  EXPECT_EQ(test_observer_.num_changes(), 1);
+
+  // Another ALS value is received in 1 sec, brightness is changed because it
+  // exceeds immediate transition threshold.
+  scoped_task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(1));
+  fake_als_reader_.ReportAmbientLightUpdate(17);
+  scoped_task_environment_.RunUntilIdle();
+  EXPECT_EQ(test_observer_.num_changes(), 2);
+
+  // Another ALS value is received in 2 sec, brightness is changed because it
+  // exceeds immediate transition threshold.
+  scoped_task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(2));
+  fake_als_reader_.ReportAmbientLightUpdate(1);
+  scoped_task_environment_.RunUntilIdle();
+  EXPECT_EQ(test_observer_.num_changes(), 3);
+}
+
+TEST_F(AdapterTest, BrightnessNotUpdatedOnStartup) {
+  std::map<std::string, std::string> params = default_params_;
+  params["update_brightness_on_startup"] = "false";
+
+  Init(AlsReader::AlsInitStatus::kSuccess, BrightnessMonitor::Status::kSuccess,
+       global_curve_, personal_curve_, params);
+
+  EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kSuccess);
+
+  scoped_task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(1));
+
+  // 1st ALS reading doesn't trigger a brightness change.
+  fake_als_reader_.ReportAmbientLightUpdate(10);
+  scoped_task_environment_.RunUntilIdle();
+  EXPECT_EQ(test_observer_.num_changes(), 0);
+
+  scoped_task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(2));
+  EXPECT_EQ(test_observer_.num_changes(), 0);
+
+  // 2nd ALS comes in so that we have |kAmbientLightShortHorizonSeconds| of
+  // data, hence brightness is changed.
+  fake_als_reader_.ReportAmbientLightUpdate(20);
+  scoped_task_environment_.RunUntilIdle();
+  EXPECT_EQ(test_observer_.num_changes(), 1);
+}
+
+TEST_F(AdapterTest, UsePersonalCurve) {
+  std::map<std::string, std::string> params = default_params_;
+  params["model_curve"] = "1";
+
+  // Init modeller with only a global curve.
+  Init(AlsReader::AlsInitStatus::kSuccess, BrightnessMonitor::Status::kSuccess,
+       global_curve_, base::nullopt /* personal_curve */, params);
+
+  EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kSuccess);
+
+  // ALS comes in but no brightness change is triggered because there is no
+  // personal curve.
+  scoped_task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(1));
+  fake_als_reader_.ReportAmbientLightUpdate(10);
+  scoped_task_environment_.RunUntilIdle();
+  EXPECT_EQ(test_observer_.num_changes(), 0);
+
+  // Personal curve is received.
+  scoped_task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(1));
+  fake_modeller_.ReportModelTrained(*personal_curve_);
+  EXPECT_EQ(test_observer_.num_changes(), 0);
+  fake_als_reader_.ReportAmbientLightUpdate(20);
+  scoped_task_environment_.RunUntilIdle();
+  EXPECT_EQ(test_observer_.num_changes(), 1);
+  EXPECT_EQ(test_observer_.GetCause(),
+            power_manager::BacklightBrightnessChange_Cause_MODEL);
+
+  const double expected_average_ambient = (10 + 20) / 2.0;
+  EXPECT_DOUBLE_EQ(adapter_->GetAverageAmbientForTesting(),
+                   expected_average_ambient);
+  const double expected_brightness_percent =
+      personal_curve_->Interpolate(ConvertToLog(expected_average_ambient));
+  EXPECT_DOUBLE_EQ(test_observer_.GetBrightnessPercent(),
+                   expected_brightness_percent);
+}
+
+TEST_F(AdapterTest, UseGlobalCurve) {
+  std::map<std::string, std::string> params = default_params_;
+  params["model_curve"] = "0";
+
+  Init(AlsReader::AlsInitStatus::kSuccess, BrightnessMonitor::Status::kSuccess,
+       global_curve_, personal_curve_, params);
+
+  EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kSuccess);
+
+  scoped_task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(1));
+  fake_als_reader_.ReportAmbientLightUpdate(10);
+  scoped_task_environment_.RunUntilIdle();
+  EXPECT_EQ(test_observer_.num_changes(), 1);
+  EXPECT_DOUBLE_EQ(adapter_->GetAverageAmbientForTesting(), 10);
+
+  const double expected_brightness_percent1 =
+      global_curve_->Interpolate(ConvertToLog(10));
+  EXPECT_DOUBLE_EQ(test_observer_.GetBrightnessPercent(),
+                   expected_brightness_percent1);
+
+  // A new personal curve is received but adapter still uses the global curve.
+  scoped_task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(20));
+  fake_modeller_.ReportModelTrained(*personal_curve_);
+  fake_als_reader_.ReportAmbientLightUpdate(20);
+  scoped_task_environment_.RunUntilIdle();
+  EXPECT_EQ(test_observer_.num_changes(), 2);
+  EXPECT_EQ(test_observer_.GetCause(),
+            power_manager::BacklightBrightnessChange_Cause_MODEL);
+
+  const double expected_average_ambient2 = (10 + 20) / 2.0;
+  EXPECT_DOUBLE_EQ(adapter_->GetAverageAmbientForTesting(),
+                   expected_average_ambient2);
+  const double expected_brightness_percent2 =
+      global_curve_->Interpolate(ConvertToLog(expected_average_ambient2));
+  EXPECT_DOUBLE_EQ(test_observer_.GetBrightnessPercent(),
+                   expected_brightness_percent2);
+}
+
+TEST_F(AdapterTest, BrightnessSetByPolicy) {
+  Init(AlsReader::AlsInitStatus::kSuccess, BrightnessMonitor::Status::kSuccess,
+       global_curve_, personal_curve_, default_params_,
+       true /* brightness_set_by_policy */);
+
+  EXPECT_EQ(adapter_->GetStatusForTesting(), Adapter::Status::kSuccess);
+
+  scoped_task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(1));
+  fake_als_reader_.ReportAmbientLightUpdate(10);
+  scoped_task_environment_.RunUntilIdle();
+  EXPECT_EQ(test_observer_.num_changes(), 0);
+}
+
+}  // namespace auto_screen_brightness
+}  // namespace power
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/als_reader.h b/chrome/browser/chromeos/power/auto_screen_brightness/als_reader.h
index 4cc31004..e56d18c 100644
--- a/chrome/browser/chromeos/power/auto_screen_brightness/als_reader.h
+++ b/chrome/browser/chromeos/power/auto_screen_brightness/als_reader.h
@@ -26,6 +26,10 @@
     kMaxValue = kMissingPath
   };
 
+  // Frequency in hertz at which we read ALS samples.
+  // TODO(jiameng): currently set frequency to 4hz. May revise.
+  static constexpr int kAlsPollFrequency = 4;
+
   // AlsReader must outlive the observers.
   class Observer : public base::CheckedObserver {
    public:
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/als_reader_impl.h b/chrome/browser/chromeos/power/auto_screen_brightness/als_reader_impl.h
index cd3e54b..04381483 100644
--- a/chrome/browser/chromeos/power/auto_screen_brightness/als_reader_impl.h
+++ b/chrome/browser/chromeos/power/auto_screen_brightness/als_reader_impl.h
@@ -31,11 +31,8 @@
       base::TimeDelta::FromSeconds(1);
   static constexpr int kMaxInitialAttempts = 20;
 
-  // Interval for polling ambient light values.
-  // TODO(jiameng): currently poll ALS samples every 250ms. May revise.
-  static constexpr int kNumberAlsPollPerSeconds = 4;
   static constexpr base::TimeDelta kAlsPollInterval =
-      base::TimeDelta::FromSecondsD(1.0 / kNumberAlsPollPerSeconds);
+      base::TimeDelta::FromSecondsD(1.0 / kAlsPollFrequency);
 
   AlsReaderImpl();
   ~AlsReaderImpl() override;
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/modeller.h b/chrome/browser/chromeos/power/auto_screen_brightness/modeller.h
index 07070f9..af1770fa 100644
--- a/chrome/browser/chromeos/power/auto_screen_brightness/modeller.h
+++ b/chrome/browser/chromeos/power/auto_screen_brightness/modeller.h
@@ -36,12 +36,12 @@
     virtual void OnModelTrained(
         const MonotoneCubicSpline& brightness_curve) = 0;
 
-    // Called when the model is initialized. Observers will be notified about
-    // both model status and initial curve (|brightness_curve|). If model status
-    // is |kDisabled|, the |brightness_curve| will be a nullopt.
+    // Called when the model is initialized. If model is disabled, both
+    // |global_curve| and |personal_curve| will be nullopt. If there is only a
+    // global curve, then |personal_curve| will be nullopt.
     virtual void OnModelInitialized(
-        Status model_status,
-        const base::Optional<MonotoneCubicSpline>& brightness_curve) = 0;
+        const base::Optional<MonotoneCubicSpline>& global_curve,
+        const base::Optional<MonotoneCubicSpline>& personal_curve) = 0;
 
    private:
     DISALLOW_COPY_AND_ASSIGN(Observer);
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/modeller_impl.cc b/chrome/browser/chromeos/power/auto_screen_brightness/modeller_impl.cc
index 0c46567c..626769c 100644
--- a/chrome/browser/chromeos/power/auto_screen_brightness/modeller_impl.cc
+++ b/chrome/browser/chromeos/power/auto_screen_brightness/modeller_impl.cc
@@ -58,9 +58,8 @@
 
 // Saves |curve| to disk. This should run in another thread to be non-blocking
 // to the main thread (if |is_testing| is false).
-// TODO(jiameng): alternative to WriteFile is WriteFileAtomically, but the
-// latter is very slow. Investigate whether we need to change to
-// WriteFileAtomically.
+// TODO(jiameng): write to a temp location and rename to |path|. Refactor out
+// the logic that's shared with the unit test to utils.
 void SaveCurveToDisk(const base::FilePath& path,
                      const MonotoneCubicSpline& curve,
                      bool is_testing) {
@@ -120,7 +119,7 @@
   DCHECK(observer);
   observers_.AddObserver(observer);
   if (model_status_ != Modeller::Status::kInitializing) {
-    observer->OnModelInitialized(model_status_, current_curve_);
+    NotifyObserverInitStatus(*observer);
   }
 }
 
@@ -303,24 +302,35 @@
 }
 
 void ModellerImpl::OnInitializationComplete() {
+  // TODO(jiameng): log model status to UMA.
+  for (auto& observer : observers_) {
+    NotifyObserverInitStatus(observer);
+  }
+}
+
+void ModellerImpl::NotifyObserverInitStatus(Modeller::Observer& observer) {
   DCHECK_NE(model_status_, Status::kInitializing);
-  for (auto& observer : observers_)
-    observer.OnModelInitialized(model_status_, current_curve_);
+  if (model_status_ == Status::kDisabled) {
+    observer.OnModelInitialized(base::nullopt, base::nullopt);
+  } else {
+    observer.OnModelInitialized(global_curve_, personal_curve_);
+  }
 }
 
 void ModellerImpl::OnCurveLoadedFromDisk(
     const base::Optional<MonotoneCubicSpline>& curve) {
   if (!curve.has_value()) {
-    current_curve_.emplace(global_curve_);
     model_status_ = Status::kGlobal;
   } else {
-    current_curve_.emplace(curve.value());
+    personal_curve_.emplace(curve.value());
     model_status_ = Status::kPersonal;
   }
 
   OnInitializationComplete();
 
-  trainer_->SetInitialCurves(global_curve_, current_curve_.value());
+  trainer_->SetInitialCurves(global_curve_, model_status_ == Status::kGlobal
+                                                ? global_curve_
+                                                : personal_curve_.value());
   ScheduleTrainerStart();
 }
 
@@ -346,7 +356,7 @@
 }
 
 void ModellerImpl::OnTrainingFinished(const MonotoneCubicSpline& curve) {
-  current_curve_.emplace(curve);
+  personal_curve_.emplace(curve);
   for (auto& observer : observers_)
     observer.OnModelTrained(curve);
 
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/modeller_impl.h b/chrome/browser/chromeos/power/auto_screen_brightness/modeller_impl.h
index 35c4443..a2bfc54 100644
--- a/chrome/browser/chromeos/power/auto_screen_brightness/modeller_impl.h
+++ b/chrome/browser/chromeos/power/auto_screen_brightness/modeller_impl.h
@@ -15,7 +15,7 @@
 #include "base/scoped_observer.h"
 #include "base/sequenced_task_runner.h"
 #include "base/time/time.h"
-#include "chrome/browser/chromeos/power/auto_screen_brightness/als_reader_impl.h"
+#include "chrome/browser/chromeos/power/auto_screen_brightness/als_reader.h"
 #include "chrome/browser/chromeos/power/auto_screen_brightness/brightness_monitor.h"
 #include "chrome/browser/chromeos/power/auto_screen_brightness/modeller.h"
 #include "chrome/browser/chromeos/power/auto_screen_brightness/trainer.h"
@@ -58,7 +58,7 @@
 
   // Size of |data_cache_|.
   static constexpr int kNumberAmbientValuesToTrack =
-      kAmbientLightHorizonSeconds * AlsReaderImpl::kNumberAlsPollPerSeconds;
+      kAmbientLightHorizonSeconds * AlsReader::kAlsPollFrequency;
 
   static constexpr char kModelDir[] = "autobrightness";
   static constexpr char kCurveFileName[] = "curve";
@@ -144,6 +144,12 @@
   // |model_status_| is not |kInitializing|.
   void OnInitializationComplete();
 
+  // Called when the modeller is initialized. It notifies its observers about
+  // constructed global curve and personal curve (loaded from the disk). Both
+  // curves will be nullopt if model is disabled, and personal curve will be
+  // nullopt if no curve is loaded from the disk.
+  void NotifyObserverInitStatus(Modeller::Observer& observer);
+
   // Called after we've attempted to construct a |curve| from data saved on
   // disk. |curve| will be assigned to |current_curve_| if |curve| is not
   // nullopt. Otherwise, |current_curve_| will have the same value as
@@ -186,8 +192,8 @@
 
   base::FilePath curve_path_;
 
-  // Latest trained curve.
-  base::Optional<MonotoneCubicSpline> current_curve_;
+  // Latest personal curve, either loaded from disk or trained.
+  base::Optional<MonotoneCubicSpline> personal_curve_;
 
   // Global curve constructed from predefined params.
   const MonotoneCubicSpline global_curve_;
diff --git a/chrome/browser/chromeos/power/auto_screen_brightness/modeller_impl_unittest.cc b/chrome/browser/chromeos/power/auto_screen_brightness/modeller_impl_unittest.cc
index 970a76a..47834bb 100644
--- a/chrome/browser/chromeos/power/auto_screen_brightness/modeller_impl_unittest.cc
+++ b/chrome/browser/chromeos/power/auto_screen_brightness/modeller_impl_unittest.cc
@@ -58,8 +58,8 @@
   // Trainer overrides:
   void SetInitialCurves(const MonotoneCubicSpline& global_curve,
                         const MonotoneCubicSpline& current_curve) override {
-    CHECK(!global_curve_.has_value());
-    CHECK(!current_curve_.has_value());
+    CHECK(!global_curve_);
+    CHECK(!current_curve_);
 
     global_curve_.emplace(global_curve);
     current_curve_.emplace(current_curve);
@@ -67,7 +67,7 @@
 
   MonotoneCubicSpline Train(
       const std::vector<TrainingDataPoint>& data) override {
-    CHECK(current_curve_.has_value());
+    CHECK(current_curve_);
     current_curve_.emplace(CreateTestCurveFromTrainingData(data));
     return current_curve_.value();
   }
@@ -86,36 +86,49 @@
 
   // Modeller::Observer overrides:
   void OnModelTrained(const MonotoneCubicSpline& brightness_curve) override {
-    brightness_curve_.emplace(brightness_curve);
+    personal_curve_.emplace(brightness_curve);
     trained_curve_received_ = true;
   }
 
   void OnModelInitialized(
-      const Modeller::Status model_status,
-      const base::Optional<MonotoneCubicSpline>& brightness_curve) override {
-    model_status_ = base::Optional<Modeller::Status>(model_status);
-    if (brightness_curve.has_value()) {
-      brightness_curve_.emplace(brightness_curve.value());
-    }
+      const base::Optional<MonotoneCubicSpline>& global_curve,
+      const base::Optional<MonotoneCubicSpline>& personal_curve) override {
+    model_initialized_ = true;
+    if (global_curve)
+      global_curve_.emplace(global_curve.value());
+
+    if (personal_curve)
+      personal_curve_.emplace(personal_curve.value());
   }
 
   Modeller::Status model_status() const {
-    CHECK(model_status_.has_value());
-    return model_status_.value();
+    CHECK(model_initialized_);
+
+    if (personal_curve_)
+      return Modeller::Status::kPersonal;
+
+    if (global_curve_)
+      return Modeller::Status::kGlobal;
+
+    return Modeller::Status::kDisabled;
   }
 
   MonotoneCubicSpline brightness_curve() const {
-    CHECK(brightness_curve_.has_value());
-    return brightness_curve_.value();
+    if (personal_curve_)
+      return personal_curve_.value();
+
+    CHECK(global_curve_);
+    return global_curve_.value();
   }
 
-  bool HasModelStatus() { return model_status_.has_value(); }
-  bool HasBrightnessCurve() { return brightness_curve_.has_value(); }
+  bool model_initialized() { return model_initialized_; }
+  bool has_brightness_curve() { return global_curve_ || personal_curve_; }
   bool trained_curve_received() { return trained_curve_received_; }
 
  private:
-  base::Optional<Modeller::Status> model_status_;
-  base::Optional<MonotoneCubicSpline> brightness_curve_;
+  bool model_initialized_ = false;
+  base::Optional<MonotoneCubicSpline> global_curve_;
+  base::Optional<MonotoneCubicSpline> personal_curve_;
   bool trained_curve_received_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(TestObserver);
@@ -190,7 +203,7 @@
   SetUpModeller();
   scoped_task_environment_.RunUntilIdle();
   EXPECT_EQ(Modeller::Status::kDisabled, test_observer_->model_status());
-  EXPECT_FALSE(test_observer_->HasBrightnessCurve());
+  EXPECT_FALSE(test_observer_->has_brightness_curve());
 }
 
 // BrightnessMonitor is |kDisabled| when Modeller is created.
@@ -200,7 +213,7 @@
   SetUpModeller();
   scoped_task_environment_.RunUntilIdle();
   EXPECT_EQ(Modeller::Status::kDisabled, test_observer_->model_status());
-  EXPECT_FALSE(test_observer_->HasBrightnessCurve());
+  EXPECT_FALSE(test_observer_->has_brightness_curve());
 }
 
 // AlsReader is |kDisabled| on later notification.
@@ -209,13 +222,13 @@
   fake_brightness_monitor_.set_status(BrightnessMonitor::Status::kSuccess);
   SetUpModeller();
   scoped_task_environment_.RunUntilIdle();
-  EXPECT_FALSE(test_observer_->HasModelStatus());
-  EXPECT_FALSE(test_observer_->HasBrightnessCurve());
+  EXPECT_FALSE(test_observer_->model_initialized());
+  EXPECT_FALSE(test_observer_->has_brightness_curve());
 
   fake_als_reader_.set_als_init_status(AlsReader::AlsInitStatus::kDisabled);
   fake_als_reader_.ReportReaderInitialized();
   EXPECT_EQ(Modeller::Status::kDisabled, test_observer_->model_status());
-  EXPECT_FALSE(test_observer_->HasBrightnessCurve());
+  EXPECT_FALSE(test_observer_->has_brightness_curve());
 }
 
 // AlsReader is |kSuccess| on later notification.
@@ -224,8 +237,8 @@
   fake_brightness_monitor_.set_status(BrightnessMonitor::Status::kSuccess);
   SetUpModeller();
   scoped_task_environment_.RunUntilIdle();
-  EXPECT_FALSE(test_observer_->HasModelStatus());
-  EXPECT_FALSE(test_observer_->HasBrightnessCurve());
+  EXPECT_FALSE(test_observer_->model_initialized());
+  EXPECT_FALSE(test_observer_->has_brightness_curve());
 
   fake_als_reader_.set_als_init_status(AlsReader::AlsInitStatus::kSuccess);
   fake_als_reader_.ReportReaderInitialized();
@@ -241,13 +254,13 @@
   fake_brightness_monitor_.set_status(BrightnessMonitor::Status::kInitializing);
   SetUpModeller();
   scoped_task_environment_.RunUntilIdle();
-  EXPECT_FALSE(test_observer_->HasModelStatus());
-  EXPECT_FALSE(test_observer_->HasBrightnessCurve());
+  EXPECT_FALSE(test_observer_->model_initialized());
+  EXPECT_FALSE(test_observer_->has_brightness_curve());
 
   fake_brightness_monitor_.set_status(BrightnessMonitor::Status::kDisabled);
   fake_brightness_monitor_.ReportBrightnessMonitorInitialized();
   EXPECT_EQ(Modeller::Status::kDisabled, test_observer_->model_status());
-  EXPECT_FALSE(test_observer_->HasBrightnessCurve());
+  EXPECT_FALSE(test_observer_->has_brightness_curve());
 }
 
 // BrightnessMonitor is |kSuccess| on later notification.
@@ -256,8 +269,8 @@
   fake_brightness_monitor_.set_status(BrightnessMonitor::Status::kInitializing);
   SetUpModeller();
   scoped_task_environment_.RunUntilIdle();
-  EXPECT_FALSE(test_observer_->HasModelStatus());
-  EXPECT_FALSE(test_observer_->HasBrightnessCurve());
+  EXPECT_FALSE(test_observer_->model_initialized());
+  EXPECT_FALSE(test_observer_->has_brightness_curve());
 
   fake_brightness_monitor_.set_status(BrightnessMonitor::Status::kSuccess);
   fake_brightness_monitor_.ReportBrightnessMonitorInitialized();
diff --git a/chrome/browser/data_use_measurement/chrome_data_use_measurement.cc b/chrome/browser/data_use_measurement/chrome_data_use_measurement.cc
index f9dc665..3ea4e4c 100644
--- a/chrome/browser/data_use_measurement/chrome_data_use_measurement.cc
+++ b/chrome/browser/data_use_measurement/chrome_data_use_measurement.cc
@@ -21,9 +21,15 @@
 #include "content/public/browser/network_service_instance.h"
 #include "services/network/public/cpp/features.h"
 
+using content::BrowserThread;
+
 namespace data_use_measurement {
 
 namespace {
+// Global instance to be used when network service is enabled, this will never
+// be deleted. When network service is disabled, this should always be null.
+ChromeDataUseMeasurement* g_chrome_data_use_measurement = nullptr;
+
 void UpdateMetricsUsagePrefs(int64_t total_bytes,
                              bool is_cellular,
                              bool is_metrics_service_usage) {
@@ -54,17 +60,20 @@
 }  // namespace
 
 // static
-std::unique_ptr<ChromeDataUseMeasurement>
-ChromeDataUseMeasurement::CreateForNetworkService() {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ChromeDataUseMeasurement* ChromeDataUseMeasurement::GetInstance() {
+  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) ||
+         !BrowserThread::IsThreadInitialized(BrowserThread::UI));
 
   // Do not create when NetworkService is disabled, since data use of URLLoader
   // is reported via the network delegate callbacks.
   if (!base::FeatureList::IsEnabled(network::features::kNetworkService))
     return nullptr;
 
-  return std::make_unique<ChromeDataUseMeasurement>(
-      nullptr, nullptr, content::GetNetworkConnectionTracker());
+  if (!g_chrome_data_use_measurement) {
+    g_chrome_data_use_measurement = new ChromeDataUseMeasurement(
+        nullptr, nullptr, content::GetNetworkConnectionTracker());
+  }
+  return g_chrome_data_use_measurement;
 }
 
 ChromeDataUseMeasurement::ChromeDataUseMeasurement(
@@ -93,7 +102,6 @@
     int64_t recv_bytes,
     int64_t sent_bytes) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   DCHECK(base::FeatureList::IsEnabled(network::features::kNetworkService));
   // Negative byte numbres is not a critical problem (i.e. should have no security implications) but
   // is not expected. TODO(rajendrant): remove these DCHECKs or consider using uint in Mojo instead.
diff --git a/chrome/browser/data_use_measurement/chrome_data_use_measurement.h b/chrome/browser/data_use_measurement/chrome_data_use_measurement.h
index 8cb7a40..646c953 100644
--- a/chrome/browser/data_use_measurement/chrome_data_use_measurement.h
+++ b/chrome/browser/data_use_measurement/chrome_data_use_measurement.h
@@ -17,7 +17,7 @@
 
 class ChromeDataUseMeasurement : public DataUseMeasurement {
  public:
-  static std::unique_ptr<ChromeDataUseMeasurement> CreateForNetworkService();
+  static ChromeDataUseMeasurement* GetInstance();
 
   ChromeDataUseMeasurement(
       std::unique_ptr<URLRequestClassifier> url_request_classifier,
diff --git a/chrome/browser/devtools/devtools_sanity_browsertest.cc b/chrome/browser/devtools/devtools_sanity_browsertest.cc
index fdb5b6bc..199fb7f1 100644
--- a/chrome/browser/devtools/devtools_sanity_browsertest.cc
+++ b/chrome/browser/devtools/devtools_sanity_browsertest.cc
@@ -1844,6 +1844,19 @@
   CloseDevToolsWindow();
 }
 
+IN_PROC_BROWSER_TEST_F(WorkerDevToolsSanityTest,
+                       InspectSharedWorkerNetworkPanel) {
+  ASSERT_TRUE(spawned_test_server()->Start());
+  GURL url = spawned_test_server()->GetURL(kSharedWorkerTestPage);
+  ui_test_utils::NavigateToURL(browser(), url);
+
+  scoped_refptr<DevToolsAgentHost> host =
+      WaitForFirstSharedWorker(kSharedWorkerTestWorker);
+  OpenDevToolsWindow(host);
+  RunTestFunction(window_, "testSharedWorkerNetworkPanel");
+  CloseDevToolsWindow();
+}
+
 class DevToolsAgentHostTest : public InProcessBrowserTest {};
 
 // Tests DevToolsAgentHost retention by its target.
diff --git a/chrome/browser/extensions/api/cast_streaming/performance_test.cc b/chrome/browser/extensions/api/cast_streaming/performance_test.cc
index 4f627788..e331dd89 100644
--- a/chrome/browser/extensions/api/cast_streaming/performance_test.cc
+++ b/chrome/browser/extensions/api/cast_streaming/performance_test.cc
@@ -522,7 +522,7 @@
     // prior stage, in whatever form it had, and so it's possible to track
     // specific frames all the way from capture until playout at the receiver.
     std::vector<std::pair<EventMap*, std::string>> event_maps;
-    event_maps.push_back(std::make_pair(&onbuffer, "timestamp"));
+    event_maps.push_back(std::make_pair(&onbuffer, "time_delta"));
     event_maps.push_back(std::make_pair(&sink, "time_delta"));
     event_maps.push_back(std::make_pair(&inserted, "timestamp"));
     event_maps.push_back(std::make_pair(&encoded, "rtp_timestamp"));
@@ -695,13 +695,7 @@
 
 }  // namespace
 
-#if defined(OS_WIN)
-#define MAYBE_Performance DISABLED_Performance
-#else
-#define MAYBE_Performance Performance
-#endif
-
-IN_PROC_BROWSER_TEST_P(CastV2PerformanceTest, MAYBE_Performance) {
+IN_PROC_BROWSER_TEST_P(CastV2PerformanceTest, Performance) {
   RunTest("CastV2Performance");
 }
 
diff --git a/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc b/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc
index 7bf5788..d02d45eb 100644
--- a/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc
+++ b/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc
@@ -1705,31 +1705,7 @@
                                                    dummy_extension->id()));
 }
 
-class DeveloperPrivateZipInstallerUnitTest
-    : public DeveloperPrivateApiUnitTest {
- public:
-  DeveloperPrivateZipInstallerUnitTest() {
-    service_manager::TestConnectorFactory::NameToServiceMap services;
-    services.insert(std::make_pair("data_decoder",
-                                   data_decoder::DataDecoderService::Create()));
-    services.insert(
-        std::make_pair("unzip_service", unzip::UnzipService::CreateService()));
-    test_connector_factory_ =
-        service_manager::TestConnectorFactory::CreateForServices(
-            std::move(services));
-    connector_ = test_connector_factory_->CreateConnector();
-  }
-  ~DeveloperPrivateZipInstallerUnitTest() override {}
-
- private:
-  std::unique_ptr<service_manager::TestConnectorFactory>
-      test_connector_factory_;
-  std::unique_ptr<service_manager::Connector> connector_;
-
-  DISALLOW_COPY_AND_ASSIGN(DeveloperPrivateZipInstallerUnitTest);
-};
-
-TEST_F(DeveloperPrivateZipInstallerUnitTest, InstallDroppedFileZip) {
+TEST_F(DeveloperPrivateApiUnitTest, InstallDroppedFileZip) {
   base::FilePath zip_path = data_dir().AppendASCII("simple_empty.zip");
   extensions::ExtensionInstallUI::set_disable_ui_for_tests();
   ScopedTestDialogAutoConfirm auto_confirm(ScopedTestDialogAutoConfirm::ACCEPT);
diff --git a/chrome/browser/extensions/api/processes/processes_api.cc b/chrome/browser/extensions/api/processes/processes_api.cc
index 8c97c36e..31099a8 100644
--- a/chrome/browser/extensions/api/processes/processes_api.cc
+++ b/chrome/browser/extensions/api/processes/processes_api.cc
@@ -521,7 +521,7 @@
 
   auto* host = content::BrowserChildProcessHost::FromID(child_process_host_id);
   if (host)
-    return host->GetData().GetHandle();
+    return host->GetData().GetProcess().Handle();
 
   return base::kNullProcessHandle;
 }
diff --git a/chrome/browser/extensions/extension_dom_clipboard_apitest.cc b/chrome/browser/extensions/extension_dom_clipboard_apitest.cc
index 7af0348b..6869d7f 100644
--- a/chrome/browser/extensions/extension_dom_clipboard_apitest.cc
+++ b/chrome/browser/extensions/extension_dom_clipboard_apitest.cc
@@ -4,6 +4,7 @@
 
 #include "base/feature_list.h"
 #include "base/strings/stringprintf.h"
+#include "build/build_config.h"
 #include "chrome/browser/extensions/extension_apitest.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
@@ -98,7 +99,13 @@
   ASSERT_TRUE(RunExtensionTest("clipboard/extension")) << message_;
 }
 
-IN_PROC_BROWSER_TEST_F(ClipboardApiTest, ExtensionNoPermission) {
+// Flaky on Mac. See https://crbug.com/900301.
+#if defined(OS_MACOSX)
+#define MAYBE_ExtensionNoPermission DISABLED_ExtensionNoPermission
+#else
+#define MAYBE_ExtensionNoPermission ExtensionNoPermission
+#endif
+IN_PROC_BROWSER_TEST_F(ClipboardApiTest, MAYBE_ExtensionNoPermission) {
   ASSERT_TRUE(StartEmbeddedTestServer());
   ASSERT_TRUE(RunExtensionTest("clipboard/extension_no_permission"))
       << message_;
diff --git a/chrome/browser/extensions/extension_util.cc b/chrome/browser/extensions/extension_util.cc
index eb72128..7a66177 100644
--- a/chrome/browser/extensions/extension_util.cc
+++ b/chrome/browser/extensions/extension_util.cc
@@ -356,7 +356,7 @@
 }
 
 const Extension* GetPwaForSecureActiveTab(Browser* browser) {
-  switch (browser->toolbar_model()->GetSecurityLevel(true)) {
+  switch (browser->location_bar_model()->GetSecurityLevel(true)) {
     case security_state::SECURITY_LEVEL_COUNT:
       NOTREACHED();
       FALLTHROUGH;
diff --git a/chrome/browser/extensions/test_extension_system.cc b/chrome/browser/extensions/test_extension_system.cc
index 3efac55..772f99b2 100644
--- a/chrome/browser/extensions/test_extension_system.cc
+++ b/chrome/browser/extensions/test_extension_system.cc
@@ -17,6 +17,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/chrome_switches.h"
 #include "components/prefs/pref_service.h"
+#include "components/services/unzip/public/interfaces/constants.mojom.h"
 #include "components/services/unzip/unzip_service.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/common/service_manager_connection.h"
@@ -32,6 +33,8 @@
 #include "extensions/browser/value_store/test_value_store_factory.h"
 #include "extensions/browser/value_store/testing_value_store.h"
 #include "services/data_decoder/data_decoder_service.h"
+#include "services/data_decoder/public/mojom/constants.mojom.h"
+#include "services/service_manager/public/cpp/service_context.h"
 #include "services/service_manager/public/cpp/test/test_connector_factory.h"
 #if defined(OS_CHROMEOS)
 #include "components/user_manager/user_manager.h"
@@ -79,14 +82,14 @@
       &ready_));
 
   if (!connector_factory_) {
-    service_manager::TestConnectorFactory::NameToServiceMap services;
-    services.insert(std::make_pair(
-        "data_decoder", std::make_unique<data_decoder::DataDecoderService>()));
-    services.insert(
-        std::make_pair("unzip_service", unzip::UnzipService::CreateService()));
     connector_factory_ =
-        service_manager::TestConnectorFactory::CreateForServices(
-            std::move(services));
+        std::make_unique<service_manager::TestConnectorFactory>();
+    data_decoder_ = std::make_unique<data_decoder::DataDecoderService>(
+        connector_factory_->RegisterInstance(
+            data_decoder::mojom::kServiceName));
+    unzip_service_context_ = std::make_unique<service_manager::ServiceContext>(
+        unzip::UnzipService::CreateService(),
+        connector_factory_->RegisterInstance(unzip::mojom::kServiceName));
     connector_ = connector_factory_->CreateConnector();
     CrxInstaller::set_connector_for_test(connector_.get());
   }
diff --git a/chrome/browser/extensions/test_extension_system.h b/chrome/browser/extensions/test_extension_system.h
index 6baafdd..e7851932 100644
--- a/chrome/browser/extensions/test_extension_system.h
+++ b/chrome/browser/extensions/test_extension_system.h
@@ -28,6 +28,8 @@
 
 namespace service_manager {
 class Connector;
+class Service;
+class ServiceContext;
 class TestConnectorFactory;
 }  // namespace service_manager
 
@@ -110,6 +112,9 @@
   std::unique_ptr<service_manager::TestConnectorFactory> connector_factory_;
   std::unique_ptr<service_manager::Connector> connector_;
 
+  std::unique_ptr<service_manager::Service> data_decoder_;
+  std::unique_ptr<service_manager::ServiceContext> unzip_service_context_;
+
 #if defined(OS_CHROMEOS)
   std::unique_ptr<chromeos::ScopedTestUserManager> test_user_manager_;
 #endif
diff --git a/chrome/browser/extensions/zipfile_installer_unittest.cc b/chrome/browser/extensions/zipfile_installer_unittest.cc
index 7fbf7d2f..e7322d3 100644
--- a/chrome/browser/extensions/zipfile_installer_unittest.cc
+++ b/chrome/browser/extensions/zipfile_installer_unittest.cc
@@ -21,6 +21,7 @@
 #include "chrome/browser/extensions/test_extension_system.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/test/base/testing_profile.h"
+#include "components/services/unzip/public/interfaces/constants.mojom.h"
 #include "components/services/unzip/unzip_service.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "content/public/test/test_utils.h"
@@ -29,7 +30,9 @@
 #include "extensions/common/constants.h"
 #include "extensions/common/extension.h"
 #include "services/data_decoder/data_decoder_service.h"
+#include "services/data_decoder/public/mojom/constants.mojom.h"
 #include "services/service_manager/public/cpp/connector.h"
+#include "services/service_manager/public/cpp/service_context.h"
 #include "services/service_manager/public/cpp/test/test_connector_factory.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -96,17 +99,13 @@
 class ZipFileInstallerTest : public testing::Test {
  public:
   ZipFileInstallerTest()
-      : browser_threads_(content::TestBrowserThreadBundle::IO_MAINLOOP) {
-    service_manager::TestConnectorFactory::NameToServiceMap services;
-    services.insert(std::make_pair("data_decoder",
-                                   data_decoder::DataDecoderService::Create()));
-    services.insert(
-        std::make_pair("unzip_service", unzip::UnzipService::CreateService()));
-    test_connector_factory_ =
-        service_manager::TestConnectorFactory::CreateForServices(
-            std::move(services));
-    connector_ = test_connector_factory_->CreateConnector();
-  }
+      : browser_threads_(content::TestBrowserThreadBundle::IO_MAINLOOP),
+        data_decoder_(test_connector_factory_.RegisterInstance(
+            data_decoder::mojom::kServiceName)),
+        unzip_service_context_(unzip::UnzipService::CreateService(),
+                               test_connector_factory_.RegisterInstance(
+                                   unzip::mojom::kServiceName)),
+        connector_(test_connector_factory_.CreateConnector()) {}
 
   void SetUp() override {
     extensions::LoadErrorReporter::Init(/*enable_noisy_errors=*/false);
@@ -180,8 +179,9 @@
 #endif
 
  private:
-  std::unique_ptr<service_manager::TestConnectorFactory>
-      test_connector_factory_;
+  service_manager::TestConnectorFactory test_connector_factory_;
+  data_decoder::DataDecoderService data_decoder_;
+  service_manager::ServiceContext unzip_service_context_;
   std::unique_ptr<service_manager::Connector> connector_;
 };
 
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 839fa12..585215c 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -2215,12 +2215,6 @@
 const char kChromeDuetDescription[] =
     "Enables Chrome Duet, split toolbar Chrome Home, on Android.";
 
-const char kChromeHomeSwipeLogicName[] = "Chrome Home Swipe Logic";
-const char kChromeHomeSwipeLogicDescription[] =
-    "Various swipe logic options for Chrome Home for sheet expansion.";
-const char kChromeHomeSwipeLogicRestrictArea[] = "Restrict swipable area";
-const char kChromeHomeSwipeLogicVelocity[] = "Velocity suppression model";
-
 const char kChromeMemexName[] = "Chrome Memex";
 const char kChromeMemexDescription[] =
     "Enables Chrome Memex homepage on Android. Restricted to opted-in "
@@ -3398,10 +3392,6 @@
     "ability to connect to other devices associated the logged-in Google "
     "account.";
 
-const char kNativeSmbName[] = "Native Smb Client";
-const char kNativeSmbDescription[] =
-    "If enabled, allows connections to an smb filesystem via Files app";
-
 const char kNetworkPortalNotificationName[] =
     "Notifications about captive portals";
 const char kNetworkPortalNotificationDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index dc709dfb..a30777a 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -1339,11 +1339,6 @@
 extern const char kChromeDuetName[];
 extern const char kChromeDuetDescription[];
 
-extern const char kChromeHomeSwipeLogicName[];
-extern const char kChromeHomeSwipeLogicDescription[];
-extern const char kChromeHomeSwipeLogicRestrictArea[];
-extern const char kChromeHomeSwipeLogicVelocity[];
-
 extern const char kChromeMemexName[];
 extern const char kChromeMemexDescription[];
 
@@ -2067,9 +2062,6 @@
 extern const char kMultiDeviceApiName[];
 extern const char kMultiDeviceApiDescription[];
 
-extern const char kNativeSmbName[];
-extern const char kNativeSmbDescription[];
-
 extern const char kNetworkPortalNotificationName[];
 extern const char kNetworkPortalNotificationDescription[];
 
diff --git a/chrome/browser/image_decoder_browsertest.cc b/chrome/browser/image_decoder_browsertest.cc
index cdc3a41..41546bb 100644
--- a/chrome/browser/image_decoder_browsertest.cc
+++ b/chrome/browser/image_decoder_browsertest.cc
@@ -118,24 +118,11 @@
   void BrowserChildProcessHostConnected(
       const content::ChildProcessData& data) override {
     DCHECK_CURRENTLY_ON(BrowserThread::UI);
-    if (!data.IsHandleValid() || data.name != utility_process_name_) {
+    if (!data.GetProcess().IsValid() || data.name != utility_process_name_) {
       return;
     }
 
     ASSERT_FALSE(did_kill_);
-    base::ProcessHandle handle = data.GetHandle();
-
-#if defined(OS_WIN)
-    // On windows, duplicate the process handle since base::Process closes it on
-    // destruction.
-    base::ProcessHandle out_handle;
-    if (!::DuplicateHandle(GetCurrentProcess(), handle,
-                           GetCurrentProcess(), &out_handle,
-                           0, FALSE, DUPLICATE_SAME_ACCESS)) {
-      return;
-    }
-    handle = out_handle;
-#endif
 
     // Use a non-zero exit code so it counts as a crash.
     // Don't wait for the process after sending the termination signal
@@ -143,7 +130,7 @@
     // removed from the process table. However, Chromium treats an error on
     // |waitpid| (in this case, ECHILD) as a "normal" termination and doesn't
     // invoke the process host delegate's OnProcessCrashed().
-    EXPECT_TRUE(base::Process(handle).Terminate(1, false));
+    EXPECT_TRUE(data.GetProcess().Terminate(1, false));
     did_kill_ = true;
   }
 
diff --git a/chrome/browser/invalidation/profile_invalidation_provider_factory.cc b/chrome/browser/invalidation/profile_invalidation_provider_factory.cc
index 10e7d00..441127df 100644
--- a/chrome/browser/invalidation/profile_invalidation_provider_factory.cc
+++ b/chrome/browser/invalidation/profile_invalidation_provider_factory.cc
@@ -12,6 +12,7 @@
 #include "chrome/browser/gcm/gcm_profile_service_factory.h"
 #include "chrome/browser/gcm/instance_id/instance_id_profile_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/common/chrome_content_client.h"
 #include "components/gcm_driver/gcm_profile_service.h"
 #include "components/gcm_driver/instance_id/instance_id_profile_service.h"
@@ -34,12 +35,6 @@
 #include "services/data_decoder/public/cpp/safe_json_parser.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 
-#if defined(OS_ANDROID)
-#include "components/invalidation/impl/invalidation_service_android.h"
-#else
-#include "chrome/browser/signin/identity_manager_factory.h"
-#endif  // defined(OS_ANDROID)
-
 #if defined(OS_CHROMEOS)
 #include "base/files/file_path.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
@@ -81,10 +76,8 @@
     : BrowserContextKeyedServiceFactory(
           "InvalidationService",
           BrowserContextDependencyManager::GetInstance()) {
-#if !defined(OS_ANDROID)
   DependsOn(IdentityManagerFactory::GetInstance());
   DependsOn(gcm::GCMProfileServiceFactory::GetInstance());
-#endif
 }
 
 ProfileInvalidationProviderFactory::~ProfileInvalidationProviderFactory() =
@@ -100,13 +93,6 @@
   if (testing_factory_)
     return testing_factory_.Run(context).release();
 
-#if defined(OS_ANDROID)
-  // Android does not need an IdentityProvider, because it gets the account
-  // on the java side.
-  auto service = std::make_unique<InvalidationServiceAndroid>();
-  return new ProfileInvalidationProvider(std::move(service), nullptr);
-#else
-
   std::unique_ptr<IdentityProvider> identity_provider;
 
 #if defined(OS_CHROMEOS)
@@ -118,7 +104,8 @@
     identity_provider.reset(new chromeos::DeviceIdentityProvider(
         chromeos::DeviceOAuth2TokenServiceFactory::Get()));
   }
-#endif
+#endif  // defined(OS_CHROMEOS)
+
   Profile* profile = Profile::FromBrowserContext(context);
 
   if (!identity_provider) {
@@ -141,7 +128,6 @@
   service->Init();
   return new ProfileInvalidationProvider(std::move(service),
                                          std::move(identity_provider));
-#endif
 }
 
 }  // namespace invalidation
diff --git a/chrome/browser/memory_details.cc b/chrome/browser/memory_details.cc
index 8594ab1..14b789a 100644
--- a/chrome/browser/memory_details.cc
+++ b/chrome/browser/memory_details.cc
@@ -196,9 +196,9 @@
   // the process is being launched, so we skip it.
   for (BrowserChildProcessHostIterator iter; !iter.Done(); ++iter) {
     ProcessMemoryInformation info;
-    if (!iter.GetData().GetHandle())
+    if (!iter.GetData().GetProcess().IsValid())
       continue;
-    info.pid = base::GetProcId(iter.GetData().GetHandle());
+    info.pid = iter.GetData().GetProcess().Pid();
     if (!info.pid)
       continue;
 
diff --git a/chrome/browser/metrics/process_memory_metrics_emitter.cc b/chrome/browser/metrics/process_memory_metrics_emitter.cc
index 56db3a0..c2c22a98 100644
--- a/chrome/browser/metrics/process_memory_metrics_emitter.cc
+++ b/chrome/browser/metrics/process_memory_metrics_emitter.cc
@@ -625,6 +625,8 @@
       }
       case memory_instrumentation::mojom::ProcessType::PLUGIN:
         FALLTHROUGH;
+      case memory_instrumentation::mojom::ProcessType::ARC:
+        FALLTHROUGH;
       case memory_instrumentation::mojom::ProcessType::OTHER:
         break;
     }
diff --git a/chrome/browser/metrics/process_memory_metrics_emitter_unittest.cc b/chrome/browser/metrics/process_memory_metrics_emitter_unittest.cc
index 19d72c2d..77efa283 100644
--- a/chrome/browser/metrics/process_memory_metrics_emitter_unittest.cc
+++ b/chrome/browser/metrics/process_memory_metrics_emitter_unittest.cc
@@ -426,6 +426,7 @@
       return;
     case ProcessType::PLUGIN:
     case ProcessType::OTHER:
+    case ProcessType::ARC:
       break;
   }
 
@@ -446,6 +447,7 @@
       return GetExpectedAudioServiceMetrics();
     case ProcessType::PLUGIN:
     case ProcessType::OTHER:
+    case ProcessType::ARC:
       break;
   }
 
diff --git a/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings.cc b/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings.cc
index c3e8243..a57f64d 100644
--- a/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings.cc
+++ b/chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings.cc
@@ -23,6 +23,7 @@
 #include "chrome/browser/previews/previews_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/common/channel_info.h"
 #include "chrome/common/pref_names.h"
 #include "components/data_reduction_proxy/content/browser/data_reduction_proxy_pingback_client_impl.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.h"
@@ -37,6 +38,7 @@
 #include "components/previews/content/previews_ui_service.h"
 #include "components/proxy_config/proxy_config_pref_names.h"
 #include "components/proxy_config/proxy_prefs.h"
+#include "components/version_info/version_info.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/network_service_instance.h"
@@ -223,11 +225,13 @@
           std::move(store),
           std::make_unique<
               data_reduction_proxy::DataReductionProxyPingbackClientImpl>(
-              url_loader_factory, ui_task_runner),
+              url_loader_factory, ui_task_runner,
+              version_info::GetChannelString(chrome::GetChannel())),
           g_browser_process->network_quality_tracker(),
           content::GetNetworkConnectionTracker(),
-          g_browser_process->data_use_measurement(), ui_task_runner,
-          io_data->io_task_runner(), db_task_runner, commit_delay);
+          data_use_measurement::ChromeDataUseMeasurement::GetInstance(),
+          ui_task_runner, io_data->io_task_runner(), db_task_runner,
+          commit_delay);
   data_reduction_proxy::DataReductionProxySettings::
       InitDataReductionProxySettings(data_reduction_proxy_enabled_pref_name_,
                                      profile_prefs, io_data,
diff --git a/chrome/browser/page_load_metrics/observers/data_reduction_proxy_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/data_reduction_proxy_metrics_observer_unittest.cc
index ebb0e41f7..171c1deb 100644
--- a/chrome/browser/page_load_metrics/observers/data_reduction_proxy_metrics_observer_unittest.cc
+++ b/chrome/browser/page_load_metrics/observers/data_reduction_proxy_metrics_observer_unittest.cc
@@ -79,7 +79,8 @@
   TestPingbackClient()
       : data_reduction_proxy::DataReductionProxyPingbackClientImpl(
             nullptr,
-            base::ThreadTaskRunnerHandle::Get()),
+            base::ThreadTaskRunnerHandle::Get(),
+            "unknown"),
         send_pingback_called_(false) {}
   ~TestPingbackClient() override {}
 
diff --git a/chrome/browser/performance_monitor/performance_monitor.cc b/chrome/browser/performance_monitor/performance_monitor.cc
index 3da1b8fc..d96a9be5 100644
--- a/chrome/browser/performance_monitor/performance_monitor.cc
+++ b/chrome/browser/performance_monitor/performance_monitor.cc
@@ -152,7 +152,7 @@
   // See https://crbug.com/821453.
   for (content::BrowserChildProcessHostIterator iter; !iter.Done(); ++iter) {
     ProcessMetricsMetadata child_process_data;
-    child_process_data.handle = iter.GetData().GetHandle();
+    child_process_data.handle = iter.GetData().GetProcess().Handle();
     child_process_data.process_type = iter.GetData().process_type;
 
     if (iter.GetData().name == base::ASCIIToUTF16(content::kFlashPluginName)) {
diff --git a/chrome/browser/printing/print_job_unittest.cc b/chrome/browser/printing/print_job_unittest.cc
index 34222c6..b7e7909 100644
--- a/chrome/browser/printing/print_job_unittest.cc
+++ b/chrome/browser/printing/print_job_unittest.cc
@@ -128,7 +128,6 @@
   job->Observe();
   job->GetSettingsDone();
   job->DetachWorker();
-  job->message_loop();
   job->settings();
   job->cookie();
   job->GetSettings(DEFAULTS, ASK_USER, nullptr);
diff --git a/chrome/browser/process_singleton_browsertest.cc b/chrome/browser/process_singleton_browsertest.cc
index ac8aa37..8913fd7c7 100644
--- a/chrome/browser/process_singleton_browsertest.cc
+++ b/chrome/browser/process_singleton_browsertest.cc
@@ -257,8 +257,7 @@
       chrome_starters_[i]->Reset();
 
       ASSERT_TRUE(chrome_starter_threads_[i]->IsRunning());
-      ASSERT_NE(static_cast<base::MessageLoop*>(NULL),
-                chrome_starter_threads_[i]->message_loop());
+      ASSERT_TRUE(chrome_starter_threads_[i]->task_runner());
 
       chrome_starter_threads_[i]->task_runner()->PostTask(
           FROM_HERE,
diff --git a/chrome/browser/profiling_host/background_profiling_triggers.cc b/chrome/browser/profiling_host/background_profiling_triggers.cc
index 6c5b5f48..b2ceeb4b 100644
--- a/chrome/browser/profiling_host/background_profiling_triggers.cc
+++ b/chrome/browser/profiling_host/background_profiling_triggers.cc
@@ -70,6 +70,7 @@
     case ProcessType::PLUGIN:
       return content::ProcessType::PROCESS_TYPE_PLUGIN_DEPRECATED;
 
+    case ProcessType::ARC:
     case ProcessType::OTHER:
       return content::ProcessType::PROCESS_TYPE_UNKNOWN;
   }
diff --git a/chrome/browser/resource_coordinator/browser_child_process_watcher.cc b/chrome/browser/resource_coordinator/browser_child_process_watcher.cc
index bb5e7866..abaca7b 100644
--- a/chrome/browser/resource_coordinator/browser_child_process_watcher.cc
+++ b/chrome/browser/resource_coordinator/browser_child_process_watcher.cc
@@ -28,8 +28,7 @@
             content::ServiceManagerConnection::GetForProcess()->GetConnector());
 
     gpu_process_resource_coordinator_->SetLaunchTime(base::Time::Now());
-    gpu_process_resource_coordinator_->SetPID(
-        base::GetProcId(data.GetHandle()));
+    gpu_process_resource_coordinator_->SetPID(data.GetProcess().Pid());
   }
 }
 
diff --git a/chrome/browser/resources/print_preview/BUILD.gn b/chrome/browser/resources/print_preview/BUILD.gn
index e553670..530db732 100644
--- a/chrome/browser/resources/print_preview/BUILD.gn
+++ b/chrome/browser/resources/print_preview/BUILD.gn
@@ -63,7 +63,7 @@
 
 js_type_check("print_preview_resources") {
   deps = [
-    ":cloud_print_interface",
+    ":cloud_print_interface_js",
     ":metrics",
     ":native_layer",
     ":print_preview",
@@ -88,7 +88,7 @@
   ]
 
   sources = [
-    "cloud_print_interface.js",
+    "cloud_print_interface_js.js",
     "common/overlay.js",
     "common/search_box.js",
     "common/search_bubble.js",
@@ -186,7 +186,7 @@
 js_library("print_preview_focus_manager") {
 }
 
-js_library("cloud_print_interface") {
+js_library("cloud_print_interface_js") {
   deps = [
     ":native_layer",
     "data:cloud_parsers",
diff --git a/chrome/browser/resources/print_preview/cloud_print_interface.html b/chrome/browser/resources/print_preview/cloud_print_interface_js.html
similarity index 86%
rename from chrome/browser/resources/print_preview/cloud_print_interface.html
rename to chrome/browser/resources/print_preview/cloud_print_interface_js.html
index 9997dacb..dbef550 100644
--- a/chrome/browser/resources/print_preview/cloud_print_interface.html
+++ b/chrome/browser/resources/print_preview/cloud_print_interface_js.html
@@ -6,4 +6,4 @@
 <link rel="import" href="data/invitation.html">
 <link rel="import" href="data/user_info.html">
 
-<script src="cloud_print_interface.js"></script>
+<script src="cloud_print_interface_js.js"></script>
diff --git a/chrome/browser/resources/print_preview/cloud_print_interface.js b/chrome/browser/resources/print_preview/cloud_print_interface_js.js
similarity index 98%
rename from chrome/browser/resources/print_preview/cloud_print_interface.js
rename to chrome/browser/resources/print_preview/cloud_print_interface_js.js
index ecf7126c..61bbe2a 100644
--- a/chrome/browser/resources/print_preview/cloud_print_interface.js
+++ b/chrome/browser/resources/print_preview/cloud_print_interface_js.js
@@ -26,7 +26,7 @@
 
   const CloudPrintInterfaceEventType = cloudprint.CloudPrintInterfaceEventType;
 
-  class CloudPrintInterface extends cr.EventTarget {
+  class CloudPrintInterfaceJS extends cr.EventTarget {
     /**
      * API to the Google Cloud Print service.
      * @param {string} baseUrl Base part of the Google Cloud Print service URL
@@ -403,8 +403,7 @@
     onAccessTokenReady_(request, accessToken) {
       assert(request.origin == print_preview.DestinationOrigin.DEVICE);
       if (accessToken) {
-        request.xhr.setRequestHeader(
-            'Authorization', 'Bearer ' + accessToken);
+        request.xhr.setRequestHeader('Authorization', 'Bearer ' + accessToken);
         this.sendRequest_(request);
       } else {  // No valid token.
         // Without abort status does not exist.
@@ -745,7 +744,7 @@
 
   // Export
   return {
-    CloudPrintInterface: CloudPrintInterface,
+    CloudPrintInterfaceJS: CloudPrintInterfaceJS,
     CloudPrintRequest: CloudPrintRequest,
   };
 });
diff --git a/chrome/browser/resources/print_preview/data/BUILD.gn b/chrome/browser/resources/print_preview/data/BUILD.gn
index a93e13c..5923349f 100644
--- a/chrome/browser/resources/print_preview/data/BUILD.gn
+++ b/chrome/browser/resources/print_preview/data/BUILD.gn
@@ -29,7 +29,7 @@
     ":destination_match",
     ":local_parsers",
     ":user_info",
-    "..:cloud_print_interface",
+    "..:cloud_print_interface_js",
     "..:metrics",
     "..:native_layer",
     "//ui/webui/resources/js:cr",
@@ -43,7 +43,7 @@
   deps = [
     ":invitation",
     ":user_info",
-    "..:cloud_print_interface",
+    "..:cloud_print_interface_js",
     "//ui/webui/resources/js:event_tracker",
     "//ui/webui/resources/js/cr:event_target",
   ]
diff --git a/chrome/browser/resources/print_preview/data/destination_store.html b/chrome/browser/resources/print_preview/data/destination_store.html
index 67f7dbc6..2ff0254 100644
--- a/chrome/browser/resources/print_preview/data/destination_store.html
+++ b/chrome/browser/resources/print_preview/data/destination_store.html
@@ -1,4 +1,5 @@
 <link rel="import" href="chrome://resources/html/cr.html">
+<link rel="import" href="../cloud_print_interface_js.html">
 <link rel="import" href="../metrics.html">
 <link rel="import" href="../native_layer.html">
 <link rel="import" href="destination.html">
diff --git a/chrome/browser/resources/print_preview/data/destination_store.js b/chrome/browser/resources/print_preview/data/destination_store.js
index 7ad063d9..b087762 100644
--- a/chrome/browser/resources/print_preview/data/destination_store.js
+++ b/chrome/browser/resources/print_preview/data/destination_store.js
@@ -196,7 +196,7 @@
 
       /**
        * Used to fetch cloud-based print destinations.
-       * @private {cloudprint.CloudPrintInterface}
+       * @private {cloudprint.CloudPrintInterfaceJS}
        */
       this.cloudPrintInterface_ = null;
 
@@ -643,7 +643,7 @@
 
     /**
      * Sets the destination store's Google Cloud Print interface.
-     * @param {!cloudprint.CloudPrintInterface} cloudPrintInterface Interface
+     * @param {!cloudprint.CloudPrintInterfaceJS} cloudPrintInterface Interface
      *     to set.
      */
     setCloudPrintInterface(cloudPrintInterface) {
diff --git a/chrome/browser/resources/print_preview/data/invitation_store.html b/chrome/browser/resources/print_preview/data/invitation_store.html
index ce123196..a5270f7 100644
--- a/chrome/browser/resources/print_preview/data/invitation_store.html
+++ b/chrome/browser/resources/print_preview/data/invitation_store.html
@@ -2,6 +2,6 @@
 <link rel="import" href="chrome://resources/html/event_tracker.html">
 <link rel="import" href="invitation.html">
 <link rel="import" href="user_info.html">
-<link rel="import" href="../cloud_print_interface.html">
+<link rel="import" href="../cloud_print_interface_js.html">
 
 <script src="invitation_store.js"></script>
diff --git a/chrome/browser/resources/print_preview/data/invitation_store.js b/chrome/browser/resources/print_preview/data/invitation_store.js
index 72ed084..4e05c52 100644
--- a/chrome/browser/resources/print_preview/data/invitation_store.js
+++ b/chrome/browser/resources/print_preview/data/invitation_store.js
@@ -52,7 +52,7 @@
 
       /**
        * Used to fetch and process invitations.
-       * @private {cloudprint.CloudPrintInterface}
+       * @private {cloudprint.CloudPrintInterfaceJS}
        */
       this.cloudPrintInterface_ = null;
 
@@ -83,7 +83,7 @@
 
     /**
      * Sets the invitation store's Google Cloud Print interface.
-     * @param {!cloudprint.CloudPrintInterface} cloudPrintInterface Interface
+     * @param {!cloudprint.CloudPrintInterfaceJS} cloudPrintInterface Interface
      *     to set.
      */
     setCloudPrintInterface(cloudPrintInterface) {
diff --git a/chrome/browser/resources/print_preview/new/BUILD.gn b/chrome/browser/resources/print_preview/new/BUILD.gn
index d10860b..a507411d 100644
--- a/chrome/browser/resources/print_preview/new/BUILD.gn
+++ b/chrome/browser/resources/print_preview/new/BUILD.gn
@@ -63,7 +63,7 @@
     ":preview_area",
     ":scaling_settings",
     ":state",
-    "..:cloud_print_interface",
+    "..:cloud_print_interface_js",
     "..:metrics",
     "..:native_layer",
     "../data:destination",
diff --git a/chrome/browser/resources/print_preview/new/app.html b/chrome/browser/resources/print_preview/new/app.html
index c89d234..1a54672 100644
--- a/chrome/browser/resources/print_preview/new/app.html
+++ b/chrome/browser/resources/print_preview/new/app.html
@@ -9,7 +9,7 @@
 <link rel="import" href="chrome://resources/html/util.html">
 <link rel="import" href="chrome://resources/html/webui_listener_tracker.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-collapse/iron-collapse.html">
-<link rel="import" href="../cloud_print_interface.html">
+<link rel="import" href="../cloud_print_interface_js.html">
 <link rel="import" href="../metrics.html">
 <link rel="import" href="../native_layer.html">
 <link rel="import" href="../data/destination.html">
diff --git a/chrome/browser/resources/print_preview/new/app.js b/chrome/browser/resources/print_preview/new/app.js
index 101be90..943b3ff0 100644
--- a/chrome/browser/resources/print_preview/new/app.js
+++ b/chrome/browser/resources/print_preview/new/app.js
@@ -148,7 +148,7 @@
   /** @private {?print_preview.NativeLayer} */
   nativeLayer_: null,
 
-  /** @private {?cloudprint.CloudPrintInterface} */
+  /** @private {?cloudprint.CloudPrintInterfaceJS} */
   cloudPrintInterface_: null,
 
   /** @private {!EventTracker} */
@@ -367,7 +367,7 @@
    */
   onCloudPrintEnable_: function(cloudPrintUrl, appKioskMode) {
     assert(!this.cloudPrintInterface_);
-    this.cloudPrintInterface_ = new cloudprint.CloudPrintInterface(
+    this.cloudPrintInterface_ = new cloudprint.CloudPrintInterfaceJS(
         cloudPrintUrl, assert(this.nativeLayer_), assert(this.userInfo_),
         appKioskMode);
     this.tracker_.add(
diff --git a/chrome/browser/resources/print_preview/print_preview.js b/chrome/browser/resources/print_preview/print_preview.js
index 74dc6c0..8242f5b 100644
--- a/chrome/browser/resources/print_preview/print_preview.js
+++ b/chrome/browser/resources/print_preview/print_preview.js
@@ -258,7 +258,7 @@
     /**
      * Interface to the Google Cloud Print API. Null if Google Cloud Print
      * integration is disabled.
-     * @type {cloudprint.CloudPrintInterface}
+     * @type {cloudprint.CloudPrintInterfaceJS}
      * @private
      */
     this.cloudPrintInterface_ = null;
@@ -761,7 +761,7 @@
      * @private
      */
     onCloudPrintEnable_: function(cloudPrintUrl, appKioskMode) {
-      this.cloudPrintInterface_ = new cloudprint.CloudPrintInterface(
+      this.cloudPrintInterface_ = new cloudprint.CloudPrintInterfaceJS(
           cloudPrintUrl, this.nativeLayer_, this.userInfo_, appKioskMode);
       this.tracker.add(
           this.cloudPrintInterface_,
@@ -1387,7 +1387,7 @@
 
 // <include src="native_layer.js">
 // <include src="print_preview_animations.js">
-// <include src="cloud_print_interface.js">
+// <include src="cloud_print_interface_js.js">
 // <include src="print_preview_utils.js">
 // <include src="print_header.js">
 // <include src="metrics.js">
diff --git a/chrome/browser/resources/print_preview/print_preview_resources.grd b/chrome/browser/resources/print_preview/print_preview_resources.grd
index 71763bd..eaac745 100644
--- a/chrome/browser/resources/print_preview/print_preview_resources.grd
+++ b/chrome/browser/resources/print_preview/print_preview_resources.grd
@@ -30,11 +30,11 @@
       <structure name="IDR_PRINT_PREVIEW_NEW_MODEL_JS"
                  file="new/model.js"
                  type="chrome_html" />
-      <structure name="IDR_PRINT_PREVIEW_CLOUD_PRINT_INTERFACE_HTML"
-                 file="cloud_print_interface.html"
+      <structure name="IDR_PRINT_PREVIEW_CLOUD_PRINT_INTERFACE_JS_HTML"
+                 file="cloud_print_interface_js.html"
                  type="chrome_html" />
-      <structure name="IDR_PRINT_PREVIEW_CLOUD_PRINT_INTERFACE_JS"
-                 file="cloud_print_interface.js"
+      <structure name="IDR_PRINT_PREVIEW_CLOUD_PRINT_INTERFACE_JS_JS"
+                 file="cloud_print_interface_js.js"
                  type="chrome_html" />
       <structure name="IDR_PRINT_PREVIEW_NATIVE_LAYER_HTML"
                  file="native_layer.html"
diff --git a/chrome/browser/resources/settings/downloads_page/downloads_page.html b/chrome/browser/resources/settings/downloads_page/downloads_page.html
index b2b2be9..3557cf1 100644
--- a/chrome/browser/resources/settings/downloads_page/downloads_page.html
+++ b/chrome/browser/resources/settings/downloads_page/downloads_page.html
@@ -52,15 +52,13 @@
           label="$i18n{disconnectGoogleDriveAccount}"
           hidden="[[!pageVisibility.googleDrive]]">
       </settings-toggle-button>
-      <template is="dom-if" if="[[enableSmbSettings_]]">
-        <div id="smbShares" class="settings-box"
-            on-click="onTapSmbShares_" actionable>
-          <div class="start"> $i18n{smbSharesTitle} </div>
-          <paper-icon-button-light class="subpage-arrow">
-            <button aria-label="$i18n{smbSharesTitle}"></button>
-          </paper-icon-button-light>
-        </div>
-      </template>
+      <div id="smbShares" class="settings-box"
+          on-click="onTapSmbShares_" actionable>
+        <div class="start"> $i18n{smbSharesTitle} </div>
+        <paper-icon-button-light class="subpage-arrow">
+          <button aria-label="$i18n{smbSharesTitle}"></button>
+        </paper-icon-button-light>
+      </div>
 </if>
       <template is="dom-if" if="[[autoOpenDownloads_]]" restamp>
         <div class="settings-box">
@@ -77,15 +75,13 @@
     </neon-animatable>
 
 <if expr="chromeos">
-    <template is="dom-if" if="[[enableSmbSettings_]]">
-      <template is="dom-if" route-path="/smbShares">
-        <settings-subpage
-            associated-control="[[$$('#smbShares')]]"
-            page-title="$i18n{smbSharesTitle}">
-          <settings-smb-shares-page prefs="[[prefs]]">
-          </settings-smb-shares-page>
-        </settings-subpage>
-      </template>
+    <template is="dom-if" route-path="/smbShares">
+      <settings-subpage
+          associated-control="[[$$('#smbShares')]]"
+          page-title="$i18n{smbSharesTitle}">
+        <settings-smb-shares-page prefs="[[prefs]]">
+        </settings-smb-shares-page>
+      </settings-subpage>
     </template>
 </if>
   </settings-animated-pages>
diff --git a/chrome/browser/resources/settings/downloads_page/downloads_page.js b/chrome/browser/resources/settings/downloads_page/downloads_page.js
index 11c89e7c..7ed19e8 100644
--- a/chrome/browser/resources/settings/downloads_page/downloads_page.js
+++ b/chrome/browser/resources/settings/downloads_page/downloads_page.js
@@ -43,18 +43,6 @@
 
     // <if expr="chromeos">
     /**
-     * Whether Smb Shares settings should be fetched and displayed.
-     * @private
-     */
-    enableSmbSettings_: {
-      type: Boolean,
-      value: function() {
-        return loadTimeData.getBoolean('enableNativeSmbSetting');
-      },
-      readOnly: true,
-    },
-
-    /**
      * The download location string that is suitable to display in the UI.
      */
     downloadLocation_: String,
diff --git a/chrome/browser/resources/settings/people_page/BUILD.gn b/chrome/browser/resources/settings/people_page/BUILD.gn
index ba5fd55..6297d7a 100644
--- a/chrome/browser/resources/settings/people_page/BUILD.gn
+++ b/chrome/browser/resources/settings/people_page/BUILD.gn
@@ -11,7 +11,6 @@
     ":change_picture",
     ":change_picture_browser_proxy",
     ":easy_unlock_browser_proxy",
-    ":easy_unlock_turn_off_dialog",
     ":fingerprint_browser_proxy",
     ":fingerprint_list",
     ":import_data_browser_proxy",
@@ -78,16 +77,6 @@
   ]
 }
 
-js_library("easy_unlock_turn_off_dialog") {
-  deps = [
-    ":easy_unlock_browser_proxy",
-    "//ui/webui/resources/cr_elements/cr_dialog:cr_dialog",
-    "//ui/webui/resources/js:cr",
-    "//ui/webui/resources/js:i18n_behavior",
-    "//ui/webui/resources/js:web_ui_listener_behavior",
-  ]
-}
-
 js_library("fingerprint_browser_proxy") {
   deps = [
     "//ui/webui/resources/js:cr",
@@ -118,7 +107,6 @@
 js_library("lock_screen") {
   deps = [
     ":easy_unlock_browser_proxy",
-    ":easy_unlock_turn_off_dialog",
     ":fingerprint_browser_proxy",
     ":lock_screen_password_prompt_dialog",
     ":lock_state_behavior",
diff --git a/chrome/browser/resources/settings/people_page/easy_unlock_browser_proxy.js b/chrome/browser/resources/settings/people_page/easy_unlock_browser_proxy.js
index 0820a032..e0b47c7 100644
--- a/chrome/browser/resources/settings/people_page/easy_unlock_browser_proxy.js
+++ b/chrome/browser/resources/settings/people_page/easy_unlock_browser_proxy.js
@@ -16,22 +16,6 @@
      * @return {!Promise<boolean>}
      */
     getEnabledStatus() {}
-
-    /**
-     * Returns the Easy Unlock turn off flow status.
-     * @return {!Promise<string>}
-     */
-    getTurnOffFlowStatus() {}
-
-    /**
-     * Begins the Easy Unlock turn off flow.
-     */
-    startTurnOffFlow() {}
-
-    /**
-     * Cancels any in-progress Easy Unlock turn-off flows.
-     */
-    cancelTurnOffFlow() {}
   }
 
   /**
@@ -42,21 +26,6 @@
     getEnabledStatus() {
       return cr.sendWithPromise('easyUnlockGetEnabledStatus');
     }
-
-    /** @override */
-    getTurnOffFlowStatus() {
-      return cr.sendWithPromise('easyUnlockGetTurnOffFlowStatus');
-    }
-
-    /** @override */
-    startTurnOffFlow() {
-      chrome.send('easyUnlockStartTurnOffFlow');
-    }
-
-    /** @override */
-    cancelTurnOffFlow() {
-      chrome.send('easyUnlockCancelTurnOffFlow');
-    }
   }
 
   // The singleton instance_ is replaced with a test version of this wrapper
diff --git a/chrome/browser/resources/settings/people_page/easy_unlock_turn_off_dialog.html b/chrome/browser/resources/settings/people_page/easy_unlock_turn_off_dialog.html
deleted file mode 100644
index df78b847..0000000
--- a/chrome/browser/resources/settings/people_page/easy_unlock_turn_off_dialog.html
+++ /dev/null
@@ -1,37 +0,0 @@
-<link rel="import" href="chrome://resources/html/polymer.html">
-
-<link rel="import" href="chrome://resources/cr_elements/cr_dialog/cr_dialog.html">
-<link rel="import" href="chrome://resources/html/i18n_behavior.html">
-<link rel="import" href="chrome://resources/html/web_ui_listener_behavior.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-spinner/paper-spinner-lite.html">
-<link rel="import" href="../i18n_setup.html">
-<link rel="import" href="easy_unlock_browser_proxy.html">
-<link rel="import" href="../settings_shared_css.html">
-
-<dom-module id="easy-unlock-turn-off-dialog">
-  <template>
-    <style include="settings-shared"></style>
-    <cr-dialog id="dialog" close-text="$i18n{close}">
-      <div slot="title">[[getTitleText_(status_)]]</div>
-      <div slot="body">
-        [[getDescriptionText_(status_)]]
-      </div>
-      <div slot="button-container"
-          hidden="[[isButtonBarHidden_(status_)]]">
-        <paper-spinner-lite active="[[isSpinnerActive_(status_)]]">
-        </paper-spinner-lite>
-        <paper-button class="cancel-button" on-click="onCancelTap_"
-            hidden="[[isCancelButtonHidden_(status_)]]">
-          $i18n{cancel}
-        </paper-button>
-        <paper-button id="turnOff" class="action-button"
-            on-click="onTurnOffTap_"
-            disabled="[[!isTurnOffButtonEnabled_(status_)]]">
-          [[getTurnOffButtonText_(status_)]]
-        </paper-button>
-      </div>
-    </cr-dialog>
-  </template>
-  <script src="easy_unlock_turn_off_dialog.js"></script>
-</dom-module>
diff --git a/chrome/browser/resources/settings/people_page/easy_unlock_turn_off_dialog.js b/chrome/browser/resources/settings/people_page/easy_unlock_turn_off_dialog.js
deleted file mode 100644
index 1e4ad8f..0000000
--- a/chrome/browser/resources/settings/people_page/easy_unlock_turn_off_dialog.js
+++ /dev/null
@@ -1,191 +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.
-
-/**
- * @fileoverview A dialog allowing the user to turn off the Easy Unlock feature.
- */
-
-cr.exportPath('settings');
-
-/**
- * Possible UI statuses for the EasyUnlockTurnOffDialogElement.
- * See easy_unlock_settings_handler.cc.
- * @enum {string}
- */
-settings.EasyUnlockTurnOffStatus = {
-  UNKNOWN: 'unknown',
-  OFFLINE: 'offline',
-  IDLE: 'idle',
-  PENDING: 'pending',
-  SERVER_ERROR: 'server-error',
-};
-
-(function() {
-
-Polymer({
-  is: 'easy-unlock-turn-off-dialog',
-
-  behaviors: [I18nBehavior, WebUIListenerBehavior],
-
-  properties: {
-    /** @private {!settings.EasyUnlockTurnOffStatus} */
-    status_: {
-      type: String,
-      value: settings.EasyUnlockTurnOffStatus.UNKNOWN,
-    },
-  },
-
-  /** @private {settings.EasyUnlockBrowserProxy} */
-  browserProxy_: null,
-
-  /** @override */
-  attached: function() {
-    this.browserProxy_ = settings.EasyUnlockBrowserProxyImpl.getInstance();
-
-    this.addWebUIListener(
-        'easy-unlock-enabled-status',
-        this.handleEasyUnlockEnabledStatusChanged_.bind(this));
-
-    this.addWebUIListener('easy-unlock-turn-off-flow-status', status => {
-      this.status_ = status;
-    });
-
-    // Since the dialog text depends on the status, defer opening until we have
-    // retrieved the turn off status to prevent UI flicker.
-    this.getTurnOffStatus_().then(status => {
-      this.status_ = status;
-      this.$.dialog.showModal();
-    });
-  },
-
-  /**
-   * @return {!Promise<!settings.EasyUnlockTurnOffStatus>}
-   * @private
-   */
-  getTurnOffStatus_: function() {
-    return navigator.onLine ?
-        this.browserProxy_.getTurnOffFlowStatus() :
-        Promise.resolve(settings.EasyUnlockTurnOffStatus.OFFLINE);
-  },
-
-  /**
-   * This dialog listens for Easy Unlock to become disabled. This signals
-   * that the turnoff process has succeeded. Regardless of whether the turnoff
-   * was initiated from this tab or another, this closes the dialog.
-   * @param {boolean} easyUnlockEnabled
-   * @private
-   */
-  handleEasyUnlockEnabledStatusChanged_: function(easyUnlockEnabled) {
-    const dialog = /** @type {!CrDialogElement} */ (this.$.dialog);
-    if (!easyUnlockEnabled && dialog.open)
-      this.onCancelTap_();
-  },
-
-  /** @private */
-  onCancelTap_: function() {
-    this.browserProxy_.cancelTurnOffFlow();
-    this.$.dialog.close();
-  },
-
-  /** @private */
-  onTurnOffTap_: function() {
-    this.browserProxy_.startTurnOffFlow();
-  },
-
-  /**
-   * @param {!settings.EasyUnlockTurnOffStatus} status
-   * @return {string}
-   * @private
-   */
-  getTitleText_: function(status) {
-    switch (status) {
-      case settings.EasyUnlockTurnOffStatus.OFFLINE:
-        return this.i18n('easyUnlockTurnOffOfflineTitle');
-      case settings.EasyUnlockTurnOffStatus.UNKNOWN:
-      case settings.EasyUnlockTurnOffStatus.IDLE:
-      case settings.EasyUnlockTurnOffStatus.PENDING:
-        return this.i18n('easyUnlockTurnOffTitle');
-      case settings.EasyUnlockTurnOffStatus.SERVER_ERROR:
-        return this.i18n('easyUnlockTurnOffErrorTitle');
-    }
-    assertNotReached();
-  },
-
-  /**
-   * @param {!settings.EasyUnlockTurnOffStatus} status
-   * @return {string}
-   * @private
-   */
-  getDescriptionText_: function(status) {
-    switch (status) {
-      case settings.EasyUnlockTurnOffStatus.OFFLINE:
-        return this.i18n('easyUnlockTurnOffOfflineMessage');
-      case settings.EasyUnlockTurnOffStatus.UNKNOWN:
-      case settings.EasyUnlockTurnOffStatus.IDLE:
-      case settings.EasyUnlockTurnOffStatus.PENDING:
-        return this.i18n('easyUnlockTurnOffDescription');
-      case settings.EasyUnlockTurnOffStatus.SERVER_ERROR:
-        return this.i18n('easyUnlockTurnOffErrorMessage');
-    }
-    assertNotReached();
-  },
-
-  /**
-   * @param {!settings.EasyUnlockTurnOffStatus} status
-   * @return {string}
-   * @private
-   */
-  getTurnOffButtonText_: function(status) {
-    switch (status) {
-      case settings.EasyUnlockTurnOffStatus.OFFLINE:
-        return '';
-      case settings.EasyUnlockTurnOffStatus.UNKNOWN:
-      case settings.EasyUnlockTurnOffStatus.IDLE:
-      case settings.EasyUnlockTurnOffStatus.PENDING:
-        return this.i18n('easyUnlockTurnOffButton');
-      case settings.EasyUnlockTurnOffStatus.SERVER_ERROR:
-        return this.i18n('retry');
-    }
-    assertNotReached();
-  },
-
-  /**
-   * @param {!settings.EasyUnlockTurnOffStatus} status
-   * @return {boolean}
-   * @private
-   */
-  isButtonBarHidden_: function(status) {
-    return status == settings.EasyUnlockTurnOffStatus.OFFLINE;
-  },
-
-  /**
-   * @param {!settings.EasyUnlockTurnOffStatus} status
-   * @return {boolean}
-   * @private
-   */
-  isSpinnerActive_: function(status) {
-    return status == settings.EasyUnlockTurnOffStatus.PENDING;
-  },
-
-  /**
-   * @param {!settings.EasyUnlockTurnOffStatus} status
-   * @return {boolean}
-   * @private
-   */
-  isCancelButtonHidden_: function(status) {
-    return status == settings.EasyUnlockTurnOffStatus.SERVER_ERROR;
-  },
-
-  /**
-   * @param {!settings.EasyUnlockTurnOffStatus} status
-   * @return {boolean}
-   * @private
-   */
-  isTurnOffButtonEnabled_: function(status) {
-    return status == settings.EasyUnlockTurnOffStatus.IDLE ||
-        status == settings.EasyUnlockTurnOffStatus.SERVER_ERROR;
-  },
-});
-
-})();
diff --git a/chrome/browser/resources/settings/people_page/lock_screen.html b/chrome/browser/resources/settings/people_page/lock_screen.html
index e7269ad..d863d6cc 100644
--- a/chrome/browser/resources/settings/people_page/lock_screen.html
+++ b/chrome/browser/resources/settings/people_page/lock_screen.html
@@ -10,7 +10,6 @@
 <link rel="import" href="chrome://resources/html/web_ui_listener_behavior.html">
 <link rel="import" href="../controls/settings_toggle_button.html">
 <link rel="import" href="easy_unlock_browser_proxy.html">
-<link rel="import" href="easy_unlock_turn_off_dialog.html">
 <link rel="import" href="fingerprint_browser_proxy.html">
 <link rel="import" href="lock_state_behavior.html">
 <link rel="import" href="lock_screen_password_prompt_dialog.html">
@@ -187,17 +186,6 @@
               </a>
             </div>
           </div>
-          <template is="dom-if" if="[[easyUnlockAvailable_(
-          multideviceSettingsEnabled_, easyUnlockAllowed_,
-          easyUnlockInLegacyHostMode_)]]">
-            <div class="separator"></div>
-            <template is="dom-if" if="[[easyUnlockEnabled_]]">
-              <paper-button id="easyUnlockTurnOff" class="secondary-button"
-                  on-click="onEasyUnlockTurnOffTap_">
-                $i18n{easyUnlockTurnOffButton}
-              </paper-button>
-            </template>
-          </template>
         </div>
         <iron-collapse opened="[[easyUnlockEnabled_]]"
             id="easyUnlockSettingsCollapsible">
@@ -231,12 +219,6 @@
             on-close="onSetupPinDialogClose_">
         </settings-setup-pin-dialog>
       </template>
-
-      <template is="dom-if" if="[[showEasyUnlockTurnOffDialog_]]" restamp>
-        <easy-unlock-turn-off-dialog id="easyUnlockTurnOffDialog"
-            on-close="onEasyUnlockTurnOffDialogClose_">
-        </easy-unlock-turn-off-dialog>
-      </template>
     </div>
   </template>
 
diff --git a/chrome/browser/resources/settings/people_page/lock_screen.js b/chrome/browser/resources/settings/people_page/lock_screen.js
index 0608e43..d4d6f36ae 100644
--- a/chrome/browser/resources/settings/people_page/lock_screen.js
+++ b/chrome/browser/resources/settings/people_page/lock_screen.js
@@ -214,12 +214,6 @@
     },
 
     /** @private */
-    showEasyUnlockTurnOffDialog_: {
-      type: Boolean,
-      value: false,
-    },
-
-    /** @private */
     showPasswordPromptDialog_: Boolean,
 
     /** @private */
@@ -401,28 +395,6 @@
    */
   handleEasyUnlockEnabledStatusChanged_: function(easyUnlockEnabled) {
     this.easyUnlockEnabled_ = easyUnlockEnabled;
-    this.showEasyUnlockTurnOffDialog_ =
-        easyUnlockEnabled && this.showEasyUnlockTurnOffDialog_;
-  },
-
-  /**
-   * @param {!Event} e
-   * @private
-   */
-  onEasyUnlockTurnOffTap_: function(e) {
-    // Prevent the end of the tap event from focusing what is underneath the
-    // button.
-    e.preventDefault();
-    this.showEasyUnlockTurnOffDialog_ = true;
-  },
-
-  /** @private */
-  onEasyUnlockTurnOffDialogClose_: function() {
-    this.showEasyUnlockTurnOffDialog_ = false;
-
-    // Restores focus on close to either the turn-off or set-up button,
-    // whichever is being displayed.
-    cr.ui.focusWithoutInk(assert(this.$$('.secondary-button')));
   },
 
   /**
diff --git a/chrome/browser/resources/settings/settings_resources.grd b/chrome/browser/resources/settings/settings_resources.grd
index bf6e6f9..9a7ff8b 100644
--- a/chrome/browser/resources/settings/settings_resources.grd
+++ b/chrome/browser/resources/settings/settings_resources.grd
@@ -1463,14 +1463,6 @@
                    type="chrome_html"
                    preprocess="true"
                    allowexternalscript="true" />
-        <structure name="IDR_SETTINGS_PEOPLE_EASY_UNLOCK_TURN_OFF_DIALOG_JS"
-                   file="people_page/easy_unlock_turn_off_dialog.js"
-                   type="chrome_html" />
-        <structure name="IDR_SETTINGS_PEOPLE_EASY_UNLOCK_TURN_OFF_DIALOG_HTML"
-                   file="people_page/easy_unlock_turn_off_dialog.html"
-                   type="chrome_html"
-                   preprocess="true"
-                   allowexternalscript="true" />
         <structure name="IDR_SETTINGS_PEOPLE_LOCK_SCREEN_PASSWORD_PROMPT_DIALOG_JS"
                    file="people_page/lock_screen_password_prompt_dialog.js"
                    type="chrome_html" />
diff --git a/chrome/browser/resources/welcome/onboarding_welcome/google_apps/BUILD.gn b/chrome/browser/resources/welcome/onboarding_welcome/google_apps/BUILD.gn
index 45020388..edbcb37 100644
--- a/chrome/browser/resources/welcome/onboarding_welcome/google_apps/BUILD.gn
+++ b/chrome/browser/resources/welcome/onboarding_welcome/google_apps/BUILD.gn
@@ -14,7 +14,9 @@
 js_library("apps_chooser") {
   deps = [
     "../shared:bookmark_proxy",
+    "//third_party/polymer/v1_0/components-chromium/iron-a11y-announcer:iron-a11y-announcer-extracted",
     "//ui/webui/resources/js:cr",
+    "//ui/webui/resources/js:i18n_behavior",
   ]
 }
 
diff --git a/chrome/browser/resources/welcome/onboarding_welcome/google_apps/apps_chooser.html b/chrome/browser/resources/welcome/onboarding_welcome/google_apps/apps_chooser.html
index b347d8b..eb6edc6a 100644
--- a/chrome/browser/resources/welcome/onboarding_welcome/google_apps/apps_chooser.html
+++ b/chrome/browser/resources/welcome/onboarding_welcome/google_apps/apps_chooser.html
@@ -3,11 +3,13 @@
 <link rel="import" href="chrome://resources/cr_elements/icons.html">
 <link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html">
 <link rel="import" href="chrome://resources/html/cr.html">
+<link rel="import" href="chrome://resources/html/i18n_behavior.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-a11y-announcer/iron-a11y-announcer.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
 <link rel="import" href="chrome://welcome/google_apps/nux_google_apps_proxy.html">
-<link rel="import" href="chrome://welcome/shared/chooser_shared_css.html">
 <link rel="import" href="chrome://welcome/shared/bookmark_proxy.html">
+<link rel="import" href="chrome://welcome/shared/chooser_shared_css.html">
 
 <dom-module id="apps-chooser">
   <template>
diff --git a/chrome/browser/resources/welcome/onboarding_welcome/google_apps/apps_chooser.js b/chrome/browser/resources/welcome/onboarding_welcome/google_apps/apps_chooser.js
index 35842df70..7fc1497 100644
--- a/chrome/browser/resources/welcome/onboarding_welcome/google_apps/apps_chooser.js
+++ b/chrome/browser/resources/welcome/onboarding_welcome/google_apps/apps_chooser.js
@@ -27,6 +27,8 @@
 Polymer({
   is: 'apps-chooser',
 
+  behaviors: [I18nBehavior],
+
   properties: {
     /**
      * @type {!Array<!nuxGoogleApps.AppItem>}
@@ -50,6 +52,13 @@
   bookmarkProxy_: null,
 
   /** @override */
+  attached: function() {
+    Polymer.RenderStatus.afterNextRender(this, () => {
+      Polymer.IronA11yAnnouncer.requestAvailability();
+    });
+  },
+
+  /** @override */
   ready() {
     this.appsProxy_ = nux.NuxGoogleAppsProxyImpl.getInstance();
     this.bookmarkProxy_ = nux.BookmarkProxyImpl.getInstance();
@@ -65,19 +74,27 @@
           app.selected = true;
           this.updateBookmark(app);
         });
+        this.updateHasAppsSelected();
+        this.fire('iron-announce', {text: this.i18n('bookmarksAdded')});
       });
     }
   },
 
   /** Called when bookmarks should be removed for all selected apps. */
   removeAllBookmarks() {
+    let removedBookmarks = false;
     this.appList_.forEach(app => {
       if (app.selected) {
         app.selected = false;
         this.updateBookmark(app);
+        removedBookmarks = true;
       }
     });
-    this.updateHasAppsSelected();
+    // Only update and announce if we removed bookmarks.
+    if (removedBookmarks) {
+      this.updateHasAppsSelected();
+      this.fire('iron-announce', {text: this.i18n('bookmarksRemoved')});
+    }
   },
 
   /**
@@ -114,6 +131,12 @@
     e.model.set('item.selected', !item.selected);
     this.updateBookmark(item);
     this.updateHasAppsSelected();
+    // Announcements should NOT be in |updateBookmark| because there should be a
+    // different utterance when all app bookmarks are added/removed.
+    if (item.selected)
+      this.fire('iron-announce', {text: this.i18n('bookmarkAdded')});
+    else
+      this.fire('iron-announce', {text: this.i18n('bookmarkRemoved')});
   },
 
   /**
diff --git a/chrome/browser/sync/test/integration/single_client_directory_sync_test.cc b/chrome/browser/sync/test/integration/single_client_directory_sync_test.cc
index 033a7bdb..e27c07c 100644
--- a/chrome/browser/sync/test/integration/single_client_directory_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_directory_sync_test.cc
@@ -50,12 +50,13 @@
   DISALLOW_COPY_AND_ASSIGN(SingleClientDirectorySyncTest);
 };
 
-void WaitForExistingTasksOnLoop(base::MessageLoop* loop) {
+void WaitForExistingTasksOnTaskRunner(
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
   base::RunLoop run_loop;
   // Post a task to |loop| that will, in turn, post a task back to the current
   // sequenced task runner to quit the nested loop.
-  loop->task_runner()->PostTaskAndReply(FROM_HERE, base::DoNothing(),
-                                        run_loop.QuitClosure());
+  task_runner->PostTaskAndReply(FROM_HERE, base::DoNothing(),
+                                run_loop.QuitClosure());
   run_loop.Run();
 }
 
@@ -98,8 +99,8 @@
                                                 run_loop.QuitClosure());
   run_loop.Run();
   // Wait for the directory deletion to finish.
-  base::MessageLoop* sync_loop = sync_service->GetSyncLoopForTest();
-  WaitForExistingTasksOnLoop(sync_loop);
+  WaitForExistingTasksOnTaskRunner(
+      sync_service->GetSyncThreadTaskRunnerForTest());
   ASSERT_FALSE(FolderContainsFiles(directory_path));
 }
 
@@ -117,8 +118,9 @@
   // completes.
   browser_sync::ProfileSyncService* sync_service = GetSyncService(0);
   sync_service->FlushDirectory();
-  base::MessageLoop* sync_loop = sync_service->GetSyncLoopForTest();
-  WaitForExistingTasksOnLoop(sync_loop);
+  scoped_refptr<base::SingleThreadTaskRunner> sync_thread_task_runner =
+      sync_service->GetSyncThreadTaskRunnerForTest();
+  WaitForExistingTasksOnTaskRunner(sync_thread_task_runner);
 
   // Now corrupt the database.
   FilePath directory_path = sync_service->GetSyncClientForTest()
@@ -153,7 +155,7 @@
 
   // Wait until the sync loop has processed any existing tasks and see that the
   // directory no longer exists.
-  WaitForExistingTasksOnLoop(sync_loop);
+  WaitForExistingTasksOnTaskRunner(sync_thread_task_runner);
   ASSERT_FALSE(FolderContainsFiles(directory_path));
 }
 
diff --git a/chrome/browser/task_manager/providers/child_process_task.cc b/chrome/browser/task_manager/providers/child_process_task.cc
index ceca7132..dbe5390 100644
--- a/chrome/browser/task_manager/providers/child_process_task.cc
+++ b/chrome/browser/task_manager/providers/child_process_task.cc
@@ -159,7 +159,7 @@
     : Task(GetLocalizedTitle(data.name, data.process_type),
            base::UTF16ToUTF8(data.name),
            FetchIcon(IDR_PLUGINS_FAVICON, &s_icon_),
-           data.GetHandle()),
+           data.GetProcess().Handle()),
       process_resources_sampler_(CreateProcessResourcesSampler(data.id)),
       v8_memory_allocated_(-1),
       v8_memory_used_(-1),
diff --git a/chrome/browser/task_manager/providers/child_process_task_provider.cc b/chrome/browser/task_manager/providers/child_process_task_provider.cc
index 8c43a5f..b93c51a 100644
--- a/chrome/browser/task_manager/providers/child_process_task_provider.cc
+++ b/chrome/browser/task_manager/providers/child_process_task_provider.cc
@@ -33,7 +33,7 @@
     const ChildProcessData& process_data = itr.GetData();
 
     // Only add processes that have already started, i.e. with valid handles.
-    if (!process_data.IsHandleValid())
+    if (!process_data.GetProcess().IsValid())
       continue;
 
     child_processes->push_back(process_data.Duplicate());
@@ -64,7 +64,7 @@
 void ChildProcessTaskProvider::BrowserChildProcessLaunchedAndConnected(
     const content::ChildProcessData& data) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  if (!data.IsHandleValid())
+  if (!data.GetProcess().IsValid())
     return;
 
   CreateTask(data);
@@ -73,7 +73,7 @@
 void ChildProcessTaskProvider::BrowserChildProcessHostDisconnected(
     const content::ChildProcessData& data) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  DeleteTask(data.GetHandle());
+  DeleteTask(data.GetProcess().Handle());
 }
 
 void ChildProcessTaskProvider::StartUpdating() {
@@ -121,7 +121,7 @@
 void ChildProcessTaskProvider::CreateTask(
     const content::ChildProcessData& data) {
   std::unique_ptr<ChildProcessTask>& task =
-      tasks_by_processid_[base::GetProcId(data.GetHandle())];
+      tasks_by_processid_[data.GetProcess().Pid()];
   if (task) {
     // This task is already known to us. This case can happen when some of the
     // child process data we collect upon StartUpdating() might be of
diff --git a/chrome/browser/task_manager/providers/child_process_task_unittest.cc b/chrome/browser/task_manager/providers/child_process_task_unittest.cc
index 70d839c9..a2c9879 100644
--- a/chrome/browser/task_manager/providers/child_process_task_unittest.cc
+++ b/chrome/browser/task_manager/providers/child_process_task_unittest.cc
@@ -106,7 +106,7 @@
   // The following process which has handle = base::kNullProcessHandle, won't be
   // added.
   ChildProcessData data1(0);
-  ASSERT_EQ(base::kNullProcessHandle, data1.GetHandle());
+  ASSERT_FALSE(data1.GetProcess().IsValid());
   provider.BrowserChildProcessLaunchedAndConnected(data1);
   EXPECT_TRUE(provided_tasks_.empty());
 
@@ -116,7 +116,7 @@
       IDS_TASK_MANAGER_PLUGIN_PREFIX, name));
 
   ChildProcessData data2(content::PROCESS_TYPE_PPAPI_PLUGIN);
-  data2.SetHandle(base::GetCurrentProcessHandle());
+  data2.SetProcess(base::Process::Current());
   data2.name = name;
   data2.id = unique_id;
   provider.BrowserChildProcessLaunchedAndConnected(data2);
@@ -163,7 +163,7 @@
   for (const auto& types_pair : process_task_types_pairs) {
     // Add the task.
     ChildProcessData data(types_pair.process_type_);
-    data.SetHandle(base::GetCurrentProcessHandle());
+    data.SetProcess(base::Process::Current());
     provider.BrowserChildProcessLaunchedAndConnected(data);
     ASSERT_EQ(1U, provided_tasks_.size());
     Task* task = provided_tasks_.begin()->second;
diff --git a/chrome/browser/task_manager/providers/render_process_host_task_provider.cc b/chrome/browser/task_manager/providers/render_process_host_task_provider.cc
index 031611d9..a83e94d 100644
--- a/chrome/browser/task_manager/providers/render_process_host_task_provider.cc
+++ b/chrome/browser/task_manager/providers/render_process_host_task_provider.cc
@@ -82,9 +82,9 @@
   // TODO(cburn): plumb out something from RPH so the title can be set here.
   // Create the task and notify the observer.
   ChildProcessData data(content::PROCESS_TYPE_RENDERER);
-  data.SetHandle(host->GetProcess().Handle());
+  data.SetProcess(host->GetProcess().Duplicate());
   data.id = host->GetID();
-  task.reset(new ChildProcessTask(data));
+  task = std::make_unique<ChildProcessTask>(data);
   NotifyObserverTaskAdded(task.get());
 }
 
diff --git a/chrome/browser/task_manager/sampling/arc_shared_sampler.cc b/chrome/browser/task_manager/sampling/arc_shared_sampler.cc
new file mode 100644
index 0000000..443e715
--- /dev/null
+++ b/chrome/browser/task_manager/sampling/arc_shared_sampler.cc
@@ -0,0 +1,77 @@
+// 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/task_manager/sampling/arc_shared_sampler.h"
+
+#include <utility>
+
+#include "base/logging.h"
+#include "chrome/browser/chromeos/arc/process/arc_process_service.h"
+#include "content/public/browser/browser_thread.h"
+
+namespace task_manager {
+
+namespace {
+enum MemoryDumpType {
+  kAppMemoryDump = 1 << 0,
+  kSystemMemoryDump = 1 << 1,
+};
+};  // namespace
+
+ArcSharedSampler::ArcSharedSampler() : weak_ptr_factory_(this) {}
+
+ArcSharedSampler::~ArcSharedSampler() = default;
+
+void ArcSharedSampler::RegisterCallback(
+    base::ProcessId process_id,
+    OnSamplingCompleteCallback on_sampling_complete) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  DCHECK_NE(process_id, base::kNullProcessId);
+  const bool result =
+      callbacks_.emplace(process_id, std::move(on_sampling_complete)).second;
+  DCHECK(result);
+}
+
+void ArcSharedSampler::UnregisterCallback(base::ProcessId process_id) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  callbacks_.erase(process_id);
+}
+
+void ArcSharedSampler::Refresh() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  arc::ArcProcessService* arc_process_service = arc::ArcProcessService::Get();
+  if (!arc_process_service)
+    return;
+  if (~pending_memory_dump_types_ & MemoryDumpType::kAppMemoryDump) {
+    arc_process_service->RequestAppMemoryInfo(base::BindOnce(
+        &ArcSharedSampler::OnReceiveMemoryDump, weak_ptr_factory_.GetWeakPtr(),
+        MemoryDumpType::kAppMemoryDump));
+    pending_memory_dump_types_ |= MemoryDumpType::kAppMemoryDump;
+  }
+  if (~pending_memory_dump_types_ & MemoryDumpType::kSystemMemoryDump) {
+    arc_process_service->RequestSystemMemoryInfo(base::BindOnce(
+        &ArcSharedSampler::OnReceiveMemoryDump, weak_ptr_factory_.GetWeakPtr(),
+        MemoryDumpType::kSystemMemoryDump));
+    pending_memory_dump_types_ |= MemoryDumpType::kSystemMemoryDump;
+  }
+}
+
+void ArcSharedSampler::OnReceiveMemoryDump(
+    int type,
+    std::unique_ptr<memory_instrumentation::GlobalMemoryDump> dump) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  pending_memory_dump_types_ &= ~type;
+  if (!dump)
+    return;
+  for (const auto& pmd : dump->process_dumps()) {
+    auto it = callbacks_.find(pmd.pid());
+    if (it == callbacks_.end())
+      continue;
+    const MemoryFootprintBytes result =
+        pmd.os_dump().private_footprint_kb * 1024;
+    it->second.Run(base::make_optional<MemoryFootprintBytes>(result));
+  }
+}
+
+}  // namespace task_manager
diff --git a/chrome/browser/task_manager/sampling/arc_shared_sampler.h b/chrome/browser/task_manager/sampling/arc_shared_sampler.h
new file mode 100644
index 0000000..88f43843
--- /dev/null
+++ b/chrome/browser/task_manager/sampling/arc_shared_sampler.h
@@ -0,0 +1,63 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_TASK_MANAGER_SAMPLING_ARC_SHARED_SAMPLER_H_
+#define CHROME_BROWSER_TASK_MANAGER_SAMPLING_ARC_SHARED_SAMPLER_H_
+
+#include <stdint.h>
+#include <map>
+
+#include "base/callback.h"
+#include "base/containers/flat_map.h"
+#include "base/memory/weak_ptr.h"
+#include "base/optional.h"
+#include "base/process/process_handle.h"
+#include "services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.h"
+
+namespace task_manager {
+
+// Defines sampler that will retrieve memory footprint metrics for all arc
+// processes at once. Created by TaskManagerImpl on the UI thread.
+class ArcSharedSampler {
+ public:
+  ArcSharedSampler();
+  ~ArcSharedSampler();
+
+  using MemoryFootprintBytes = uint64_t;
+
+  using OnSamplingCompleteCallback =
+      base::RepeatingCallback<void(base::Optional<MemoryFootprintBytes>)>;
+
+  // Registers task group specific callback.
+  void RegisterCallback(base::ProcessId process_id,
+                        OnSamplingCompleteCallback on_sampling_complete);
+  // Unregisters task group specific callbacks.
+  void UnregisterCallback(base::ProcessId process_id);
+
+  // Triggers a refresh of process stats.
+  void Refresh();
+
+ private:
+  using CallbacksMap =
+      base::flat_map<base::ProcessId, OnSamplingCompleteCallback>;
+
+  // Called when ArcProcessService returns memory dump.
+  void OnReceiveMemoryDump(
+      int dump_type,
+      std::unique_ptr<memory_instrumentation::GlobalMemoryDump> dump);
+
+  // Holds callbacks registered by TaskGroup objects.
+  CallbacksMap callbacks_;
+
+  // Keeps track of whether there is a pending request for memory footprint of
+  // app or system processes.
+  int pending_memory_dump_types_ = 0;
+
+  base::WeakPtrFactory<ArcSharedSampler> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(ArcSharedSampler);
+};
+
+}  // namespace task_manager
+#endif  // CHROME_BROWSER_TASK_MANAGER_SAMPLING_ARC_SHARED_SAMPLER_H_
diff --git a/chrome/browser/task_manager/sampling/task_group.cc b/chrome/browser/task_manager/sampling/task_group.cc
index 91a53e2..ac096caad 100644
--- a/chrome/browser/task_manager/sampling/task_group.cc
+++ b/chrome/browser/task_manager/sampling/task_group.cc
@@ -91,6 +91,9 @@
       on_background_calculations_done_(on_background_calculations_done),
       worker_thread_sampler_(nullptr),
       shared_sampler_(shared_sampler),
+#if defined(OS_CHROMEOS)
+      arc_shared_sampler_(nullptr),
+#endif  // defined(OS_CHROMEOS)
       expected_on_bg_done_flags_(kBackgroundRefreshTypesMask),
       current_on_bg_done_flags_(0),
       platform_independent_cpu_usage_(0.0),
@@ -140,6 +143,10 @@
 
 TaskGroup::~TaskGroup() {
   shared_sampler_->UnregisterCallback(process_id_);
+#if defined(OS_CHROMEOS)
+  if (arc_shared_sampler_)
+    arc_shared_sampler_->UnregisterCallback(process_id_);
+#endif  // defined(OS_CHROMEOS)
 }
 
 void TaskGroup::AddTask(Task* task) {
@@ -239,6 +246,16 @@
   return expected_on_bg_done_flags_ == current_on_bg_done_flags_;
 }
 
+#if defined(OS_CHROMEOS)
+void TaskGroup::SetArcSampler(ArcSharedSampler* sampler) {
+  DCHECK(sampler);
+  arc_shared_sampler_ = sampler;
+  arc_shared_sampler_->RegisterCallback(
+      process_id_, base::BindRepeating(&TaskGroup::OnArcSamplerRefreshDone,
+                                       weak_ptr_factory_.GetWeakPtr()));
+}
+#endif  // defined(OS_CHROMEOS)
+
 void TaskGroup::RefreshGpuMemory(
     const gpu::VideoMemoryUsageStats& gpu_memory_stats) {
   auto itr = gpu_memory_stats.process_map.find(process_id_);
@@ -344,6 +361,14 @@
                                   shared_sampler_->GetSupportedFlags());
 }
 
+#if defined(OS_CHROMEOS)
+void TaskGroup::OnArcSamplerRefreshDone(
+    base::Optional<ArcSharedSampler::MemoryFootprintBytes> memory_footprint) {
+  if (memory_footprint)
+    set_footprint_bytes(*memory_footprint);
+}
+#endif  // defined(OS_CHROMEOS)
+
 void TaskGroup::OnBackgroundRefreshTypeFinished(int64_t finished_refresh_type) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
diff --git a/chrome/browser/task_manager/sampling/task_group.h b/chrome/browser/task_manager/sampling/task_group.h
index 709e006..16661eb5 100644
--- a/chrome/browser/task_manager/sampling/task_group.h
+++ b/chrome/browser/task_manager/sampling/task_group.h
@@ -17,6 +17,7 @@
 #include "base/time/time.h"
 #include "build/build_config.h"
 #include "chrome/browser/task_manager/providers/task.h"
+#include "chrome/browser/task_manager/sampling/arc_shared_sampler.h"
 #include "chrome/browser/task_manager/sampling/shared_sampler.h"
 #include "chrome/browser/task_manager/sampling/task_group_sampler.h"
 #include "chrome/browser/task_manager/task_manager_observer.h"
@@ -62,6 +63,10 @@
   // process represented by this TaskGroup have completed.
   bool AreBackgroundCalculationsDone() const;
 
+#if defined(OS_CHROMEOS)
+  void SetArcSampler(ArcSharedSampler* sampler);
+#endif  // defined(OS_CHROMEOS)
+
   const base::ProcessHandle& process_handle() const { return process_handle_; }
   const base::ProcessId& process_id() const { return process_id_; }
 
@@ -106,7 +111,6 @@
 #endif  // defined(OS_LINUX)
 
   int idle_wakeups_per_second() const { return idle_wakeups_per_second_; }
-
  private:
   void RefreshGpuMemory(const gpu::VideoMemoryUsageStats& gpu_memory_stats);
 
@@ -129,6 +133,11 @@
   void OnSamplerRefreshDone(
       base::Optional<SharedSampler::SamplingResult> results);
 
+#if defined(OS_CHROMEOS)
+  void OnArcSamplerRefreshDone(
+      base::Optional<ArcSharedSampler::MemoryFootprintBytes> results);
+#endif  // defined(OS_CHROMEOS)
+
   void OnBackgroundRefreshTypeFinished(int64_t finished_refresh_type);
 
   // The process' handle and ID.
@@ -142,6 +151,10 @@
   scoped_refptr<TaskGroupSampler> worker_thread_sampler_;
 
   scoped_refptr<SharedSampler> shared_sampler_;
+#if defined(OS_CHROMEOS)
+  // Shared sampler that retrieves memory footprint for all ARC processes.
+  ArcSharedSampler* arc_shared_sampler_;  // Not owned
+#endif                                    // defined(OS_CHROMEOS)
 
   // Lists the Tasks in this TaskGroup.
   // Tasks are not owned by the TaskGroup. They're owned by the TaskProviders.
diff --git a/chrome/browser/task_manager/sampling/task_manager_impl.cc b/chrome/browser/task_manager/sampling/task_manager_impl.cc
index bef0b2d..fcf6477 100644
--- a/chrome/browser/task_manager/sampling/task_manager_impl.cc
+++ b/chrome/browser/task_manager/sampling/task_manager_impl.cc
@@ -5,15 +5,16 @@
 #include "chrome/browser/task_manager/sampling/task_manager_impl.h"
 
 #include <algorithm>
+#include <memory>
 #include <string>
 #include <unordered_map>
 #include <unordered_set>
+#include <utility>
 #include <vector>
 
 #include "base/command_line.h"
 #include "base/containers/adapters.h"
 #include "base/task/post_task.h"
-#include "build/build_config.h"
 #include "chrome/browser/task_manager/providers/browser_process_task_provider.h"
 #include "chrome/browser/task_manager/providers/child_process_task_provider.h"
 #include "chrome/browser/task_manager/providers/fallback_task_provider.h"
@@ -34,6 +35,7 @@
 #include "services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.h"
 
 #if defined(OS_CHROMEOS)
+#include "chrome/browser/chromeos/arc/process/arc_process_service.h"
 #include "chrome/browser/task_manager/providers/arc/arc_process_task_provider.h"
 #include "chrome/browser/task_manager/providers/crostini/crostini_process_task_provider.h"
 #include "components/arc/arc_util.h"
@@ -89,6 +91,7 @@
   if (arc::IsArcAvailable())
     task_providers_.emplace_back(new ArcProcessTaskProvider());
   task_providers_.emplace_back(new CrostiniProcessTaskProvider());
+  arc_shared_sampler_ = std::make_unique<ArcSharedSampler>();
 #endif  // defined(OS_CHROMEOS)
 }
 
@@ -442,10 +445,15 @@
   const TaskId task_id = task->task_id();
 
   std::unique_ptr<TaskGroup>& task_group = task_groups_by_proc_id_[proc_id];
-  if (!task_group)
+  if (!task_group) {
     task_group.reset(new TaskGroup(task->process_handle(), proc_id,
                                    on_background_data_ready_callback_,
                                    shared_sampler_, blocking_pool_runner_));
+#if defined(OS_CHROMEOS)
+    if (task->GetType() == Task::ARC)
+      task_group->SetArcSampler(arc_shared_sampler_.get());
+#endif
+  }
 
   task_group->AddTask(task);
 
@@ -602,6 +610,13 @@
                                enabled_resources_flags());
   }
 
+#if defined(OS_CHROMEOS)
+  if (TaskManagerObserver::IsResourceRefreshEnabled(
+          REFRESH_TYPE_MEMORY_FOOTPRINT, enabled_resources_flags())) {
+    arc_shared_sampler_->Refresh();
+  }
+#endif  // defined(OS_CHROMEOS)
+
   NotifyObserversOnRefresh(GetTaskIdsList());
 }
 
diff --git a/chrome/browser/task_manager/sampling/task_manager_impl.h b/chrome/browser/task_manager/sampling/task_manager_impl.h
index 15fb353..7ef9949 100644
--- a/chrome/browser/task_manager/sampling/task_manager_impl.h
+++ b/chrome/browser/task_manager/sampling/task_manager_impl.h
@@ -20,6 +20,7 @@
 #include "base/time/time.h"
 #include "chrome/browser/task_manager/providers/task_provider.h"
 #include "chrome/browser/task_manager/providers/task_provider_observer.h"
+#include "chrome/browser/task_manager/sampling/arc_shared_sampler.h"
 #include "chrome/browser/task_manager/sampling/task_group.h"
 #include "chrome/browser/task_manager/sampling/task_manager_io_thread_helper.h"
 #include "chrome/browser/task_manager/task_manager_interface.h"
@@ -181,6 +182,12 @@
   // subset of resources for all processes at once.
   scoped_refptr<SharedSampler> shared_sampler_;
 
+#if defined(OS_CHROMEOS)
+  // A sampler shared with all instances of TaskGroup that hold ARC tasks and
+  // calculates memory footprint for all processes at once.
+  std::unique_ptr<ArcSharedSampler> arc_shared_sampler_;
+#endif  // defined(OS_CHROMEOS)
+
   // This will be set to true while there are observers and the task manager is
   // running.
   bool is_running_;
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 6ee5ea9..b6fe05c 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -205,8 +205,8 @@
     "tab_modal_confirm_dialog.h",
     "tab_ui_helper.cc",
     "tab_ui_helper.h",
-    "toolbar/chrome_toolbar_model_delegate.cc",
-    "toolbar/chrome_toolbar_model_delegate.h",
+    "toolbar/chrome_location_bar_model_delegate.cc",
+    "toolbar/chrome_location_bar_model_delegate.h",
     "translate/language_combobox_model.cc",
     "translate/language_combobox_model.h",
     "translate/translate_bubble_model.h",
@@ -697,8 +697,8 @@
       "android/tab_model/tab_model_observer.h",
       "android/tab_model/tab_model_observer_jni_bridge.cc",
       "android/tab_model/tab_model_observer_jni_bridge.h",
-      "android/toolbar/toolbar_model_android.cc",
-      "android/toolbar/toolbar_model_android.h",
+      "android/toolbar/location_bar_model_android.cc",
+      "android/toolbar/location_bar_model_android.h",
       "android/usb_chooser_dialog_android.cc",
       "android/usb_chooser_dialog_android.h",
       "android/view_android_helper.cc",
@@ -786,6 +786,8 @@
       "browser_list_observer.h",
       "browser_live_tab_context.cc",
       "browser_live_tab_context.h",
+      "browser_location_bar_model_delegate.cc",
+      "browser_location_bar_model_delegate.h",
       "browser_navigator.cc",
       "browser_navigator.h",
       "browser_otr_state.cc",
@@ -800,8 +802,6 @@
       "browser_tabrestore.h",
       "browser_tabstrip.cc",
       "browser_tabstrip.h",
-      "browser_toolbar_model_delegate.cc",
-      "browser_toolbar_model_delegate.h",
       "browser_view_prefs.cc",
       "browser_view_prefs.h",
       "browser_window.h",
@@ -1643,6 +1643,8 @@
       "webui/chromeos/slow_trace_ui.h",
       "webui/chromeos/slow_ui.cc",
       "webui/chromeos/slow_ui.h",
+      "webui/chromeos/smb_shares/smb_handler.cc",
+      "webui/chromeos/smb_shares/smb_handler.h",
       "webui/chromeos/sys_internals/sys_internals_message_handler.cc",
       "webui/chromeos/sys_internals/sys_internals_message_handler.h",
       "webui/chromeos/sys_internals/sys_internals_ui.cc",
@@ -1693,8 +1695,6 @@
       "webui/settings/chromeos/internet_handler.h",
       "webui/settings/chromeos/multidevice_handler.cc",
       "webui/settings/chromeos/multidevice_handler.h",
-      "webui/settings/chromeos/smb_handler.cc",
-      "webui/settings/chromeos/smb_handler.h",
       "webui/settings/tts_handler.cc",
       "webui/settings/tts_handler.h",
       "webui/signin/inline_login_handler_chromeos.cc",
diff --git a/chrome/browser/ui/android/tab_model/tab_model.cc b/chrome/browser/ui/android/tab_model/tab_model.cc
index d3ce012..f407949 100644
--- a/chrome/browser/ui/android/tab_model/tab_model.cc
+++ b/chrome/browser/ui/android/tab_model/tab_model.cc
@@ -11,7 +11,7 @@
 #include "chrome/browser/sync/glue/synced_window_delegate_android.h"
 #include "chrome/browser/sync/sessions/sync_sessions_web_contents_router.h"
 #include "chrome/browser/sync/sessions/sync_sessions_web_contents_router_factory.h"
-#include "components/omnibox/browser/toolbar_model_impl.h"
+#include "components/omnibox/browser/location_bar_model_impl.h"
 #include "content/public/browser/notification_service.h"
 
 using content::NotificationService;
diff --git a/chrome/browser/ui/android/tab_model/tab_model.h b/chrome/browser/ui/android/tab_model/tab_model.h
index 2fa081b..46847e4 100644
--- a/chrome/browser/ui/android/tab_model/tab_model.h
+++ b/chrome/browser/ui/android/tab_model/tab_model.h
@@ -9,8 +9,8 @@
 
 #include "base/macros.h"
 #include "chrome/browser/ui/android/tab_model/android_live_tab_context.h"
-#include "components/omnibox/browser/toolbar_model.h"
-#include "components/omnibox/browser/toolbar_model_delegate.h"
+#include "components/omnibox/browser/location_bar_model.h"
+#include "components/omnibox/browser/location_bar_model_delegate.h"
 #include "components/sessions/core/session_id.h"
 #include "components/sync_sessions/synced_window_delegate.h"
 #include "content/public/browser/notification_observer.h"
@@ -115,7 +115,7 @@
   // loaded from storage.
   void BroadcastSessionRestoreComplete();
 
-  ToolbarModel* GetToolbarModel();
+  LocationBarModel* GetLocationBarModel();
 
  private:
   // Determines how TabModel will interact with the profile.
diff --git a/chrome/browser/ui/android/toolbar/location_bar_model_android.cc b/chrome/browser/ui/android/toolbar/location_bar_model_android.cc
new file mode 100644
index 0000000..6bf2adf
--- /dev/null
+++ b/chrome/browser/ui/android/toolbar/location_bar_model_android.cc
@@ -0,0 +1,57 @@
+// 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/browser/ui/android/toolbar/location_bar_model_android.h"
+
+#include "base/android/jni_string.h"
+#include "components/omnibox/browser/location_bar_model_impl.h"
+#include "content/public/browser/navigation_entry.h"
+#include "content/public/browser/ssl_status.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/common/content_constants.h"
+#include "jni/LocationBarModel_jni.h"
+
+using base::android::JavaParamRef;
+using base::android::JavaRef;
+using base::android::ScopedJavaLocalRef;
+
+LocationBarModelAndroid::LocationBarModelAndroid(JNIEnv* env,
+                                                 const JavaRef<jobject>& obj)
+    : location_bar_model_(
+          std::make_unique<LocationBarModelImpl>(this,
+                                                 content::kMaxURLDisplayChars)),
+      java_object_(obj) {}
+
+LocationBarModelAndroid::~LocationBarModelAndroid() {}
+
+void LocationBarModelAndroid::Destroy(JNIEnv* env,
+                                      const JavaParamRef<jobject>& obj) {
+  delete this;
+}
+
+ScopedJavaLocalRef<jstring> LocationBarModelAndroid::GetFormattedFullURL(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& obj) {
+  return base::android::ConvertUTF16ToJavaString(
+      env, location_bar_model_->GetFormattedFullURL());
+}
+
+ScopedJavaLocalRef<jstring> LocationBarModelAndroid::GetURLForDisplay(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& obj) {
+  return base::android::ConvertUTF16ToJavaString(
+      env, location_bar_model_->GetURLForDisplay());
+}
+
+content::WebContents* LocationBarModelAndroid::GetActiveWebContents() const {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  ScopedJavaLocalRef<jobject> jweb_contents =
+      Java_LocationBarModel_getActiveWebContents(env, java_object_);
+  return content::WebContents::FromJavaWebContents(jweb_contents);
+}
+
+// static
+jlong JNI_LocationBarModel_Init(JNIEnv* env, const JavaParamRef<jobject>& obj) {
+  return reinterpret_cast<intptr_t>(new LocationBarModelAndroid(env, obj));
+}
diff --git a/chrome/browser/ui/android/toolbar/location_bar_model_android.h b/chrome/browser/ui/android/toolbar/location_bar_model_android.h
new file mode 100644
index 0000000..7da168f7
--- /dev/null
+++ b/chrome/browser/ui/android/toolbar/location_bar_model_android.h
@@ -0,0 +1,45 @@
+// 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_BROWSER_UI_ANDROID_TOOLBAR_LOCATION_BAR_MODEL_ANDROID_H_
+#define CHROME_BROWSER_UI_ANDROID_TOOLBAR_LOCATION_BAR_MODEL_ANDROID_H_
+
+#include <memory>
+
+#include "base/android/jni_android.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/macros.h"
+#include "chrome/browser/ui/toolbar/chrome_location_bar_model_delegate.h"
+#include "components/omnibox/browser/location_bar_model.h"
+
+namespace content {
+class WebContents;
+}  // namespace content
+
+// Owns a LocationBarModel and provides a way for Java to interact with it.
+class LocationBarModelAndroid : public ChromeLocationBarModelDelegate {
+ public:
+  LocationBarModelAndroid(JNIEnv* env,
+                          const base::android::JavaRef<jobject>& obj);
+  ~LocationBarModelAndroid() override;
+
+  void Destroy(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj);
+  base::android::ScopedJavaLocalRef<jstring> GetFormattedFullURL(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& obj);
+  base::android::ScopedJavaLocalRef<jstring> GetURLForDisplay(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& obj);
+
+  // ChromeLocationBarModelDelegate:
+  content::WebContents* GetActiveWebContents() const override;
+
+ private:
+  std::unique_ptr<LocationBarModel> location_bar_model_;
+  base::android::ScopedJavaGlobalRef<jobject> java_object_;
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(LocationBarModelAndroid);
+};
+
+#endif  // CHROME_BROWSER_UI_ANDROID_TOOLBAR_LOCATION_BAR_MODEL_ANDROID_H_
diff --git a/chrome/browser/ui/android/toolbar/toolbar_model_android.cc b/chrome/browser/ui/android/toolbar/toolbar_model_android.cc
deleted file mode 100644
index 429f8c21..0000000
--- a/chrome/browser/ui/android/toolbar/toolbar_model_android.cc
+++ /dev/null
@@ -1,58 +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/browser/ui/android/toolbar/toolbar_model_android.h"
-
-#include "base/android/jni_string.h"
-#include "components/omnibox/browser/toolbar_model_impl.h"
-#include "content/public/browser/navigation_entry.h"
-#include "content/public/browser/ssl_status.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/common/content_constants.h"
-#include "jni/ToolbarModel_jni.h"
-
-using base::android::JavaParamRef;
-using base::android::JavaRef;
-using base::android::ScopedJavaLocalRef;
-
-ToolbarModelAndroid::ToolbarModelAndroid(JNIEnv* env,
-                                         const JavaRef<jobject>& obj)
-    : toolbar_model_(
-          std::make_unique<ToolbarModelImpl>(this,
-                                             content::kMaxURLDisplayChars)),
-      java_object_(obj) {}
-
-ToolbarModelAndroid::~ToolbarModelAndroid() {
-}
-
-void ToolbarModelAndroid::Destroy(JNIEnv* env,
-                                  const JavaParamRef<jobject>& obj) {
-  delete this;
-}
-
-ScopedJavaLocalRef<jstring> ToolbarModelAndroid::GetFormattedFullURL(
-    JNIEnv* env,
-    const JavaParamRef<jobject>& obj) {
-  return base::android::ConvertUTF16ToJavaString(
-      env, toolbar_model_->GetFormattedFullURL());
-}
-
-ScopedJavaLocalRef<jstring> ToolbarModelAndroid::GetURLForDisplay(
-    JNIEnv* env,
-    const JavaParamRef<jobject>& obj) {
-  return base::android::ConvertUTF16ToJavaString(
-      env, toolbar_model_->GetURLForDisplay());
-}
-
-content::WebContents* ToolbarModelAndroid::GetActiveWebContents() const {
-  JNIEnv* env = base::android::AttachCurrentThread();
-  ScopedJavaLocalRef<jobject> jweb_contents =
-      Java_ToolbarModel_getActiveWebContents(env, java_object_);
-  return content::WebContents::FromJavaWebContents(jweb_contents);
-}
-
-// static
-jlong JNI_ToolbarModel_Init(JNIEnv* env, const JavaParamRef<jobject>& obj) {
-  return reinterpret_cast<intptr_t>(new ToolbarModelAndroid(env, obj));
-}
diff --git a/chrome/browser/ui/android/toolbar/toolbar_model_android.h b/chrome/browser/ui/android/toolbar/toolbar_model_android.h
deleted file mode 100644
index 515a525..0000000
--- a/chrome/browser/ui/android/toolbar/toolbar_model_android.h
+++ /dev/null
@@ -1,44 +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_BROWSER_UI_ANDROID_TOOLBAR_TOOLBAR_MODEL_ANDROID_H_
-#define CHROME_BROWSER_UI_ANDROID_TOOLBAR_TOOLBAR_MODEL_ANDROID_H_
-
-#include <memory>
-
-#include "base/android/jni_android.h"
-#include "base/android/scoped_java_ref.h"
-#include "base/macros.h"
-#include "chrome/browser/ui/toolbar/chrome_toolbar_model_delegate.h"
-#include "components/omnibox/browser/toolbar_model.h"
-
-namespace content {
-class WebContents;
-}  // content
-
-// Owns a ToolbarModel and provides a way for Java to interact with it.
-class ToolbarModelAndroid : public ChromeToolbarModelDelegate {
- public:
-  ToolbarModelAndroid(JNIEnv* env, const base::android::JavaRef<jobject>& obj);
-  ~ToolbarModelAndroid() override;
-
-  void Destroy(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj);
-  base::android::ScopedJavaLocalRef<jstring> GetFormattedFullURL(
-      JNIEnv* env,
-      const base::android::JavaParamRef<jobject>& obj);
-  base::android::ScopedJavaLocalRef<jstring> GetURLForDisplay(
-      JNIEnv* env,
-      const base::android::JavaParamRef<jobject>& obj);
-
-  // ChromeToolbarModelDelegate:
-  content::WebContents* GetActiveWebContents() const override;
-
- private:
-  std::unique_ptr<ToolbarModel> toolbar_model_;
-  base::android::ScopedJavaGlobalRef<jobject> java_object_;
-
-  DISALLOW_IMPLICIT_CONSTRUCTORS(ToolbarModelAndroid);
-};
-
-#endif  // CHROME_BROWSER_UI_ANDROID_TOOLBAR_TOOLBAR_MODEL_ANDROID_H_
diff --git a/chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc b/chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc
index 8df262c..9274e24a 100644
--- a/chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc
+++ b/chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc
@@ -856,10 +856,16 @@
   // Match this requirement and don't show pre-installed apps for managed users
   // in app list.
   if (arc::policy_util::IsAccountManaged(profile_)) {
-    default_apps_->set_filter_level(
-        arc::IsArcPlayStoreEnabledForProfile(profile_)
-            ? ArcDefaultAppList::FilterLevel::OPTIONAL_APPS
-            : ArcDefaultAppList::FilterLevel::ALL);
+    if (profile_->IsChild()) {
+      // For child accounts, filter only optional apps.
+      default_apps_->set_filter_level(
+          ArcDefaultAppList::FilterLevel::OPTIONAL_APPS);
+    } else {
+      default_apps_->set_filter_level(
+          arc::IsArcPlayStoreEnabledForProfile(profile_)
+              ? ArcDefaultAppList::FilterLevel::OPTIONAL_APPS
+              : ArcDefaultAppList::FilterLevel::ALL);
+    }
   } else {
     default_apps_->set_filter_level(ArcDefaultAppList::FilterLevel::NOTHING);
   }
diff --git a/chrome/browser/ui/ash/accelerator_commands_browsertest.cc b/chrome/browser/ui/ash/accelerator_commands_browsertest.cc
index 9b34584..e508ca1c 100644
--- a/chrome/browser/ui/ash/accelerator_commands_browsertest.cc
+++ b/chrome/browser/ui/ash/accelerator_commands_browsertest.cc
@@ -4,6 +4,7 @@
 
 #include "ash/accelerators/accelerator_commands.h"
 
+#include "ash/public/cpp/window_properties.h"
 #include "ash/public/interfaces/constants.mojom.h"
 #include "ash/public/interfaces/shell_test_api.mojom.h"
 #include "base/command_line.h"
@@ -64,7 +65,7 @@
 bool IsInImmersive(aura::Window* window) {
   aura::Window* toplevel =
       features::IsUsingWindowService() ? window->GetRootWindow() : window;
-  return toplevel->GetProperty(aura::client::kImmersiveFullscreenKey);
+  return toplevel->GetProperty(ash::kImmersiveIsActive);
 }
 
 }  // namespace
diff --git a/chrome/browser/ui/blocked_content/popup_blocker.cc b/chrome/browser/ui/blocked_content/popup_blocker.cc
index 5ea2b668..a798720 100644
--- a/chrome/browser/ui/blocked_content/popup_blocker.cc
+++ b/chrome/browser/ui/blocked_content/popup_blocker.cc
@@ -17,34 +17,18 @@
 #include "content/public/browser/page_navigator.h"
 #include "content/public/browser/web_contents.h"
 
-bool ConsiderForPopupBlocking(WindowOpenDisposition disposition) {
-  return disposition == WindowOpenDisposition::NEW_POPUP ||
-         disposition == WindowOpenDisposition::NEW_FOREGROUND_TAB ||
-         disposition == WindowOpenDisposition::NEW_BACKGROUND_TAB ||
-         disposition == WindowOpenDisposition::NEW_WINDOW;
-}
+namespace {
 
-bool MaybeBlockPopup(content::WebContents* web_contents,
-                     const base::Optional<GURL>& opener_url,
-                     NavigateParams* params,
-                     const content::OpenURLParams* open_url_params,
-                     const blink::mojom::WindowFeatures& window_features) {
-  DCHECK(web_contents);
-  DCHECK(!open_url_params ||
-         open_url_params->user_gesture == params->user_gesture);
-
-  PopupBlockerTabHelper::LogAction(PopupBlockerTabHelper::Action::kInitiated);
-  const bool user_gesture = params->user_gesture;
-
+// If the popup should be blocked, returns the reason why it was blocked.
+// Otherwise returns kNotBlocked.
+PopupBlockType ShouldBlockPopup(content::WebContents* web_contents,
+                                const base::Optional<GURL>& opener_url,
+                                bool user_gesture,
+                                const content::OpenURLParams* open_url_params) {
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kDisablePopupBlocking)) {
-    return false;
+    return PopupBlockType::kNotBlocked;
   }
-
-  auto* popup_blocker = PopupBlockerTabHelper::FromWebContents(web_contents);
-  if (!popup_blocker)
-    return false;
-
   // If an explicit opener is not given, use the current committed load in this
   // web contents. This is because A page can't spawn popups (or do anything
   // else, either) until its load commits, so when we reach here, the popup was
@@ -60,21 +44,46 @@
       HostContentSettingsMapFactory::GetForProfile(profile)->GetContentSetting(
           url, url, CONTENT_SETTINGS_TYPE_POPUPS, std::string()) ==
           CONTENT_SETTING_ALLOW) {
-    return false;
+    return PopupBlockType::kNotBlocked;
   }
 
-  PopupBlockType block_type = PopupBlockType::kNoGesture;
-  if (user_gesture) {
-    auto* safe_browsing_blocker =
-        SafeBrowsingTriggeredPopupBlocker::FromWebContents(web_contents);
-    if (!safe_browsing_blocker ||
-        !safe_browsing_blocker->ShouldApplyStrongPopupBlocker(
-            open_url_params)) {
-      return false;
-    }
-    block_type = PopupBlockType::kAbusive;
-  }
+  if (!user_gesture)
+    return PopupBlockType::kNoGesture;
 
-  popup_blocker->AddBlockedPopup(params, window_features, block_type);
-  return true;
+  auto* safe_browsing_blocker =
+      SafeBrowsingTriggeredPopupBlocker::FromWebContents(web_contents);
+  if (safe_browsing_blocker &&
+      safe_browsing_blocker->ShouldApplyStrongPopupBlocker(open_url_params)) {
+    return PopupBlockType::kAbusive;
+  }
+  return PopupBlockType::kNotBlocked;
+}
+
+}  // namespace
+
+bool ConsiderForPopupBlocking(WindowOpenDisposition disposition) {
+  return disposition == WindowOpenDisposition::NEW_POPUP ||
+         disposition == WindowOpenDisposition::NEW_FOREGROUND_TAB ||
+         disposition == WindowOpenDisposition::NEW_BACKGROUND_TAB ||
+         disposition == WindowOpenDisposition::NEW_WINDOW;
+}
+
+bool MaybeBlockPopup(content::WebContents* web_contents,
+                     const base::Optional<GURL>& opener_url,
+                     NavigateParams* params,
+                     const content::OpenURLParams* open_url_params,
+                     const blink::mojom::WindowFeatures& window_features) {
+  DCHECK(web_contents);
+  DCHECK(!open_url_params ||
+         open_url_params->user_gesture == params->user_gesture);
+  PopupBlockerTabHelper::LogAction(PopupBlockerTabHelper::Action::kInitiated);
+
+  PopupBlockType block_type = ShouldBlockPopup(
+      web_contents, opener_url, params->user_gesture, open_url_params);
+  auto* popup_blocker = PopupBlockerTabHelper::FromWebContents(web_contents);
+  if (popup_blocker && block_type != PopupBlockType::kNotBlocked) {
+    popup_blocker->AddBlockedPopup(params, window_features, block_type);
+    return true;
+  }
+  return false;
 }
diff --git a/chrome/browser/ui/blocked_content/popup_blocker.h b/chrome/browser/ui/blocked_content/popup_blocker.h
index 0b5f28b..8298d95 100644
--- a/chrome/browser/ui/blocked_content/popup_blocker.h
+++ b/chrome/browser/ui/blocked_content/popup_blocker.h
@@ -19,6 +19,8 @@
 
 // Classifies what caused a popup to be blocked.
 enum class PopupBlockType {
+  kNotBlocked,
+
   // Popup blocked due to no user gesture.
   kNoGesture,
   // Popup blocked due to the abusive popup blocker.
diff --git a/chrome/browser/ui/blocked_content/popup_blocker_tab_helper.cc b/chrome/browser/ui/blocked_content/popup_blocker_tab_helper.cc
index 5502345..54af28124 100644
--- a/chrome/browser/ui/blocked_content/popup_blocker_tab_helper.cc
+++ b/chrome/browser/ui/blocked_content/popup_blocker_tab_helper.cc
@@ -144,6 +144,9 @@
   }
 
   switch (popup->block_type) {
+    case PopupBlockType::kNotBlocked:
+      NOTREACHED();
+      break;
     case PopupBlockType::kNoGesture:
       LogAction(Action::kClickedThroughNoGesture);
       break;
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
index 51bd0a1..0e2be7d 100644
--- a/chrome/browser/ui/browser.cc
+++ b/chrome/browser/ui/browser.cc
@@ -109,11 +109,11 @@
 #include "chrome/browser/ui/browser_instant_controller.h"
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/browser_live_tab_context.h"
+#include "chrome/browser/ui/browser_location_bar_model_delegate.h"
 #include "chrome/browser/ui/browser_navigator.h"
 #include "chrome/browser/ui/browser_navigator_params.h"
 #include "chrome/browser/ui/browser_tab_strip_model_delegate.h"
 #include "chrome/browser/ui/browser_tabstrip.h"
-#include "chrome/browser/ui/browser_toolbar_model_delegate.h"
 #include "chrome/browser/ui/browser_ui_prefs.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/chrome_bubble_manager.h"
@@ -166,7 +166,7 @@
 #include "components/keep_alive_registry/keep_alive_registry.h"
 #include "components/keep_alive_registry/keep_alive_types.h"
 #include "components/keep_alive_registry/scoped_keep_alive.h"
-#include "components/omnibox/browser/toolbar_model_impl.h"
+#include "components/omnibox/browser/location_bar_model_impl.h"
 #include "components/prefs/pref_service.h"
 #include "components/search/search.h"
 #include "components/security_state/content/content_utils.h"
@@ -400,7 +400,7 @@
       is_session_restore_(params.is_session_restore),
       content_setting_bubble_model_delegate_(
           new BrowserContentSettingBubbleModelDelegate(this)),
-      toolbar_model_delegate_(new BrowserToolbarModelDelegate(this)),
+      location_bar_model_delegate_(new BrowserLocationBarModelDelegate(this)),
       live_tab_context_(new BrowserLiveTabContext(this)),
       synced_window_delegate_(new BrowserSyncedWindowDelegate(this)),
       hosted_app_controller_(MaybeCreateHostedAppController(this)),
@@ -426,8 +426,8 @@
 
   tab_strip_model_->AddObserver(this);
 
-  toolbar_model_.reset(new ToolbarModelImpl(toolbar_model_delegate_.get(),
-                                            content::kMaxURLDisplayChars));
+  location_bar_model_.reset(new LocationBarModelImpl(
+      location_bar_model_delegate_.get(), content::kMaxURLDisplayChars));
 
   extension_registry_observer_.Add(
       extensions::ExtensionRegistry::Get(profile_));
diff --git a/chrome/browser/ui/browser.h b/chrome/browser/ui/browser.h
index dd4c877..30324c9 100644
--- a/chrome/browser/ui/browser.h
+++ b/chrome/browser/ui/browser.h
@@ -33,7 +33,7 @@
 #include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
 #include "components/content_settings/core/common/content_settings.h"
 #include "components/content_settings/core/common/content_settings_types.h"
-#include "components/omnibox/browser/toolbar_model.h"
+#include "components/omnibox/browser/location_bar_model.h"
 #include "components/prefs/pref_change_registrar.h"
 #include "components/sessions/core/session_id.h"
 #include "components/translate/content/browser/content_translate_driver.h"
@@ -62,7 +62,7 @@
 class BrowserContentSettingBubbleModelDelegate;
 class BrowserInstantController;
 class BrowserSyncedWindowDelegate;
-class BrowserToolbarModelDelegate;
+class BrowserLocationBarModelDelegate;
 class BrowserLiveTabContext;
 class BrowserWindow;
 class FastUnloadController;
@@ -256,11 +256,14 @@
   // |window()| will return NULL if called before |CreateBrowserWindow()|
   // is done.
   BrowserWindow* window() const { return window_; }
-  ToolbarModel* toolbar_model() { return toolbar_model_.get(); }
-  const ToolbarModel* toolbar_model() const { return toolbar_model_.get(); }
+  LocationBarModel* location_bar_model() { return location_bar_model_.get(); }
+  const LocationBarModel* location_bar_model() const {
+    return location_bar_model_.get();
+  }
 #if defined(UNIT_TEST)
-  void swap_toolbar_models(std::unique_ptr<ToolbarModel>* toolbar_model) {
-    toolbar_model->swap(toolbar_model_);
+  void swap_location_bar_models(
+      std::unique_ptr<LocationBarModel>* location_bar_model) {
+    location_bar_model->swap(location_bar_model_);
   }
 #endif
   TabStripModel* tab_strip_model() const { return tab_strip_model_.get(); }
@@ -931,7 +934,7 @@
   const SessionID session_id_;
 
   // The model for the toolbar view.
-  std::unique_ptr<ToolbarModel> toolbar_model_;
+  std::unique_ptr<LocationBarModel> location_bar_model_;
 
   // UI update coalescing and handling ////////////////////////////////////////
 
@@ -987,8 +990,8 @@
   std::unique_ptr<BrowserContentSettingBubbleModelDelegate>
       content_setting_bubble_model_delegate_;
 
-  // Helper which implements the ToolbarModelDelegate interface.
-  std::unique_ptr<BrowserToolbarModelDelegate> toolbar_model_delegate_;
+  // Helper which implements the LocationBarModelDelegate interface.
+  std::unique_ptr<BrowserLocationBarModelDelegate> location_bar_model_delegate_;
 
   // Helper which implements the LiveTabContext interface.
   std::unique_ptr<BrowserLiveTabContext> live_tab_context_;
diff --git a/chrome/browser/ui/browser_commands.cc b/chrome/browser/ui/browser_commands.cc
index 0afb5263..80950b8 100644
--- a/chrome/browser/ui/browser_commands.cc
+++ b/chrome/browser/ui/browser_commands.cc
@@ -1004,8 +1004,11 @@
 }
 
 bool CanEmailPageLocation(const Browser* browser) {
-  return browser->toolbar_model()->ShouldDisplayURL() &&
-      browser->tab_strip_model()->GetActiveWebContents()->GetURL().is_valid();
+  return browser->location_bar_model()->ShouldDisplayURL() &&
+         browser->tab_strip_model()
+             ->GetActiveWebContents()
+             ->GetURL()
+             .is_valid();
 }
 
 void CutCopyPaste(Browser* browser, int command_id) {
diff --git a/chrome/browser/ui/browser_location_bar_model_delegate.cc b/chrome/browser/ui/browser_location_bar_model_delegate.cc
new file mode 100644
index 0000000..a99eb54
--- /dev/null
+++ b/chrome/browser/ui/browser_location_bar_model_delegate.cc
@@ -0,0 +1,19 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/browser_location_bar_model_delegate.h"
+
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+
+BrowserLocationBarModelDelegate::BrowserLocationBarModelDelegate(
+    Browser* browser)
+    : browser_(browser) {}
+
+BrowserLocationBarModelDelegate::~BrowserLocationBarModelDelegate() {}
+
+content::WebContents* BrowserLocationBarModelDelegate::GetActiveWebContents()
+    const {
+  return browser_->tab_strip_model()->GetActiveWebContents();
+}
diff --git a/chrome/browser/ui/browser_location_bar_model_delegate.h b/chrome/browser/ui/browser_location_bar_model_delegate.h
new file mode 100644
index 0000000..9467fb2e
--- /dev/null
+++ b/chrome/browser/ui/browser_location_bar_model_delegate.h
@@ -0,0 +1,30 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_BROWSER_LOCATION_BAR_MODEL_DELEGATE_H_
+#define CHROME_BROWSER_UI_BROWSER_LOCATION_BAR_MODEL_DELEGATE_H_
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "chrome/browser/ui/toolbar/chrome_location_bar_model_delegate.h"
+
+class Browser;
+
+// Implementation of LocationBarModelDelegate which uses an instance of
+// Browser in order to fulfil its duties.
+class BrowserLocationBarModelDelegate : public ChromeLocationBarModelDelegate {
+ public:
+  explicit BrowserLocationBarModelDelegate(Browser* browser);
+  ~BrowserLocationBarModelDelegate() override;
+
+  // ChromeLocationBarModelDelegate:
+  content::WebContents* GetActiveWebContents() const override;
+
+ private:
+  Browser* const browser_;
+
+  DISALLOW_COPY_AND_ASSIGN(BrowserLocationBarModelDelegate);
+};
+
+#endif  // CHROME_BROWSER_UI_BROWSER_LOCATION_BAR_MODEL_DELEGATE_H_
diff --git a/chrome/browser/ui/browser_toolbar_model_delegate.cc b/chrome/browser/ui/browser_toolbar_model_delegate.cc
deleted file mode 100644
index 089064cc..0000000
--- a/chrome/browser/ui/browser_toolbar_model_delegate.cc
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/browser_toolbar_model_delegate.h"
-
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/tabs/tab_strip_model.h"
-
-BrowserToolbarModelDelegate::BrowserToolbarModelDelegate(Browser* browser)
-    : browser_(browser) {
-}
-
-BrowserToolbarModelDelegate::~BrowserToolbarModelDelegate() {
-}
-
-content::WebContents*
-BrowserToolbarModelDelegate::GetActiveWebContents() const {
-  return browser_->tab_strip_model()->GetActiveWebContents();
-}
diff --git a/chrome/browser/ui/browser_toolbar_model_delegate.h b/chrome/browser/ui/browser_toolbar_model_delegate.h
deleted file mode 100644
index 9b3e5d5..0000000
--- a/chrome/browser/ui/browser_toolbar_model_delegate.h
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_BROWSER_TOOLBAR_MODEL_DELEGATE_H_
-#define CHROME_BROWSER_UI_BROWSER_TOOLBAR_MODEL_DELEGATE_H_
-
-#include "base/compiler_specific.h"
-#include "base/macros.h"
-#include "chrome/browser/ui/toolbar/chrome_toolbar_model_delegate.h"
-
-class Browser;
-
-// Implementation of ToolbarModelDelegate which uses an instance of
-// Browser in order to fulfil its duties.
-class BrowserToolbarModelDelegate : public ChromeToolbarModelDelegate {
- public:
-  explicit BrowserToolbarModelDelegate(Browser* browser);
-  ~BrowserToolbarModelDelegate() override;
-
-  // ChromeToolbarModelDelegate:
-  content::WebContents* GetActiveWebContents() const override;
-
- private:
-  Browser* const browser_;
-
-  DISALLOW_COPY_AND_ASSIGN(BrowserToolbarModelDelegate);
-};
-
-#endif  // CHROME_BROWSER_UI_BROWSER_TOOLBAR_MODEL_DELEGATE_H_
diff --git a/chrome/browser/ui/cocoa/apps/native_app_window_cocoa_browsertest.mm b/chrome/browser/ui/cocoa/apps/native_app_window_cocoa_browsertest.mm
index 7ab3a03..e5b4f1f 100644
--- a/chrome/browser/ui/cocoa/apps/native_app_window_cocoa_browsertest.mm
+++ b/chrome/browser/ui/cocoa/apps/native_app_window_cocoa_browsertest.mm
@@ -5,7 +5,6 @@
 #include "extensions/browser/app_window/native_app_window.h"
 
 #import <Cocoa/Cocoa.h>
-#include <memory>
 
 #import "base/mac/foundation_util.h"
 #import "base/mac/mac_util.h"
@@ -13,8 +12,6 @@
 #import "base/mac/scoped_nsobject.h"
 #import "base/mac/sdk_forward_declarations.h"
 #include "base/macros.h"
-#include "chrome/browser/apps/app_shim/app_shim_host_bootstrap_mac.h"
-#include "chrome/browser/apps/app_shim/app_shim_host_mac.h"
 #include "chrome/browser/apps/app_shim/extension_app_shim_handler_mac.h"
 #include "chrome/browser/apps/app_shim/test/app_shim_host_manager_test_api_mac.h"
 #include "chrome/browser/apps/platform_apps/app_browsertest_util.h"
@@ -142,19 +139,19 @@
 
 namespace {
 
-class MockAppShimHost : public AppShimHost {
+class MockAppShimHost : public apps::AppShimHandler::Host {
  public:
-  MockAppShimHost()
-      : AppShimHost("app", base::FilePath("Profile")), weak_factory_(this) {}
+  MockAppShimHost() {}
   ~MockAppShimHost() override {}
 
+  MOCK_METHOD1(OnAppLaunchComplete, void(apps::AppShimLaunchResult));
+  MOCK_METHOD0(OnAppClosed, void());
+  MOCK_METHOD0(OnAppHide, void());
   MOCK_METHOD0(OnAppUnhideWithoutActivation, void());
-  base::WeakPtr<MockAppShimHost> GetWeakPtr() {
-    return weak_factory_.GetWeakPtr();
-  }
-
- private:
-  base::WeakPtrFactory<MockAppShimHost> weak_factory_;
+  MOCK_METHOD1(OnAppRequestUserAttention, void(apps::AppShimAttentionType));
+  MOCK_CONST_METHOD0(GetProfilePath, base::FilePath());
+  MOCK_CONST_METHOD0(GetAppId, std::string());
+  MOCK_CONST_METHOD0(GetViewsBridgeFactoryHost, views::BridgeFactoryHost*());
 };
 
 class MockExtensionAppShimHandler : public apps::ExtensionAppShimHandler {
@@ -179,8 +176,7 @@
   test_api.SetExtensionAppShimHandler(
       std::unique_ptr<apps::ExtensionAppShimHandler>(
           mock));  // Takes ownership.
-  base::WeakPtr<MockAppShimHost> mock_host =
-      (new MockAppShimHost)->GetWeakPtr();
+  MockAppShimHost mock_host;
 
   SetUpAppWithWindows(1);
   extensions::AppWindowRegistry::AppWindowList windows =
@@ -195,24 +191,24 @@
   EXPECT_FALSE([ns_window isVisible]);
 
   // Show notifies the shim to unhide.
-  EXPECT_CALL(*mock_host, OnAppUnhideWithoutActivation());
-  EXPECT_CALL(*mock, FindHost(_, _)).WillOnce(Return(mock_host.get()));
+  EXPECT_CALL(mock_host, OnAppUnhideWithoutActivation());
+  EXPECT_CALL(*mock, FindHost(_, _)).WillOnce(Return(&mock_host));
   app_window->Show(extensions::AppWindow::SHOW_ACTIVE);
   EXPECT_TRUE([ns_window isVisible]);
   testing::Mock::VerifyAndClearExpectations(mock);
-  testing::Mock::VerifyAndClearExpectations(mock_host.get());
+  testing::Mock::VerifyAndClearExpectations(&mock_host);
 
   // HideWithApp
   native_window->HideWithApp();
   EXPECT_FALSE([ns_window isVisible]);
 
   // Activate does the same.
-  EXPECT_CALL(*mock_host, OnAppUnhideWithoutActivation());
-  EXPECT_CALL(*mock, FindHost(_, _)).WillOnce(Return(mock_host.get()));
+  EXPECT_CALL(mock_host, OnAppUnhideWithoutActivation());
+  EXPECT_CALL(*mock, FindHost(_, _)).WillOnce(Return(&mock_host));
   native_window->Activate();
   EXPECT_TRUE([ns_window isVisible]);
   testing::Mock::VerifyAndClearExpectations(mock);
-  testing::Mock::VerifyAndClearExpectations(mock_host.get());
+  testing::Mock::VerifyAndClearExpectations(&mock_host);
 }
 
 // Test that NativeAppWindow and AppWindow fullscreen state is updated when
diff --git a/chrome/browser/ui/extensions/hosted_app_menu_model.cc b/chrome/browser/ui/extensions/hosted_app_menu_model.cc
index b8da2a8..8dd36d6e 100644
--- a/chrome/browser/ui/extensions/hosted_app_menu_model.cc
+++ b/chrome/browser/ui/extensions/hosted_app_menu_model.cc
@@ -37,7 +37,8 @@
                        ->tab_strip_model()
                        ->GetActiveWebContents()
                        ->GetVisibleURL()));
-  SetMinorIcon(app_info_index, browser()->toolbar_model()->GetVectorIcon());
+  SetMinorIcon(app_info_index,
+               browser()->location_bar_model()->GetVectorIcon());
 
   AddSeparator(ui::NORMAL_SEPARATOR);
   AddItemWithStringId(IDC_COPY_URL, IDS_COPY_URL);
diff --git a/chrome/browser/ui/hung_plugin_tab_helper.cc b/chrome/browser/ui/hung_plugin_tab_helper.cc
index cb4ec669..ca2afe9 100644
--- a/chrome/browser/ui/hung_plugin_tab_helper.cc
+++ b/chrome/browser/ui/hung_plugin_tab_helper.cc
@@ -40,10 +40,8 @@
   while (!iter.Done()) {
     const content::ChildProcessData& data = iter.GetData();
     if (data.id == child_id) {
-      CrashDumpHungChildProcess(data.GetHandle());
-      base::Process process =
-          base::Process::DeprecatedGetProcessFromHandle(data.GetHandle());
-      process.Terminate(content::RESULT_CODE_HUNG, false);
+      CrashDumpHungChildProcess(data.GetProcess().Handle());
+      data.GetProcess().Terminate(content::RESULT_CODE_HUNG, false);
       break;
     }
     ++iter;
diff --git a/chrome/browser/ui/libgtkui/app_indicator_icon.cc b/chrome/browser/ui/libgtkui/app_indicator_icon.cc
index a9c828f..266ae5d 100644
--- a/chrome/browser/ui/libgtkui/app_indicator_icon.cc
+++ b/chrome/browser/ui/libgtkui/app_indicator_icon.cc
@@ -12,7 +12,7 @@
 #include "base/files/file_util.h"
 #include "base/md5.h"
 #include "base/memory/ref_counted_memory.h"
-#include "base/strings/stringize_macros.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/post_task.h"
@@ -89,16 +89,13 @@
 
   g_attempted_load = true;
 
-  void* indicator_lib = nullptr;
+  std::string lib_name =
+      "libappindicator" + base::NumberToString(GTK_MAJOR_VERSION) + ".so";
+  void* indicator_lib = dlopen(lib_name.c_str(), RTLD_LAZY);
 
   if (!indicator_lib) {
-    indicator_lib =
-        dlopen("libappindicator" STRINGIZE(GTK_MAJOR_VERSION) ".so", RTLD_LAZY);
-  }
-
-  if (!indicator_lib) {
-    indicator_lib = dlopen(
-        "libappindicator" STRINGIZE(GTK_MAJOR_VERSION) ".so.1", RTLD_LAZY);
+    lib_name += ".1";
+    indicator_lib = dlopen(lib_name.c_str(), RTLD_LAZY);
   }
 
   if (!indicator_lib)
diff --git a/chrome/browser/ui/omnibox/chrome_omnibox_client.cc b/chrome/browser/ui/omnibox/chrome_omnibox_client.cc
index 4b9b3e1..a7d718e 100644
--- a/chrome/browser/ui/omnibox/chrome_omnibox_client.cc
+++ b/chrome/browser/ui/omnibox/chrome_omnibox_client.cc
@@ -57,8 +57,8 @@
 #include "components/feature_engagement/buildflags.h"
 #include "components/omnibox/browser/autocomplete_match.h"
 #include "components/omnibox/browser/autocomplete_result.h"
+#include "components/omnibox/browser/location_bar_model.h"
 #include "components/omnibox/browser/search_provider.h"
-#include "components/omnibox/browser/toolbar_model.h"
 #include "components/prefs/pref_service.h"
 #include "components/search/search.h"
 #include "components/search_engines/search_engines_pref_names.h"
@@ -471,7 +471,7 @@
 // and current URLs, but users edit URLs rarely enough that this is a
 // reasonable approximation.
 #if BUILDFLAG(ENABLE_DESKTOP_IN_PRODUCT_HELP)
-  if (controller_->GetToolbarModel()->ShouldDisplayURL()) {
+  if (controller_->GetLocationBarModel()->ShouldDisplayURL()) {
     feature_engagement::NewTabTrackerFactory::GetInstance()
         ->GetForProfile(profile_)
         ->OnOmniboxNavigation();
diff --git a/chrome/browser/ui/omnibox/chrome_omnibox_edit_controller.cc b/chrome/browser/ui/omnibox/chrome_omnibox_edit_controller.cc
index 71955519..56d25ad92 100644
--- a/chrome/browser/ui/omnibox/chrome_omnibox_edit_controller.cc
+++ b/chrome/browser/ui/omnibox/chrome_omnibox_edit_controller.cc
@@ -11,7 +11,7 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "components/omnibox/browser/toolbar_model.h"
+#include "components/omnibox/browser/location_bar_model.h"
 #include "extensions/buildflags/buildflags.h"
 
 #if BUILDFLAG(ENABLE_EXTENSIONS)
@@ -37,7 +37,7 @@
 }
 
 void ChromeOmniboxEditController::OnInputInProgress(bool in_progress) {
-  GetToolbarModel()->set_input_in_progress(in_progress);
+  GetLocationBarModel()->set_input_in_progress(in_progress);
   UpdateWithoutTabRestore();
 }
 
diff --git a/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc b/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc
index d88091f..647b968a 100644
--- a/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc
+++ b/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc
@@ -42,7 +42,7 @@
 #include "components/omnibox/browser/history_quick_provider.h"
 #include "components/omnibox/browser/omnibox_popup_model.h"
 #include "components/omnibox/browser/omnibox_view.h"
-#include "components/omnibox/browser/test_toolbar_model.h"
+#include "components/omnibox/browser/test_location_bar_model.h"
 #include "components/policy/core/browser/browser_policy_connector.h"
 #include "components/policy/core/common/mock_configuration_policy_provider.h"
 #include "components/search_engines/template_url.h"
@@ -357,17 +357,18 @@
     OmniboxEditModel* edit_model = omnibox_view->model();
     ASSERT_NE(nullptr, edit_model);
 
-    if (!test_toolbar_model_) {
-      test_toolbar_model_ = new TestToolbarModel;
-      std::unique_ptr<ToolbarModel> toolbar_model(test_toolbar_model_);
-      browser()->swap_toolbar_models(&toolbar_model);
+    if (!test_location_bar_model_) {
+      test_location_bar_model_ = new TestLocationBarModel;
+      std::unique_ptr<LocationBarModel> location_bar_model(
+          test_location_bar_model_);
+      browser()->swap_location_bar_models(&location_bar_model);
     }
 
-    test_toolbar_model_->set_formatted_full_url(text);
+    test_location_bar_model_->set_formatted_full_url(text);
 
     // Normally the URL for display has portions elided. We aren't doing that in
     // this case, because that is irrevelant for these tests.
-    test_toolbar_model_->set_url_for_display(text);
+    test_location_bar_model_->set_url_for_display(text);
 
     omnibox_view->Update();
   }
@@ -394,7 +395,7 @@
   policy::MockConfigurationPolicyProvider policy_provider_;
 
   // Non-owning pointer.
-  TestToolbarModel* test_toolbar_model_ = nullptr;
+  TestLocationBarModel* test_location_bar_model_ = nullptr;
 
   DISALLOW_COPY_AND_ASSIGN(OmniboxViewTest);
 };
diff --git a/chrome/browser/ui/toolbar/chrome_toolbar_model_delegate.cc b/chrome/browser/ui/toolbar/chrome_location_bar_model_delegate.cc
similarity index 83%
rename from chrome/browser/ui/toolbar/chrome_toolbar_model_delegate.cc
rename to chrome/browser/ui/toolbar/chrome_location_bar_model_delegate.cc
index 7afe700..a1970f5 100644
--- a/chrome/browser/ui/toolbar/chrome_toolbar_model_delegate.cc
+++ b/chrome/browser/ui/toolbar/chrome_location_bar_model_delegate.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/ui/toolbar/chrome_toolbar_model_delegate.h"
+#include "chrome/browser/ui/toolbar/chrome_location_bar_model_delegate.h"
 
 #include "base/logging.h"
 #include "build/build_config.h"
@@ -26,23 +26,24 @@
 
 #if !defined(OS_ANDROID)
 #include "components/omnibox/browser/vector_icons.h"  // nogncheck
-#endif  // !defined(OS_ANDROID)
+#endif                                                // !defined(OS_ANDROID)
 
 #if BUILDFLAG(ENABLE_OFFLINE_PAGES)
 #include "chrome/browser/offline_pages/offline_page_utils.h"
 #endif  // BUILDFLAG(ENABLE_OFFLINE_PAGES)
 
-ChromeToolbarModelDelegate::ChromeToolbarModelDelegate() {}
+ChromeLocationBarModelDelegate::ChromeLocationBarModelDelegate() {}
 
-ChromeToolbarModelDelegate::~ChromeToolbarModelDelegate() {}
+ChromeLocationBarModelDelegate::~ChromeLocationBarModelDelegate() {}
 
-content::NavigationEntry* ChromeToolbarModelDelegate::GetNavigationEntry()
+content::NavigationEntry* ChromeLocationBarModelDelegate::GetNavigationEntry()
     const {
   content::NavigationController* controller = GetNavigationController();
   return controller ? controller->GetVisibleEntry() : nullptr;
 }
 
-base::string16 ChromeToolbarModelDelegate::FormattedStringWithEquivalentMeaning(
+base::string16
+ChromeLocationBarModelDelegate::FormattedStringWithEquivalentMeaning(
     const GURL& url,
     const base::string16& formatted_url) const {
   return AutocompleteInput::FormattedStringWithEquivalentMeaning(
@@ -50,7 +51,7 @@
       nullptr);
 }
 
-bool ChromeToolbarModelDelegate::GetURL(GURL* url) const {
+bool ChromeLocationBarModelDelegate::GetURL(GURL* url) const {
   DCHECK(url);
   content::NavigationEntry* entry = GetNavigationEntry();
   if (!entry)
@@ -60,7 +61,7 @@
   return true;
 }
 
-bool ChromeToolbarModelDelegate::ShouldDisplayURL() const {
+bool ChromeLocationBarModelDelegate::ShouldDisplayURL() const {
   // Note: The order here is important.
   // - The WebUI test must come before the extension scheme test because there
   //   can be WebUIs that have extension schemes (e.g. the bookmark manager). In
@@ -90,7 +91,7 @@
   return !profile || !search::IsInstantNTPURL(url, profile);
 }
 
-security_state::SecurityLevel ChromeToolbarModelDelegate::GetSecurityLevel()
+security_state::SecurityLevel ChromeLocationBarModelDelegate::GetSecurityLevel()
     const {
   content::WebContents* web_contents = GetActiveWebContents();
   // If there is no active WebContents (which can happen during toolbar
@@ -103,15 +104,15 @@
   return security_info.security_level;
 }
 
-scoped_refptr<net::X509Certificate> ChromeToolbarModelDelegate::GetCertificate()
-    const {
+scoped_refptr<net::X509Certificate>
+ChromeLocationBarModelDelegate::GetCertificate() const {
   content::NavigationEntry* entry = GetNavigationEntry();
   if (!entry)
     return scoped_refptr<net::X509Certificate>();
   return entry->GetSSL().certificate;
 }
 
-bool ChromeToolbarModelDelegate::FailsBillingCheck() const {
+bool ChromeLocationBarModelDelegate::FailsBillingCheck() const {
   content::WebContents* web_contents = GetActiveWebContents();
   // If there is no active WebContents (which can happen during toolbar
   // initialization), nothing can fail.
@@ -124,7 +125,7 @@
          security_state::MALICIOUS_CONTENT_STATUS_BILLING;
 }
 
-bool ChromeToolbarModelDelegate::FailsMalwareCheck() const {
+bool ChromeLocationBarModelDelegate::FailsMalwareCheck() const {
   content::WebContents* web_contents = GetActiveWebContents();
   // If there is no active WebContents (which can happen during toolbar
   // initialization), nothing can fail.
@@ -138,7 +139,7 @@
          status != security_state::MALICIOUS_CONTENT_STATUS_NONE;
 }
 
-const gfx::VectorIcon* ChromeToolbarModelDelegate::GetVectorIconOverride()
+const gfx::VectorIcon* ChromeLocationBarModelDelegate::GetVectorIconOverride()
     const {
 #if !defined(OS_ANDROID)
   GURL url;
@@ -154,7 +155,7 @@
   return nullptr;
 }
 
-bool ChromeToolbarModelDelegate::IsOfflinePage() const {
+bool ChromeLocationBarModelDelegate::IsOfflinePage() const {
 #if BUILDFLAG(ENABLE_OFFLINE_PAGES)
   content::WebContents* web_contents = GetActiveWebContents();
   return web_contents &&
@@ -166,7 +167,7 @@
 }
 
 content::NavigationController*
-ChromeToolbarModelDelegate::GetNavigationController() const {
+ChromeLocationBarModelDelegate::GetNavigationController() const {
   // This |current_tab| can be null during the initialization of the toolbar
   // during window creation (i.e. before any tabs have been added to the
   // window).
@@ -174,7 +175,7 @@
   return current_tab ? &current_tab->GetController() : nullptr;
 }
 
-Profile* ChromeToolbarModelDelegate::GetProfile() const {
+Profile* ChromeLocationBarModelDelegate::GetProfile() const {
   content::NavigationController* controller = GetNavigationController();
   return controller
              ? Profile::FromBrowserContext(controller->GetBrowserContext())
diff --git a/chrome/browser/ui/toolbar/chrome_toolbar_model_delegate.h b/chrome/browser/ui/toolbar/chrome_location_bar_model_delegate.h
similarity index 67%
rename from chrome/browser/ui/toolbar/chrome_toolbar_model_delegate.h
rename to chrome/browser/ui/toolbar/chrome_location_bar_model_delegate.h
index 70a4491..64851742 100644
--- a/chrome/browser/ui/toolbar/chrome_toolbar_model_delegate.h
+++ b/chrome/browser/ui/toolbar/chrome_location_bar_model_delegate.h
@@ -2,11 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_UI_TOOLBAR_CHROME_TOOLBAR_MODEL_DELEGATE_H_
-#define CHROME_BROWSER_UI_TOOLBAR_CHROME_TOOLBAR_MODEL_DELEGATE_H_
+#ifndef CHROME_BROWSER_UI_TOOLBAR_CHROME_LOCATION_BAR_MODEL_DELEGATE_H_
+#define CHROME_BROWSER_UI_TOOLBAR_CHROME_LOCATION_BAR_MODEL_DELEGATE_H_
 
 #include "base/macros.h"
-#include "components/omnibox/browser/toolbar_model_delegate.h"
+#include "components/omnibox/browser/location_bar_model_delegate.h"
 
 class Profile;
 
@@ -14,21 +14,21 @@
 class NavigationEntry;
 class NavigationController;
 class WebContents;
-}
+}  // namespace content
 
-// Implementation of ToolbarModelDelegate for the Chrome embedder. It leaves out
-// how to fetch the active WebContents to its subclasses.
-class ChromeToolbarModelDelegate : public ToolbarModelDelegate {
+// Implementation of LocationBarModelDelegate for the Chrome embedder. It leaves
+// out how to fetch the active WebContents to its subclasses.
+class ChromeLocationBarModelDelegate : public LocationBarModelDelegate {
  public:
   // Returns active WebContents.
   virtual content::WebContents* GetActiveWebContents() const = 0;
 
-  // ToolbarModelDelegate:
+  // LocationBarModelDelegate:
   bool ShouldDisplayURL() const override;
 
  protected:
-  ChromeToolbarModelDelegate();
-  ~ChromeToolbarModelDelegate() override;
+  ChromeLocationBarModelDelegate();
+  ~ChromeLocationBarModelDelegate() override;
 
   // Helper method to get the navigation entry from the navigation controller.
   content::NavigationEntry* GetNavigationEntry() const;
@@ -53,7 +53,7 @@
   // Helper method to extract the profile from the navigation controller.
   Profile* GetProfile() const;
 
-  DISALLOW_COPY_AND_ASSIGN(ChromeToolbarModelDelegate);
+  DISALLOW_COPY_AND_ASSIGN(ChromeLocationBarModelDelegate);
 };
 
-#endif  // CHROME_BROWSER_UI_TOOLBAR_CHROME_TOOLBAR_MODEL_DELEGATE_H_
+#endif  // CHROME_BROWSER_UI_TOOLBAR_CHROME_LOCATION_BAR_MODEL_DELEGATE_H_
diff --git a/chrome/browser/ui/toolbar/toolbar_model_unittest.cc b/chrome/browser/ui/toolbar/location_bar_model_unittest.cc
similarity index 81%
rename from chrome/browser/ui/toolbar/toolbar_model_unittest.cc
rename to chrome/browser/ui/toolbar/location_bar_model_unittest.cc
index ed8467d..506ccc64b 100644
--- a/chrome/browser/ui/toolbar/toolbar_model_unittest.cc
+++ b/chrome/browser/ui/toolbar/location_bar_model_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 "components/omnibox/browser/toolbar_model.h"
+#include "components/omnibox/browser/location_bar_model.h"
 
 #include <stddef.h>
 
@@ -17,7 +17,6 @@
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/test/base/browser_with_test_window_test.h"
 #include "components/omnibox/browser/omnibox_field_trial.h"
-#include "components/omnibox/browser/toolbar_model.h"
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/ssl_status.h"
 #include "content/public/common/content_constants.h"
@@ -81,13 +80,13 @@
 
 }  // namespace
 
+// LocationBarModelTest
+// -----------------------------------------------------------
 
-// ToolbarModelTest -----------------------------------------------------------
-
-class ToolbarModelTest : public BrowserWithTestWindowTest {
+class LocationBarModelTest : public BrowserWithTestWindowTest {
  public:
-  ToolbarModelTest();
-  ~ToolbarModelTest() override;
+  LocationBarModelTest();
+  ~LocationBarModelTest() override;
 
   // BrowserWithTestWindowTest:
   void SetUp() override;
@@ -100,16 +99,14 @@
   void NavigateAndCheckElided(const GURL& https_url);
 
  private:
-  DISALLOW_COPY_AND_ASSIGN(ToolbarModelTest);
+  DISALLOW_COPY_AND_ASSIGN(LocationBarModelTest);
 };
 
-ToolbarModelTest::ToolbarModelTest() {
-}
+LocationBarModelTest::LocationBarModelTest() {}
 
-ToolbarModelTest::~ToolbarModelTest() {
-}
+LocationBarModelTest::~LocationBarModelTest() {}
 
-void ToolbarModelTest::SetUp() {
+void LocationBarModelTest::SetUp() {
   BrowserWithTestWindowTest::SetUp();
   AutocompleteClassifierFactory::GetInstance()->SetTestingFactoryAndUse(
       profile(),
@@ -132,7 +129,7 @@
 #endif
 }
 
-void ToolbarModelTest::NavigateAndCheckText(
+void LocationBarModelTest::NavigateAndCheckText(
     const GURL& url,
     const base::string16& expected_formatted_full_url,
     const base::string16& expected_elided_url_for_display) {
@@ -141,34 +138,39 @@
       &browser()->tab_strip_model()->GetActiveWebContents()->GetController();
   controller->LoadURL(url, content::Referrer(), ui::PAGE_TRANSITION_LINK,
                       std::string());
-  ToolbarModel* toolbar_model = browser()->toolbar_model();
-  EXPECT_EQ(expected_formatted_full_url, toolbar_model->GetFormattedFullURL());
+  LocationBarModel* location_bar_model = browser()->location_bar_model();
+  EXPECT_EQ(expected_formatted_full_url,
+            location_bar_model->GetFormattedFullURL());
   EXPECT_NE(expected_formatted_full_url.empty(),
-            toolbar_model->ShouldDisplayURL());
-  EXPECT_EQ(expected_elided_url_for_display, toolbar_model->GetURLForDisplay());
+            location_bar_model->ShouldDisplayURL());
+  EXPECT_EQ(expected_elided_url_for_display,
+            location_bar_model->GetURLForDisplay());
 
   // Check after commit.
   CommitPendingLoad(controller);
-  EXPECT_EQ(expected_formatted_full_url, toolbar_model->GetFormattedFullURL());
+  EXPECT_EQ(expected_formatted_full_url,
+            location_bar_model->GetFormattedFullURL());
   EXPECT_NE(expected_formatted_full_url.empty(),
-            toolbar_model->ShouldDisplayURL());
-  EXPECT_EQ(expected_elided_url_for_display, toolbar_model->GetURLForDisplay());
+            location_bar_model->ShouldDisplayURL());
+  EXPECT_EQ(expected_elided_url_for_display,
+            location_bar_model->GetURLForDisplay());
 }
 
-void ToolbarModelTest::NavigateAndCheckElided(const GURL& url) {
+void LocationBarModelTest::NavigateAndCheckElided(const GURL& url) {
   // Check while loading.
   content::NavigationController* controller =
       &browser()->tab_strip_model()->GetActiveWebContents()->GetController();
   controller->LoadURL(url, content::Referrer(), ui::PAGE_TRANSITION_LINK,
                       std::string());
-  ToolbarModel* toolbar_model = browser()->toolbar_model();
+  LocationBarModel* location_bar_model = browser()->location_bar_model();
   const base::string16 formatted_full_url_before(
-      toolbar_model->GetFormattedFullURL());
+      location_bar_model->GetFormattedFullURL());
   EXPECT_LT(formatted_full_url_before.size(), url.spec().size());
   EXPECT_TRUE(base::EndsWith(formatted_full_url_before,
                              base::string16(gfx::kEllipsisUTF16),
                              base::CompareCase::SENSITIVE));
-  const base::string16 display_url_before(toolbar_model->GetURLForDisplay());
+  const base::string16 display_url_before(
+      location_bar_model->GetURLForDisplay());
   EXPECT_LT(display_url_before.size(), url.spec().size());
   EXPECT_TRUE(base::EndsWith(display_url_before,
                              base::string16(gfx::kEllipsisUTF16),
@@ -177,12 +179,13 @@
   // Check after commit.
   CommitPendingLoad(controller);
   const base::string16 formatted_full_url_after(
-      toolbar_model->GetFormattedFullURL());
+      location_bar_model->GetFormattedFullURL());
   EXPECT_LT(formatted_full_url_after.size(), url.spec().size());
   EXPECT_TRUE(base::EndsWith(formatted_full_url_after,
                              base::string16(gfx::kEllipsisUTF16),
                              base::CompareCase::SENSITIVE));
-  const base::string16 display_url_after(toolbar_model->GetURLForDisplay());
+  const base::string16 display_url_after(
+      location_bar_model->GetURLForDisplay());
   EXPECT_LT(display_url_after.size(), url.spec().size());
   EXPECT_TRUE(base::EndsWith(display_url_after,
                              base::string16(gfx::kEllipsisUTF16),
@@ -192,7 +195,7 @@
 // Actual tests ---------------------------------------------------------------
 
 // Test URL display.
-TEST_F(ToolbarModelTest, ShouldDisplayURL) {
+TEST_F(LocationBarModelTest, ShouldDisplayURL) {
   base::test::ScopedFeatureList feature_list;
   feature_list.InitWithFeatures({omnibox::kHideSteadyStateUrlScheme,
                                  omnibox::kHideSteadyStateUrlTrivialSubdomains},
@@ -209,7 +212,7 @@
 }
 
 // Tests every combination of Steady State Elision flags.
-TEST_F(ToolbarModelTest, SteadyStateElisionsFlags) {
+TEST_F(LocationBarModelTest, SteadyStateElisionsFlags) {
   AddTab(browser(), GURL(url::kAboutBlankURL));
 
   // Hide Scheme and Hide Trivial Subdomains both Disabled.
@@ -258,7 +261,7 @@
   }
 }
 
-TEST_F(ToolbarModelTest, ShouldElideLongURLs) {
+TEST_F(LocationBarModelTest, ShouldElideLongURLs) {
   AddTab(browser(), GURL(url::kAboutBlankURL));
   const std::string long_text(content::kMaxURLDisplayChars + 1024, '0');
   NavigateAndCheckElided(
@@ -267,13 +270,13 @@
 }
 
 // Regression test for crbug.com/792401.
-TEST_F(ToolbarModelTest, ShouldDisplayURLWhileNavigatingAwayFromNTP) {
-  ToolbarModel* toolbar_model = browser()->toolbar_model();
+TEST_F(LocationBarModelTest, ShouldDisplayURLWhileNavigatingAwayFromNTP) {
+  LocationBarModel* location_bar_model = browser()->location_bar_model();
 
   // Open an NTP. Its URL should not be displayed.
   AddTab(browser(), GURL("chrome://newtab"));
-  ASSERT_FALSE(toolbar_model->ShouldDisplayURL());
-  ASSERT_TRUE(toolbar_model->GetFormattedFullURL().empty());
+  ASSERT_FALSE(location_bar_model->ShouldDisplayURL());
+  ASSERT_TRUE(location_bar_model->GetFormattedFullURL().empty());
 
   const std::string other_url = "https://www.foo.com";
 
@@ -283,13 +286,13 @@
       &browser()->tab_strip_model()->GetActiveWebContents()->GetController();
   controller->LoadURL(GURL(other_url), content::Referrer(),
                       ui::PAGE_TRANSITION_LINK, std::string());
-  EXPECT_TRUE(toolbar_model->ShouldDisplayURL());
+  EXPECT_TRUE(location_bar_model->ShouldDisplayURL());
   EXPECT_EQ(base::ASCIIToUTF16(other_url),
-            toolbar_model->GetFormattedFullURL());
+            location_bar_model->GetFormattedFullURL());
 
   // Of course the same should still hold after committing.
   CommitPendingLoad(controller);
-  EXPECT_TRUE(toolbar_model->ShouldDisplayURL());
+  EXPECT_TRUE(location_bar_model->ShouldDisplayURL());
   EXPECT_EQ(base::ASCIIToUTF16(other_url),
-            toolbar_model->GetFormattedFullURL());
+            location_bar_model->GetFormattedFullURL());
 }
diff --git a/chrome/browser/ui/toolbar/toolbar_actions_model.h b/chrome/browser/ui/toolbar/toolbar_actions_model.h
index bd0aab4..c49624c 100644
--- a/chrome/browser/ui/toolbar/toolbar_actions_model.h
+++ b/chrome/browser/ui/toolbar/toolbar_actions_model.h
@@ -192,7 +192,7 @@
   void OnActionToolbarPrefChange();
 
   // Highlights the actions specified by |action_ids|. This will cause
-  // the ToolbarModel to only display those actions.
+  // the LocationBarModel to only display those actions.
   // Highlighting mode is only entered if there is at least one action to be
   // shown.
   // Returns true if highlighting mode is entered, false otherwise.
diff --git a/chrome/browser/ui/toolbar/toolbar_actions_model_unittest.cc b/chrome/browser/ui/toolbar/toolbar_actions_model_unittest.cc
index 8060033..7c797045 100644
--- a/chrome/browser/ui/toolbar/toolbar_actions_model_unittest.cc
+++ b/chrome/browser/ui/toolbar/toolbar_actions_model_unittest.cc
@@ -1161,7 +1161,7 @@
 
 // Check that the toolbar model correctly clears and reorders when it detects
 // a preference change.
-TEST_F(ToolbarActionsModelUnitTest, ToolbarModelPrefChange) {
+TEST_F(ToolbarActionsModelUnitTest, LocationBarModelPrefChange) {
   Init();
 
   ASSERT_TRUE(AddBrowserActionExtensions());
diff --git a/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.cc b/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.cc
index 29e612b..10bc1666 100644
--- a/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.cc
+++ b/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura_ash.cc
@@ -507,6 +507,7 @@
     ash::wm::WindowState* window_state,
     ash::mojom::WindowStateType old_type) {
   DCHECK(!features::IsUsingWindowService());
+  DCHECK(!IsFrameless());
   DCHECK_EQ(GetNativeWindow(), window_state->window());
   if (window_state->IsFullscreen() != app_window()->IsFullscreen()) {
     // Report OS-initiated state changes to |app_window()|. This is done in
@@ -587,8 +588,8 @@
 }
 
 bool ChromeNativeAppWindowViewsAuraAsh::ShouldEnableImmersiveMode() const {
-  // No immersive mode for forced fullscreen.
-  if (app_window()->IsForcedFullscreen())
+  // No immersive mode for forced fullscreen or frameless windows.
+  if (app_window()->IsForcedFullscreen() || IsFrameless())
     return false;
 
   // Always use immersive mode in a public session in fullscreen state.
@@ -605,8 +606,6 @@
   // have access to window controls. Non resizable windows do not gain
   // size by hidding the title bar, so it is not hidden and thus there
   // is no need for immersive mode.
-  // TODO(sammiequon): Investigate whether we should check
-  // resizability using WindowState instead of CanResize.
   // TODO(crbug.com/801619): This adds a little extra animation
   // when minimizing or unminimizing window.
   return client && client->tablet_mode_enabled() && CanResize() &&
diff --git a/chrome/browser/ui/views/frame/immersive_context_mus.cc b/chrome/browser/ui/views/frame/immersive_context_mus.cc
index 6e27f23..85dc0324 100644
--- a/chrome/browser/ui/views/frame/immersive_context_mus.cc
+++ b/chrome/browser/ui/views/frame/immersive_context_mus.cc
@@ -31,8 +31,6 @@
       controller->widget()->GetNativeWindow()->GetRootWindow();
   // Auto hide the shelf in immersive fullscreen instead of hiding it.
   window->SetProperty(ash::kHideShelfWhenFullscreenKey, !entering);
-  // Update the window's immersive mode state for the window manager.
-  window->SetProperty(aura::client::kImmersiveFullscreenKey, entering);
 }
 
 gfx::Rect ImmersiveContextMus::GetDisplayBoundsInScreen(views::Widget* widget) {
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 bacbe888..aa8cb90 100644
--- a/chrome/browser/ui/views/location_bar/location_bar_view.cc
+++ b/chrome/browser/ui/views/location_bar/location_bar_view.cc
@@ -61,10 +61,10 @@
 #include "chrome/grit/generated_resources.h"
 #include "components/bookmarks/common/bookmark_pref_names.h"
 #include "components/favicon/content/content_favicon_driver.h"
+#include "components/omnibox/browser/location_bar_model.h"
 #include "components/omnibox/browser/omnibox_field_trial.h"
 #include "components/omnibox/browser/omnibox_popup_model.h"
 #include "components/omnibox/browser/omnibox_popup_view.h"
-#include "components/omnibox/browser/toolbar_model.h"
 #include "components/omnibox/browser/vector_icons.h"
 #include "components/prefs/pref_service.h"
 #include "components/search_engines/template_url.h"
@@ -656,8 +656,8 @@
   Update(nullptr);
 }
 
-ToolbarModel* LocationBarView::GetToolbarModel() {
-  return delegate_->GetToolbarModel();
+LocationBarModel* LocationBarView::GetLocationBarModel() {
+  return delegate_->GetLocationBarModel();
 }
 
 WebContents* LocationBarView::GetWebContents() {
@@ -672,7 +672,8 @@
 }
 
 content::WebContents* LocationBarView::GetContentSettingWebContents() {
-  return GetToolbarModel()->input_in_progress() ? nullptr : GetWebContents();
+  return GetLocationBarModel()->input_in_progress() ? nullptr
+                                                    : GetWebContents();
 }
 
 ContentSettingBubbleModelDelegate*
@@ -948,11 +949,11 @@
 
 void LocationBarView::UpdateBookmarkStarVisibility() {
   if (star_view_) {
-    star_view_->SetVisible(
-        browser_defaults::bookmarks_enabled && !is_popup_mode_ &&
-        !GetToolbarModel()->input_in_progress() &&
-        edit_bookmarks_enabled_.GetValue() &&
-        !IsBookmarkStarHiddenByExtension());
+    star_view_->SetVisible(browser_defaults::bookmarks_enabled &&
+                           !is_popup_mode_ &&
+                           !GetLocationBarModel()->input_in_progress() &&
+                           edit_bookmarks_enabled_.GetValue() &&
+                           !IsBookmarkStarHiddenByExtension());
   }
 }
 
@@ -1112,7 +1113,7 @@
 
 void LocationBarView::OnChanged() {
   location_icon_view_->Update();
-  clear_all_button_->SetVisible(GetToolbarModel()->input_in_progress() &&
+  clear_all_button_->SetVisible(GetLocationBarModel()->input_in_progress() &&
                                 !omnibox_view_->text().empty() &&
                                 IsVirtualKeyboardVisible(GetWidget()));
   Layout();
@@ -1132,8 +1133,8 @@
   }
 }
 
-const ToolbarModel* LocationBarView::GetToolbarModel() const {
-  return delegate_->GetToolbarModel();
+const LocationBarModel* LocationBarView::GetLocationBarModel() const {
+  return delegate_->GetLocationBarModel();
 }
 
 void LocationBarView::OnOmniboxFocused() {
@@ -1270,12 +1271,13 @@
 
 gfx::ImageSkia LocationBarView::GetLocationIcon(
     LocationIconView::Delegate::IconFetchedCallback on_icon_fetched) const {
-  return omnibox_view() ? omnibox_view()->GetIcon(
-                              GetLayoutConstant(LOCATION_BAR_ICON_SIZE),
-                              GetSecurityChipColor(
-                                  GetToolbarModel()->GetSecurityLevel(false)),
-                              std::move(on_icon_fetched))
-                        : gfx::ImageSkia();
+  return omnibox_view()
+             ? omnibox_view()->GetIcon(
+                   GetLayoutConstant(LOCATION_BAR_ICON_SIZE),
+                   GetSecurityChipColor(
+                       GetLocationBarModel()->GetSecurityLevel(false)),
+                   std::move(on_icon_fetched))
+             : gfx::ImageSkia();
 }
 
 SkColor LocationBarView::GetLocationIconInkDropColor() const {
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 7c1b89bb..a39e379 100644
--- a/chrome/browser/ui/views/location_bar/location_bar_view.h
+++ b/chrome/browser/ui/views/location_bar/location_bar_view.h
@@ -89,8 +89,8 @@
     // Should return the current web contents.
     virtual content::WebContents* GetWebContents() = 0;
 
-    virtual ToolbarModel* GetToolbarModel() = 0;
-    virtual const ToolbarModel* GetToolbarModel() const = 0;
+    virtual LocationBarModel* GetLocationBarModel() = 0;
+    virtual const LocationBarModel* GetLocationBarModel() const = 0;
 
     // Returns ContentSettingBubbleModelDelegate.
     virtual ContentSettingBubbleModelDelegate*
@@ -225,7 +225,7 @@
 
   // ChromeOmniboxEditController:
   void UpdateWithoutTabRestore() override;
-  ToolbarModel* GetToolbarModel() override;
+  LocationBarModel* GetLocationBarModel() override;
   content::WebContents* GetWebContents() override;
 
   // ContentSettingImageView::Delegate:
@@ -364,7 +364,7 @@
   // ChromeOmniboxEditController:
   void OnChanged() override;
   void OnPopupVisibilityChanged() override;
-  const ToolbarModel* GetToolbarModel() const override;
+  const LocationBarModel* GetLocationBarModel() const override;
 
   // DropdownBarHostDelegate:
   void SetFocusAndSelection(bool select_all) override;
diff --git a/chrome/browser/ui/views/location_bar/location_bar_view_browsertest.cc b/chrome/browser/ui/views/location_bar/location_bar_view_browsertest.cc
index 79cfa92..362ae13c 100644
--- a/chrome/browser/ui/views/location_bar/location_bar_view_browsertest.cc
+++ b/chrome/browser/ui/views/location_bar/location_bar_view_browsertest.cc
@@ -21,8 +21,8 @@
 #include "chrome/common/chrome_paths.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
+#include "components/omnibox/browser/location_bar_model_impl.h"
 #include "components/omnibox/browser/omnibox_field_trial.h"
-#include "components/omnibox/browser/toolbar_model_impl.h"
 #include "components/security_state/core/security_state.h"
 #include "components/zoom/zoom_controller.h"
 #include "content/public/browser/browser_thread.h"
diff --git a/chrome/browser/ui/views/location_bar/location_icon_view.cc b/chrome/browser/ui/views/location_bar/location_icon_view.cc
index 61774fa..44d5abc 100644
--- a/chrome/browser/ui/views/location_bar/location_icon_view.cc
+++ b/chrome/browser/ui/views/location_bar/location_icon_view.cc
@@ -13,7 +13,6 @@
 #include "chrome/grit/generated_resources.h"
 #include "components/omnibox/browser/omnibox_edit_model.h"
 #include "components/omnibox/browser/omnibox_field_trial.h"
-#include "components/omnibox/browser/toolbar_model.h"
 #include "components/security_state/core/security_state.h"
 #include "components/strings/grit/components_strings.h"
 #include "content/public/browser/web_contents.h"
@@ -62,7 +61,7 @@
 
 SkColor LocationIconView::GetTextColor() const {
   return delegate_->GetSecurityChipColor(
-      delegate_->GetToolbarModel()->GetSecurityLevel(false));
+      delegate_->GetLocationBarModel()->GetSecurityLevel(false));
 }
 
 bool LocationIconView::ShouldShowSeparator() const {
@@ -98,7 +97,7 @@
   }
 
   security_state::SecurityLevel security_level =
-      delegate_->GetToolbarModel()->GetSecurityLevel(false);
+      delegate_->GetLocationBarModel()->GetSecurityLevel(false);
   if (label()->text().empty() && (security_level == security_state::EV_SECURE ||
                                   security_level == security_state::SECURE)) {
     node_data->AddStringAttribute(
@@ -132,24 +131,25 @@
 }
 
 bool LocationIconView::ShouldShowText() const {
-  const auto* toolbar_model = delegate_->GetToolbarModel();
+  const auto* location_bar_model = delegate_->GetLocationBarModel();
 
-  if (!toolbar_model->input_in_progress()) {
-    const GURL& url = toolbar_model->GetURL();
+  if (!location_bar_model->input_in_progress()) {
+    const GURL& url = location_bar_model->GetURL();
     if (url.SchemeIs(content::kChromeUIScheme) ||
         url.SchemeIs(extensions::kExtensionScheme) ||
         url.SchemeIs(url::kFileScheme))
       return true;
   }
 
-  return !toolbar_model->GetSecureVerboseText().empty();
+  return !location_bar_model->GetSecureVerboseText().empty();
 }
 
 base::string16 LocationIconView::GetText() const {
-  if (delegate_->GetToolbarModel()->GetURL().SchemeIs(content::kChromeUIScheme))
+  if (delegate_->GetLocationBarModel()->GetURL().SchemeIs(
+          content::kChromeUIScheme))
     return l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME);
 
-  if (delegate_->GetToolbarModel()->GetURL().SchemeIs(url::kFileScheme))
+  if (delegate_->GetLocationBarModel()->GetURL().SchemeIs(url::kFileScheme))
     return l10n_util::GetStringUTF16(IDS_OMNIBOX_FILE);
 
   if (delegate_->GetWebContents()) {
@@ -160,18 +160,19 @@
     // instead.
     const base::string16 extension_name =
         extensions::ui_util::GetEnabledExtensionNameForUrl(
-            delegate_->GetToolbarModel()->GetURL(),
+            delegate_->GetLocationBarModel()->GetURL(),
             delegate_->GetWebContents()->GetBrowserContext());
     if (!extension_name.empty())
       return extension_name;
   }
 
-  return delegate_->GetToolbarModel()->GetSecureVerboseText();
+  return delegate_->GetLocationBarModel()->GetSecureVerboseText();
 }
 
 bool LocationIconView::ShouldAnimateTextVisibilityChange() const {
   using SecurityLevel = security_state::SecurityLevel;
-  SecurityLevel level = delegate_->GetToolbarModel()->GetSecurityLevel(false);
+  SecurityLevel level =
+      delegate_->GetLocationBarModel()->GetSecurityLevel(false);
   // Do not animate transitions from HTTP_SHOW_WARNING to DANGEROUS, since the
   // transition can look confusing/messy.
   if (level == SecurityLevel::DANGEROUS &&
@@ -238,7 +239,7 @@
 #endif
 
   last_update_security_level_ =
-      delegate_->GetToolbarModel()->GetSecurityLevel(false);
+      delegate_->GetLocationBarModel()->GetSecurityLevel(false);
 }
 
 bool LocationIconView::IsTriggerableEvent(const ui::Event& event) {
diff --git a/chrome/browser/ui/views/location_bar/location_icon_view.h b/chrome/browser/ui/views/location_bar/location_icon_view.h
index 0106fc0..a4cc2e00 100644
--- a/chrome/browser/ui/views/location_bar/location_icon_view.h
+++ b/chrome/browser/ui/views/location_bar/location_icon_view.h
@@ -7,7 +7,7 @@
 
 #include "base/macros.h"
 #include "chrome/browser/ui/views/location_bar/icon_label_bubble_view.h"
-#include "components/omnibox/browser/toolbar_model.h"
+#include "components/omnibox/browser/location_bar_model.h"
 
 namespace content {
 class WebContents;
@@ -50,8 +50,8 @@
     // false otherwise.
     virtual bool ShowPageInfoDialog() = 0;
 
-    // Gets the ToolbarModel.
-    const virtual ToolbarModel* GetToolbarModel() const = 0;
+    // Gets the LocationBarModel.
+    const virtual LocationBarModel* GetLocationBarModel() const = 0;
 
     // Gets an icon for the location bar icon chip.
     virtual gfx::ImageSkia GetLocationIcon(
diff --git a/chrome/browser/ui/views/media_router/presentation_receiver_window_view.cc b/chrome/browser/ui/views/media_router/presentation_receiver_window_view.cc
index 25960497..72f6baba 100644
--- a/chrome/browser/ui/views/media_router/presentation_receiver_window_view.cc
+++ b/chrome/browser/ui/views/media_router/presentation_receiver_window_view.cc
@@ -25,7 +25,7 @@
 #include "chrome/browser/ui/views/accelerator_table.h"
 #include "chrome/browser/ui/views/exclusive_access_bubble_views.h"
 #include "chrome/browser/ui/views/media_router/presentation_receiver_window_frame.h"
-#include "components/omnibox/browser/toolbar_model_impl.h"
+#include "components/omnibox/browser/location_bar_model_impl.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/content_constants.h"
 #include "ui/base/accelerators/accelerator_manager.h"
@@ -104,9 +104,9 @@
     PresentationReceiverWindowDelegate* delegate)
     : frame_(frame),
       delegate_(delegate),
-      toolbar_model_(
-          std::make_unique<ToolbarModelImpl>(this,
-                                             content::kMaxURLDisplayChars)),
+      location_bar_model_(
+          std::make_unique<LocationBarModelImpl>(this,
+                                                 content::kMaxURLDisplayChars)),
       command_updater_(this),
       exclusive_access_manager_(this) {
   DCHECK(frame);
@@ -221,12 +221,13 @@
   return delegate_->web_contents();
 }
 
-ToolbarModel* PresentationReceiverWindowView::GetToolbarModel() {
-  return toolbar_model_.get();
+LocationBarModel* PresentationReceiverWindowView::GetLocationBarModel() {
+  return location_bar_model_.get();
 }
 
-const ToolbarModel* PresentationReceiverWindowView::GetToolbarModel() const {
-  return toolbar_model_.get();
+const LocationBarModel* PresentationReceiverWindowView::GetLocationBarModel()
+    const {
+  return location_bar_model_.get();
 }
 
 ContentSettingBubbleModelDelegate*
diff --git a/chrome/browser/ui/views/media_router/presentation_receiver_window_view.h b/chrome/browser/ui/views/media_router/presentation_receiver_window_view.h
index aae8675..f74da59 100644
--- a/chrome/browser/ui/views/media_router/presentation_receiver_window_view.h
+++ b/chrome/browser/ui/views/media_router/presentation_receiver_window_view.h
@@ -15,7 +15,7 @@
 #include "chrome/browser/ui/exclusive_access/exclusive_access_context.h"
 #include "chrome/browser/ui/exclusive_access/exclusive_access_manager.h"
 #include "chrome/browser/ui/media_router/presentation_receiver_window.h"
-#include "chrome/browser/ui/toolbar/chrome_toolbar_model_delegate.h"
+#include "chrome/browser/ui/toolbar/chrome_location_bar_model_delegate.h"
 #include "chrome/browser/ui/views/exclusive_access_bubble_views_context.h"
 #include "chrome/browser/ui/views/location_bar/location_bar_view.h"
 #include "ui/views/widget/widget_delegate.h"
@@ -23,7 +23,7 @@
 class ExclusiveAccessBubbleViews;
 class PresentationReceiverWindowDelegate;
 class PresentationReceiverWindowFrame;
-class ToolbarModelImpl;
+class LocationBarModelImpl;
 
 #if defined(OS_CHROMEOS)
 class FullscreenWindowObserver;
@@ -37,7 +37,7 @@
       public views::WidgetDelegateView,
       public LocationBarView::Delegate,
       public CommandUpdaterDelegate,
-      public ChromeToolbarModelDelegate,
+      public ChromeLocationBarModelDelegate,
       public ExclusiveAccessContext,
       public ExclusiveAccessBubbleViewsContext,
       public ui::AcceleratorProvider {
@@ -61,8 +61,8 @@
 
   // LocationBarView::Delegate overrides.
   content::WebContents* GetWebContents() final;
-  ToolbarModel* GetToolbarModel() final;
-  const ToolbarModel* GetToolbarModel() const final;
+  LocationBarModel* GetLocationBarModel() final;
+  const LocationBarModel* GetLocationBarModel() const final;
   ContentSettingBubbleModelDelegate* GetContentSettingBubbleModelDelegate()
       final;
 
@@ -70,7 +70,7 @@
   void ExecuteCommandWithDisposition(int id,
                                      WindowOpenDisposition disposition) final;
 
-  // ChromeToolbarModelDelegate overrides.
+  // ChromeLocationBarModelDelegate overrides.
   content::WebContents* GetActiveWebContents() const final;
 
   // views::WidgetDelegateView overrides.
@@ -123,7 +123,7 @@
   PresentationReceiverWindowFrame* const frame_;
   PresentationReceiverWindowDelegate* const delegate_;
   base::string16 title_;
-  const std::unique_ptr<ToolbarModelImpl> toolbar_model_;
+  const std::unique_ptr<LocationBarModelImpl> location_bar_model_;
   CommandUpdaterImpl command_updater_;
   LocationBarView* location_bar_view_ = nullptr;
   ExclusiveAccessManager exclusive_access_manager_;
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
index d4ec646..5d9fc013 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
@@ -28,12 +28,12 @@
 #include "components/feature_engagement/buildflags.h"
 #include "components/omnibox/browser/autocomplete_input.h"
 #include "components/omnibox/browser/autocomplete_match.h"
+#include "components/omnibox/browser/location_bar_model.h"
 #include "components/omnibox/browser/omnibox_client.h"
 #include "components/omnibox/browser/omnibox_edit_controller.h"
 #include "components/omnibox/browser/omnibox_edit_model.h"
 #include "components/omnibox/browser/omnibox_field_trial.h"
 #include "components/omnibox/browser/omnibox_popup_model.h"
-#include "components/omnibox/browser/toolbar_model.h"
 #include "components/search_engines/template_url_service.h"
 #include "components/strings/grit/components_strings.h"
 #include "content/public/browser/web_contents.h"
@@ -537,7 +537,8 @@
 }
 
 void OmniboxViewViews::UpdateSecurityLevel() {
-  security_level_ = controller()->GetToolbarModel()->GetSecurityLevel(false);
+  security_level_ =
+      controller()->GetLocationBarModel()->GetSecurityLevel(false);
 }
 
 void OmniboxViewViews::SetWindowTextAndCaretPos(const base::string16& text,
@@ -664,7 +665,7 @@
     return false;
 
   base::string16 full_url =
-      controller()->GetToolbarModel()->GetFormattedFullURL();
+      controller()->GetLocationBarModel()->GetFormattedFullURL();
   size_t start, end;
   GetSelectionBounds(&start, &end);
 
@@ -1064,7 +1065,7 @@
 // it would be immediately useful.
 #if BUILDFLAG(ENABLE_DESKTOP_IN_PRODUCT_HELP)
   if (location_bar_view_ &&
-      controller()->GetToolbarModel()->ShouldDisplayURL()) {
+      controller()->GetLocationBarModel()->ShouldDisplayURL()) {
     feature_engagement::NewTabTrackerFactory::GetInstance()
         ->GetForProfile(location_bar_view_->profile())
         ->OnOmniboxFocused();
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views.h b/chrome/browser/ui/views/omnibox/omnibox_view_views.h
index de32d45..30dfd0ee 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_view_views.h
+++ b/chrome/browser/ui/views/omnibox/omnibox_view_views.h
@@ -179,7 +179,7 @@
   // Handle keyword hint tab-to-search and tabbing through dropdown results.
   bool HandleEarlyTabActions(const ui::KeyEvent& event);
 
-  // Updates |security_level_| based on the toolbar model's current value.
+  // Updates |security_level_| based on the location bar model's current value.
   void UpdateSecurityLevel();
 
   void ClearAccessibilityLabel();
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc
index 290dda0..eabe3f1 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc
@@ -27,7 +27,7 @@
 #include "chrome/test/views/chrome_views_test_base.h"
 #include "components/omnibox/browser/omnibox_edit_model.h"
 #include "components/omnibox/browser/omnibox_field_trial.h"
-#include "components/omnibox/browser/test_toolbar_model.h"
+#include "components/omnibox/browser/test_location_bar_model.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/ime/input_method.h"
@@ -166,18 +166,20 @@
 class TestingOmniboxEditController : public ChromeOmniboxEditController {
  public:
   TestingOmniboxEditController(CommandUpdater* command_updater,
-                               ToolbarModel* toolbar_model)
+                               LocationBarModel* location_bar_model)
       : ChromeOmniboxEditController(command_updater),
-        toolbar_model_(toolbar_model) {}
+        location_bar_model_(location_bar_model) {}
 
  private:
   // ChromeOmniboxEditController:
-  ToolbarModel* GetToolbarModel() override { return toolbar_model_; }
-  const ToolbarModel* GetToolbarModel() const override {
-    return toolbar_model_;
+  LocationBarModel* GetLocationBarModel() override {
+    return location_bar_model_;
+  }
+  const LocationBarModel* GetLocationBarModel() const override {
+    return location_bar_model_;
   }
 
-  ToolbarModel* toolbar_model_;
+  LocationBarModel* location_bar_model_;
 
   DISALLOW_COPY_AND_ASSIGN(TestingOmniboxEditController);
 };
@@ -205,7 +207,7 @@
 
   OmniboxViewViewsTest() : OmniboxViewViewsTest(std::vector<base::Feature>()) {}
 
-  TestToolbarModel* toolbar_model() { return &toolbar_model_; }
+  TestLocationBarModel* location_bar_model() { return &location_bar_model_; }
   TestingOmniboxView* omnibox_view() const { return omnibox_view_; }
   views::Textfield* omnibox_textfield() const { return omnibox_view(); }
   ui::TextEditCommand scheduled_text_edit_command() const {
@@ -236,7 +238,7 @@
   TestingProfile profile_;
   TemplateURLServiceFactoryTestUtil util_;
   CommandUpdaterImpl command_updater_;
-  TestToolbarModel toolbar_model_;
+  TestLocationBarModel location_bar_model_;
   TestingOmniboxEditController omnibox_edit_controller_;
 
   std::unique_ptr<views::Widget> widget_;
@@ -254,7 +256,7 @@
     : OmniboxViewViewsTestBase(enabled_features),
       util_(&profile_),
       command_updater_(nullptr),
-      omnibox_edit_controller_(&command_updater_, &toolbar_model_) {}
+      omnibox_edit_controller_(&command_updater_, &location_bar_model_) {}
 
 void OmniboxViewViewsTest::SetAndEmphasizeText(const std::string& new_text,
                                                bool accept_input) {
@@ -478,7 +480,7 @@
 }
 
 TEST_F(OmniboxViewViewsTest, RevertOnBlur) {
-  toolbar_model()->set_url(GURL("https://permanent-text.com/"));
+  location_bar_model()->set_url(GURL("https://permanent-text.com/"));
   omnibox_view()->model()->ResetDisplayTexts();
   omnibox_view()->RevertAll();
 
@@ -551,8 +553,9 @@
     clock_.Advance(base::TimeDelta::FromSeconds(5));
     ui::SetEventTickClockForTesting(&clock_);
 
-    toolbar_model()->set_url(kFullUrl);
-    toolbar_model()->set_url_for_display(base::ASCIIToUTF16("example.com"));
+    location_bar_model()->set_url(kFullUrl);
+    location_bar_model()->set_url_for_display(
+        base::ASCIIToUTF16("example.com"));
 
     gfx::test::RenderTextTestApi render_text_test_api(
         omnibox_view()->GetRenderText());
@@ -959,8 +962,9 @@
   void SetUp() override {
     OmniboxViewViewsSteadyStateElisionsTest::SetUp();
 
-    toolbar_model()->set_url(kValidSearchResultsPage);
-    toolbar_model()->set_security_level(security_state::SecurityLevel::SECURE);
+    location_bar_model()->set_url(kValidSearchResultsPage);
+    location_bar_model()->set_security_level(
+        security_state::SecurityLevel::SECURE);
 
     omnibox_view()->model()->ResetDisplayTexts();
     omnibox_view()->RevertAll();
diff --git a/chrome/browser/ui/views/page_action/zoom_view.cc b/chrome/browser/ui/views/page_action/zoom_view.cc
index 769166a..a5bd5f91 100644
--- a/chrome/browser/ui/views/page_action/zoom_view.cc
+++ b/chrome/browser/ui/views/page_action/zoom_view.cc
@@ -9,7 +9,7 @@
 #include "chrome/browser/ui/view_ids.h"
 #include "chrome/browser/ui/views/location_bar/zoom_bubble_view.h"
 #include "chrome/grit/generated_resources.h"
-#include "components/omnibox/browser/toolbar_model.h"
+#include "components/omnibox/browser/location_bar_model.h"
 #include "components/zoom/zoom_controller.h"
 #include "ui/accessibility/ax_node_data.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -34,7 +34,7 @@
 
 bool ZoomView::ShouldBeVisible(bool can_show_bubble) const {
   if (location_bar_delegate_ &&
-      location_bar_delegate_->GetToolbarModel()->input_in_progress()) {
+      location_bar_delegate_->GetLocationBarModel()->input_in_progress()) {
     return false;
   }
 
diff --git a/chrome/browser/ui/views/toolbar/toolbar_view.cc b/chrome/browser/ui/views/toolbar/toolbar_view.cc
index 5bcaff1..3a07ec4 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_view.cc
+++ b/chrome/browser/ui/views/toolbar/toolbar_view.cc
@@ -357,12 +357,12 @@
   return browser_->tab_strip_model()->GetActiveWebContents();
 }
 
-ToolbarModel* ToolbarView::GetToolbarModel() {
-  return browser_->toolbar_model();
+LocationBarModel* ToolbarView::GetLocationBarModel() {
+  return browser_->location_bar_model();
 }
 
-const ToolbarModel* ToolbarView::GetToolbarModel() const {
-  return browser_->toolbar_model();
+const LocationBarModel* ToolbarView::GetLocationBarModel() const {
+  return browser_->location_bar_model();
 }
 
 ContentSettingBubbleModelDelegate*
diff --git a/chrome/browser/ui/views/toolbar/toolbar_view.h b/chrome/browser/ui/views/toolbar/toolbar_view.h
index 62de79a..03f771fa 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_view.h
+++ b/chrome/browser/ui/views/toolbar/toolbar_view.h
@@ -132,8 +132,8 @@
 
   // LocationBarView::Delegate:
   content::WebContents* GetWebContents() override;
-  ToolbarModel* GetToolbarModel() override;
-  const ToolbarModel* GetToolbarModel() const override;
+  LocationBarModel* GetLocationBarModel() override;
+  const LocationBarModel* GetLocationBarModel() const override;
   ContentSettingBubbleModelDelegate* GetContentSettingBubbleModelDelegate()
       override;
 
diff --git a/chrome/browser/ui/webui/chromeos/smb_shares/OWNERS b/chrome/browser/ui/webui/chromeos/smb_shares/OWNERS
new file mode 100644
index 0000000..704b95c8
--- /dev/null
+++ b/chrome/browser/ui/webui/chromeos/smb_shares/OWNERS
@@ -0,0 +1 @@
+khorimoto@chromium.org
\ No newline at end of file
diff --git a/chrome/browser/ui/webui/settings/chromeos/smb_handler.cc b/chrome/browser/ui/webui/chromeos/smb_shares/smb_handler.cc
similarity index 95%
rename from chrome/browser/ui/webui/settings/chromeos/smb_handler.cc
rename to chrome/browser/ui/webui/chromeos/smb_shares/smb_handler.cc
index fe49987..de5f8a9 100644
--- a/chrome/browser/ui/webui/settings/chromeos/smb_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/smb_shares/smb_handler.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/ui/webui/settings/chromeos/smb_handler.h"
+#include "chrome/browser/ui/webui/chromeos/smb_shares/smb_handler.h"
 
 #include <string>
 #include <utility>
@@ -11,10 +11,9 @@
 #include "base/values.h"
 #include "chrome/browser/chromeos/file_system_provider/provided_file_system_info.h"
 #include "chrome/browser/profiles/profile.h"
-#include "content/public/browser/web_ui_message_handler.h"
 
 namespace chromeos {
-namespace settings {
+namespace smb_dialog {
 
 namespace {
 
@@ -115,6 +114,5 @@
   FireWebUIListener("on-shares-found", BuildShareList(shares_gathered));
 }
 
-
-}  // namespace settings
+}  // namespace smb_dialog
 }  // namespace chromeos
diff --git a/chrome/browser/ui/webui/settings/chromeos/smb_handler.h b/chrome/browser/ui/webui/chromeos/smb_shares/smb_handler.h
similarity index 73%
rename from chrome/browser/ui/webui/settings/chromeos/smb_handler.h
rename to chrome/browser/ui/webui/chromeos/smb_shares/smb_handler.h
index 42a5602..33f4e62 100644
--- a/chrome/browser/ui/webui/settings/chromeos/smb_handler.h
+++ b/chrome/browser/ui/webui/chromeos/smb_shares/smb_handler.h
@@ -2,33 +2,32 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_SMB_HANDLER_H_
-#define CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_SMB_HANDLER_H_
+#ifndef CHROME_BROWSER_UI_WEBUI_CHROMEOS_SMB_SHARES_SMB_HANDLER_H_
+#define CHROME_BROWSER_UI_WEBUI_CHROMEOS_SMB_SHARES_SMB_HANDLER_H_
 
 #include "base/callback_forward.h"
 #include "base/files/file.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/chromeos/smb_client/smb_service.h"
-#include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h"
+#include "content/public/browser/web_ui_message_handler.h"
 
 class Profile;
 
 namespace chromeos {
-namespace settings {
+namespace smb_dialog {
 
 using smb_client::SmbMountResult;
 
-class SmbHandler : public ::settings::SettingsPageUIHandler {
+class SmbHandler : public content::WebUIMessageHandler {
  public:
   explicit SmbHandler(Profile* profile);
   ~SmbHandler() override;
 
-  void RegisterMessages() override;
-  void OnJavascriptAllowed() override {}
-  void OnJavascriptDisallowed() override {}
-
  private:
+  // content::WebUIMessageHandler
+  void RegisterMessages() override;
+
   // WebUI call to mount an Smb Filesystem.
   void HandleSmbMount(const base::ListValue* args);
 
@@ -53,7 +52,7 @@
   DISALLOW_COPY_AND_ASSIGN(SmbHandler);
 };
 
-}  // namespace settings
+}  // namespace smb_dialog
 }  // namespace chromeos
 
-#endif  // CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_SMB_HANDLER_H_
+#endif  // CHROME_BROWSER_UI_WEBUI_CHROMEOS_SMB_SHARES_SMB_HANDLER_H_
diff --git a/chrome/browser/ui/webui/memory_internals_ui.cc b/chrome/browser/ui/webui/memory_internals_ui.cc
index a6ba990..01ef46e 100644
--- a/chrome/browser/ui/webui/memory_internals_ui.cc
+++ b/chrome/browser/ui/webui/memory_internals_ui.cc
@@ -288,8 +288,8 @@
 
     if (data.process_type == content::PROCESS_TYPE_GPU ||
         data.process_type == content::PROCESS_TYPE_UTILITY) {
-      result.push_back(MakeProcessInfo(base::GetProcId(data.GetHandle()),
-                                       GetChildDescription(data)));
+      result.push_back(
+          MakeProcessInfo(data.GetProcess().Pid(), GetChildDescription(data)));
     }
   }
 
diff --git a/chrome/browser/ui/webui/settings/chromeos/easy_unlock_settings_handler.cc b/chrome/browser/ui/webui/settings/chromeos/easy_unlock_settings_handler.cc
index f204d4c..412da7d 100644
--- a/chrome/browser/ui/webui/settings/chromeos/easy_unlock_settings_handler.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/easy_unlock_settings_handler.cc
@@ -25,9 +25,7 @@
   profile_pref_registrar_.Init(profile->GetPrefs());
 }
 
-EasyUnlockSettingsHandler::~EasyUnlockSettingsHandler() {
-  EasyUnlockService::Get(profile_)->RemoveObserver(this);
-}
+EasyUnlockSettingsHandler::~EasyUnlockSettingsHandler() {}
 
 EasyUnlockSettingsHandler* EasyUnlockSettingsHandler::Create(
     content::WebUIDataSource* html_source,
@@ -56,24 +54,9 @@
       "easyUnlockGetEnabledStatus",
       base::BindRepeating(&EasyUnlockSettingsHandler::HandleGetEnabledStatus,
                           base::Unretained(this)));
-  web_ui()->RegisterMessageCallback(
-      "easyUnlockGetTurnOffFlowStatus",
-      base::BindRepeating(
-          &EasyUnlockSettingsHandler::HandleGetTurnOffFlowStatus,
-          base::Unretained(this)));
-  web_ui()->RegisterMessageCallback(
-      "easyUnlockStartTurnOffFlow",
-      base::BindRepeating(&EasyUnlockSettingsHandler::HandleStartTurnOffFlow,
-                          base::Unretained(this)));
-  web_ui()->RegisterMessageCallback(
-      "easyUnlockCancelTurnOffFlow",
-      base::BindRepeating(&EasyUnlockSettingsHandler::HandleCancelTurnOffFlow,
-                          base::Unretained(this)));
 }
 
 void EasyUnlockSettingsHandler::OnJavascriptAllowed() {
-  EasyUnlockService::Get(profile_)->AddObserver(this);
-
   profile_pref_registrar_.Add(
       prefs::kEasyUnlockPairing,
       base::Bind(&EasyUnlockSettingsHandler::SendEnabledStatus,
@@ -81,47 +64,15 @@
 }
 
 void EasyUnlockSettingsHandler::OnJavascriptDisallowed() {
-  EasyUnlockService::Get(profile_)->RemoveObserver(this);
   profile_pref_registrar_.RemoveAll();
 }
 
-void EasyUnlockSettingsHandler::OnTurnOffOperationStatusChanged() {
-  FireWebUIListener("easy-unlock-turn-off-flow-status",
-                    base::Value(GetTurnOffFlowStatus()));
-}
-
 void EasyUnlockSettingsHandler::SendEnabledStatus() {
   CallJavascriptFunction(
       "cr.webUIListenerCallback", base::Value("easy-unlock-enabled-status"),
       base::Value(EasyUnlockService::Get(profile_)->IsEnabled()));
 }
 
-std::string EasyUnlockSettingsHandler::GetTurnOffFlowStatus() {
-  EasyUnlockService::TurnOffFlowStatus status =
-      EasyUnlockService::Get(profile_)->GetTurnOffFlowStatus();
-
-  // Translate status into JS UI state string. Note the translated string
-  // should match UIState defined in easy_unlock_turn_off_dialog.js.
-  std::string status_string;
-  switch (status) {
-    case EasyUnlockService::IDLE:
-      status_string = "idle";
-      break;
-    case EasyUnlockService::PENDING:
-      status_string = "pending";
-      break;
-    case EasyUnlockService::FAIL:
-      status_string = "server-error";
-      break;
-    default:
-      LOG(ERROR) << "Unknown Easy unlock turn-off operation status: " << status;
-      status_string = "idle";
-      break;
-  }
-
-  return status_string;
-}
-
 void EasyUnlockSettingsHandler::HandleGetEnabledStatus(
     const base::ListValue* args) {
   AllowJavascript();
@@ -133,23 +84,5 @@
       *callback_id, base::Value(EasyUnlockService::Get(profile_)->IsEnabled()));
 }
 
-void EasyUnlockSettingsHandler::HandleGetTurnOffFlowStatus(
-    const base::ListValue* args) {
-  CHECK_EQ(1U, args->GetSize());
-  const base::Value* callback_id;
-  CHECK(args->Get(0, &callback_id));
-  ResolveJavascriptCallback(*callback_id, base::Value(GetTurnOffFlowStatus()));
-}
-
-void EasyUnlockSettingsHandler::HandleStartTurnOffFlow(
-    const base::ListValue* args) {
-  EasyUnlockService::Get(profile_)->RunTurnOffFlow();
-}
-
-void EasyUnlockSettingsHandler::HandleCancelTurnOffFlow(
-    const base::ListValue* args) {
-  EasyUnlockService::Get(profile_)->ResetTurnOffFlow();
-}
-
 }  // namespace settings
 }  // namespace chromeos
diff --git a/chrome/browser/ui/webui/settings/chromeos/easy_unlock_settings_handler.h b/chrome/browser/ui/webui/settings/chromeos/easy_unlock_settings_handler.h
index e4509d75..3323704 100644
--- a/chrome/browser/ui/webui/settings/chromeos/easy_unlock_settings_handler.h
+++ b/chrome/browser/ui/webui/settings/chromeos/easy_unlock_settings_handler.h
@@ -19,8 +19,7 @@
 namespace chromeos {
 namespace settings {
 
-class EasyUnlockSettingsHandler : public ::settings::SettingsPageUIHandler,
-                                  public EasyUnlockServiceObserver {
+class EasyUnlockSettingsHandler : public ::settings::SettingsPageUIHandler {
  public:
   // Returns nullptr if EasyUnlock is not allowed for this device.
   static EasyUnlockSettingsHandler* Create(
@@ -34,25 +33,16 @@
   void OnJavascriptAllowed() override;
   void OnJavascriptDisallowed() override;
 
-  // EasyUnlockServiceObserver:
-  void OnTurnOffOperationStatusChanged() override;
-
  protected:
   explicit EasyUnlockSettingsHandler(Profile* profile);
 
  private:
   FRIEND_TEST_ALL_PREFIXES(EasyUnlockSettingsHandlerTest, EnabledStatus);
-  FRIEND_TEST_ALL_PREFIXES(EasyUnlockSettingsHandlerTest, TurnOffFlowStatus);
 
   void SendEnabledStatus();
-  std::string GetTurnOffFlowStatus();
 
   // JS callbacks.
   void HandleGetEnabledStatus(const base::ListValue* args);
-  void HandleStartTurnOnFlow(const base::ListValue* args);
-  void HandleGetTurnOffFlowStatus(const base::ListValue* args);
-  void HandleStartTurnOffFlow(const base::ListValue* args);
-  void HandleCancelTurnOffFlow(const base::ListValue* args);
 
   Profile* const profile_;
 
diff --git a/chrome/browser/ui/webui/settings/chromeos/easy_unlock_settings_handler_unittest.cc b/chrome/browser/ui/webui/settings/chromeos/easy_unlock_settings_handler_unittest.cc
index 8218652..e5c4d1c 100644
--- a/chrome/browser/ui/webui/settings/chromeos/easy_unlock_settings_handler_unittest.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/easy_unlock_settings_handler_unittest.cc
@@ -24,35 +24,15 @@
  public:
   explicit FakeEasyUnlockService(Profile* profile)
       : EasyUnlockService(profile, nullptr /* secure_channel_client */),
-        turn_off_status_(IDLE),
         is_allowed_(true),
         is_enabled_(false) {}
 
-  TurnOffFlowStatus GetTurnOffFlowStatus() const override {
-    return turn_off_status_;
-  }
-
   bool IsAllowed() const override { return is_allowed_; }
   void set_is_allowed(bool is_allowed) { is_allowed_ = is_allowed; }
 
   bool IsEnabled() const override { return is_enabled_; }
   void set_is_enabled(bool is_enabled) { is_enabled_ = is_enabled; }
 
-  void RunTurnOffFlow() override {
-    turn_off_status_ = PENDING;
-    NotifyTurnOffOperationStatusChanged();
-  }
-
-  void ResetTurnOffFlow() override {
-    turn_off_status_ = IDLE;
-    NotifyTurnOffOperationStatusChanged();
-  }
-
-  void SetTurnOffFlowFailForTest() {
-    turn_off_status_ = FAIL;
-    NotifyTurnOffOperationStatusChanged();
-  }
-
  private:
   Type GetType() const override { return TYPE_REGULAR; }
   AccountId GetAccountId() const override { return EmptyAccountId(); }
@@ -73,7 +53,6 @@
   void OnWillFinalizeUnlock(bool success) override {}
   void OnSuspendDoneInternal() override {}
 
-  TurnOffFlowStatus turn_off_status_;
   bool is_allowed_;
   bool is_enabled_;
 };
@@ -142,41 +121,6 @@
     EXPECT_EQ(expected_status, status);
   }
 
-  void VerifyTurnOffFlowStatusWebUIListenerCallback(
-      size_t expected_total_calls,
-      const std::string& expected_status) {
-    std::string event;
-    std::string status;
-
-    EXPECT_EQ(expected_total_calls, web_ui_.call_data().size());
-
-    const content::TestWebUI::CallData& data = *web_ui_.call_data().back();
-    EXPECT_EQ("cr.webUIListenerCallback", data.function_name());
-    ASSERT_TRUE(data.arg1()->GetAsString(&event));
-    EXPECT_EQ("easy-unlock-turn-off-flow-status", event);
-    ASSERT_TRUE(data.arg2()->GetAsString(&status));
-
-    EXPECT_EQ(expected_status, status);
-  }
-
-  void VerifyTurnOffFlowStatusWebUIResponse(
-      size_t expected_total_calls,
-      const std::string& expected_callback_id,
-      const std::string& expected_status) {
-    EXPECT_EQ(expected_total_calls, web_ui()->call_data().size());
-
-    const content::TestWebUI::CallData& data = *web_ui()->call_data().back();
-    EXPECT_EQ("cr.webUIResponse", data.function_name());
-
-    std::string callback_id;
-    ASSERT_TRUE(data.arg1()->GetAsString(&callback_id));
-    EXPECT_EQ(expected_callback_id, callback_id);
-
-    std::string actual_status;
-    ASSERT_TRUE(data.arg3()->GetAsString(&actual_status));
-    EXPECT_EQ(expected_status, actual_status);
-  }
-
  private:
   content::TestBrowserThreadBundle thread_bundle_;
   std::unique_ptr<TestingProfile> profile_;
@@ -239,42 +183,5 @@
   VerifyEnabledStatusCallback(3U, true);
 }
 
-TEST_F(EasyUnlockSettingsHandlerTest, TurnOffFlowStatus) {
-  std::unique_ptr<EasyUnlockSettingsHandler> handler;
-  handler.reset(new TestEasyUnlockSettingsHandler(profile()));
-  handler->set_web_ui(web_ui());
-
-  // Send an initial status query to turn on service observer.
-  base::ListValue list_args1;
-  list_args1.AppendString("test-callback-id-1");
-  handler->HandleGetEnabledStatus(&list_args1);
-  EXPECT_EQ(1U, web_ui()->call_data().size());
-
-  base::ListValue list_args2;
-  list_args2.AppendString("test-callback-id-2");
-  handler->HandleGetTurnOffFlowStatus(&list_args2);
-  VerifyTurnOffFlowStatusWebUIResponse(2U, "test-callback-id-2", "idle");
-
-  handler->HandleStartTurnOffFlow(nullptr);
-  VerifyTurnOffFlowStatusWebUIListenerCallback(3U, "pending");
-
-  base::ListValue list_args3;
-  list_args3.AppendString("test-callback-id-3");
-  handler->HandleGetTurnOffFlowStatus(&list_args3);
-  VerifyTurnOffFlowStatusWebUIResponse(4U, "test-callback-id-3", "pending");
-
-  handler->HandleCancelTurnOffFlow(nullptr);
-  VerifyTurnOffFlowStatusWebUIListenerCallback(5U, "idle");
-
-  fake_easy_unlock_service()->SetTurnOffFlowFailForTest();
-  VerifyTurnOffFlowStatusWebUIListenerCallback(6U, "server-error");
-
-  base::ListValue list_args4;
-  list_args4.AppendString("test-callback-id-4");
-  handler->HandleGetTurnOffFlowStatus(&list_args4);
-  VerifyTurnOffFlowStatusWebUIResponse(7U, "test-callback-id-4",
-                                       "server-error");
-}
-
 }  // namespace settings
 }  // namespace chromeos
diff --git a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
index ee8ec878..8ceefb5 100644
--- a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
@@ -880,8 +880,6 @@
                           arraysize(localized_strings));
 
 #if defined(OS_CHROMEOS)
-  html_source->AddBoolean("enableNativeSmbSetting",
-                          base::FeatureList::IsEnabled(features::kNativeSmb));
   html_source->AddString("smbSharesLearnMoreURL",
                          GetHelpUrlWithBoard(chrome::kSmbSharesLearnMoreURL));
 #endif
@@ -1114,16 +1112,6 @@
 void AddEasyUnlockStrings(content::WebUIDataSource* html_source) {
   LocalizedString localized_strings[] = {
       {"easyUnlockSectionTitle", IDS_SETTINGS_EASY_UNLOCK_SECTION_TITLE},
-      // Easy Unlock turn-off dialog.
-      {"easyUnlockTurnOffButton", IDS_SETTINGS_EASY_UNLOCK_TURN_OFF},
-      {"easyUnlockTurnOffOfflineTitle",
-       IDS_SETTINGS_EASY_UNLOCK_TURN_OFF_OFFLINE_TITLE},
-      {"easyUnlockTurnOffOfflineMessage",
-       IDS_SETTINGS_EASY_UNLOCK_TURN_OFF_OFFLINE_MESSAGE},
-      {"easyUnlockTurnOffErrorTitle",
-       IDS_SETTINGS_EASY_UNLOCK_TURN_OFF_ERROR_TITLE},
-      {"easyUnlockTurnOffErrorMessage",
-       IDS_SETTINGS_EASY_UNLOCK_TURN_OFF_ERROR_MESSAGE},
       {"easyUnlockAllowSignInLabel",
        IDS_SETTINGS_EASY_UNLOCK_ALLOW_SIGN_IN_LABEL},
       {"easyUnlockProximityThresholdLabel",
@@ -1155,14 +1143,6 @@
       l10n_util::GetStringFUTF16(IDS_SETTINGS_EASY_UNLOCK_DESCRIPTION,
                                  device_name));
   html_source->AddString(
-      "easyUnlockTurnOffTitle",
-      l10n_util::GetStringFUTF16(IDS_SETTINGS_EASY_UNLOCK_TURN_OFF_TITLE,
-                                 device_name));
-  html_source->AddString(
-      "easyUnlockTurnOffDescription",
-      l10n_util::GetStringFUTF16(IDS_SETTINGS_EASY_UNLOCK_TURN_OFF_DESCRIPTION,
-                                 device_name));
-  html_source->AddString(
       "easyUnlockProximityThresholdLabel",
       l10n_util::GetStringFUTF16(
           IDS_SETTINGS_EASY_UNLOCK_PROXIMITY_THRESHOLD_LABEL, device_name));
diff --git a/chrome/browser/ui/webui/settings/md_settings_ui.cc b/chrome/browser/ui/webui/settings/md_settings_ui.cc
index ad94f46..1505122 100644
--- a/chrome/browser/ui/webui/settings/md_settings_ui.cc
+++ b/chrome/browser/ui/webui/settings/md_settings_ui.cc
@@ -80,6 +80,7 @@
 #include "chrome/browser/chromeos/multidevice_setup/android_sms_app_helper_delegate_impl.h"
 #include "chrome/browser/chromeos/multidevice_setup/multidevice_setup_client_factory.h"
 #include "chrome/browser/signin/account_tracker_service_factory.h"
+#include "chrome/browser/ui/webui/chromeos/smb_shares/smb_handler.h"
 #include "chrome/browser/ui/webui/settings/chromeos/accessibility_handler.h"
 #include "chrome/browser/ui/webui/settings/chromeos/account_manager_handler.h"
 #include "chrome/browser/ui/webui/settings/chromeos/android_apps_handler.h"
@@ -97,7 +98,6 @@
 #include "chrome/browser/ui/webui/settings/chromeos/google_assistant_handler.h"
 #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"
@@ -237,14 +237,14 @@
   AddSettingsPageUIHandler(
       std::make_unique<chromeos::settings::PointerHandler>());
   AddSettingsPageUIHandler(
-      std::make_unique<chromeos::settings::SmbHandler>(profile));
-  AddSettingsPageUIHandler(
       std::make_unique<chromeos::settings::StorageHandler>(profile));
   AddSettingsPageUIHandler(
       std::make_unique<chromeos::settings::StylusHandler>());
   AddSettingsPageUIHandler(
       std::make_unique<chromeos::settings::InternetHandler>(profile));
   AddSettingsPageUIHandler(std::make_unique<TtsHandler>());
+  AddSettingsPageUIHandler(
+      std::make_unique<chromeos::smb_dialog::SmbHandler>(profile));
 #else
   AddSettingsPageUIHandler(std::make_unique<DefaultBrowserHandler>());
   AddSettingsPageUIHandler(std::make_unique<ManageProfileHandler>(profile));
diff --git a/chrome/browser/ui/webui/welcome/welcome_ui.cc b/chrome/browser/ui/webui/welcome/welcome_ui.cc
index d1d9b05..4a2f33c 100644
--- a/chrome/browser/ui/webui/welcome/welcome_ui.cc
+++ b/chrome/browser/ui/webui/welcome/welcome_ui.cc
@@ -57,7 +57,9 @@
       // Shared strings.
       {"acceptText", IDS_WELCOME_ACCEPT_BUTTON},
       {"bookmarkAdded", IDS_ONBOARDING_WELCOME_BOOKMARK_ADDED},
+      {"bookmarksAdded", IDS_ONBOARDING_WELCOME_BOOKMARKS_ADDED},
       {"bookmarkRemoved", IDS_ONBOARDING_WELCOME_BOOKMARK_REMOVED},
+      {"bookmarksRemoved", IDS_ONBOARDING_WELCOME_BOOKMARKS_REMOVED},
       {"bookmarkReplaced", IDS_ONBOARDING_WELCOME_BOOKMARK_REPLACED},
       {"getStarted", IDS_ONBOARDING_WELCOME_GET_STARTED},
       {"headerText", IDS_WELCOME_HEADER},
diff --git a/chrome/browser/vr/BUILD.gn b/chrome/browser/vr/BUILD.gn
index 0872602..8807045 100644
--- a/chrome/browser/vr/BUILD.gn
+++ b/chrome/browser/vr/BUILD.gn
@@ -238,6 +238,8 @@
     "input_delegate.h",
     "input_delegate_for_testing.cc",
     "input_delegate_for_testing.h",
+    "location_bar_helper.cc",
+    "location_bar_helper.h",
     "platform_controller.h",
     "sample_queue.cc",
     "sample_queue.h",
@@ -255,8 +257,6 @@
     "sliding_average.h",
     "sounds_manager_audio_delegate.cc",
     "sounds_manager_audio_delegate.h",
-    "toolbar_helper.cc",
-    "toolbar_helper.h",
     "ui_factory.cc",
     "ui_factory.h",
     "vr_web_contents_observer.cc",
@@ -353,14 +353,14 @@
     "model/controller_model.cc",
     "model/controller_model.h",
     "model/hosted_platform_ui.h",
+    "model/location_bar_state.cc",
+    "model/location_bar_state.h",
     "model/omnibox_suggestions.cc",
     "model/omnibox_suggestions.h",
     "model/reticle_model.h",
     "model/speech_recognition_model.h",
     "model/text_input_info.cc",
     "model/text_input_info.h",
-    "model/toolbar_state.cc",
-    "model/toolbar_state.h",
     "model/ui_mode.h",
     "model/web_vr_model.h",
     "platform_input_handler.h",
diff --git a/chrome/browser/vr/browser_ui_interface.h b/chrome/browser/vr/browser_ui_interface.h
index 34dcdb4..ca37122 100644
--- a/chrome/browser/vr/browser_ui_interface.h
+++ b/chrome/browser/vr/browser_ui_interface.h
@@ -22,7 +22,7 @@
 struct Assets;
 struct KeyboardTestInput;
 struct OmniboxSuggestions;
-struct ToolbarState;
+struct LocationBarState;
 
 // The browser communicates state changes to the VR UI via this interface.
 // A GL thread would also implement this interface to provide a convenient way
@@ -33,7 +33,7 @@
 
   virtual void SetWebVrMode(bool enabled) = 0;
   virtual void SetFullscreen(bool enabled) = 0;
-  virtual void SetToolbarState(const ToolbarState& state) = 0;
+  virtual void SetLocationBarState(const LocationBarState& state) = 0;
   virtual void SetIncognito(bool enabled) = 0;
   virtual void SetLoading(bool loading) = 0;
   virtual void SetLoadProgress(float progress) = 0;
diff --git a/chrome/browser/vr/location_bar_helper.cc b/chrome/browser/vr/location_bar_helper.cc
new file mode 100644
index 0000000..29ead743
--- /dev/null
+++ b/chrome/browser/vr/location_bar_helper.cc
@@ -0,0 +1,45 @@
+// 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 "chrome/browser/vr/location_bar_helper.h"
+
+#include <memory>
+
+#include "components/omnibox/browser/location_bar_model_impl.h"
+
+class LocationBarModelDelegate;
+
+namespace vr {
+
+namespace {
+
+// This number is arbitrary. For VR, use a number smaller than desktop's 32K, as
+// the URL indicator does not show long URLs.
+constexpr int kMaxURLDisplayChars = 1024;
+
+}  // namespace
+
+LocationBarHelper::LocationBarHelper(BrowserUiInterface* ui,
+                                     LocationBarModelDelegate* delegate)
+    : ui_(ui),
+      location_bar_model_(
+          std::make_unique<LocationBarModelImpl>(delegate,
+                                                 kMaxURLDisplayChars)) {}
+
+LocationBarHelper::~LocationBarHelper() {}
+
+void LocationBarHelper::Update() {
+  LocationBarState state(location_bar_model_->GetURL(),
+                         location_bar_model_->GetSecurityLevel(true),
+                         &location_bar_model_->GetVectorIcon(),
+                         location_bar_model_->ShouldDisplayURL(),
+                         location_bar_model_->IsOfflinePage());
+
+  if (current_state_ == state)
+    return;
+  current_state_ = state;
+  ui_->SetLocationBarState(state);
+}
+
+}  // namespace vr
diff --git a/chrome/browser/vr/location_bar_helper.h b/chrome/browser/vr/location_bar_helper.h
new file mode 100644
index 0000000..44ee884
--- /dev/null
+++ b/chrome/browser/vr/location_bar_helper.h
@@ -0,0 +1,37 @@
+// 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 CHROME_BROWSER_VR_LOCATION_BAR_HELPER_H_
+#define CHROME_BROWSER_VR_LOCATION_BAR_HELPER_H_
+
+#include "chrome/browser/vr/browser_ui_interface.h"
+#include "chrome/browser/vr/model/location_bar_state.h"
+#include "chrome/browser/vr/vr_export.h"
+
+class LocationBarModel;
+class LocationBarModelDelegate;
+
+namespace vr {
+
+class BrowserUiInterface;
+
+// This class houses an instance of LocationBarModel, and queries it when
+// requested, passing a snapshot of the toolbar state to the UI when necessary.
+class VR_EXPORT LocationBarHelper {
+ public:
+  LocationBarHelper(BrowserUiInterface* ui, LocationBarModelDelegate* delegate);
+  virtual ~LocationBarHelper();
+
+  // Poll LocationBarModel and post an update to the UI if state has changed.
+  void Update();
+
+ private:
+  BrowserUiInterface* ui_;
+  std::unique_ptr<LocationBarModel> location_bar_model_;
+  LocationBarState current_state_;
+};
+
+}  // namespace vr
+
+#endif  // CHROME_BROWSER_VR_LOCATION_BAR_HELPER_H_
diff --git a/chrome/browser/vr/model/location_bar_state.cc b/chrome/browser/vr/model/location_bar_state.cc
new file mode 100644
index 0000000..41b5b76f
--- /dev/null
+++ b/chrome/browser/vr/model/location_bar_state.cc
@@ -0,0 +1,40 @@
+// 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 "chrome/browser/vr/model/location_bar_state.h"
+
+namespace vr {
+
+LocationBarState::LocationBarState()
+    : gurl(GURL()),
+      security_level(security_state::SecurityLevel::NONE),
+      vector_icon(nullptr),
+      should_display_url(true),
+      offline_page(false) {}
+
+LocationBarState::LocationBarState(const GURL& url,
+                                   security_state::SecurityLevel level,
+                                   const gfx::VectorIcon* icon,
+                                   bool display_url,
+                                   bool offline)
+    : gurl(url),
+      security_level(level),
+      vector_icon(icon),
+      should_display_url(display_url),
+      offline_page(offline) {}
+
+LocationBarState::LocationBarState(const LocationBarState& other) = default;
+
+bool LocationBarState::operator==(const LocationBarState& other) const {
+  return (gurl == other.gurl && security_level == other.security_level &&
+          vector_icon == other.vector_icon &&
+          should_display_url == other.should_display_url &&
+          offline_page == other.offline_page);
+}
+
+bool LocationBarState::operator!=(const LocationBarState& other) const {
+  return !(*this == other);
+}
+
+}  // namespace vr
diff --git a/chrome/browser/vr/model/location_bar_state.h b/chrome/browser/vr/model/location_bar_state.h
new file mode 100644
index 0000000..b8109886
--- /dev/null
+++ b/chrome/browser/vr/model/location_bar_state.h
@@ -0,0 +1,41 @@
+// 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 CHROME_BROWSER_VR_MODEL_LOCATION_BAR_STATE_H_
+#define CHROME_BROWSER_VR_MODEL_LOCATION_BAR_STATE_H_
+
+#include "chrome/browser/vr/vr_export.h"
+#include "components/security_state/core/security_state.h"
+#include "url/gurl.h"
+
+namespace gfx {
+struct VectorIcon;
+}
+
+namespace vr {
+
+// Passes information obtained from LocationBarModel to the VR UI framework.
+struct VR_EXPORT LocationBarState {
+ public:
+  LocationBarState();
+  LocationBarState(const GURL& url,
+                   security_state::SecurityLevel level,
+                   const gfx::VectorIcon* icon,
+                   bool display_url,
+                   bool offline);
+  LocationBarState(const LocationBarState& other);
+
+  bool operator==(const LocationBarState& other) const;
+  bool operator!=(const LocationBarState& other) const;
+
+  GURL gurl;
+  security_state::SecurityLevel security_level;
+  const gfx::VectorIcon* vector_icon;
+  bool should_display_url;
+  bool offline_page;
+};
+
+}  // namespace vr
+
+#endif  // CHROME_BROWSER_VR_MODEL_LOCATION_BAR_STATE_H_
diff --git a/chrome/browser/vr/model/model.h b/chrome/browser/vr/model/model.h
index 5197078..4c3b6dd 100644
--- a/chrome/browser/vr/model/model.h
+++ b/chrome/browser/vr/model/model.h
@@ -13,6 +13,7 @@
 #include "chrome/browser/vr/model/color_scheme.h"
 #include "chrome/browser/vr/model/controller_model.h"
 #include "chrome/browser/vr/model/hosted_platform_ui.h"
+#include "chrome/browser/vr/model/location_bar_state.h"
 #include "chrome/browser/vr/model/modal_prompt_type.h"
 #include "chrome/browser/vr/model/omnibox_suggestions.h"
 #include "chrome/browser/vr/model/platform_toast.h"
@@ -20,7 +21,6 @@
 #include "chrome/browser/vr/model/speech_recognition_model.h"
 #include "chrome/browser/vr/model/tab_model.h"
 #include "chrome/browser/vr/model/text_input_info.h"
-#include "chrome/browser/vr/model/toolbar_state.h"
 #include "chrome/browser/vr/model/ui_mode.h"
 #include "chrome/browser/vr/model/web_vr_model.h"
 #include "chrome/browser/vr/vr_ui_export.h"
@@ -39,7 +39,7 @@
   bool incognito = false;
   bool can_navigate_back = false;
   bool can_navigate_forward = false;
-  ToolbarState toolbar_state;
+  LocationBarState location_bar_state;
   std::vector<OmniboxSuggestion> omnibox_suggestions;
   SpeechRecognitionModel speech;
   const ColorScheme& color_scheme() const;
diff --git a/chrome/browser/vr/model/toolbar_state.cc b/chrome/browser/vr/model/toolbar_state.cc
deleted file mode 100644
index dccae839..0000000
--- a/chrome/browser/vr/model/toolbar_state.cc
+++ /dev/null
@@ -1,40 +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 "chrome/browser/vr/model/toolbar_state.h"
-
-namespace vr {
-
-ToolbarState::ToolbarState()
-    : gurl(GURL()),
-      security_level(security_state::SecurityLevel::NONE),
-      vector_icon(nullptr),
-      should_display_url(true),
-      offline_page(false) {}
-
-ToolbarState::ToolbarState(const GURL& url,
-                           security_state::SecurityLevel level,
-                           const gfx::VectorIcon* icon,
-                           bool display_url,
-                           bool offline)
-    : gurl(url),
-      security_level(level),
-      vector_icon(icon),
-      should_display_url(display_url),
-      offline_page(offline) {}
-
-ToolbarState::ToolbarState(const ToolbarState& other) = default;
-
-bool ToolbarState::operator==(const ToolbarState& other) const {
-  return (gurl == other.gurl && security_level == other.security_level &&
-          vector_icon == other.vector_icon &&
-          should_display_url == other.should_display_url &&
-          offline_page == other.offline_page);
-}
-
-bool ToolbarState::operator!=(const ToolbarState& other) const {
-  return !(*this == other);
-}
-
-}  // namespace vr
diff --git a/chrome/browser/vr/model/toolbar_state.h b/chrome/browser/vr/model/toolbar_state.h
deleted file mode 100644
index c5b877b0..0000000
--- a/chrome/browser/vr/model/toolbar_state.h
+++ /dev/null
@@ -1,41 +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 CHROME_BROWSER_VR_MODEL_TOOLBAR_STATE_H_
-#define CHROME_BROWSER_VR_MODEL_TOOLBAR_STATE_H_
-
-#include "chrome/browser/vr/vr_export.h"
-#include "components/security_state/core/security_state.h"
-#include "url/gurl.h"
-
-namespace gfx {
-struct VectorIcon;
-}
-
-namespace vr {
-
-// Passes information obtained from ToolbarModel to the VR UI framework.
-struct VR_EXPORT ToolbarState {
- public:
-  ToolbarState();
-  ToolbarState(const GURL& url,
-               security_state::SecurityLevel level,
-               const gfx::VectorIcon* icon,
-               bool display_url,
-               bool offline);
-  ToolbarState(const ToolbarState& other);
-
-  bool operator==(const ToolbarState& other) const;
-  bool operator!=(const ToolbarState& other) const;
-
-  GURL gurl;
-  security_state::SecurityLevel security_level;
-  const gfx::VectorIcon* vector_icon;
-  bool should_display_url;
-  bool offline_page;
-};
-
-}  // namespace vr
-
-#endif  // CHROME_BROWSER_VR_MODEL_TOOLBAR_STATE_H_
diff --git a/chrome/browser/vr/test/mock_browser_ui_interface.h b/chrome/browser/vr/test/mock_browser_ui_interface.h
index 8f6ab71..cc51571 100644
--- a/chrome/browser/vr/test/mock_browser_ui_interface.h
+++ b/chrome/browser/vr/test/mock_browser_ui_interface.h
@@ -8,8 +8,8 @@
 #include "base/macros.h"
 #include "chrome/browser/vr/browser_ui_interface.h"
 #include "chrome/browser/vr/model/assets.h"
+#include "chrome/browser/vr/model/location_bar_state.h"
 #include "chrome/browser/vr/model/omnibox_suggestions.h"
-#include "chrome/browser/vr/model/toolbar_state.h"
 #include "chrome/browser/vr/ui_test_input.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
@@ -22,7 +22,7 @@
 
   MOCK_METHOD1(SetWebVrMode, void(bool enabled));
   MOCK_METHOD1(SetFullscreen, void(bool enabled));
-  MOCK_METHOD1(SetToolbarState, void(const ToolbarState& state));
+  MOCK_METHOD1(SetLocationBarState, void(const LocationBarState& state));
   MOCK_METHOD1(SetIncognito, void(bool enabled));
   MOCK_METHOD1(SetLoading, void(bool loading));
   MOCK_METHOD1(SetLoadProgress, void(float progress));
diff --git a/chrome/browser/vr/test/ui_pixel_test.cc b/chrome/browser/vr/test/ui_pixel_test.cc
index b5062b3..14e9cd8 100644
--- a/chrome/browser/vr/test/ui_pixel_test.cc
+++ b/chrome/browser/vr/test/ui_pixel_test.cc
@@ -42,12 +42,12 @@
 }
 
 void UiPixelTest::MakeUi(const UiInitialState& ui_initial_state,
-                         const ToolbarState& toolbar_state) {
+                         const LocationBarState& location_bar_state) {
   ui_ = std::make_unique<Ui>(browser_.get(), nullptr, nullptr, nullptr, nullptr,
                              ui_initial_state);
   ui_->OnGlInitialized(kGlTextureLocationLocal, content_texture_,
                        content_overlay_texture_, 0);
-  ui_->GetBrowserUiWeakPtr()->SetToolbarState(toolbar_state);
+  ui_->GetBrowserUiWeakPtr()->SetLocationBarState(location_bar_state);
 }
 
 void UiPixelTest::DrawUi(const gfx::Vector3dF& laser_direction,
diff --git a/chrome/browser/vr/test/ui_pixel_test.h b/chrome/browser/vr/test/ui_pixel_test.h
index e9c6119..199d1a9 100644
--- a/chrome/browser/vr/test/ui_pixel_test.h
+++ b/chrome/browser/vr/test/ui_pixel_test.h
@@ -5,7 +5,7 @@
 #ifndef CHROME_BROWSER_VR_TEST_UI_PIXEL_TEST_H_
 #define CHROME_BROWSER_VR_TEST_UI_PIXEL_TEST_H_
 
-#include "chrome/browser/vr/model/toolbar_state.h"
+#include "chrome/browser/vr/model/location_bar_state.h"
 #include "chrome/browser/vr/test/gl_test_environment.h"
 #include "chrome/browser/vr/test/mock_content_input_delegate.h"
 #include "chrome/browser/vr/test/mock_ui_browser_interface.h"
@@ -27,7 +27,7 @@
 
  protected:
   void MakeUi(const UiInitialState& ui_initial_state,
-              const ToolbarState& toolbar_state);
+              const LocationBarState& location_bar_state);
   void DrawUi(const gfx::Vector3dF& laser_direction,
               const gfx::Point3F& laser_origin,
               ControllerModel::ButtonState button_state,
diff --git a/chrome/browser/vr/testapp/vr_test_context.cc b/chrome/browser/vr/testapp/vr_test_context.cc
index 87a4aee..d298ee5b 100644
--- a/chrome/browser/vr/testapp/vr_test_context.cc
+++ b/chrome/browser/vr/testapp/vr_test_context.cc
@@ -18,9 +18,9 @@
 #include "chrome/browser/vr/gl_texture_location.h"
 #include "chrome/browser/vr/graphics_delegate.h"
 #include "chrome/browser/vr/model/assets.h"
+#include "chrome/browser/vr/model/location_bar_state.h"
 #include "chrome/browser/vr/model/model.h"
 #include "chrome/browser/vr/model/omnibox_suggestions.h"
-#include "chrome/browser/vr/model/toolbar_state.h"
 #include "chrome/browser/vr/render_info.h"
 #include "chrome/browser/vr/speech_recognizer.h"
 #include "chrome/browser/vr/test/constants.h"
@@ -579,9 +579,9 @@
 }
 
 void VrTestContext::Navigate(GURL gurl, NavigationMethod method) {
-  ToolbarState state(gurl, security_state::SecurityLevel::HTTP_SHOW_WARNING,
-                     &omnibox::kHttpIcon, true, false);
-  ui_->GetBrowserUiWeakPtr()->SetToolbarState(state);
+  LocationBarState state(gurl, security_state::SecurityLevel::HTTP_SHOW_WARNING,
+                         &omnibox::kHttpIcon, true, false);
+  ui_->GetBrowserUiWeakPtr()->SetLocationBarState(state);
   page_load_start_ = base::TimeTicks::Now();
 }
 
@@ -739,7 +739,7 @@
 }
 
 void VrTestContext::CycleOrigin() {
-  const std::vector<ToolbarState> states = {
+  const std::vector<LocationBarState> states = {
       {GURL("http://domain.com"),
        security_state::SecurityLevel::HTTP_SHOW_WARNING, &omnibox::kHttpIcon,
        true, false},
@@ -791,7 +791,7 @@
   };
 
   static int state = 0;
-  ui_->GetBrowserUiWeakPtr()->SetToolbarState(states[state]);
+  ui_->GetBrowserUiWeakPtr()->SetLocationBarState(states[state]);
   state = (state + 1) % states.size();
 }
 
diff --git a/chrome/browser/vr/toolbar_helper.cc b/chrome/browser/vr/toolbar_helper.cc
deleted file mode 100644
index baf59f8..0000000
--- a/chrome/browser/vr/toolbar_helper.cc
+++ /dev/null
@@ -1,43 +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 "chrome/browser/vr/toolbar_helper.h"
-
-#include <memory>
-
-#include "components/omnibox/browser/toolbar_model_impl.h"
-
-class ToolbarModelDelegate;
-
-namespace vr {
-
-namespace {
-
-// This number is arbitrary. For VR, use a number smaller than desktop's 32K, as
-// the URL indicator does not show long URLs.
-constexpr int kMaxURLDisplayChars = 1024;
-
-}  // namespace
-
-ToolbarHelper::ToolbarHelper(BrowserUiInterface* ui,
-                             ToolbarModelDelegate* delegate)
-    : ui_(ui),
-      toolbar_model_(
-          std::make_unique<ToolbarModelImpl>(delegate, kMaxURLDisplayChars)) {}
-
-ToolbarHelper::~ToolbarHelper() {}
-
-void ToolbarHelper::Update() {
-  ToolbarState state(
-      toolbar_model_->GetURL(), toolbar_model_->GetSecurityLevel(true),
-      &toolbar_model_->GetVectorIcon(), toolbar_model_->ShouldDisplayURL(),
-      toolbar_model_->IsOfflinePage());
-
-  if (current_state_ == state)
-    return;
-  current_state_ = state;
-  ui_->SetToolbarState(state);
-}
-
-}  // namespace vr
diff --git a/chrome/browser/vr/toolbar_helper.h b/chrome/browser/vr/toolbar_helper.h
deleted file mode 100644
index 43cc021..0000000
--- a/chrome/browser/vr/toolbar_helper.h
+++ /dev/null
@@ -1,37 +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 CHROME_BROWSER_VR_TOOLBAR_HELPER_H_
-#define CHROME_BROWSER_VR_TOOLBAR_HELPER_H_
-
-#include "chrome/browser/vr/browser_ui_interface.h"
-#include "chrome/browser/vr/model/toolbar_state.h"
-#include "chrome/browser/vr/vr_export.h"
-
-class ToolbarModel;
-class ToolbarModelDelegate;
-
-namespace vr {
-
-class BrowserUiInterface;
-
-// This class houses an instance of ToolbarModel, and queries it when requested,
-// passing a snapshot of the toolbar state to the UI when necessary.
-class VR_EXPORT ToolbarHelper {
- public:
-  ToolbarHelper(BrowserUiInterface* ui, ToolbarModelDelegate* delegate);
-  virtual ~ToolbarHelper();
-
-  // Poll ToolbarModel and post an update to the UI if state has changed.
-  void Update();
-
- private:
-  BrowserUiInterface* ui_;
-  std::unique_ptr<ToolbarModel> toolbar_model_;
-  ToolbarState current_state_;
-};
-
-}  // namespace vr
-
-#endif  // CHROME_BROWSER_VR_TOOLBAR_HELPER_H_
diff --git a/chrome/browser/vr/ui.cc b/chrome/browser/vr/ui.cc
index 331f733..c9e610f 100644
--- a/chrome/browser/vr/ui.cc
+++ b/chrome/browser/vr/ui.cc
@@ -163,8 +163,8 @@
   }
 }
 
-void Ui::SetToolbarState(const ToolbarState& state) {
-  model_->toolbar_state = state;
+void Ui::SetLocationBarState(const LocationBarState& state) {
+  model_->location_bar_state = state;
 }
 
 void Ui::SetIncognito(bool enabled) {
diff --git a/chrome/browser/vr/ui.h b/chrome/browser/vr/ui.h
index a1eaa7c2..36ff73a 100644
--- a/chrome/browser/vr/ui.h
+++ b/chrome/browser/vr/ui.h
@@ -90,7 +90,7 @@
   // BrowserUiInterface
   void SetWebVrMode(bool enabled) override;
   void SetFullscreen(bool enabled) override;
-  void SetToolbarState(const ToolbarState& state) override;
+  void SetLocationBarState(const LocationBarState& state) override;
   void SetIncognito(bool enabled) override;
   void SetLoading(bool loading) override;
   void SetLoadProgress(float progress) override;
diff --git a/chrome/browser/vr/ui_pixeltest.cc b/chrome/browser/vr/ui_pixeltest.cc
index 3b24fabb..958741a 100644
--- a/chrome/browser/vr/ui_pixeltest.cc
+++ b/chrome/browser/vr/ui_pixeltest.cc
@@ -4,7 +4,7 @@
 
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
-#include "chrome/browser/vr/model/toolbar_state.h"
+#include "chrome/browser/vr/model/location_bar_state.h"
 #include "chrome/browser/vr/test/constants.h"
 #include "chrome/browser/vr/test/ui_pixel_test.h"
 #include "components/omnibox/browser/vector_icons.h"
@@ -24,8 +24,8 @@
   ui_initial_state.in_web_vr = false;
   ui_initial_state.web_vr_autopresentation_expected = false;
   MakeUi(ui_initial_state,
-         ToolbarState(GURL("https://example.com"), security_state::SECURE,
-                      &omnibox::kHttpsValidIcon, true, false));
+         LocationBarState(GURL("https://example.com"), security_state::SECURE,
+                          &omnibox::kHttpsValidIcon, true, false));
 
   // Draw UI.
   DrawUi(gfx::Vector3dF(0.0f, 0.0f, -1.0f), gfx::Point3F(0.5f, -0.5f, 0.0f),
diff --git a/chrome/browser/vr/ui_scene_creator.cc b/chrome/browser/vr/ui_scene_creator.cc
index f746b54..b331d5dc4 100644
--- a/chrome/browser/vr/ui_scene_creator.cc
+++ b/chrome/browser/vr/ui_scene_creator.cc
@@ -758,9 +758,10 @@
   icon_element->set_y_anchoring(TOP);
   icon_element->SetSize(kWebVrPermissionIconSize, kWebVrPermissionIconSize);
   if (spec.is_url) {
-    icon_element->AddBinding(VR_BIND_FUNC(
-        const gfx::VectorIcon*, Model, model, model->toolbar_state.vector_icon,
-        VectorIcon, icon_element.get(), SetIcon));
+    icon_element->AddBinding(VR_BIND_FUNC(const gfx::VectorIcon*, Model, model,
+                                          model->location_bar_state.vector_icon,
+                                          VectorIcon, icon_element.get(),
+                                          SetIcon));
   } else {
     icon_element->SetIcon(spec.icon);
   }
@@ -776,7 +777,7 @@
             );
     url_text->SetFieldWidth(kWebVrPermissionTextWidth);
     url_text->AddBinding(VR_BIND_FUNC(GURL, Model, model,
-                                      model->toolbar_state.gurl, UrlText,
+                                      model->location_bar_state.gurl, UrlText,
                                       url_text.get(), SetUrl));
     VR_BIND_COLOR(model, url_text.get(),
                   &ColorScheme::webvr_permission_foreground,
@@ -2099,14 +2100,16 @@
   // This layout contains the page info icon and URL.
   auto origin_layout = Create<LinearLayout>(kUrlBarOriginLayout, kPhaseNone,
                                             LinearLayout::kRight);
-  VR_BIND_VISIBILITY(origin_layout, model->toolbar_state.should_display_url);
+  VR_BIND_VISIBILITY(origin_layout,
+                     model->location_bar_state.should_display_url);
 
   scene_->AddUiElement(kUrlBarOriginRegion, std::move(origin_layout));
 
   // This layout contains hint-text items, shown when there's no origin.
   auto hint_layout =
       Create<LinearLayout>(kUrlBarHintLayout, kPhaseNone, LinearLayout::kRight);
-  VR_BIND_VISIBILITY(hint_layout, !model->toolbar_state.should_display_url);
+  VR_BIND_VISIBILITY(hint_layout,
+                     !model->location_bar_state.should_display_url);
   scene_->AddUiElement(kUrlBarOriginRegion, std::move(hint_layout));
 
   auto security_button_region =
@@ -2127,7 +2130,7 @@
   VR_BIND_BUTTON_COLORS(model_, security_button.get(),
                         &ColorScheme::url_bar_button, &Button::SetButtonColors);
   security_button->AddBinding(std::make_unique<Binding<const gfx::VectorIcon*>>(
-      VR_BIND_LAMBDA([](Model* m) { return m->toolbar_state.vector_icon; },
+      VR_BIND_LAMBDA([](Model* m) { return m->location_bar_state.vector_icon; },
                      base::Unretained(model_)),
       VR_BIND_LAMBDA(
           [](VectorIconButton* e, const gfx::VectorIcon* const& icon) {
@@ -2140,7 +2143,7 @@
       VR_BIND_LAMBDA(
           [](Model* m) {
             ButtonColors colors = m->color_scheme().url_bar_button;
-            if (m->toolbar_state.security_level ==
+            if (m->location_bar_state.security_level ==
                 security_state::SecurityLevel::DANGEROUS) {
               colors.foreground = m->color_scheme().url_bar_dangerous_icon;
             }
@@ -2161,7 +2164,7 @@
                           UiUnsupportedMode::kUnhandledCodePoint));
   url_text->SetFieldWidth(kUrlBarUrlWidthDMM);
   url_text->AddBinding(VR_BIND_FUNC(GURL, Model, model_,
-                                    model->toolbar_state.gurl, UrlText,
+                                    model->location_bar_state.gurl, UrlText,
                                     url_text.get(), SetUrl));
   VR_BIND_COLOR(model_, url_text.get(), &ColorScheme::url_text_emphasized,
                 &UrlText::SetEmphasizedColor);
@@ -2716,7 +2719,7 @@
           [](Model* m) {
             bool editing_omnibox = m->has_mode_in_stack(kModeEditingOmnibox);
             base::string16 url_text =
-                FormatUrlForVr(m->toolbar_state.gurl, nullptr);
+                FormatUrlForVr(m->location_bar_state.gurl, nullptr);
             return std::make_pair(editing_omnibox, url_text);
           },
           base::Unretained(model_)),
diff --git a/chrome/browser/vr/vr_web_contents_observer.cc b/chrome/browser/vr/vr_web_contents_observer.cc
index ee12a962..8a6a096 100644
--- a/chrome/browser/vr/vr_web_contents_observer.cc
+++ b/chrome/browser/vr/vr_web_contents_observer.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/browser/vr/vr_web_contents_observer.h"
 
-#include "chrome/browser/vr/toolbar_helper.h"
+#include "chrome/browser/vr/location_bar_helper.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/render_widget_host.h"
 #include "content/public/browser/render_widget_host_view.h"
@@ -13,7 +13,7 @@
 
 VrWebContentsObserver::VrWebContentsObserver(content::WebContents* web_contents,
                                              BrowserUiInterface* ui_interface,
-                                             ToolbarHelper* toolbar,
+                                             LocationBarHelper* toolbar,
                                              base::OnceClosure on_destroy)
     : WebContentsObserver(web_contents),
       ui_interface_(ui_interface),
diff --git a/chrome/browser/vr/vr_web_contents_observer.h b/chrome/browser/vr/vr_web_contents_observer.h
index 661dedd1..46088d6 100644
--- a/chrome/browser/vr/vr_web_contents_observer.h
+++ b/chrome/browser/vr/vr_web_contents_observer.h
@@ -17,13 +17,13 @@
 namespace vr {
 
 class BrowserUiInterface;
-class ToolbarHelper;
+class LocationBarHelper;
 
 class VR_EXPORT VrWebContentsObserver : public content::WebContentsObserver {
  public:
   VrWebContentsObserver(content::WebContents* web_contents,
                         BrowserUiInterface* ui_interface,
-                        ToolbarHelper* toolbar,
+                        LocationBarHelper* toolbar,
                         base::OnceClosure on_destroy);
   ~VrWebContentsObserver() override;
 
@@ -46,7 +46,7 @@
 
   // This class does not own these pointers.
   BrowserUiInterface* ui_interface_;
-  ToolbarHelper* toolbar_;
+  LocationBarHelper* toolbar_;
 
   base::OnceClosure on_destroy_;
 
diff --git a/chrome/chrome_cleaner/components/recovery_component.cc b/chrome/chrome_cleaner/components/recovery_component.cc
index cc75282..87f4e9a 100644
--- a/chrome/chrome_cleaner/components/recovery_component.cc
+++ b/chrome/chrome_cleaner/components/recovery_component.cc
@@ -17,7 +17,6 @@
 #include "base/files/file.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
-#include "base/message_loop/message_loop.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/process/kill.h"
 #include "base/process/launch.h"
@@ -232,7 +231,7 @@
 }
 
 void RecoveryComponent::FetchOnIOThread() {
-  DCHECK_EQ(base::MessageLoop::current(), recovery_io_thread_.message_loop());
+  DCHECK(recovery_io_thread_.task_runner()->BelongsToCurrentThread());
   std::unique_ptr<chrome_cleaner::HttpAgent> http_agent =
       GetHttpAgentFactory()->CreateHttpAgent();
 
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index 8a4b4b4..4b78f5f 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -763,9 +763,6 @@
 // Android authentication account type for SPNEGO authentication
 const char kAuthAndroidNegotiateAccountType[] = "auth-spnego-account-type";
 
-// Android authentication account type for SPNEGO authentication
-const char kChromeHomeSwipeLogicType[] = "chrome-home-swipe-logic";
-
 // Disables Contextual Search.
 const char kDisableContextualSearch[] = "disable-contextual-search";
 
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index f724e53..9618667 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -225,7 +225,6 @@
 
 #if defined(OS_ANDROID)
 extern const char kAuthAndroidNegotiateAccountType[];
-extern const char kChromeHomeSwipeLogicType[];
 extern const char kDisableContextualSearch[];
 extern const char kEnableAccessibilityTabSwitcher[];
 extern const char kEnableContextualSearch[];
diff --git a/chrome/services/diagnosticsd/OWNERS b/chrome/services/diagnosticsd/OWNERS
new file mode 100644
index 0000000..8c3eff5
--- /dev/null
+++ b/chrome/services/diagnosticsd/OWNERS
@@ -0,0 +1,2 @@
+emaxx@chromium.org
+pmarko@chromium.org
diff --git a/chrome/services/diagnosticsd/public/mojom/BUILD.gn b/chrome/services/diagnosticsd/public/mojom/BUILD.gn
new file mode 100644
index 0000000..d5d88ed
--- /dev/null
+++ b/chrome/services/diagnosticsd/public/mojom/BUILD.gn
@@ -0,0 +1,13 @@
+# 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.
+
+import("//mojo/public/tools/bindings/mojom.gni")
+
+assert(is_chromeos)
+
+mojom("mojom") {
+  sources = [
+    "diagnosticsd.mojom",
+  ]
+}
diff --git a/chrome/services/diagnosticsd/public/mojom/OWNERS b/chrome/services/diagnosticsd/public/mojom/OWNERS
new file mode 100644
index 0000000..08850f4
--- /dev/null
+++ b/chrome/services/diagnosticsd/public/mojom/OWNERS
@@ -0,0 +1,2 @@
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/chrome/services/diagnosticsd/public/mojom/diagnosticsd.mojom b/chrome/services/diagnosticsd/public/mojom/diagnosticsd.mojom
new file mode 100644
index 0000000..3f992b8
--- /dev/null
+++ b/chrome/services/diagnosticsd/public/mojom/diagnosticsd.mojom
@@ -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.
+
+// API exposed by the diagnosticsd daemon. Normally the consumer of this API is
+// the browser.
+
+// NOTE: This mojom should be kept in sync with the copy in Chromium OS's repo
+// in src/platform2/diagnostics/mojo/.
+
+module chromeos.diagnosticsd.mojom;
+
+// Factory interface exposed by the diagnosticsd daemon, which allows both
+// endpoints (the diagnosticsd and the browser) to exchange with their
+// interfaces (DiagnosticsdService and DiagnosticsdClient correspondingly).
+interface DiagnosticsdServiceFactory {
+  // Returns an interface to DiagnosticsdService in response to the passed
+  // interface to DiagnosticsdClient.
+  GetService@0(DiagnosticsdService& service, DiagnosticsdClient client) => ();
+};
+
+// Interface exposed by the diagnosticsd daemon.
+interface DiagnosticsdService {
+};
+
+// Interface exposed by the consumer of DiagnosticsdService. In production this
+// is the browser.
+interface DiagnosticsdClient {
+};
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 47cf5c6f..449f0b0 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -3181,6 +3181,7 @@
       "../browser/ui/toolbar/app_menu_model_unittest.cc",
       "../browser/ui/toolbar/back_forward_menu_model_unittest.cc",
       "../browser/ui/toolbar/component_toolbar_actions_factory_unittest.cc",
+      "../browser/ui/toolbar/location_bar_model_unittest.cc",
       "../browser/ui/toolbar/mock_component_toolbar_actions_factory.cc",
       "../browser/ui/toolbar/mock_component_toolbar_actions_factory.h",
       "../browser/ui/toolbar/recent_tabs_builder_test_helper.cc",
@@ -3191,7 +3192,6 @@
       "../browser/ui/toolbar/toolbar_actions_bar_unittest.cc",
       "../browser/ui/toolbar/toolbar_actions_bar_unittest.h",
       "../browser/ui/toolbar/toolbar_actions_model_unittest.cc",
-      "../browser/ui/toolbar/toolbar_model_unittest.cc",
       "../browser/ui/webui/browsing_history_handler_unittest.cc",
       "../browser/ui/webui/help/version_updater_chromeos_unittest.cc",
       "../browser/ui/webui/md_downloads/downloads_list_tracker_unittest.cc",
@@ -5131,6 +5131,9 @@
       "//base",
       "//base:i18n",
       "//base/test:test_support",
+      "//chrome:browser_tests_pak",
+      "//chrome:packed_resources",
+      "//chrome:resources",
       "//chrome/app:chrome_dll_resources",
       "//chrome/browser",
       "//chrome/renderer",
diff --git a/chrome/test/base/testing_browser_process.cc b/chrome/test/base/testing_browser_process.cc
index 71d2ed5..e4aec28 100644
--- a/chrome/test/base/testing_browser_process.cc
+++ b/chrome/test/base/testing_browser_process.cc
@@ -452,11 +452,6 @@
   return nullptr;
 }
 
-data_use_measurement::ChromeDataUseMeasurement*
-TestingBrowserProcess::data_use_measurement() {
-  return nullptr;
-}
-
 void TestingBrowserProcess::SetSystemRequestContext(
     net::URLRequestContextGetter* context_getter) {
   system_request_context_ = context_getter;
diff --git a/chrome/test/base/testing_browser_process.h b/chrome/test/base/testing_browser_process.h
index 3a61df1..6d0b415 100644
--- a/chrome/test/base/testing_browser_process.h
+++ b/chrome/test/base/testing_browser_process.h
@@ -137,8 +137,6 @@
   shell_integration::DefaultWebClientState CachedDefaultWebClientState()
       override;
   prefs::InProcessPrefServiceFactory* pref_service_factory() const override;
-  data_use_measurement::ChromeDataUseMeasurement* data_use_measurement()
-      override;
 
   // Set the local state for tests. Consumer is responsible for cleaning it up
   // afterwards (using ScopedTestingLocalState, for example).
diff --git a/chrome/test/chromedriver/test/run_py_tests.py b/chrome/test/chromedriver/test/run_py_tests.py
index cbf3749..312bec6 100755
--- a/chrome/test/chromedriver/test/run_py_tests.py
+++ b/chrome/test/chromedriver/test/run_py_tests.py
@@ -181,6 +181,8 @@
     # RemoteBrowserTest requires extra setup. TODO(johnchen@chromium.org):
     # Modify the test so it runs correctly as isolated test.
     'RemoteBrowserTest.*',
+    # Flaky: https://crbug.com/899919
+    'SessionHandlingTest.testGetSessions',
 ]
 
 
diff --git a/chrome/test/chromedriver/test/test_expectations b/chrome/test/chromedriver/test/test_expectations
index a9b6bd9..fe8be1a9 100644
--- a/chrome/test/chromedriver/test/test_expectations
+++ b/chrome/test/chromedriver/test/test_expectations
@@ -30,18 +30,8 @@
 
 _OS_NEGATIVE_FILTER = {}
 _OS_NEGATIVE_FILTER['win'] = [
-    # https://crbug.com/899919
-    'SessionHandlingTest.testGetSessions',
-    'SessionHandlingTest.testQuitASessionMoreThanOnce',
-    'SupportIPv4AndIPv6.testSupportIPv4AndIPv6',
-    'ZChromeStartRetryCountTest.testChromeStartRetryCount',
 ]
 _OS_NEGATIVE_FILTER['linux'] = [
-    # https://crbug.com/899919
-    'SessionHandlingTest.testGetSessions',
-    'SessionHandlingTest.testQuitASessionMoreThanOnce',
-    'SupportIPv4AndIPv6.testSupportIPv4AndIPv6',
-    'ZChromeStartRetryCountTest.testChromeStartRetryCount',
 ]
 _OS_NEGATIVE_FILTER['mac'] = [
     # https://crbug.com/868599
@@ -49,12 +39,6 @@
     'WindowTest.testCanMaximizeTheWindowFromIframe',
     'WindowTest.testSetsTheSizeOfTheCurrentWindow',
     'WindowTest.testCanMaximizeTheWindow',
-
-    # https://crbug.com/899919
-    'SessionHandlingTest.testGetSessions',
-    'SessionHandlingTest.testQuitASessionMoreThanOnce',
-    'SupportIPv4AndIPv6.testSupportIPv4AndIPv6',
-    'ZChromeStartRetryCountTest.testChromeStartRetryCount',
 ]
 
 _SPECIFIC_OS_REVISION_NEGATIVE_FILTER = {}
diff --git a/chrome/test/data/webui/BUILD.gn b/chrome/test/data/webui/BUILD.gn
index 81e95cf..a5bbd89 100644
--- a/chrome/test/data/webui/BUILD.gn
+++ b/chrome/test/data/webui/BUILD.gn
@@ -100,7 +100,6 @@
   if (is_chromeos) {
     sources += [
       "certificate_viewer_dialog_test.js",
-      "settings/easy_unlock_browsertest_chromeos.js",
       "sys_internals/sys_internals_browsertest.js",
     ]
   } else {
diff --git a/chrome/test/data/webui/print_preview/invalid_settings_browsertest.js b/chrome/test/data/webui/print_preview/invalid_settings_browsertest.js
index ab61608..3bde3da8 100644
--- a/chrome/test/data/webui/print_preview/invalid_settings_browsertest.js
+++ b/chrome/test/data/webui/print_preview/invalid_settings_browsertest.js
@@ -43,7 +43,7 @@
 
     /** @override */
     setup(function() {
-      cloudprint.CloudPrintInterface = print_preview.CloudPrintInterfaceStub;
+      cloudprint.CloudPrintInterfaceJS = print_preview.CloudPrintInterfaceStub;
       nativeLayer = new print_preview.NativeLayerStub();
       print_preview.NativeLayer.setInstance(nativeLayer);
       PolymerTest.clearBody();
diff --git a/chrome/test/data/webui/print_preview/print_preview_tests.js b/chrome/test/data/webui/print_preview/print_preview_tests.js
index 5850593..2749154 100644
--- a/chrome/test/data/webui/print_preview/print_preview_tests.js
+++ b/chrome/test/data/webui/print_preview/print_preview_tests.js
@@ -279,7 +279,7 @@
 
   suite(suiteName, function() {
     suiteSetup(function() {
-      cloudprint.CloudPrintInterface = print_preview.CloudPrintInterfaceStub;
+      cloudprint.CloudPrintInterfaceJS = print_preview.CloudPrintInterfaceStub;
       print_preview.PreviewArea.prototype.checkPluginCompatibility_ =
           function() {
         return true;
diff --git a/chrome/test/data/webui/settings/easy_unlock_browsertest_chromeos.js b/chrome/test/data/webui/settings/easy_unlock_browsertest_chromeos.js
deleted file mode 100644
index 304b4b0..0000000
--- a/chrome/test/data/webui/settings/easy_unlock_browsertest_chromeos.js
+++ /dev/null
@@ -1,195 +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.
-
-/** @fileoverview Suite of tests for Easy Unlock within People section. */
-
-GEN_INCLUDE(['settings_page_browsertest.js']);
-
-/**
- * @constructor
- * @extends {SettingsPageBrowserTest}
- */
-function SettingsEasyUnlockBrowserTest() {}
-
-SettingsEasyUnlockBrowserTest.prototype = {
-  __proto__: SettingsPageBrowserTest.prototype,
-
-  /** @override */
-  extraLibraries: PolymerTest.getLibraries(ROOT_PATH).concat([
-    '../test_browser_proxy.js',
-  ]),
-};
-
-// Times out on debug builders and may time out on memory bots because
-// the Settings page can take several seconds to load in a Release build
-// and several times that in a Debug build. See https://crbug.com/558434
-// and http://crbug.com/711256.
-
-// Runs easy unlock tests.
-TEST_F('SettingsEasyUnlockBrowserTest', 'DISABLED_EasyUnlock', function() {
-  /**
-   * A test version of EasyUnlockBrowserProxy. Provides helper methods
-   * for allowing tests to know when a method was called, as well as
-   * specifying mock responses.
-   *
-   * @implements {settings.EasyUnlockBrowserProxy}
-   */
-  class TestEasyUnlockBrowserProxy extends TestBrowserProxy {
-    constructor() {
-      super([
-        'getEnabledStatus',
-        'getTurnOffFlowStatus',
-        'startTurnOffFlow',
-        'cancelTurnOffFlow',
-      ]);
-
-      /** @private {boolean} */
-      this.isEnabled_ = false;
-    }
-
-    /**
-     * @param {boolean} easyUnlockEnabled
-     */
-    setEnabledStatus(easyUnlockEnabled) {
-      this.isEnabled_ = easyUnlockEnabled;
-    }
-
-    /** @override */
-    getEnabledStatus() {
-      this.methodCalled('getEnabledStatus');
-      return Promise.resolve(this.isEnabled_);
-    }
-
-    /** @override */
-    getTurnOffFlowStatus() {
-      this.methodCalled('getTurnOffFlowStatus');
-      return Promise.resolve('idle');
-    }
-
-    /** @override */
-    startTurnOffFlow() {
-      this.methodCalled('startTurnOffFlow');
-    }
-
-    /** @override */
-    cancelTurnOffFlow() {
-      this.methodCalled('cancelTurnOffFlow');
-    }
-  }
-
-  /** @type {?SettingsLockScreenElement} */
-  let lockScreen = null;
-
-  /** @type {?TestEasyUnlockBrowserProxy} */
-  let browserProxy = null;
-
-  suite('SettingsEasyUnlock', function() {
-    suiteSetup(function() {
-      Polymer.dom.flush();
-
-      // These overrides are necessary for this test to function on ChromeOS
-      // bots that do not have Bluetooth (don't actually support Easy Unlock).
-      loadTimeData.overrideValues({
-        easyUnlockAllowed: true,
-
-        easyUnlockSectionTitle: '',
-        easyUnlockLearnMoreURL: '',
-        easyUnlockSetupIntro: '',
-
-        easyUnlockDescription: '',
-        easyUnlockTurnOffTitle: '',
-        easyUnlockTurnOffDescription: '',
-        easyUnlockTurnOffButton: '',
-      });
-    });
-
-    setup(function() {
-      browserProxy = new TestEasyUnlockBrowserProxy();
-      settings.EasyUnlockBrowserProxyImpl.instance_ = browserProxy;
-
-      PolymerTest.clearBody();
-      lockScreen = document.createElement('settings-lock-screen');
-    });
-
-    test('turn off dialog', function() {
-      browserProxy.setEnabledStatus(true);
-      document.body.appendChild(lockScreen);
-
-      let turnOffDialog = null;
-
-      return browserProxy.whenCalled('getEnabledStatus')
-          .then(function() {
-            assertTrue(lockScreen.easyUnlockAllowed_);
-            expectTrue(lockScreen.easyUnlockEnabled_);
-
-            Polymer.dom.flush();
-
-            const turnOffButton = lockScreen.$$('#easyUnlockTurnOff');
-            assertTrue(!!turnOffButton);
-            expectFalse(turnOffButton.hidden);
-
-            turnOffButton.click();
-            return browserProxy.whenCalled('getTurnOffFlowStatus');
-          })
-          .then(function() {
-            Polymer.dom.flush();
-
-            turnOffDialog = lockScreen.$$('#easyUnlockTurnOffDialog');
-            assertTrue(!!turnOffDialog);
-
-            // Verify that elements on the turn off dialog are hidden or active
-            // according to the easy unlock turn off status.
-            const turnOffDialogButtonContainer =
-                turnOffDialog.$$('[slot=button-container]');
-            const turnOffDialogButtonSpinner =
-                turnOffDialog.$$('paper-spinner-lite');
-            const turnOffDialogConfirmButton = turnOffDialog.$$('#turnOff');
-            const turnOffDialogCancelButton =
-                turnOffDialog.$$('.cancel-button');
-            assertTrue(!!turnOffDialogButtonContainer);
-            assertTrue(!!turnOffDialogButtonSpinner);
-            assertTrue(!!turnOffDialogConfirmButton);
-            assertTrue(!!turnOffDialogCancelButton);
-
-            cr.webUIListenerCallback(
-                'easy-unlock-turn-off-flow-status', 'offline');
-            expectTrue(turnOffDialogButtonContainer.hidden);
-            expectFalse(turnOffDialogButtonSpinner.active);
-
-            cr.webUIListenerCallback(
-                'easy-unlock-turn-off-flow-status', 'pending');
-            expectFalse(turnOffDialogButtonContainer.hidden);
-            expectTrue(turnOffDialogButtonSpinner.active);
-
-            cr.webUIListenerCallback(
-                'easy-unlock-turn-off-flow-status', 'server-error');
-            expectFalse(turnOffDialogButtonContainer.hidden);
-            expectTrue(turnOffDialogCancelButton.hidden);
-
-            cr.webUIListenerCallback(
-                'easy-unlock-turn-off-flow-status', 'idle');
-            expectFalse(turnOffDialogConfirmButton.hidden);
-
-            turnOffDialogConfirmButton.click();
-
-            return browserProxy.whenCalled('startTurnOffFlow');
-          })
-          .then(function() {
-            // To signal successful turnoff, the enabled status is broadcast
-            // as false. At that point, the dialog should close and cancel
-            // any in-progress turnoff flow. The cancellation should be
-            // a no-op assuming the turnoff originated from this tab.
-            cr.webUIListenerCallback('easy-unlock-enabled-status', false);
-            return browserProxy.whenCalled('cancelTurnOffFlow');
-          })
-          .then(function() {
-            Polymer.dom.flush();
-            expectFalse(turnOffDialog.$.dialog.open);
-          });
-    });
-  });
-
-  // Run all registered tests.
-  mocha.run();
-});
diff --git a/chromeos/components/proximity_auth/OWNERS b/chromeos/components/proximity_auth/OWNERS
index 72f32f3..32c13108 100644
--- a/chromeos/components/proximity_auth/OWNERS
+++ b/chromeos/components/proximity_auth/OWNERS
@@ -1,5 +1,3 @@
-tengs@chromium.org
-xiyuan@chromium.org
 khorimoto@chromium.org
 hansberry@chromium.org
 jhawkins@chromium.org
diff --git a/chromeos/dbus/BUILD.gn b/chromeos/dbus/BUILD.gn
index 1792e43..c4d82f6b 100644
--- a/chromeos/dbus/BUILD.gn
+++ b/chromeos/dbus/BUILD.gn
@@ -85,6 +85,8 @@
     "dbus_thread_manager.h",
     "debug_daemon_client.cc",
     "debug_daemon_client.h",
+    "diagnosticsd_client.cc",
+    "diagnosticsd_client.h",
     "easy_unlock_client.cc",
     "easy_unlock_client.h",
     "fake_arc_appfuse_provider_client.cc",
@@ -111,6 +113,8 @@
     "fake_cryptohome_client.h",
     "fake_debug_daemon_client.cc",
     "fake_debug_daemon_client.h",
+    "fake_diagnosticsd_client.cc",
+    "fake_diagnosticsd_client.h",
     "fake_easy_unlock_client.cc",
     "fake_easy_unlock_client.h",
     "fake_gsm_sms_client.cc",
diff --git a/chromeos/dbus/OWNERS b/chromeos/dbus/OWNERS
index 4d6cd32..b6c283f 100644
--- a/chromeos/dbus/OWNERS
+++ b/chromeos/dbus/OWNERS
@@ -6,5 +6,7 @@
 per-file *auth_policy*=rsorokin@chromium.org
 per-file *auth_policy*=tnagel@chromium.org
 per-file *cryptohome*=dkrahn@chromium.org
+per-file *diagnosticsd*=emaxx@chromium.org
+per-file *diagnosticsd*=pmarko@chromium.org
 per-file *power*=derat@chromium.org
 per-file *smb_provider*=zentaro@chromium.org
diff --git a/chromeos/dbus/dbus_clients_browser.cc b/chromeos/dbus/dbus_clients_browser.cc
index 5010ed5..2c0931bc 100644
--- a/chromeos/dbus/dbus_clients_browser.cc
+++ b/chromeos/dbus/dbus_clients_browser.cc
@@ -16,6 +16,7 @@
 #include "chromeos/dbus/dbus_client_implementation_type.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/debug_daemon_client.h"
+#include "chromeos/dbus/diagnosticsd_client.h"
 #include "chromeos/dbus/easy_unlock_client.h"
 #include "chromeos/dbus/fake_arc_appfuse_provider_client.h"
 #include "chromeos/dbus/fake_arc_midis_client.h"
@@ -25,6 +26,7 @@
 #include "chromeos/dbus/fake_cicerone_client.h"
 #include "chromeos/dbus/fake_concierge_client.h"
 #include "chromeos/dbus/fake_debug_daemon_client.h"
+#include "chromeos/dbus/fake_diagnosticsd_client.h"
 #include "chromeos/dbus/fake_easy_unlock_client.h"
 #include "chromeos/dbus/fake_image_burner_client.h"
 #include "chromeos/dbus/fake_image_loader_client.h"
@@ -93,6 +95,11 @@
     debug_daemon_client_.reset(new FakeDebugDaemonClient);
 
   if (use_real_clients)
+    diagnosticsd_client_ = DiagnosticsdClient::Create();
+  else
+    diagnosticsd_client_ = std::make_unique<FakeDiagnosticsdClient>();
+
+  if (use_real_clients)
     easy_unlock_client_.reset(EasyUnlockClient::Create());
   else
     easy_unlock_client_.reset(new FakeEasyUnlockClient);
@@ -152,6 +159,7 @@
   concierge_client_->Init(system_bus);
   cros_disks_client_->Init(system_bus);
   debug_daemon_client_->Init(system_bus);
+  diagnosticsd_client_->Init(system_bus);
   easy_unlock_client_->Init(system_bus);
   image_burner_client_->Init(system_bus);
   image_loader_client_->Init(system_bus);
diff --git a/chromeos/dbus/dbus_clients_browser.h b/chromeos/dbus/dbus_clients_browser.h
index 9166044..b6b0b07 100644
--- a/chromeos/dbus/dbus_clients_browser.h
+++ b/chromeos/dbus/dbus_clients_browser.h
@@ -25,6 +25,7 @@
 class ConciergeClient;
 class CrosDisksClient;
 class DebugDaemonClient;
+class DiagnosticsdClient;
 class EasyUnlockClient;
 class ImageBurnerClient;
 class ImageLoaderClient;
@@ -59,6 +60,7 @@
   std::unique_ptr<ConciergeClient> concierge_client_;
   std::unique_ptr<CrosDisksClient> cros_disks_client_;
   std::unique_ptr<DebugDaemonClient> debug_daemon_client_;
+  std::unique_ptr<DiagnosticsdClient> diagnosticsd_client_;
   std::unique_ptr<EasyUnlockClient> easy_unlock_client_;
   std::unique_ptr<ImageBurnerClient> image_burner_client_;
   std::unique_ptr<ImageLoaderClient> image_loader_client_;
diff --git a/chromeos/dbus/dbus_thread_manager.cc b/chromeos/dbus/dbus_thread_manager.cc
index 9e7b5890..0bb3f712 100644
--- a/chromeos/dbus/dbus_thread_manager.cc
+++ b/chromeos/dbus/dbus_thread_manager.cc
@@ -177,6 +177,11 @@
                           : nullptr;
 }
 
+DiagnosticsdClient* DBusThreadManager::GetDiagnosticsdClient() {
+  return clients_browser_ ? clients_browser_->diagnosticsd_client_.get()
+                          : nullptr;
+}
+
 EasyUnlockClient* DBusThreadManager::GetEasyUnlockClient() {
   return clients_browser_ ? clients_browser_->easy_unlock_client_.get()
                           : nullptr;
diff --git a/chromeos/dbus/dbus_thread_manager.h b/chromeos/dbus/dbus_thread_manager.h
index c933c60..34005d7 100644
--- a/chromeos/dbus/dbus_thread_manager.h
+++ b/chromeos/dbus/dbus_thread_manager.h
@@ -40,6 +40,7 @@
 class DBusClientsCommon;
 class DBusThreadManagerSetter;
 class DebugDaemonClient;
+class DiagnosticsdClient;
 class EasyUnlockClient;
 class GsmSMSClient;
 class HammerdClient;
@@ -147,6 +148,7 @@
   CrosDisksClient* GetCrosDisksClient();
   CryptohomeClient* GetCryptohomeClient();
   DebugDaemonClient* GetDebugDaemonClient();
+  DiagnosticsdClient* GetDiagnosticsdClient();
   EasyUnlockClient* GetEasyUnlockClient();
   GsmSMSClient* GetGsmSMSClient();
   HammerdClient* GetHammerdClient();
diff --git a/chromeos/dbus/diagnosticsd_client.cc b/chromeos/dbus/diagnosticsd_client.cc
new file mode 100644
index 0000000..ceebf90
--- /dev/null
+++ b/chromeos/dbus/diagnosticsd_client.cc
@@ -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.
+
+#include "chromeos/dbus/diagnosticsd_client.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/memory/weak_ptr.h"
+#include "dbus/bus.h"
+#include "dbus/message.h"
+#include "third_party/cros_system_api/dbus/service_constants.h"
+
+namespace chromeos {
+
+namespace {
+
+void OnVoidDBusMethod(VoidDBusMethodCallback callback,
+                      dbus::Response* response) {
+  std::move(callback).Run(response != nullptr);
+}
+
+// The DiagnosticsdClient implementation used in production.
+class DiagnosticsdClientImpl final : public DiagnosticsdClient {
+ public:
+  DiagnosticsdClientImpl();
+  ~DiagnosticsdClientImpl() override;
+
+  // DiagnosticsdClient overrides:
+  void WaitForServiceToBeAvailable(
+      dbus::ObjectProxy::WaitForServiceToBeAvailableCallback callback) override;
+  void BootstrapMojoConnection(base::ScopedFD fd,
+                               VoidDBusMethodCallback callback) override;
+
+ protected:
+  // DiagnosticsdClient overrides:
+  void Init(dbus::Bus* bus) override;
+
+ private:
+  dbus::ObjectProxy* diagnosticsd_proxy_ = nullptr;
+
+  base::WeakPtrFactory<DiagnosticsdClientImpl> weak_ptr_factory_{this};
+
+  DISALLOW_COPY_AND_ASSIGN(DiagnosticsdClientImpl);
+};
+
+DiagnosticsdClientImpl::DiagnosticsdClientImpl() = default;
+
+DiagnosticsdClientImpl::~DiagnosticsdClientImpl() = default;
+
+void DiagnosticsdClientImpl::WaitForServiceToBeAvailable(
+    dbus::ObjectProxy::WaitForServiceToBeAvailableCallback callback) {
+  diagnosticsd_proxy_->WaitForServiceToBeAvailable(std::move(callback));
+}
+
+void DiagnosticsdClientImpl::BootstrapMojoConnection(
+    base::ScopedFD fd,
+    VoidDBusMethodCallback callback) {
+  dbus::MethodCall method_call(
+      ::diagnostics::kDiagnosticsdServiceInterface,
+      ::diagnostics::kDiagnosticsdBootstrapMojoConnectionMethod);
+  dbus::MessageWriter writer(&method_call);
+  writer.AppendFileDescriptor(fd.get());
+  diagnosticsd_proxy_->CallMethod(
+      &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
+      base::BindOnce(&OnVoidDBusMethod, std::move(callback)));
+}
+
+void DiagnosticsdClientImpl::Init(dbus::Bus* bus) {
+  diagnosticsd_proxy_ = bus->GetObjectProxy(
+      ::diagnostics::kDiagnosticsdServiceName,
+      dbus::ObjectPath(::diagnostics::kDiagnosticsdServicePath));
+}
+
+}  // namespace
+
+// static
+std::unique_ptr<DiagnosticsdClient> DiagnosticsdClient::Create() {
+  return std::make_unique<DiagnosticsdClientImpl>();
+}
+
+DiagnosticsdClient::DiagnosticsdClient() = default;
+
+}  // namespace chromeos
diff --git a/chromeos/dbus/diagnosticsd_client.h b/chromeos/dbus/diagnosticsd_client.h
new file mode 100644
index 0000000..05f8c8a
--- /dev/null
+++ b/chromeos/dbus/diagnosticsd_client.h
@@ -0,0 +1,44 @@
+// 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 CHROMEOS_DBUS_DIAGNOSTICSD_CLIENT_H_
+#define CHROMEOS_DBUS_DIAGNOSTICSD_CLIENT_H_
+
+#include <memory>
+
+#include "base/files/scoped_file.h"
+#include "base/macros.h"
+#include "chromeos/chromeos_export.h"
+#include "chromeos/dbus/dbus_client.h"
+#include "chromeos/dbus/dbus_method_call_status.h"
+#include "dbus/object_proxy.h"
+
+namespace chromeos {
+
+class CHROMEOS_EXPORT DiagnosticsdClient : public DBusClient {
+ public:
+  // Factory function.
+  static std::unique_ptr<DiagnosticsdClient> Create();
+
+  // Registers |callback| to run when the diagnosticsd service becomes
+  // available.
+  virtual void WaitForServiceToBeAvailable(
+      dbus::ObjectProxy::WaitForServiceToBeAvailableCallback callback) = 0;
+
+  // Bootstrap the Mojo connection between Chrome and the diagnosticsd daemon.
+  // |fd| is the file descriptor with the child end of the Mojo pipe.
+  virtual void BootstrapMojoConnection(base::ScopedFD fd,
+                                       VoidDBusMethodCallback callback) = 0;
+
+ protected:
+  // Create() should be used instead.
+  DiagnosticsdClient();
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(DiagnosticsdClient);
+};
+
+}  // namespace chromeos
+
+#endif  // CHROMEOS_DBUS_DIAGNOSTICSD_CLIENT_H_
diff --git a/chromeos/dbus/fake_diagnosticsd_client.cc b/chromeos/dbus/fake_diagnosticsd_client.cc
new file mode 100644
index 0000000..0d74f50
--- /dev/null
+++ b/chromeos/dbus/fake_diagnosticsd_client.cc
@@ -0,0 +1,34 @@
+// 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 "chromeos/dbus/fake_diagnosticsd_client.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/threading/thread_task_runner_handle.h"
+
+namespace chromeos {
+
+FakeDiagnosticsdClient::FakeDiagnosticsdClient() = default;
+
+FakeDiagnosticsdClient::~FakeDiagnosticsdClient() = default;
+
+void FakeDiagnosticsdClient::Init(dbus::Bus* bus) {}
+
+void FakeDiagnosticsdClient::WaitForServiceToBeAvailable(
+    dbus::ObjectProxy::WaitForServiceToBeAvailableCallback callback) {
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE,
+      base::BindOnce(std::move(callback), false /* service_is_available */));
+}
+
+void FakeDiagnosticsdClient::BootstrapMojoConnection(
+    base::ScopedFD fd,
+    VoidDBusMethodCallback callback) {
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::BindOnce(std::move(callback), false /* result */));
+}
+
+}  // namespace chromeos
diff --git a/chromeos/dbus/fake_diagnosticsd_client.h b/chromeos/dbus/fake_diagnosticsd_client.h
new file mode 100644
index 0000000..c4bac61
--- /dev/null
+++ b/chromeos/dbus/fake_diagnosticsd_client.h
@@ -0,0 +1,34 @@
+// 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 CHROMEOS_DBUS_FAKE_DIAGNOSTICSD_CLIENT_H_
+#define CHROMEOS_DBUS_FAKE_DIAGNOSTICSD_CLIENT_H_
+
+#include "base/macros.h"
+#include "chromeos/chromeos_export.h"
+#include "chromeos/dbus/diagnosticsd_client.h"
+
+namespace chromeos {
+
+class CHROMEOS_EXPORT FakeDiagnosticsdClient final : public DiagnosticsdClient {
+ public:
+  FakeDiagnosticsdClient();
+  ~FakeDiagnosticsdClient() override;
+
+  // DBusClient overrides:
+  void Init(dbus::Bus* bus) override;
+
+  // DiagnosticsdClient overrides:
+  void WaitForServiceToBeAvailable(
+      dbus::ObjectProxy::WaitForServiceToBeAvailableCallback callback) override;
+  void BootstrapMojoConnection(base::ScopedFD fd,
+                               VoidDBusMethodCallback callback) override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(FakeDiagnosticsdClient);
+};
+
+}  // namespace chromeos
+
+#endif  // CHROMEOS_DBUS_FAKE_DIAGNOSTICSD_CLIENT_H_
diff --git a/components/arc/common/BUILD.gn b/components/arc/common/BUILD.gn
index 93305c8..21597bd 100644
--- a/components/arc/common/BUILD.gn
+++ b/components/arc/common/BUILD.gn
@@ -67,6 +67,7 @@
       "//device/usb/public/mojom",
       "//mojo/public/mojom/base",
       "//services/media_session/public/mojom",
+      "//services/resource_coordinator/public/mojom",
       "//ui/accessibility/mojom",
       "//ui/gfx/geometry/mojo",
       "//url/mojom:url_mojom_gurl",
diff --git a/components/arc/common/process.mojom b/components/arc/common/process.mojom
index 62137d0b..1dd08326 100644
--- a/components/arc/common/process.mojom
+++ b/components/arc/common/process.mojom
@@ -2,10 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 //
-// Next MinVersion: 7
+// Next MinVersion: 8
 
 module arc.mojom;
 
+import "services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom";
+
 // Describes the current process state, as defined by AOSP in
 // android.app.ActivityManager.
 [Extensible]
@@ -107,6 +109,7 @@
   int64 last_activity_time;
 };
 
+// Next Method ID: 8
 interface ProcessInstance {
   // Requests ARC instance to kill a process.
   [MinVersion=1]
@@ -114,4 +117,14 @@
 
   [MinVersion=6]
   RequestProcessList@5() => (array<RunningAppProcessInfo> processes);
+
+  // Requests memory usage dumps for all ARC application processes.
+  [MinVersion=7]
+  RequestApplicationProcessMemoryInfo@6()
+      => (memory_instrumentation.mojom.GlobalMemoryDump dump);
+
+  // Requests memory usage dumps for all ARC system processes.
+  [MinVersion=7]
+  RequestSystemProcessMemoryInfo@7(array<uint32> nspids)
+      => (memory_instrumentation.mojom.GlobalMemoryDump dump);
 };
diff --git a/components/autofill/core/browser/autofill_manager.cc b/components/autofill/core/browser/autofill_manager.cc
index e49bd2c3..5b29dae 100644
--- a/components/autofill/core/browser/autofill_manager.cc
+++ b/components/autofill/core/browser/autofill_manager.cc
@@ -699,12 +699,11 @@
       /*is_credit_card=*/true, cvc, form_structure, autofill_field);
 }
 
-void AutofillManager::FillProfileForm(const std::string& guid,
+void AutofillManager::FillProfileForm(const autofill::AutofillProfile& profile,
                                       const FormData& form,
                                       const FormFieldData& field) {
   FillOrPreviewProfileForm(AutofillDriver::FORM_DATA_ACTION_FILL,
-                           /*query_id=*/-1, form, field,
-                           *personal_data_->GetProfileByGUID(guid));
+                           /*query_id=*/-1, form, field, profile);
 }
 
 void AutofillManager::OnFocusNoLongerOnForm() {
diff --git a/components/autofill/core/browser/autofill_manager.h b/components/autofill/core/browser/autofill_manager.h
index 2e5fef7..fca6cc7f 100644
--- a/components/autofill/core/browser/autofill_manager.h
+++ b/components/autofill/core/browser/autofill_manager.h
@@ -111,7 +111,7 @@
                           const FormFieldData& field);
 
   // Called from autofill assistant.
-  virtual void FillProfileForm(const std::string& guid,
+  virtual void FillProfileForm(const autofill::AutofillProfile& profile,
                                const FormData& form,
                                const FormFieldData& field);
 
diff --git a/components/autofill/core/browser/local_card_migration_manager.cc b/components/autofill/core/browser/local_card_migration_manager.cc
index 701ef2d..89d4a38 100644
--- a/components/autofill/core/browser/local_card_migration_manager.cc
+++ b/components/autofill/core/browser/local_card_migration_manager.cc
@@ -92,7 +92,10 @@
       /*active_experiments=*/std::vector<const char*>(), app_locale_,
       base::BindOnce(&LocalCardMigrationManager::OnDidGetUploadDetails,
                      weak_ptr_factory_.GetWeakPtr(), is_from_settings_page),
-      payments::kMigrateCardsBillableServiceNumber);
+      payments::kMigrateCardsBillableServiceNumber,
+      is_from_settings_page
+          ? payments::PaymentsClient::MigrationSource::SETTINGS_PAGE
+          : payments::PaymentsClient::MigrationSource::CHECKOUT_FLOW);
 }
 
 // Callback function when user agrees to migration on the intermediate dialog.
diff --git a/components/autofill/core/browser/payments/payments_client.cc b/components/autofill/core/browser/payments/payments_client.cc
index 70d7ad9..91e1a8483 100644
--- a/components/autofill/core/browser/payments/payments_client.cc
+++ b/components/autofill/core/browser/payments/payments_client.cc
@@ -319,14 +319,16 @@
       base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
                               const base::string16&,
                               std::unique_ptr<base::DictionaryValue>)> callback,
-      const int billable_service_number)
+      const int billable_service_number,
+      PaymentsClient::MigrationSource migration_source)
       : addresses_(addresses),
         detected_values_(detected_values),
         active_experiments_(active_experiments),
         full_sync_enabled_(full_sync_enabled),
         app_locale_(app_locale),
         callback_(std::move(callback)),
-        billable_service_number_(billable_service_number) {}
+        billable_service_number_(billable_service_number),
+        migration_source_(migration_source) {}
   ~GetUploadDetailsRequest() override {}
 
   std::string GetRequestUrlPath() override {
@@ -369,6 +371,20 @@
 
     SetActiveExperiments(active_experiments_, &request_dict);
 
+    switch (migration_source_) {
+      case PaymentsClient::MigrationSource::UNKNOWN_MIGRATION_SOURCE:
+        request_dict.SetString("migration_source", "UNKNOWN_MIGRATION_SOURCE");
+        break;
+      case PaymentsClient::MigrationSource::CHECKOUT_FLOW:
+        request_dict.SetString("migration_source", "CHECKOUT_FLOW");
+        break;
+      case PaymentsClient::MigrationSource::SETTINGS_PAGE:
+        request_dict.SetString("migration_source", "SETTINGS_PAGE");
+        break;
+      default:
+        NOTREACHED();
+    }
+
     std::string request_content;
     base::JSONWriter::Write(request_dict, &request_content);
     VLOG(3) << "getdetailsforsavecard request body: " << request_content;
@@ -403,6 +419,7 @@
   base::string16 context_token_;
   std::unique_ptr<base::DictionaryValue> legal_message_;
   const int billable_service_number_;
+  PaymentsClient::MigrationSource migration_source_;
 };
 
 class UploadCardRequest : public PaymentsRequest {
@@ -700,12 +717,14 @@
     base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
                             const base::string16&,
                             std::unique_ptr<base::DictionaryValue>)> callback,
-    const int billable_service_number) {
-  IssueRequest(std::make_unique<GetUploadDetailsRequest>(
-                   addresses, detected_values, active_experiments,
-                   account_info_getter_->IsSyncFeatureEnabled(), app_locale,
-                   std::move(callback), billable_service_number),
-               false);
+    const int billable_service_number,
+    MigrationSource migration_source) {
+  IssueRequest(
+      std::make_unique<GetUploadDetailsRequest>(
+          addresses, detected_values, active_experiments,
+          account_info_getter_->IsSyncFeatureEnabled(), app_locale,
+          std::move(callback), billable_service_number, migration_source),
+      false);
 }
 
 void PaymentsClient::UploadCard(
diff --git a/components/autofill/core/browser/payments/payments_client.h b/components/autofill/core/browser/payments/payments_client.h
index 0c689ae..eacd1047 100644
--- a/components/autofill/core/browser/payments/payments_client.h
+++ b/components/autofill/core/browser/payments/payments_client.h
@@ -110,6 +110,18 @@
     std::string app_locale;
   };
 
+  // An enum set in the GetUploadDetailsRequest indicating the source of the
+  // request. It should stay consistent with the same enum in Google Payments
+  // server code.
+  enum MigrationSource {
+    // Source unknown or unnecessary (such as during single credit card upload).
+    UNKNOWN_MIGRATION_SOURCE,
+    // Migration request comes from the checkout flow.
+    CHECKOUT_FLOW,
+    // Migration request comes from settings page.
+    SETTINGS_PAGE,
+  };
+
   // |url_loader_factory| is reference counted so it has no lifetime or
   // ownership requirements. |pref_service| is used to get the registered
   // preference value, |identity_manager| and |account_info_getter|
@@ -147,8 +159,9 @@
   // when get response from server. |billable_service_number| is used to set the
   // billable service number in the GetUploadDetails request. If the conditions
   // are met, the legal message will be returned via |callback|.
-  // |active_experiments| is use by Payments server to track requests that were
-  // triggered by enabled features.
+  // |active_experiments| is used by Payments server to track requests that were
+  // triggered by enabled features. |migration_source| is used by Payments
+  // server metrics to track the source of the request.
   virtual void GetUploadDetails(
       const std::vector<AutofillProfile>& addresses,
       const int detected_values,
@@ -157,7 +170,9 @@
       base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
                               const base::string16&,
                               std::unique_ptr<base::DictionaryValue>)> callback,
-      const int billable_service_number);
+      const int billable_service_number,
+      MigrationSource migration_source =
+          MigrationSource::UNKNOWN_MIGRATION_SOURCE);
 
   // The user has indicated that they would like to upload a card with the given
   // cvc. This request will fail server-side if a successful call to
diff --git a/components/autofill/core/browser/payments/payments_client_unittest.cc b/components/autofill/core/browser/payments/payments_client_unittest.cc
index f414299..d8bfc91 100644
--- a/components/autofill/core/browser/payments/payments_client_unittest.cc
+++ b/components/autofill/core/browser/payments/payments_client_unittest.cc
@@ -155,13 +155,15 @@
   }
 
   // Issue a GetUploadDetails request.
-  void StartGettingUploadDetails() {
+  void StartGettingUploadDetails(
+      PaymentsClient::MigrationSource migration_source =
+          PaymentsClient::MigrationSource::UNKNOWN_MIGRATION_SOURCE) {
     client_->GetUploadDetails(
         BuildTestProfiles(), kAllDetectableValues, std::vector<const char*>(),
         "language-LOCALE",
         base::BindOnce(&PaymentsClientTest::OnDidGetUploadDetails,
                        weak_ptr_factory_.GetWeakPtr()),
-        /*billable_service_number=*/12345);
+        /*billable_service_number=*/12345, migration_source);
   }
 
   // Issue an UploadCard request. This requires an OAuth token before starting
@@ -444,6 +446,30 @@
   EXPECT_TRUE(GetUploadData().find("full_sync_enabled") == std::string::npos);
 }
 
+TEST_F(PaymentsClientTest,
+       GetDetailsIncludesCheckoutFlowMigrationSourceInRequest) {
+  StartGettingUploadDetails(PaymentsClient::MigrationSource::CHECKOUT_FLOW);
+
+  // Verify that the correct migration source was included in the request.
+  EXPECT_TRUE(GetUploadData().find("CHECKOUT_FLOW") != std::string::npos);
+}
+
+TEST_F(PaymentsClientTest,
+       GetDetailsIncludesSettingsPageMigrationSourceInRequest) {
+  StartGettingUploadDetails(PaymentsClient::MigrationSource::SETTINGS_PAGE);
+
+  // Verify that the correct migration source was included in the request.
+  EXPECT_TRUE(GetUploadData().find("SETTINGS_PAGE") != std::string::npos);
+}
+
+TEST_F(PaymentsClientTest, GetDetailsIncludesUnknownMigrationSourceInRequest) {
+  StartGettingUploadDetails();
+
+  // Verify that the absence of a migration source results in UNKNOWN.
+  EXPECT_TRUE(GetUploadData().find("UNKNOWN_MIGRATION_SOURCE") !=
+              std::string::npos);
+}
+
 TEST_F(PaymentsClientTest, GetUploadAccountFromSyncTest) {
   EnableAutofillGetPaymentsIdentityFromSync();
   // Set up a different account.
diff --git a/components/autofill/core/browser/payments/test_payments_client.cc b/components/autofill/core/browser/payments/test_payments_client.cc
index 173c4b0..0010615 100644
--- a/components/autofill/core/browser/payments/test_payments_client.cc
+++ b/components/autofill/core/browser/payments/test_payments_client.cc
@@ -31,10 +31,12 @@
     base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
                             const base::string16&,
                             std::unique_ptr<base::DictionaryValue>)> callback,
-    const int billable_service_number) {
+    const int billable_service_number,
+    PaymentsClient::MigrationSource migration_source) {
   upload_details_addresses_ = addresses;
   detected_values_ = detected_values;
   active_experiments_ = active_experiments;
+  migration_source_ = migration_source;
   std::move(callback).Run(app_locale == "en-US"
                               ? AutofillClient::SUCCESS
                               : AutofillClient::PERMANENT_FAILURE,
diff --git a/components/autofill/core/browser/payments/test_payments_client.h b/components/autofill/core/browser/payments/test_payments_client.h
index 710fda1..231cf00 100644
--- a/components/autofill/core/browser/payments/test_payments_client.h
+++ b/components/autofill/core/browser/payments/test_payments_client.h
@@ -35,7 +35,9 @@
       base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
                               const base::string16&,
                               std::unique_ptr<base::DictionaryValue>)> callback,
-      const int billable_service_number) override;
+      const int billable_service_number,
+      MigrationSource migration_source =
+          MigrationSource::UNKNOWN_MIGRATION_SOURCE) override;
 
   void UploadCard(
       const payments::PaymentsClient::UploadRequestDetails& request_details,
@@ -71,6 +73,7 @@
   int detected_values_;
   std::string pan_first_six_;
   std::vector<const char*> active_experiments_;
+  PaymentsClient::MigrationSource migration_source_;
   std::unique_ptr<std::unordered_map<std::string, std::string>> save_result_;
 
   DISALLOW_COPY_AND_ASSIGN(TestPaymentsClient);
diff --git a/components/autofill/core/browser/test_personal_data_manager.h b/components/autofill/core/browser/test_personal_data_manager.h
index bdf9d4a..86ea84a 100644
--- a/components/autofill/core/browser/test_personal_data_manager.h
+++ b/components/autofill/core/browser/test_personal_data_manager.h
@@ -126,7 +126,7 @@
   base::Optional<bool> autofill_profile_enabled_;
   base::Optional<bool> autofill_credit_card_enabled_;
   base::Optional<bool> autofill_wallet_import_enabled_;
-  bool sync_feature_enabled_;
+  bool sync_feature_enabled_ = false;
   AccountInfo account_info_;
 
   DISALLOW_COPY_AND_ASSIGN(TestPersonalDataManager);
diff --git a/components/autofill_assistant/browser/actions/action_delegate.h b/components/autofill_assistant/browser/actions/action_delegate.h
index 75cbb7f..99e1be5 100644
--- a/components/autofill_assistant/browser/actions/action_delegate.h
+++ b/components/autofill_assistant/browser/actions/action_delegate.h
@@ -16,6 +16,7 @@
 class GURL;
 
 namespace autofill {
+class AutofillProfile;
 class CreditCard;
 class PersonalDataManager;
 }  // namespace autofill
@@ -71,9 +72,9 @@
       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.
-  virtual void FillAddressForm(const std::string& guid,
+  // Fill the address form given by |selectors| with the given address
+  // |profile|. |profile| cannot be nullptr.
+  virtual void FillAddressForm(const autofill::AutofillProfile* profile,
                                const std::vector<std::string>& selectors,
                                base::OnceCallback<void(bool)> callback) = 0;
 
diff --git a/components/autofill_assistant/browser/actions/autofill_action.cc b/components/autofill_assistant/browser/actions/autofill_action.cc
index 7090b94..1f6609c 100644
--- a/components/autofill_assistant/browser/actions/autofill_action.cc
+++ b/components/autofill_assistant/browser/actions/autofill_action.cc
@@ -226,8 +226,11 @@
     return;
   }
 
+  const autofill::AutofillProfile* profile =
+      delegate->GetPersonalDataManager()->GetProfileByGUID(guid);
+  DCHECK(profile);
   delegate->FillAddressForm(
-      guid, selectors_,
+      profile, selectors_,
       base::BindOnce(&AutofillAction::OnFormFilled,
                      weak_ptr_factory_.GetWeakPtr(), guid, delegate));
 }
diff --git a/components/autofill_assistant/browser/actions/autofill_action_unittest.cc b/components/autofill_assistant/browser/actions/autofill_action_unittest.cc
index 85cc640..379c922b 100644
--- a/components/autofill_assistant/browser/actions/autofill_action_unittest.cc
+++ b/components/autofill_assistant/browser/actions/autofill_action_unittest.cc
@@ -218,9 +218,12 @@
       .WillOnce(Return(autofill_profile_guid_));
 
   // Autofill succeeds.
+  const auto* expected_profile =
+      personal_data_manager_->GetProfileByGUID(autofill_profile_guid_);
+  ASSERT_TRUE(expected_profile);
   EXPECT_CALL(
       mock_action_delegate_,
-      OnFillAddressForm(autofill_profile_guid_, ElementsAre(kFakeSelector), _))
+      OnFillAddressForm(expected_profile, ElementsAre(kFakeSelector), _))
       .WillOnce(RunOnceCallback<2>(true));
 
   // Validation succeeds.
@@ -246,9 +249,12 @@
       .WillOnce(Return(autofill_profile_guid_));
 
   // Autofill succeeds.
+  const auto* expected_profile =
+      personal_data_manager_->GetProfileByGUID(autofill_profile_guid_);
+  ASSERT_TRUE(expected_profile);
   EXPECT_CALL(
       mock_action_delegate_,
-      OnFillAddressForm(autofill_profile_guid_, ElementsAre(kFakeSelector), _))
+      OnFillAddressForm(expected_profile, ElementsAre(kFakeSelector), _))
       .WillOnce(RunOnceCallback<2>(true));
 
   // Validation fails when getting FIRST_NAME.
@@ -283,11 +289,13 @@
   // Return a fake selected address.
   EXPECT_CALL(mock_client_memory_, selected_address(kAddressName))
       .WillOnce(Return(autofill_profile_guid_));
-
+  const auto* expected_profile =
+      personal_data_manager_->GetProfileByGUID(autofill_profile_guid_);
+  ASSERT_TRUE(expected_profile);
   // Autofill succeeds.
   EXPECT_CALL(
       mock_action_delegate_,
-      OnFillAddressForm(autofill_profile_guid_, ElementsAre(kFakeSelector), _))
+      OnFillAddressForm(expected_profile, ElementsAre(kFakeSelector), _))
       .WillOnce(RunOnceCallback<2>(true));
 
   {
diff --git a/components/autofill_assistant/browser/actions/mock_action_delegate.h b/components/autofill_assistant/browser/actions/mock_action_delegate.h
index 1153400..0d525ab 100644
--- a/components/autofill_assistant/browser/actions/mock_action_delegate.h
+++ b/components/autofill_assistant/browser/actions/mock_action_delegate.h
@@ -46,14 +46,14 @@
   MOCK_METHOD1(OnChooseAddress,
                void(base::OnceCallback<void(const std::string&)>& callback));
 
-  void FillAddressForm(const std::string& guid,
+  void FillAddressForm(const autofill::AutofillProfile* profile,
                        const std::vector<std::string>& selectors,
                        base::OnceCallback<void(bool)> callback) override {
-    OnFillAddressForm(guid, selectors, callback);
+    OnFillAddressForm(profile, selectors, callback);
   }
 
   MOCK_METHOD3(OnFillAddressForm,
-               void(const std::string& guid,
+               void(const autofill::AutofillProfile* profile,
                     const std::vector<std::string>& selectors,
                     base::OnceCallback<void(bool)>& callback));
 
diff --git a/components/autofill_assistant/browser/script_executor.cc b/components/autofill_assistant/browser/script_executor.cc
index 82eedb3..353cb81a 100644
--- a/components/autofill_assistant/browser/script_executor.cc
+++ b/components/autofill_assistant/browser/script_executor.cc
@@ -98,10 +98,10 @@
   delegate_->GetUiController()->ChooseAddress(std::move(callback));
 }
 
-void ScriptExecutor::FillAddressForm(const std::string& guid,
+void ScriptExecutor::FillAddressForm(const autofill::AutofillProfile* profile,
                                      const std::vector<std::string>& selectors,
                                      base::OnceCallback<void(bool)> callback) {
-  delegate_->GetWebController()->FillAddressForm(guid, selectors,
+  delegate_->GetWebController()->FillAddressForm(profile, selectors,
                                                  std::move(callback));
 }
 
diff --git a/components/autofill_assistant/browser/script_executor.h b/components/autofill_assistant/browser/script_executor.h
index 5efa844..bc1fb57 100644
--- a/components/autofill_assistant/browser/script_executor.h
+++ b/components/autofill_assistant/browser/script_executor.h
@@ -75,7 +75,7 @@
       const std::string& title) override;
   void ChooseAddress(
       base::OnceCallback<void(const std::string&)> callback) override;
-  void FillAddressForm(const std::string& guid,
+  void FillAddressForm(const autofill::AutofillProfile* profile,
                        const std::vector<std::string>& selectors,
                        base::OnceCallback<void(bool)> callback) override;
   void ChooseCard(
diff --git a/components/autofill_assistant/browser/web_controller.cc b/components/autofill_assistant/browser/web_controller.cc
index 0560024..21a84552 100644
--- a/components/autofill_assistant/browser/web_controller.cc
+++ b/components/autofill_assistant/browser/web_controller.cc
@@ -518,11 +518,12 @@
   OnResult(true, std::move(callback));
 }
 
-void WebController::FillAddressForm(const std::string& guid,
+void WebController::FillAddressForm(const autofill::AutofillProfile* profile,
                                     const std::vector<std::string>& selectors,
                                     base::OnceCallback<void(bool)> callback) {
   auto data_to_autofill = std::make_unique<FillFormInputData>();
-  data_to_autofill->autofill_data_guid = guid;
+  data_to_autofill->profile =
+      std::make_unique<autofill::AutofillProfile>(*profile);
   FindElement(selectors,
               /* strict_mode= */ true,
               base::BindOnce(&WebController::OnFindElementForFillingForm,
@@ -581,8 +582,8 @@
         autofill::kNoQueryId, form_data, form_field, *data_to_autofill->card,
         data_to_autofill->cvc);
   } else {
-    driver->autofill_manager()->FillProfileForm(
-        data_to_autofill->autofill_data_guid, form_data, form_field);
+    driver->autofill_manager()->FillProfileForm(*data_to_autofill->profile,
+                                                form_data, form_field);
   }
 
   OnResult(true, std::move(callback));
diff --git a/components/autofill_assistant/browser/web_controller.h b/components/autofill_assistant/browser/web_controller.h
index 3123769..1ea2e626 100644
--- a/components/autofill_assistant/browser/web_controller.h
+++ b/components/autofill_assistant/browser/web_controller.h
@@ -19,6 +19,7 @@
 #include "components/autofill_assistant/browser/devtools/devtools_client.h"
 
 namespace autofill {
+class AutofillProfile;
 class CreditCard;
 }  // namespace autofill
 
@@ -68,9 +69,9 @@
   virtual void ClickElement(const std::vector<std::string>& selectors,
                             base::OnceCallback<void(bool)> callback);
 
-  // Fill the address form given by |selectors| with the given address |guid| in
-  // personal data manager.
-  virtual void FillAddressForm(const std::string& guid,
+  // Fill the address form given by |selectors| with the given address
+  // |profile|.
+  virtual void FillAddressForm(const autofill::AutofillProfile* profile,
                                const std::vector<std::string>& selectors,
                                base::OnceCallback<void(bool)> callback);
 
@@ -164,7 +165,7 @@
     ~FillFormInputData();
 
     // Data for filling address form.
-    std::string autofill_data_guid;
+    std::unique_ptr<autofill::AutofillProfile> profile;
 
     // Data for filling card form.
     std::unique_ptr<autofill::CreditCard> card;
diff --git a/components/browser_sync/profile_sync_service.cc b/components/browser_sync/profile_sync_service.cc
index 61554d8..e38892f4 100644
--- a/components/browser_sync/profile_sync_service.cc
+++ b/components/browser_sync/profile_sync_service.cc
@@ -2146,9 +2146,10 @@
     observer.OnForeignSessionUpdated(this);
 }
 
-base::MessageLoop* ProfileSyncService::GetSyncLoopForTest() const {
+scoped_refptr<base::SingleThreadTaskRunner>
+ProfileSyncService::GetSyncThreadTaskRunnerForTest() const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  return sync_thread_ ? sync_thread_->message_loop() : nullptr;
+  return sync_thread_ ? sync_thread_->task_runner() : nullptr;
 }
 
 syncer::SyncEncryptionHandler::Observer*
diff --git a/components/browser_sync/profile_sync_service.h b/components/browser_sync/profile_sync_service.h
index 385d919f..c8f6ebd 100644
--- a/components/browser_sync/profile_sync_service.h
+++ b/components/browser_sync/profile_sync_service.h
@@ -14,9 +14,11 @@
 #include "base/location.h"
 #include "base/macros.h"
 #include "base/memory/memory_pressure_listener.h"
+#include "base/memory/scoped_refptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
 #include "base/sequence_checker.h"
+#include "base/single_thread_task_runner.h"
 #include "base/threading/thread.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
@@ -47,10 +49,6 @@
 #include "google_apis/gaia/google_service_auth_error.h"
 #include "url/gurl.h"
 
-namespace base {
-class MessageLoop;
-}
-
 namespace identity {
 class IdentityManager;
 }
@@ -457,7 +455,8 @@
   void SetSyncAllowedByPlatform(bool allowed);
 
   // Sometimes we need to wait for tasks on the sync thread in tests.
-  base::MessageLoop* GetSyncLoopForTest() const;
+  scoped_refptr<base::SingleThreadTaskRunner> GetSyncThreadTaskRunnerForTest()
+      const;
 
   // Some tests rely on injecting calls to the encryption observer.
   syncer::SyncEncryptionHandler::Observer* GetEncryptionObserverForTest();
diff --git a/components/browser_watcher/window_hang_monitor_win_unittest.cc b/components/browser_watcher/window_hang_monitor_win_unittest.cc
index 0ccf8a7..f4827ed3 100644
--- a/components/browser_watcher/window_hang_monitor_win_unittest.cc
+++ b/components/browser_watcher/window_hang_monitor_win_unittest.cc
@@ -10,8 +10,6 @@
 #include "base/base_paths.h"
 #include "base/base_switches.h"
 #include "base/command_line.h"
-#include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_current.h"
 #include "base/path_service.h"
 #include "base/process/launch.h"
 #include "base/process/process.h"
@@ -174,8 +172,7 @@
                             WPARAM wparam,
                             LPARAM lparam,
                             LRESULT* result) {
-    EXPECT_EQ(message_window_thread_.message_loop(),
-              base::MessageLoopCurrent::Get());
+    EXPECT_TRUE(message_window_thread_.task_runner()->BelongsToCurrentThread());
     return false;  // Pass through to DefWindowProc.
   }
 
diff --git a/components/crash/content/browser/child_exit_observer_android.cc b/components/crash/content/browser/child_exit_observer_android.cc
index a8a27eb3..fe3c572 100644
--- a/components/crash/content/browser/child_exit_observer_android.cc
+++ b/components/crash/content/browser/child_exit_observer_android.cc
@@ -153,7 +153,7 @@
     browser_child_process_info_.erase(it);
   } else {
     info.process_host_id = data.id;
-    info.pid = data.GetHandle();
+    info.pid = data.GetProcess().Pid();
     info.process_type = static_cast<content::ProcessType>(data.process_type);
     info.app_state = base::android::ApplicationStatusListener::GetState();
     info.normal_termination = true;
@@ -168,7 +168,7 @@
   DCHECK(!base::ContainsKey(browser_child_process_info_, data.id));
   TerminationInfo info;
   info.process_host_id = data.id;
-  info.pid = data.GetHandle();
+  info.pid = data.GetProcess().Pid();
   info.process_type = static_cast<content::ProcessType>(data.process_type);
   info.app_state = base::android::ApplicationStatusListener::GetState();
   PopulateTerminationInfo(content_info, &info);
diff --git a/components/data_reduction_proxy/content/browser/data_reduction_proxy_pingback_client_impl.cc b/components/data_reduction_proxy/content/browser/data_reduction_proxy_pingback_client_impl.cc
index 3d2f488..e1d176e0 100644
--- a/components/data_reduction_proxy/content/browser/data_reduction_proxy_pingback_client_impl.cc
+++ b/components/data_reduction_proxy/content/browser/data_reduction_proxy_pingback_client_impl.cc
@@ -66,7 +66,9 @@
 void AddDataToPageloadMetrics(const DataReductionProxyData& request_data,
                               const DataReductionProxyPageLoadTiming& timing,
                               PageloadMetrics_RendererCrashType crash_type,
+                              std::string channel,
                               PageloadMetrics* request) {
+  request->set_channel(channel);
   request->set_session_key(request_data.session_key());
   request->set_holdback_group(params::HoldbackFieldTrialGroup());
   // For the timing events, any of them could be zero. Fill the message as a
@@ -221,13 +223,15 @@
 
 DataReductionProxyPingbackClientImpl::DataReductionProxyPingbackClientImpl(
     scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
-    scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner)
+    scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
+    const std::string& channel)
     : url_loader_factory_(std::move(url_loader_factory)),
       pingback_url_(util::AddApiKeyToUrl(params::GetPingbackURL())),
       pingback_reporting_fraction_(0.0),
       current_loader_message_count_(0u),
       current_loader_crash_count_(0u),
       ui_task_runner_(std::move(ui_task_runner)),
+      channel_(channel),
 #if defined(OS_ANDROID)
       scoped_observer_(this),
       weak_factory_(this) {
@@ -368,7 +372,8 @@
     PageloadMetrics_RendererCrashType crash_type) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   PageloadMetrics* pageload_metrics = metrics_request_.add_pageloads();
-  AddDataToPageloadMetrics(request_data, timing, crash_type, pageload_metrics);
+  AddDataToPageloadMetrics(request_data, timing, crash_type, channel_,
+                           pageload_metrics);
   if (current_loader_)
     return;
   DCHECK_EQ(1, metrics_request_.pageloads_size());
diff --git a/components/data_reduction_proxy/content/browser/data_reduction_proxy_pingback_client_impl.h b/components/data_reduction_proxy/content/browser/data_reduction_proxy_pingback_client_impl.h
index 524c2b5..69c71e726 100644
--- a/components/data_reduction_proxy/content/browser/data_reduction_proxy_pingback_client_impl.h
+++ b/components/data_reduction_proxy/content/browser/data_reduction_proxy_pingback_client_impl.h
@@ -7,6 +7,7 @@
 
 #include <map>
 #include <memory>
+#include <string>
 
 #include "base/macros.h"
 #include "base/memory/scoped_refptr.h"
@@ -48,7 +49,8 @@
  public:
   DataReductionProxyPingbackClientImpl(
       scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
-      scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner);
+      scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
+      const std::string& channel);
   ~DataReductionProxyPingbackClientImpl() override;
 
  protected:
@@ -122,6 +124,9 @@
 
   scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_;
 
+  // The release channel of this Chrome instance.
+  std::string channel_;
+
 #if defined(OS_ANDROID)
   typedef std::tuple<DataReductionProxyData, DataReductionProxyPageLoadTiming>
       CrashPageLoadInformation;
diff --git a/components/data_reduction_proxy/content/browser/data_reduction_proxy_pingback_client_impl_unittest.cc b/components/data_reduction_proxy/content/browser/data_reduction_proxy_pingback_client_impl_unittest.cc
index 51f08184..b16b06d 100644
--- a/components/data_reduction_proxy/content/browser/data_reduction_proxy_pingback_client_impl_unittest.cc
+++ b/components/data_reduction_proxy/content/browser/data_reduction_proxy_pingback_client_impl_unittest.cc
@@ -49,6 +49,7 @@
     "DataReductionProxy.Pingback.Attempted";
 static const char kSessionKey[] = "fake-session";
 static const char kFakeURL[] = "http://www.google.com/";
+static const char kChannel[] = "channel";
 static const int64_t kBytes = 10000;
 static const int64_t kBytesOriginal = 1000000;
 static const int64_t kTotalPageSizeBytes = 20000;
@@ -81,7 +82,8 @@
       scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
       scoped_refptr<base::SingleThreadTaskRunner> thread_task_runner)
       : DataReductionProxyPingbackClientImpl(url_loader_factory,
-                                             std::move(thread_task_runner)),
+                                             std::move(thread_task_runner),
+                                             kChannel),
         should_override_random_(false),
         override_value_(0.0f),
         current_time_(base::Time::Now()) {}
@@ -314,6 +316,7 @@
       protobuf_parser::DurationToTimeDelta(pageload_metrics.page_end_time()));
 
   EXPECT_EQ(kSessionKey, pageload_metrics.session_key());
+  EXPECT_EQ(kChannel, pageload_metrics.channel());
   EXPECT_EQ(kFakeURL, pageload_metrics.first_request_url());
   EXPECT_EQ(kBytes, pageload_metrics.compressed_page_size_bytes());
   EXPECT_EQ(kBytesOriginal, pageload_metrics.original_page_size_bytes());
@@ -485,6 +488,7 @@
         protobuf_parser::DurationToTimeDelta(pageload_metrics.page_end_time()));
 
     EXPECT_EQ(kSessionKey, pageload_metrics.session_key());
+    EXPECT_EQ(kChannel, pageload_metrics.channel());
     EXPECT_EQ(kFakeURL, pageload_metrics.first_request_url());
     EXPECT_EQ(kBytes, pageload_metrics.compressed_page_size_bytes());
     EXPECT_EQ(kBytesOriginal, pageload_metrics.original_page_size_bytes());
diff --git a/components/data_reduction_proxy/proto/pageload_metrics.proto b/components/data_reduction_proxy/proto/pageload_metrics.proto
index f4275bdb..5c91b49 100644
--- a/components/data_reduction_proxy/proto/pageload_metrics.proto
+++ b/components/data_reduction_proxy/proto/pageload_metrics.proto
@@ -56,7 +56,7 @@
 
 // Metrics for a single pageload.
 message PageloadMetrics {
-  // Next ID: 31
+  // Next ID: 32
   reserved 3;
 
   // The possible effective connection type values.
@@ -251,4 +251,8 @@
 
   // The number of scroll events that happened on the page.
   optional uint32 scroll_count = 30;
+
+  // The release channel of this Chrome instance, e.g.: "stable", "beta", "dev",
+  // "canary", "unknown".
+  optional string channel = 31;
 }
diff --git a/components/exo/shell_surface_base.cc b/components/exo/shell_surface_base.cc
index 813dc3d..796dd64 100644
--- a/components/exo/shell_surface_base.cc
+++ b/components/exo/shell_surface_base.cc
@@ -816,7 +816,7 @@
     views::Widget* widget) {
   aura::Window* window = widget_->GetNativeWindow();
   // ShellSurfaces always use immersive mode.
-  window->SetProperty(aura::client::kImmersiveFullscreenKey, true);
+  window->SetProperty(ash::kImmersiveIsActive, true);
   ash::wm::WindowState* window_state = ash::wm::GetWindowState(window);
   if (!frame_enabled() && !window_state->HasDelegate()) {
     window_state->SetDelegate(std::make_unique<CustomWindowStateDelegate>());
diff --git a/components/exo/wayland/clients/test/run_all_client_perftests.cc b/components/exo/wayland/clients/test/run_all_client_perftests.cc
index c944937..c765855 100644
--- a/components/exo/wayland/clients/test/run_all_client_perftests.cc
+++ b/components/exo/wayland/clients/test/run_all_client_perftests.cc
@@ -36,7 +36,7 @@
     client_thread.Start();
 
     base::RunLoop run_loop;
-    client_thread.message_loop()->task_runner()->PostTask(
+    client_thread.task_runner()->PostTask(
         FROM_HERE,
         base::BindOnce(&ExoClientPerfTestSuite::RunTestsOnClientThread,
                        base::Unretained(this), run_loop.QuitWhenIdleClosure()));
diff --git a/components/heap_profiling/client_connection_manager.cc b/components/heap_profiling/client_connection_manager.cc
index e395afa..9a281e76 100644
--- a/components/heap_profiling/client_connection_manager.cc
+++ b/components/heap_profiling/client_connection_manager.cc
@@ -111,8 +111,7 @@
 
 void StartProfilingNonRendererChildOnIOThread(
     base::WeakPtr<Controller> controller,
-    const content::ChildProcessData& data,
-    base::ProcessId pid) {
+    const content::ChildProcessData& data) {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
 
   if (!controller)
@@ -130,7 +129,8 @@
 
   // Tell the child process to start profiling.
   ProfilingClientBinder client(host);
-  controller->StartProfilingClient(client.take(), pid, process_type);
+  controller->StartProfilingClient(client.take(), data.GetProcess().Pid(),
+                                   process_type);
 }
 
 void StartProfilingClientOnIOThread(base::WeakPtr<Controller> controller,
@@ -177,8 +177,8 @@
   for (content::BrowserChildProcessHostIterator browser_child_iter;
        !browser_child_iter.Done(); ++browser_child_iter) {
     const content::ChildProcessData& data = browser_child_iter.GetData();
-    if (base::GetProcId(data.GetHandle()) == pid) {
-      StartProfilingNonRendererChildOnIOThread(controller, data, pid);
+    if (data.GetProcess().Pid() == pid) {
+      StartProfilingNonRendererChildOnIOThread(controller, data);
       return;
     }
   }
@@ -200,9 +200,8 @@
        !browser_child_iter.Done(); ++browser_child_iter) {
     const content::ChildProcessData& data = browser_child_iter.GetData();
     if (ShouldProfileNonRendererProcessType(mode, data.process_type) &&
-        data.IsHandleValid()) {
-      StartProfilingNonRendererChildOnIOThread(
-          controller, data, base::GetProcId(data.GetHandle()));
+        data.GetProcess().IsValid()) {
+      StartProfilingNonRendererChildOnIOThread(controller, data);
     }
   }
 }
@@ -312,10 +311,9 @@
     const content::ChildProcessData& data) {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
   base::CreateSingleThreadTaskRunnerWithTraits({content::BrowserThread::IO})
-      ->PostTask(
-          FROM_HERE,
-          base::BindOnce(&StartProfilingNonRendererChildOnIOThread, controller_,
-                         data.Duplicate(), base::GetProcId(data.GetHandle())));
+      ->PostTask(FROM_HERE,
+                 base::BindOnce(&StartProfilingNonRendererChildOnIOThread,
+                                controller_, data.Duplicate()));
 }
 
 void ClientConnectionManager::Observe(
diff --git a/components/history/core/browser/history_service.h b/components/history/core/browser/history_service.h
index 24b23fab..b1981d1 100644
--- a/components/history/core/browser/history_service.h
+++ b/components/history/core/browser/history_service.h
@@ -860,7 +860,7 @@
 
   // This class has most of the implementation and runs on the 'thread_'.
   // You MUST communicate with this class ONLY through the thread_'s
-  // message_loop().
+  // task_runner().
   //
   // This pointer will be null once Cleanup() has been called, meaning no
   // more calls should be made to the history thread.
diff --git a/components/invalidation/impl/BUILD.gn b/components/invalidation/impl/BUILD.gn
index f8dd86a..9482066f 100644
--- a/components/invalidation/impl/BUILD.gn
+++ b/components/invalidation/impl/BUILD.gn
@@ -21,6 +21,16 @@
   sources = [
     "deprecated_invalidator_registrar.cc",
     "deprecated_invalidator_registrar.h",
+    "fcm_invalidation_listener.cc",
+    "fcm_invalidation_listener.h",
+    "fcm_invalidation_service.cc",
+    "fcm_invalidation_service.h",
+    "fcm_invalidator.cc",
+    "fcm_invalidator.h",
+    "fcm_network_handler.cc",
+    "fcm_network_handler.h",
+    "fcm_sync_network_channel.cc",
+    "fcm_sync_network_channel.h",
     "invalidation_logger.cc",
     "invalidation_logger.h",
     "invalidation_logger_observer.h",
@@ -38,8 +48,12 @@
     "invalidator_registrar_with_memory.h",
     "invalidator_storage.cc",
     "invalidator_storage.h",
+    "logger.cc",
+    "logger.h",
     "mock_ack_handler.cc",
     "mock_ack_handler.h",
+    "per_user_topic_invalidation_client.cc",
+    "per_user_topic_invalidation_client.h",
     "per_user_topic_registration_manager.cc",
     "per_user_topic_registration_manager.h",
     "per_user_topic_registration_request.cc",
@@ -63,6 +77,7 @@
     "//base:i18n",
     "//components/data_use_measurement/core",
     "//components/gcm_driver",
+    "//components/gcm_driver/common",
     "//components/keyed_service/core",
     "//components/pref_registry",
     "//components/prefs",
@@ -79,16 +94,6 @@
 
   if (!is_android) {
     sources += [
-      "fcm_invalidation_listener.cc",
-      "fcm_invalidation_listener.h",
-      "fcm_invalidation_service.cc",
-      "fcm_invalidation_service.h",
-      "fcm_invalidator.cc",
-      "fcm_invalidator.h",
-      "fcm_network_handler.cc",
-      "fcm_network_handler.h",
-      "fcm_sync_network_channel.cc",
-      "fcm_sync_network_channel.h",
       "gcm_invalidation_bridge.cc",
       "gcm_invalidation_bridge.h",
       "gcm_network_channel.cc",
@@ -96,8 +101,6 @@
       "gcm_network_channel_delegate.h",
       "invalidation_notifier.cc",
       "invalidation_notifier.h",
-      "logger.cc",
-      "logger.h",
       "network_channel.h",
       "non_blocking_invalidator.cc",
       "non_blocking_invalidator.h",
@@ -105,8 +108,6 @@
       "notifier_reason_util.h",
       "p2p_invalidator.cc",
       "p2p_invalidator.h",
-      "per_user_topic_invalidation_client.cc",
-      "per_user_topic_invalidation_client.h",
       "push_client_channel.cc",
       "push_client_channel.h",
       "registration_manager.cc",
@@ -123,7 +124,6 @@
       "ticl_settings_provider.cc",
       "ticl_settings_provider.h",
     ]
-    deps += [ "//components/gcm_driver/common" ]
   }
 
   if (is_android) {
@@ -151,7 +151,14 @@
 source_set("unit_tests") {
   testonly = true
   sources = [
+    "fcm_invalidation_listener_unittest.cc",
+    "fcm_invalidation_service_unittest.cc",
+    "fcm_invalidator_unittest.cc",
+    "fcm_network_handler_unittests.cc",
     "invalidation_logger_unittest.cc",
+    "invalidator_registrar_unittest.cc",
+    "per_user_topic_invalidation_client_unittest.cc",
+    "per_user_topic_registration_manager_unittest.cc",
     "per_user_topic_registration_request_unittest.cc",
   ]
   deps = [
@@ -160,8 +167,16 @@
     ":test_support",
     "//base",
     "//base/test:test_support",
+    "//components/gcm_driver:test_support",
+    "//components/gcm_driver/instance_id:test_support",
     "//components/prefs",
+    "//components/signin/core/browser:test_support",
+    "//components/sync_preferences:test_support",
+    "//google_apis:test_support",
+    "//google_apis/gcm:gcm",
+    "//net",
     "//net:test_support",
+    "//services/identity/public/cpp:test_support",
     "//services/network:test_support",
     "//testing/gmock",
     "//testing/gtest",
@@ -175,20 +190,13 @@
     sources += [
       "deprecated_invalidator_registrar_unittest.cc",
       "fake_invalidator_unittest.cc",
-      "fcm_invalidation_listener_unittest.cc",
-      "fcm_invalidation_service_unittest.cc",
-      "fcm_invalidator_unittest.cc",
-      "fcm_network_handler_unittests.cc",
       "gcm_invalidation_bridge_unittest.cc",
       "gcm_network_channel_unittest.cc",
       "invalidation_notifier_unittest.cc",
-      "invalidator_registrar_unittest.cc",
       "invalidator_storage_unittest.cc",
       "non_blocking_invalidator_unittest.cc",
       "object_id_invalidation_map_unittest.cc",
       "p2p_invalidator_unittest.cc",
-      "per_user_topic_invalidation_client_unittest.cc",
-      "per_user_topic_registration_manager_unittest.cc",
       "push_client_channel_unittest.cc",
       "registration_manager_unittest.cc",
       "single_object_invalidation_set_unittest.cc",
@@ -198,16 +206,6 @@
       "ticl_profile_settings_provider_unittest.cc",
       "unacked_invalidation_set_unittest.cc",
     ]
-    deps += [
-      "//components/gcm_driver:test_support",
-      "//components/gcm_driver/instance_id:test_support",
-      "//components/signin/core/browser:test_support",
-      "//components/sync_preferences:test_support",
-      "//google_apis:test_support",
-      "//google_apis/gcm:gcm",
-      "//net",
-      "//services/identity/public/cpp:test_support",
-    ]
   }
 }
 
diff --git a/components/invalidation/impl/android/java/src/org/chromium/components/invalidation/InvalidationClientService.java b/components/invalidation/impl/android/java/src/org/chromium/components/invalidation/InvalidationClientService.java
index 855aa0a..01d8e25 100644
--- a/components/invalidation/impl/android/java/src/org/chromium/components/invalidation/InvalidationClientService.java
+++ b/components/invalidation/impl/android/java/src/org/chromium/components/invalidation/InvalidationClientService.java
@@ -72,6 +72,8 @@
     private static final String TAG = "cr_invalidation";
     private static final String CLIENT_SERVICE_KEY = "ipc.invalidation.ticl.listener_service_class";
 
+    protected static boolean sShouldCreateService = true;
+
     /**
      * Whether the underlying notification client has been started. This boolean is updated when a
      * start or stop intent is issued to the underlying client, not when the intent is actually
@@ -548,6 +550,7 @@
     }
 
     private void startServiceIfPossible(Intent intent) {
+        if (!sShouldCreateService) return;
         // The use of background services is restricted when the application is not in foreground
         // for O. See crbug.com/680812.
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
@@ -560,4 +563,8 @@
             startService(intent);
         }
     }
+
+    public void setShouldCreateService(boolean shouldCreate) {
+        sShouldCreateService = shouldCreate;
+    }
 }
diff --git a/components/nacl/browser/nacl_broker_host_win.cc b/components/nacl/browser/nacl_broker_host_win.cc
index 3f36568..4fe82b4f 100644
--- a/components/nacl/browser/nacl_broker_host_win.cc
+++ b/components/nacl/browser/nacl_broker_host_win.cc
@@ -96,14 +96,16 @@
 
 void NaClBrokerHost::OnLoaderLaunched(int launch_id,
                                       base::ProcessHandle handle) {
-  NaClBrokerService::GetInstance()->OnLoaderLaunched(launch_id, handle);
+  NaClBrokerService::GetInstance()->OnLoaderLaunched(launch_id,
+                                                     base::Process(handle));
 }
 
 bool NaClBrokerHost::LaunchDebugExceptionHandler(
     int32_t pid,
     base::ProcessHandle process_handle,
     const std::string& startup_info) {
-  base::ProcessHandle broker_process = process_->GetData().GetHandle();
+  base::ProcessHandle broker_process =
+      process_->GetData().GetProcess().Handle();
   base::ProcessHandle handle_in_broker_process;
   if (!DuplicateHandle(::GetCurrentProcess(), process_handle,
                        broker_process, &handle_in_broker_process,
diff --git a/components/nacl/browser/nacl_broker_service_win.cc b/components/nacl/browser/nacl_broker_service_win.cc
index 1895049..370201c 100644
--- a/components/nacl/browser/nacl_broker_service_win.cc
+++ b/components/nacl/browser/nacl_broker_service_win.cc
@@ -50,8 +50,7 @@
   return true;
 }
 
-void NaClBrokerService::OnLoaderLaunched(int launch_id,
-                                         base::ProcessHandle handle) {
+void NaClBrokerService::OnLoaderLaunched(int launch_id, base::Process process) {
   PendingLaunchesMap::iterator it = pending_launches_.find(launch_id);
   if (pending_launches_.end() == it) {
     NOTREACHED();
@@ -60,7 +59,7 @@
 
   NaClProcessHost* client = it->second.get();
   if (client)
-    client->OnProcessLaunchedByBroker(handle);
+    client->OnProcessLaunchedByBroker(std::move(process));
   pending_launches_.erase(it);
   ++loaders_running_;
 }
diff --git a/components/nacl/browser/nacl_broker_service_win.h b/components/nacl/browser/nacl_broker_service_win.h
index ddf69e9..60be4b9 100644
--- a/components/nacl/browser/nacl_broker_service_win.h
+++ b/components/nacl/browser/nacl_broker_service_win.h
@@ -12,6 +12,7 @@
 #include "base/macros.h"
 #include "base/memory/singleton.h"
 #include "base/memory/weak_ptr.h"
+#include "base/process/process.h"
 #include "components/nacl/browser/nacl_broker_host_win.h"
 #include "services/service_manager/public/mojom/service.mojom.h"
 
@@ -33,7 +34,7 @@
                     service_manager::mojom::ServiceRequest service_request);
 
   // Called by NaClBrokerHost to notify the service that a loader was launched.
-  void OnLoaderLaunched(int launch_id, base::ProcessHandle handle);
+  void OnLoaderLaunched(int launch_id, base::Process process);
 
   // Called by NaClProcessHost when a loader process is terminated
   void OnLoaderDied();
diff --git a/components/nacl/browser/nacl_process_host.cc b/components/nacl/browser/nacl_process_host.cc
index 2b81bc09..8cdc8c5 100644
--- a/components/nacl/browser/nacl_process_host.cc
+++ b/components/nacl/browser/nacl_process_host.cc
@@ -250,7 +250,7 @@
 
 NaClProcessHost::~NaClProcessHost() {
   // Report exit status only if the process was successfully started.
-  if (!process_->GetData().IsHandleValid()) {
+  if (!process_->GetData().GetProcess().IsValid()) {
     content::ChildProcessTerminationInfo info =
         process_->GetTerminationInfo(false /* known_dead */);
     std::string message =
@@ -427,9 +427,9 @@
 }
 
 #if defined(OS_WIN)
-void NaClProcessHost::OnProcessLaunchedByBroker(base::ProcessHandle handle) {
+void NaClProcessHost::OnProcessLaunchedByBroker(base::Process process) {
   process_launched_by_broker_ = true;
-  process_->SetHandle(handle);
+  process_->SetProcess(std::move(process));
   SetDebugStubPort(nacl::kGdbDebugStubPortUnknown);
   if (!StartWithLaunchedProcess())
     delete this;
@@ -641,11 +641,10 @@
 
   const ChildProcessData& data = process_->GetData();
   SendMessageToRenderer(
-      NaClLaunchResult(ppapi_channel_handle.release(),
-                       trusted_channel_handle.release(),
-                       manifest_service_channel_handle.release(),
-                       base::GetProcId(data.GetHandle()), data.id,
-                       crash_info_shmem_renderer_handle),
+      NaClLaunchResult(
+          ppapi_channel_handle.release(), trusted_channel_handle.release(),
+          manifest_service_channel_handle.release(), data.GetProcess().Pid(),
+          data.id, crash_info_shmem_renderer_handle),
       error_message);
 
   // Now that the crash information shmem handles have been shared with the
@@ -763,8 +762,8 @@
   if (uses_nonsfi_mode_) {
     // Currently, non-SFI mode is supported only on Linux.
     if (enable_nacl_debug) {
-      base::ProcessId pid = base::GetProcId(process_->GetData().GetHandle());
-      LOG(WARNING) << "nonsfi nacl plugin running in " << pid;
+      LOG(WARNING) << "nonsfi nacl plugin running in "
+                   << process_->GetData().GetProcess().Pid();
     }
   } else {
     params.validation_cache_enabled = nacl_browser->ValidationCacheIsEnabled();
@@ -910,9 +909,9 @@
   // browser process.
   ppapi_host_.reset(content::BrowserPpapiHost::CreateExternalPluginProcess(
       ipc_proxy_channel_.get(),  // sender
-      permissions_, process_->GetData().GetHandle(), ipc_proxy_channel_.get(),
-      nacl_host_message_filter_->render_process_id(), render_view_id_,
-      profile_directory_));
+      permissions_, process_->GetData().GetProcess().Handle(),
+      ipc_proxy_channel_.get(), nacl_host_message_filter_->render_process_id(),
+      render_view_id_, profile_directory_));
 
   ppapi::PpapiNaClPluginArgs args;
   args.off_the_record = nacl_host_message_filter_->off_the_record();
@@ -1106,7 +1105,7 @@
   }
   debug_exception_handler_requested_ = true;
 
-  base::ProcessId nacl_pid = base::GetProcId(process_->GetData().GetHandle());
+  base::ProcessId nacl_pid = process_->GetData().GetProcess().Pid();
   // We cannot use process_->GetData().handle because it does not have
   // the necessary access rights.  We open the new handle here rather
   // than in the NaCl broker process in case the NaCl loader process
diff --git a/components/nacl/browser/nacl_process_host.h b/components/nacl/browser/nacl_process_host.h
index ea72847..9771dbae 100644
--- a/components/nacl/browser/nacl_process_host.h
+++ b/components/nacl/browser/nacl_process_host.h
@@ -103,7 +103,7 @@
   void OnChannelConnected(int32_t peer_pid) override;
 
 #if defined(OS_WIN)
-  void OnProcessLaunchedByBroker(base::ProcessHandle handle);
+  void OnProcessLaunchedByBroker(base::Process process);
   void OnDebugExceptionHandlerLaunchedByBroker(bool success);
 #endif
 
diff --git a/components/omnibox/browser/BUILD.gn b/components/omnibox/browser/BUILD.gn
index e370130..8acd7a6 100644
--- a/components/omnibox/browser/BUILD.gn
+++ b/components/omnibox/browser/BUILD.gn
@@ -118,6 +118,11 @@
     "keyword_extensions_delegate.h",
     "keyword_provider.cc",
     "keyword_provider.h",
+    "location_bar_model.h",
+    "location_bar_model_delegate.cc",
+    "location_bar_model_delegate.h",
+    "location_bar_model_impl.cc",
+    "location_bar_model_impl.h",
     "match_compare.h",
     "omnibox_client.cc",
     "omnibox_client.h",
@@ -173,11 +178,6 @@
     "tailored_word_break_iterator.h",
     "titled_url_match_utils.cc",
     "titled_url_match_utils.h",
-    "toolbar_model.h",
-    "toolbar_model_delegate.cc",
-    "toolbar_model_delegate.h",
-    "toolbar_model_impl.cc",
-    "toolbar_model_impl.h",
     "url_index_private_data.cc",
     "url_index_private_data.h",
     "url_prefix.cc",
@@ -272,6 +272,8 @@
     "mock_autocomplete_provider_client.h",
     "shortcuts_provider_test_util.cc",
     "shortcuts_provider_test_util.h",
+    "test_location_bar_model.cc",
+    "test_location_bar_model.h",
     "test_omnibox_client.cc",
     "test_omnibox_client.h",
     "test_omnibox_edit_controller.cc",
@@ -282,8 +284,6 @@
     "test_omnibox_view.h",
     "test_scheme_classifier.cc",
     "test_scheme_classifier.h",
-    "test_toolbar_model.cc",
-    "test_toolbar_model.h",
   ]
 
   public_deps = [
@@ -351,6 +351,7 @@
     "in_memory_url_index_types_unittest.cc",
     "in_memory_url_index_unittest.cc",
     "keyword_provider_unittest.cc",
+    "location_bar_model_impl_unittest.cc",
     "omnibox_controller_unittest.cc",
     "omnibox_edit_model_unittest.cc",
     "omnibox_field_trial_unittest.cc",
@@ -367,7 +368,6 @@
     "suggestion_answer_unittest.cc",
     "tailored_word_break_iterator_unittest.cc",
     "titled_url_match_utils_unittest.cc",
-    "toolbar_model_impl_unittest.cc",
     "url_prefix_unittest.cc",
     "zero_suggest_provider_unittest.cc",
   ]
diff --git a/components/omnibox/browser/autocomplete_result.cc b/components/omnibox/browser/autocomplete_result.cc
index 742c670..1cb0f9c 100644
--- a/components/omnibox/browser/autocomplete_result.cc
+++ b/components/omnibox/browser/autocomplete_result.cc
@@ -36,7 +36,9 @@
   // The |bool| is whether the match is a calculator suggestion. We want them
   // compare differently against other matches with the same URL.
   size_t operator()(const std::pair<GURL, bool>& p) const {
-    return std::hash<std::string>()(p.first.spec()) + p.second;
+    // Certain omnibox inputs such as `http:www.` produce matches with invalid
+    // urls, so we use GURL::possibly_invalid_spec.
+    return std::hash<std::string>()(p.first.possibly_invalid_spec()) + p.second;
   }
 };
 
diff --git a/components/omnibox/browser/toolbar_model.h b/components/omnibox/browser/location_bar_model.h
similarity index 90%
rename from components/omnibox/browser/toolbar_model.h
rename to components/omnibox/browser/location_bar_model.h
index 53997e1..71d1fad 100644
--- a/components/omnibox/browser/toolbar_model.h
+++ b/components/omnibox/browser/location_bar_model.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 COMPONENTS_OMNIBOX_BROWSER_TOOLBAR_MODEL_H_
-#define COMPONENTS_OMNIBOX_BROWSER_TOOLBAR_MODEL_H_
+#ifndef COMPONENTS_OMNIBOX_BROWSER_LOCATION_BAR_MODEL_H_
+#define COMPONENTS_OMNIBOX_BROWSER_LOCATION_BAR_MODEL_H_
 
 #include <stddef.h>
 
@@ -21,9 +21,9 @@
 // This class is the model used by the toolbar, location bar and autocomplete
 // edit.  It populates its states from the current navigation entry retrieved
 // from the navigation controller returned by GetNavigationController().
-class ToolbarModel {
+class LocationBarModel {
  public:
-  virtual ~ToolbarModel() = default;
+  virtual ~LocationBarModel() = default;
 
   // Returns the formatted full URL for the toolbar. The formatting includes:
   //   - Some characters may be unescaped.
@@ -80,12 +80,12 @@
   bool input_in_progress() const { return input_in_progress_; }
 
  protected:
-  ToolbarModel() : input_in_progress_(false) {}
+  LocationBarModel() : input_in_progress_(false) {}
 
  private:
   bool input_in_progress_;
 
-  DISALLOW_COPY_AND_ASSIGN(ToolbarModel);
+  DISALLOW_COPY_AND_ASSIGN(LocationBarModel);
 };
 
-#endif  // COMPONENTS_OMNIBOX_BROWSER_TOOLBAR_MODEL_H_
+#endif  // COMPONENTS_OMNIBOX_BROWSER_LOCATION_BAR_MODEL_H_
diff --git a/components/omnibox/browser/location_bar_model_delegate.cc b/components/omnibox/browser/location_bar_model_delegate.cc
new file mode 100644
index 0000000..2c35e31
--- /dev/null
+++ b/components/omnibox/browser/location_bar_model_delegate.cc
@@ -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.
+
+#include "components/omnibox/browser/location_bar_model_delegate.h"
+
+bool LocationBarModelDelegate::ShouldDisplayURL() const {
+  return true;
+}
+
+LocationBarModelDelegate::SecurityLevel
+LocationBarModelDelegate::GetSecurityLevel() const {
+  return SecurityLevel::NONE;
+}
+
+scoped_refptr<net::X509Certificate> LocationBarModelDelegate::GetCertificate()
+    const {
+  return nullptr;
+}
+
+bool LocationBarModelDelegate::FailsBillingCheck() const {
+  return false;
+}
+
+bool LocationBarModelDelegate::FailsMalwareCheck() const {
+  return false;
+}
+
+const gfx::VectorIcon* LocationBarModelDelegate::GetVectorIconOverride() const {
+  return nullptr;
+}
+
+bool LocationBarModelDelegate::IsOfflinePage() const {
+  return false;
+}
diff --git a/components/omnibox/browser/toolbar_model_delegate.h b/components/omnibox/browser/location_bar_model_delegate.h
similarity index 86%
rename from components/omnibox/browser/toolbar_model_delegate.h
rename to components/omnibox/browser/location_bar_model_delegate.h
index 05e51dfb..8efb5f5 100644
--- a/components/omnibox/browser/toolbar_model_delegate.h
+++ b/components/omnibox/browser/location_bar_model_delegate.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 COMPONENTS_OMNIBOX_BROWSER_TOOLBAR_MODEL_DELEGATE_H_
-#define COMPONENTS_OMNIBOX_BROWSER_TOOLBAR_MODEL_DELEGATE_H_
+#ifndef COMPONENTS_OMNIBOX_BROWSER_LOCATION_BAR_MODEL_DELEGATE_H_
+#define COMPONENTS_OMNIBOX_BROWSER_LOCATION_BAR_MODEL_DELEGATE_H_
 
 #include <string>
 
@@ -21,8 +21,8 @@
 class X509Certificate;
 }
 
-// Delegate which is used by ToolbarModel class.
-class ToolbarModelDelegate {
+// Delegate which is used by LocationBarModel class.
+class LocationBarModelDelegate {
  public:
   using SecurityLevel = security_state::SecurityLevel;
 
@@ -64,7 +64,7 @@
   virtual bool IsOfflinePage() const;
 
  protected:
-  virtual ~ToolbarModelDelegate() {}
+  virtual ~LocationBarModelDelegate() {}
 };
 
-#endif  // COMPONENTS_OMNIBOX_BROWSER_TOOLBAR_MODEL_DELEGATE_H_
+#endif  // COMPONENTS_OMNIBOX_BROWSER_LOCATION_BAR_MODEL_DELEGATE_H_
diff --git a/components/omnibox/browser/toolbar_model_impl.cc b/components/omnibox/browser/location_bar_model_impl.cc
similarity index 86%
rename from components/omnibox/browser/toolbar_model_impl.cc
rename to components/omnibox/browser/location_bar_model_impl.cc
index 9dccb81..7c3c67a 100644
--- a/components/omnibox/browser/toolbar_model_impl.cc
+++ b/components/omnibox/browser/location_bar_model_impl.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 "components/omnibox/browser/toolbar_model_impl.h"
+#include "components/omnibox/browser/location_bar_model_impl.h"
 
 #include "base/feature_list.h"
 #include "base/logging.h"
@@ -11,8 +11,8 @@
 #include "base/time/time.h"
 #include "build/build_config.h"
 #include "components/omnibox/browser/buildflags.h"
+#include "components/omnibox/browser/location_bar_model_delegate.h"
 #include "components/omnibox/browser/omnibox_field_trial.h"
-#include "components/omnibox/browser/toolbar_model_delegate.h"
 #include "components/prefs/pref_service.h"
 #include "components/security_state/core/security_state.h"
 #include "components/strings/grit/components_strings.h"
@@ -28,20 +28,20 @@
 #include "components/vector_icons/vector_icons.h"     // nogncheck
 #endif
 
-ToolbarModelImpl::ToolbarModelImpl(ToolbarModelDelegate* delegate,
-                                   size_t max_url_display_chars)
+LocationBarModelImpl::LocationBarModelImpl(LocationBarModelDelegate* delegate,
+                                           size_t max_url_display_chars)
     : delegate_(delegate), max_url_display_chars_(max_url_display_chars) {
   DCHECK(delegate_);
 }
 
-ToolbarModelImpl::~ToolbarModelImpl() {}
+LocationBarModelImpl::~LocationBarModelImpl() {}
 
-// ToolbarModelImpl Implementation.
-base::string16 ToolbarModelImpl::GetFormattedFullURL() const {
+// LocationBarModelImpl Implementation.
+base::string16 LocationBarModelImpl::GetFormattedFullURL() const {
   return GetFormattedURL(url_formatter::kFormatUrlOmitDefaults);
 }
 
-base::string16 ToolbarModelImpl::GetURLForDisplay() const {
+base::string16 LocationBarModelImpl::GetURLForDisplay() const {
   url_formatter::FormatUrlTypes format_types =
       url_formatter::kFormatUrlOmitDefaults;
 
@@ -66,7 +66,7 @@
   return GetFormattedURL(format_types);
 }
 
-base::string16 ToolbarModelImpl::GetFormattedURL(
+base::string16 LocationBarModelImpl::GetFormattedURL(
     url_formatter::FormatUrlTypes format_types) const {
   GURL url(GetURL());
   // Note that we can't unescape spaces here, because if the user copies this
@@ -87,12 +87,12 @@
                              gfx::CHARACTER_BREAK);
 }
 
-GURL ToolbarModelImpl::GetURL() const {
+GURL LocationBarModelImpl::GetURL() const {
   GURL url;
   return delegate_->GetURL(&url) ? url : GURL(url::kAboutBlankURL);
 }
 
-security_state::SecurityLevel ToolbarModelImpl::GetSecurityLevel(
+security_state::SecurityLevel LocationBarModelImpl::GetSecurityLevel(
     bool ignore_editing) const {
   // When editing or empty, assume no security style.
   return ((input_in_progress() && !ignore_editing) || !ShouldDisplayURL())
@@ -100,7 +100,7 @@
              : delegate_->GetSecurityLevel();
 }
 
-const gfx::VectorIcon& ToolbarModelImpl::GetVectorIcon() const {
+const gfx::VectorIcon& LocationBarModelImpl::GetVectorIcon() const {
 #if (!defined(OS_ANDROID) || BUILDFLAG(ENABLE_VR)) && !defined(OS_IOS)
   auto* const icon_override = delegate_->GetVectorIconOverride();
   if (icon_override)
@@ -133,7 +133,7 @@
 #endif
 }
 
-base::string16 ToolbarModelImpl::GetEVCertName() const {
+base::string16 LocationBarModelImpl::GetEVCertName() const {
   if (GetSecurityLevel(false) != security_state::EV_SECURE)
     return base::string16();
 
@@ -150,7 +150,7 @@
       base::UTF8ToUTF16(cert->subject().country_name));
 }
 
-base::string16 ToolbarModelImpl::GetSecureText() const {
+base::string16 LocationBarModelImpl::GetSecureText() const {
   switch (GetSecurityLevel(false)) {
     case security_state::HTTP_SHOW_WARNING:
       return l10n_util::GetStringUTF16(IDS_NOT_SECURE_VERBOSE_STATE);
@@ -171,7 +171,7 @@
   }
 }
 
-base::string16 ToolbarModelImpl::GetSecureVerboseText() const {
+base::string16 LocationBarModelImpl::GetSecureVerboseText() const {
   if (IsOfflinePage())
     return l10n_util::GetStringUTF16(IDS_OFFLINE_VERBOSE_STATE);
 
@@ -203,17 +203,17 @@
   return GetSecureText();
 }
 
-base::string16 ToolbarModelImpl::GetSecureAccessibilityText() const {
+base::string16 LocationBarModelImpl::GetSecureAccessibilityText() const {
   if (IsOfflinePage())
     return l10n_util::GetStringUTF16(IDS_OFFLINE_VERBOSE_STATE);
 
   return GetSecureText();
 }
 
-bool ToolbarModelImpl::ShouldDisplayURL() const {
+bool LocationBarModelImpl::ShouldDisplayURL() const {
   return delegate_->ShouldDisplayURL();
 }
 
-bool ToolbarModelImpl::IsOfflinePage() const {
+bool LocationBarModelImpl::IsOfflinePage() const {
   return delegate_->IsOfflinePage();
 }
diff --git a/components/omnibox/browser/toolbar_model_impl.h b/components/omnibox/browser/location_bar_model_impl.h
similarity index 70%
rename from components/omnibox/browser/toolbar_model_impl.h
rename to components/omnibox/browser/location_bar_model_impl.h
index b1a0a21..4c68a8a 100644
--- a/components/omnibox/browser/toolbar_model_impl.h
+++ b/components/omnibox/browser/location_bar_model_impl.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 COMPONENTS_OMNIBOX_BROWSER_TOOLBAR_MODEL_IMPL_H_
-#define COMPONENTS_OMNIBOX_BROWSER_TOOLBAR_MODEL_IMPL_H_
+#ifndef COMPONENTS_OMNIBOX_BROWSER_LOCATION_BAR_MODEL_IMPL_H_
+#define COMPONENTS_OMNIBOX_BROWSER_LOCATION_BAR_MODEL_IMPL_H_
 
 #include <stddef.h>
 
@@ -12,22 +12,22 @@
 #include "base/compiler_specific.h"
 #include "base/macros.h"
 #include "base/strings/string16.h"
-#include "components/omnibox/browser/toolbar_model.h"
+#include "components/omnibox/browser/location_bar_model.h"
 #include "components/url_formatter/url_formatter.h"
 #include "url/gurl.h"
 
-class ToolbarModelDelegate;
+class LocationBarModelDelegate;
 
 // This class is the model used by the toolbar, location bar and autocomplete
 // edit.  It populates its states from the current navigation entry retrieved
 // from the navigation controller returned by GetNavigationController().
-class ToolbarModelImpl : public ToolbarModel {
+class LocationBarModelImpl : public LocationBarModel {
  public:
-  ToolbarModelImpl(ToolbarModelDelegate* delegate,
-                   size_t max_url_display_chars);
-  ~ToolbarModelImpl() override;
+  LocationBarModelImpl(LocationBarModelDelegate* delegate,
+                       size_t max_url_display_chars);
+  ~LocationBarModelImpl() override;
 
-  // ToolbarModel:
+  // LocationBarModel:
   base::string16 GetFormattedFullURL() const override;
   base::string16 GetURLForDisplay() const override;
   GURL GetURL() const override;
@@ -46,10 +46,10 @@
   base::string16 GetFormattedURL(
       url_formatter::FormatUrlTypes format_types) const;
 
-  ToolbarModelDelegate* delegate_;
+  LocationBarModelDelegate* delegate_;
   const size_t max_url_display_chars_;
 
-  DISALLOW_IMPLICIT_CONSTRUCTORS(ToolbarModelImpl);
+  DISALLOW_IMPLICIT_CONSTRUCTORS(LocationBarModelImpl);
 };
 
-#endif  // COMPONENTS_OMNIBOX_BROWSER_TOOLBAR_MODEL_IMPL_H_
+#endif  // COMPONENTS_OMNIBOX_BROWSER_LOCATION_BAR_MODEL_IMPL_H_
diff --git a/components/omnibox/browser/toolbar_model_impl_unittest.cc b/components/omnibox/browser/location_bar_model_impl_unittest.cc
similarity index 79%
rename from components/omnibox/browser/toolbar_model_impl_unittest.cc
rename to components/omnibox/browser/location_bar_model_impl_unittest.cc
index df2f6d6..2c3a642e 100644
--- a/components/omnibox/browser/toolbar_model_impl_unittest.cc
+++ b/components/omnibox/browser/location_bar_model_impl_unittest.cc
@@ -2,22 +2,22 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/omnibox/browser/toolbar_model_impl.h"
+#include "components/omnibox/browser/location_bar_model_impl.h"
 
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/scoped_feature_list.h"
+#include "components/omnibox/browser/location_bar_model_delegate.h"
 #include "components/omnibox/browser/omnibox_field_trial.h"
-#include "components/omnibox/browser/toolbar_model_delegate.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
 
 namespace {
 
-class FakeToolbarModelDelegate : public ToolbarModelDelegate {
+class FakeLocationBarModelDelegate : public LocationBarModelDelegate {
  public:
   void SetURL(const GURL& url) { url_ = url; }
 
-  // ToolbarModelDelegate:
+  // LocationBarModelDelegate:
   base::string16 FormattedStringWithEquivalentMeaning(
       const GURL& url,
       const base::string16& formatted_url) const override {
@@ -33,15 +33,15 @@
   GURL url_;
 };
 
-TEST(ToolbarModelImplTest,
+TEST(LocationBarModelImplTest,
      DisplayUrlAppliesFormattedStringWithEquivalentMeaning) {
   base::test::ScopedFeatureList feature_list;
   feature_list.InitWithFeatures({omnibox::kHideSteadyStateUrlScheme,
                                  omnibox::kHideSteadyStateUrlTrivialSubdomains},
                                 {});
 
-  FakeToolbarModelDelegate delegate;
-  auto model = std::make_unique<ToolbarModelImpl>(&delegate, 1024);
+  FakeLocationBarModelDelegate delegate;
+  auto model = std::make_unique<LocationBarModelImpl>(&delegate, 1024);
 
   delegate.SetURL(GURL("http://www.google.com/"));
 
diff --git a/components/omnibox/browser/omnibox_edit_controller.cc b/components/omnibox/browser/omnibox_edit_controller.cc
index b374aa2d..9c96103 100644
--- a/components/omnibox/browser/omnibox_edit_controller.cc
+++ b/components/omnibox/browser/omnibox_edit_controller.cc
@@ -4,7 +4,7 @@
 
 #include "components/omnibox/browser/omnibox_edit_controller.h"
 
-#include "components/omnibox/browser/toolbar_model.h"
+#include "components/omnibox/browser/location_bar_model.h"
 
 void OmniboxEditController::OnAutocompleteAccept(
     const GURL& destination_url,
diff --git a/components/omnibox/browser/omnibox_edit_controller.h b/components/omnibox/browser/omnibox_edit_controller.h
index de8befb..c34a333 100644
--- a/components/omnibox/browser/omnibox_edit_controller.h
+++ b/components/omnibox/browser/omnibox_edit_controller.h
@@ -12,7 +12,7 @@
 #include "ui/base/window_open_disposition.h"
 #include "url/gurl.h"
 
-class ToolbarModel;
+class LocationBarModel;
 
 class OmniboxEditController {
  public:
@@ -32,8 +32,8 @@
   // Called when the omnibox popup is shown or hidden.
   virtual void OnPopupVisibilityChanged();
 
-  virtual ToolbarModel* GetToolbarModel() = 0;
-  virtual const ToolbarModel* GetToolbarModel() const = 0;
+  virtual LocationBarModel* GetLocationBarModel() = 0;
+  virtual const LocationBarModel* GetLocationBarModel() const = 0;
 
  protected:
   OmniboxEditController();
diff --git a/components/omnibox/browser/omnibox_edit_model.cc b/components/omnibox/browser/omnibox_edit_model.cc
index b93ef26e..b81e20d 100644
--- a/components/omnibox/browser/omnibox_edit_model.cc
+++ b/components/omnibox/browser/omnibox_edit_model.cc
@@ -26,6 +26,7 @@
 #include "components/omnibox/browser/autocomplete_provider.h"
 #include "components/omnibox/browser/history_url_provider.h"
 #include "components/omnibox/browser/keyword_provider.h"
+#include "components/omnibox/browser/location_bar_model.h"
 #include "components/omnibox/browser/omnibox_client.h"
 #include "components/omnibox/browser/omnibox_edit_controller.h"
 #include "components/omnibox/browser/omnibox_event_global_tracker.h"
@@ -38,7 +39,6 @@
 #include "components/omnibox/browser/omnibox_view.h"
 #include "components/omnibox/browser/query_in_omnibox.h"
 #include "components/omnibox/browser/search_provider.h"
-#include "components/omnibox/browser/toolbar_model.h"
 #include "components/search_engines/template_url.h"
 #include "components/search_engines/template_url_prepopulate_data.h"
 #include "components/search_engines/template_url_service.h"
@@ -230,8 +230,8 @@
   // the user has merely made a partial selection.
   bool user_has_modified_text = view_->GetText() != old_display_text;
 
-  ToolbarModel* toolbar_model = controller()->GetToolbarModel();
-  url_for_editing_ = toolbar_model->GetFormattedFullURL();
+  LocationBarModel* location_bar_model = controller()->GetLocationBarModel();
+  url_for_editing_ = location_bar_model->GetFormattedFullURL();
 
   if (GetQueryInOmniboxSearchTerms(&display_text_)) {
     // The search query has been inserted into |display_text_|.
@@ -239,11 +239,11 @@
   } else {
 #if defined(OS_IOS)
     // iOS is unusual in that it uses a separate LocationView to show the
-    // ToolbarModel's display-only URL. The actual OmniboxViewIOS widget is
+    // LocationBarModel's display-only URL. The actual OmniboxViewIOS widget is
     // hidden in the defocused state, and always contains the URL for editing.
     display_text_ = url_for_editing_;
 #else
-    display_text_ = toolbar_model->GetURLForDisplay();
+    display_text_ = location_bar_model->GetURLForDisplay();
 #endif
   }
 
@@ -1365,10 +1365,10 @@
   if (!query_in_omnibox)
     return false;
 
-  ToolbarModel* toolbar_model = controller()->GetToolbarModel();
+  LocationBarModel* location_bar_model = controller()->GetLocationBarModel();
   return query_in_omnibox->GetDisplaySearchTerms(
-      toolbar_model->GetSecurityLevel(false /* ignore_editing */),
-      toolbar_model->GetURL(), search_terms);
+      location_bar_model->GetSecurityLevel(false /* ignore_editing */),
+      location_bar_model->GetURL(), search_terms);
 }
 
 // static
diff --git a/components/omnibox/browser/omnibox_edit_model_unittest.cc b/components/omnibox/browser/omnibox_edit_model_unittest.cc
index 68851c7..ae7967f 100644
--- a/components/omnibox/browser/omnibox_edit_model_unittest.cc
+++ b/components/omnibox/browser/omnibox_edit_model_unittest.cc
@@ -16,11 +16,11 @@
 #include "components/omnibox/browser/omnibox_field_trial.h"
 #include "components/omnibox/browser/omnibox_view.h"
 #include "components/omnibox/browser/search_provider.h"
+#include "components/omnibox/browser/test_location_bar_model.h"
 #include "components/omnibox/browser/test_omnibox_client.h"
 #include "components/omnibox/browser/test_omnibox_edit_controller.h"
 #include "components/omnibox/browser/test_omnibox_edit_model.h"
 #include "components/omnibox/browser/test_omnibox_view.h"
-#include "components/omnibox/browser/test_toolbar_model.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 class OmniboxEditModelTest : public testing::Test {
@@ -33,7 +33,9 @@
   }
 
   TestOmniboxView* view() { return view_.get(); }
-  TestToolbarModel* toolbar_model() { return controller_->GetToolbarModel(); }
+  TestLocationBarModel* location_bar_model() {
+    return controller_->GetLocationBarModel();
+  }
   TestOmniboxEditModel* model() {
     return static_cast<TestOmniboxEditModel*>(view_->model());
   }
@@ -130,9 +132,9 @@
   };
 
   for (size_t i = 0; i < arraysize(input); ++i) {
-    toolbar_model()->set_formatted_full_url(
+    location_bar_model()->set_formatted_full_url(
         base::ASCIIToUTF16(input[i].url_for_editing));
-    toolbar_model()->set_url_for_display(
+    location_bar_model()->set_url_for_display(
         base::ASCIIToUTF16(input[i].url_for_display));
     model()->ResetDisplayTexts();
 
@@ -158,8 +160,8 @@
 // Tests that AdjustTextForCopy behaves properly with Query in Omnibox enabled.
 // For more general tests of copy adjustment, see the AdjustTextForCopy test.
 TEST_F(OmniboxEditModelTest, AdjustTextForCopyQueryInOmnibox) {
-  toolbar_model()->set_url(GURL("https://www.example.com/"));
-  toolbar_model()->set_url_for_display(base::ASCIIToUTF16("example.com"));
+  location_bar_model()->set_url(GURL("https://www.example.com/"));
+  location_bar_model()->set_url_for_display(base::ASCIIToUTF16("example.com"));
 
   TestOmniboxClient* client =
       static_cast<TestOmniboxClient*>(model()->client());
@@ -254,8 +256,8 @@
 }
 
 TEST_F(OmniboxEditModelTest, CurrentMatch) {
-  toolbar_model()->set_url(GURL("http://localhost/"));
-  toolbar_model()->set_url_for_display(base::ASCIIToUTF16("localhost"));
+  location_bar_model()->set_url(GURL("http://localhost/"));
+  location_bar_model()->set_url_for_display(base::ASCIIToUTF16("localhost"));
   model()->ResetDisplayTexts();
 
   // Tests that we use the formatted full URL instead of the elided URL to
@@ -281,8 +283,8 @@
 }
 
 TEST_F(OmniboxEditModelTest, DisplayText) {
-  toolbar_model()->set_url(GURL("https://www.example.com/"));
-  toolbar_model()->set_url_for_display(base::ASCIIToUTF16("example.com"));
+  location_bar_model()->set_url(GURL("https://www.example.com/"));
+  location_bar_model()->set_url_for_display(base::ASCIIToUTF16("example.com"));
 
   // Verify we show the display text when there is no Query in Omnibox match.
   model()->ResetDisplayTexts();
@@ -311,8 +313,8 @@
 }
 
 TEST_F(OmniboxEditModelTest, DisplayAndExitQueryInOmnibox) {
-  toolbar_model()->set_url(GURL("https://www.example.com/"));
-  toolbar_model()->set_url_for_display(base::ASCIIToUTF16("example.com"));
+  location_bar_model()->set_url(GURL("https://www.example.com/"));
+  location_bar_model()->set_url_for_display(base::ASCIIToUTF16("example.com"));
 
   // Verify the displayed text when there is a Query in Omnibox match.
   TestOmniboxClient* client =
diff --git a/components/omnibox/browser/omnibox_field_trial.cc b/components/omnibox/browser/omnibox_field_trial.cc
index 6a3c2a0..c9d4a6a 100644
--- a/components/omnibox/browser/omnibox_field_trial.cc
+++ b/components/omnibox/browser/omnibox_field_trial.cc
@@ -36,8 +36,16 @@
 
 // Feature used to hide the scheme from steady state URLs displayed in the
 // toolbar. It is restored during editing.
-const base::Feature kHideFileUrlScheme{"OmniboxUIExperimentHideFileUrlScheme",
-                                       base::FEATURE_ENABLED_BY_DEFAULT};
+const base::Feature kHideFileUrlScheme {
+  "OmniboxUIExperimentHideFileUrlScheme",
+// Android and iOS don't have the File security chip, and therefore still
+// need to show the file scheme.
+#if defined(OS_ANDROID) || defined(OS_IOS)
+      base::FEATURE_DISABLED_BY_DEFAULT
+#else
+      base::FEATURE_ENABLED_BY_DEFAULT
+#endif
+};
 
 // Feature used to hide the scheme from steady state URLs displayed in the
 // toolbar. It is restored during editing.
diff --git a/components/omnibox/browser/omnibox_pedal_unittest.cc b/components/omnibox/browser/omnibox_pedal_unittest.cc
index 2ceb587..b575bc1 100644
--- a/components/omnibox/browser/omnibox_pedal_unittest.cc
+++ b/components/omnibox/browser/omnibox_pedal_unittest.cc
@@ -19,10 +19,6 @@
       : omnibox_client_(new TestOmniboxClient),
         omnibox_edit_controller_(new TestOmniboxEditController) {}
 
-  TestToolbarModel* toolbar() {
-    return omnibox_edit_controller_->GetToolbarModel();
-  }
-
   base::MessageLoop message_loop_;
   std::unique_ptr<TestOmniboxClient> omnibox_client_;
   std::unique_ptr<TestOmniboxEditController> omnibox_edit_controller_;
diff --git a/components/omnibox/browser/omnibox_view.cc b/components/omnibox/browser/omnibox_view.cc
index 10714b9..35622cc1 100644
--- a/components/omnibox/browser/omnibox_view.cc
+++ b/components/omnibox/browser/omnibox_view.cc
@@ -16,11 +16,11 @@
 #include "build/build_config.h"
 #include "components/bookmarks/browser/bookmark_model.h"
 #include "components/omnibox/browser/autocomplete_match.h"
+#include "components/omnibox/browser/location_bar_model.h"
 #include "components/omnibox/browser/omnibox_edit_controller.h"
 #include "components/omnibox/browser/omnibox_edit_model.h"
 #include "components/omnibox/browser/omnibox_field_trial.h"
 #include "components/omnibox/browser/query_in_omnibox.h"
-#include "components/omnibox/browser/toolbar_model.h"
 #include "extensions/common/constants.h"
 #include "ui/base/l10n/l10n_util.h"
 
@@ -128,7 +128,7 @@
     }
 
     return gfx::CreateVectorIcon(
-        controller_->GetToolbarModel()->GetVectorIcon(), dip_size, color);
+        controller_->GetLocationBarModel()->GetVectorIcon(), dip_size, color);
   }
 
   // For tests, model_ will be null.
diff --git a/components/omnibox/browser/test_location_bar_model.cc b/components/omnibox/browser/test_location_bar_model.cc
new file mode 100644
index 0000000..f16d75f
--- /dev/null
+++ b/components/omnibox/browser/test_location_bar_model.cc
@@ -0,0 +1,69 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/omnibox/browser/test_location_bar_model.h"
+
+#include "base/strings/utf_string_conversions.h"
+
+#if defined(TOOLKIT_VIEWS)
+#include "components/omnibox/browser/vector_icons.h"  // nogncheck
+#endif
+
+TestLocationBarModel::TestLocationBarModel()
+    : security_level_(security_state::NONE),
+#if defined(TOOLKIT_VIEWS)
+      icon_(&omnibox::kHttpIcon),
+#endif
+      should_display_url_(true) {
+}
+
+TestLocationBarModel::~TestLocationBarModel() {}
+
+base::string16 TestLocationBarModel::GetFormattedFullURL() const {
+  if (!formatted_full_url_)
+    return base::UTF8ToUTF16(url_.spec());
+
+  return *formatted_full_url_;
+}
+
+base::string16 TestLocationBarModel::GetURLForDisplay() const {
+  if (!url_for_display_)
+    return base::UTF8ToUTF16(url_.spec());
+
+  return *url_for_display_;
+}
+
+GURL TestLocationBarModel::GetURL() const {
+  return url_;
+}
+
+security_state::SecurityLevel TestLocationBarModel::GetSecurityLevel(
+    bool ignore_editing) const {
+  return security_level_;
+}
+
+const gfx::VectorIcon& TestLocationBarModel::GetVectorIcon() const {
+  return *icon_;
+}
+
+base::string16 TestLocationBarModel::GetSecureVerboseText() const {
+  return base::string16();
+}
+
+base::string16 TestLocationBarModel::GetSecureAccessibilityText() const {
+  return base::string16();
+}
+
+base::string16 TestLocationBarModel::GetEVCertName() const {
+  return (security_level_ == security_state::EV_SECURE) ? ev_cert_name_
+                                                        : base::string16();
+}
+
+bool TestLocationBarModel::ShouldDisplayURL() const {
+  return should_display_url_;
+}
+
+bool TestLocationBarModel::IsOfflinePage() const {
+  return offline_page_;
+}
diff --git a/components/omnibox/browser/test_toolbar_model.h b/components/omnibox/browser/test_location_bar_model.h
similarity index 77%
rename from components/omnibox/browser/test_toolbar_model.h
rename to components/omnibox/browser/test_location_bar_model.h
index 599b943..6ab703b 100644
--- a/components/omnibox/browser/test_toolbar_model.h
+++ b/components/omnibox/browser/test_location_bar_model.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 COMPONENTS_OMNIBOX_BROWSER_TEST_TOOLBAR_MODEL_H_
-#define COMPONENTS_OMNIBOX_BROWSER_TEST_TOOLBAR_MODEL_H_
+#ifndef COMPONENTS_OMNIBOX_BROWSER_TEST_LOCATION_BAR_MODEL_H_
+#define COMPONENTS_OMNIBOX_BROWSER_TEST_LOCATION_BAR_MODEL_H_
 
 #include <stddef.h>
 #include <memory>
@@ -11,19 +11,19 @@
 #include "base/compiler_specific.h"
 #include "base/macros.h"
 #include "base/strings/string16.h"
-#include "components/omnibox/browser/toolbar_model.h"
+#include "components/omnibox/browser/location_bar_model.h"
 
 namespace gfx {
 struct VectorIcon;
 }
 
-// A ToolbarModel that is backed by instance variables, which are initialized
-// with some basic values that can be changed with the provided setters. This
-// should be used only for testing.
-class TestToolbarModel : public ToolbarModel {
+// A LocationBarModel that is backed by instance variables, which are
+// initialized with some basic values that can be changed with the provided
+// setters. This should be used only for testing.
+class TestLocationBarModel : public LocationBarModel {
  public:
-  TestToolbarModel();
-  ~TestToolbarModel() override;
+  TestLocationBarModel();
+  ~TestLocationBarModel() override;
   base::string16 GetFormattedFullURL() const override;
   base::string16 GetURLForDisplay() const override;
   GURL GetURL() const override;
@@ -68,7 +68,7 @@
   bool should_display_url_ = false;
   bool offline_page_ = false;
 
-  DISALLOW_COPY_AND_ASSIGN(TestToolbarModel);
+  DISALLOW_COPY_AND_ASSIGN(TestLocationBarModel);
 };
 
-#endif  // COMPONENTS_OMNIBOX_BROWSER_TEST_TOOLBAR_MODEL_H_
+#endif  // COMPONENTS_OMNIBOX_BROWSER_TEST_LOCATION_BAR_MODEL_H_
diff --git a/components/omnibox/browser/test_omnibox_edit_controller.cc b/components/omnibox/browser/test_omnibox_edit_controller.cc
index d4b0fe5..41528a6c 100644
--- a/components/omnibox/browser/test_omnibox_edit_controller.cc
+++ b/components/omnibox/browser/test_omnibox_edit_controller.cc
@@ -4,10 +4,11 @@
 
 #include "components/omnibox/browser/test_omnibox_edit_controller.h"
 
-TestToolbarModel* TestOmniboxEditController::GetToolbarModel() {
-  return &toolbar_model_;
+TestLocationBarModel* TestOmniboxEditController::GetLocationBarModel() {
+  return &location_bar_model_;
 }
 
-const TestToolbarModel* TestOmniboxEditController::GetToolbarModel() const {
-  return &toolbar_model_;
+const TestLocationBarModel* TestOmniboxEditController::GetLocationBarModel()
+    const {
+  return &location_bar_model_;
 }
diff --git a/components/omnibox/browser/test_omnibox_edit_controller.h b/components/omnibox/browser/test_omnibox_edit_controller.h
index 60c7340..a38e664 100644
--- a/components/omnibox/browser/test_omnibox_edit_controller.h
+++ b/components/omnibox/browser/test_omnibox_edit_controller.h
@@ -6,20 +6,20 @@
 #define COMPONENTS_OMNIBOX_BROWSER_TEST_OMNIBOX_EDIT_CONTROLLER_H_
 
 #include "components/omnibox/browser/omnibox_edit_controller.h"
-#include "components/omnibox/browser/test_toolbar_model.h"
+#include "components/omnibox/browser/test_location_bar_model.h"
 
 class TestOmniboxEditController : public OmniboxEditController {
  public:
   TestOmniboxEditController() {}
 
   // OmniboxEditController:
-  TestToolbarModel* GetToolbarModel() override;
-  const TestToolbarModel* GetToolbarModel() const override;
+  TestLocationBarModel* GetLocationBarModel() override;
+  const TestLocationBarModel* GetLocationBarModel() const override;
 
   using OmniboxEditController::destination_url;
 
  private:
-  TestToolbarModel toolbar_model_;
+  TestLocationBarModel location_bar_model_;
 
   DISALLOW_COPY_AND_ASSIGN(TestOmniboxEditController);
 };
diff --git a/components/omnibox/browser/test_toolbar_model.cc b/components/omnibox/browser/test_toolbar_model.cc
deleted file mode 100644
index daa8642..0000000
--- a/components/omnibox/browser/test_toolbar_model.cc
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/omnibox/browser/test_toolbar_model.h"
-
-#include "base/strings/utf_string_conversions.h"
-
-#if defined(TOOLKIT_VIEWS)
-#include "components/omnibox/browser/vector_icons.h"  // nogncheck
-#endif
-
-TestToolbarModel::TestToolbarModel()
-    : security_level_(security_state::NONE),
-#if defined(TOOLKIT_VIEWS)
-      icon_(&omnibox::kHttpIcon),
-#endif
-      should_display_url_(true) {
-}
-
-TestToolbarModel::~TestToolbarModel() {}
-
-base::string16 TestToolbarModel::GetFormattedFullURL() const {
-  if (!formatted_full_url_)
-    return base::UTF8ToUTF16(url_.spec());
-
-  return *formatted_full_url_;
-}
-
-base::string16 TestToolbarModel::GetURLForDisplay() const {
-  if (!url_for_display_)
-    return base::UTF8ToUTF16(url_.spec());
-
-  return *url_for_display_;
-}
-
-GURL TestToolbarModel::GetURL() const {
-  return url_;
-}
-
-security_state::SecurityLevel TestToolbarModel::GetSecurityLevel(
-    bool ignore_editing) const {
-  return security_level_;
-}
-
-const gfx::VectorIcon& TestToolbarModel::GetVectorIcon() const {
-  return *icon_;
-}
-
-base::string16 TestToolbarModel::GetSecureVerboseText() const {
-  return base::string16();
-}
-
-base::string16 TestToolbarModel::GetSecureAccessibilityText() const {
-  return base::string16();
-}
-
-base::string16 TestToolbarModel::GetEVCertName() const {
-  return (security_level_ == security_state::EV_SECURE) ? ev_cert_name_
-                                                        : base::string16();
-}
-
-bool TestToolbarModel::ShouldDisplayURL() const {
-  return should_display_url_;
-}
-
-bool TestToolbarModel::IsOfflinePage() const {
-  return offline_page_;
-}
diff --git a/components/omnibox/browser/toolbar_model_delegate.cc b/components/omnibox/browser/toolbar_model_delegate.cc
deleted file mode 100644
index 6509f5c..0000000
--- a/components/omnibox/browser/toolbar_model_delegate.cc
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/omnibox/browser/toolbar_model_delegate.h"
-
-bool ToolbarModelDelegate::ShouldDisplayURL() const {
-  return true;
-}
-
-ToolbarModelDelegate::SecurityLevel ToolbarModelDelegate::GetSecurityLevel()
-    const {
-  return SecurityLevel::NONE;
-}
-
-scoped_refptr<net::X509Certificate> ToolbarModelDelegate::GetCertificate()
-    const {
-  return nullptr;
-}
-
-bool ToolbarModelDelegate::FailsBillingCheck() const {
-  return false;
-}
-
-bool ToolbarModelDelegate::FailsMalwareCheck() const {
-  return false;
-}
-
-const gfx::VectorIcon* ToolbarModelDelegate::GetVectorIconOverride() const {
-  return nullptr;
-}
-
-bool ToolbarModelDelegate::IsOfflinePage() const {
-  return false;
-}
diff --git a/components/search_engines/template_url_service.h b/components/search_engines/template_url_service.h
index 3400b47..93cd041 100644
--- a/components/search_engines/template_url_service.h
+++ b/components/search_engines/template_url_service.h
@@ -433,7 +433,7 @@
                            ResolveSyncKeywordConflict);
   FRIEND_TEST_ALL_PREFIXES(TemplateURLServiceSyncTest, PreSyncDeletes);
   FRIEND_TEST_ALL_PREFIXES(TemplateURLServiceSyncTest, MergeInSyncTemplateURL);
-  FRIEND_TEST_ALL_PREFIXES(ToolbarModelTest, GoogleBaseURL);
+  FRIEND_TEST_ALL_PREFIXES(LocationBarModelTest, GoogleBaseURL);
 
   friend class InstantUnitTestBase;
   friend class Scoper;
diff --git a/components/security_state/core/security_state.h b/components/security_state/core/security_state.h
index 7c8ec4d..c962593 100644
--- a/components/security_state/core/security_state.h
+++ b/components/security_state/core/security_state.h
@@ -33,7 +33,7 @@
 // numeric values should never be reused.
 //
 // If you change this enum, you may need to update the UI icons in
-// ToolbarModelImpl::GetVectorIcon and GetIconForSecurityState.
+// LocationBarModelImpl::GetVectorIcon and GetIconForSecurityState.
 //
 // A Java counterpart will be generated for this enum.
 // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.components.security_state
diff --git a/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountManagerFacade.java b/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountManagerFacade.java
index 00a8033..6be795db 100644
--- a/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountManagerFacade.java
+++ b/components/signin/core/browser/android/java/src/org/chromium/components/signin/AccountManagerFacade.java
@@ -26,7 +26,6 @@
 import org.chromium.base.Log;
 import org.chromium.base.ObserverList;
 import org.chromium.base.ThreadUtils;
-import org.chromium.base.TraceEvent;
 import org.chromium.base.VisibleForTesting;
 import org.chromium.base.metrics.CachedMetrics;
 import org.chromium.base.task.AsyncTask;
@@ -142,15 +141,13 @@
      */
     @MainThread
     public static void initializeAccountManagerFacade(AccountManagerDelegate delegate) {
-        try (TraceEvent e = TraceEvent.scoped("initializeAccountManagerFacade()")) {
-            ThreadUtils.assertOnUiThread();
-            if (sInstance != null) {
-                throw new IllegalStateException("AccountManagerFacade is already initialized!");
-            }
-            sInstance = new AccountManagerFacade(delegate);
-            if (sTestingInstance != null) return;
-            sAtomicInstance.set(sInstance);
+        ThreadUtils.assertOnUiThread();
+        if (sInstance != null) {
+            throw new IllegalStateException("AccountManagerFacade is already initialized!");
         }
+        sInstance = new AccountManagerFacade(delegate);
+        if (sTestingInstance != null) return;
+        sAtomicInstance.set(sInstance);
     }
 
     /**
diff --git a/components/subresource_filter/tools/BUILD.gn b/components/subresource_filter/tools/BUILD.gn
index 54b7ba5..2b0f9e1 100644
--- a/components/subresource_filter/tools/BUILD.gn
+++ b/components/subresource_filter/tools/BUILD.gn
@@ -15,7 +15,7 @@
     "../core/browser",
     "../core/common",
     "//base",
-    "//components/url_pattern_index:util",
+    "//components/url_pattern_index",
     "//url",
   ]
 }
diff --git a/components/sync/engine/net/http_bridge_unittest.cc b/components/sync/engine/net/http_bridge_unittest.cc
index 17f170e..3984c77 100644
--- a/components/sync/engine/net/http_bridge_unittest.cc
+++ b/components/sync/engine/net/http_bridge_unittest.cc
@@ -71,7 +71,9 @@
   void RunSyncThreadBridgeUseTest(base::WaitableEvent* signal_when_created,
                                   base::WaitableEvent* signal_when_released);
 
-  base::MessageLoop* GetIOThreadLoop() { return io_thread_.message_loop(); }
+  scoped_refptr<base::SingleThreadTaskRunner> GetIOThreadTaskRunner() {
+    return io_thread_.task_runner();
+  }
 
   net::EmbeddedTestServer test_server_;
 
@@ -130,14 +132,13 @@
 
  protected:
   void MakeAsynchronousPost() override {
-    ASSERT_TRUE(
-        test_->GetIOThreadLoop()->task_runner()->BelongsToCurrentThread());
+    ASSERT_TRUE(test_->GetIOThreadTaskRunner()->BelongsToCurrentThread());
     if (never_finishes_)
       return;
 
     // We don't actually want to make a request for this test, so just callback
     // as if it completed.
-    test_->GetIOThreadLoop()->task_runner()->PostTask(
+    test_->GetIOThreadTaskRunner()->PostTask(
         FROM_HERE,
         base::BindOnce(&ShuntedHttpBridge::CallOnURLFetchComplete, this));
   }
@@ -146,8 +147,7 @@
   ~ShuntedHttpBridge() override {}
 
   void CallOnURLFetchComplete() {
-    ASSERT_TRUE(
-        test_->GetIOThreadLoop()->task_runner()->BelongsToCurrentThread());
+    ASSERT_TRUE(test_->GetIOThreadTaskRunner()->BelongsToCurrentThread());
 
     // Set up a dummy content response.
     OnURLLoadCompleteInternal(200, net::OK, 0 /* content length, irrelevant */,
diff --git a/components/tracing/common/trace_startup.cc b/components/tracing/common/trace_startup.cc
index 7af997250..f50a8882 100644
--- a/components/tracing/common/trace_startup.cc
+++ b/components/tracing/common/trace_startup.cc
@@ -19,6 +19,13 @@
   const base::CommandLine& command_line =
       *base::CommandLine::ForCurrentProcess();
 
+  // TODO(oysteine): Startup tracing using Perfetto
+  // is enabled by the Mojo consumer in content/browser
+  // for now; this is too late in the browser startup
+  // process however.
+  if (command_line.HasSwitch(switches::kPerfettoOutputFile))
+    return;
+
   // Ensure TraceLog is initialized first.
   // https://crbug.com/764357
   base::trace_event::TraceLog::GetInstance();
diff --git a/components/tracing/common/tracing_switches.cc b/components/tracing/common/tracing_switches.cc
index 3adedc9b..533ad021 100644
--- a/components/tracing/common/tracing_switches.cc
+++ b/components/tracing/common/tracing_switches.cc
@@ -54,6 +54,12 @@
 // "record-until-full" mode will be used.
 const char kTraceStartupRecordMode[] = "trace-startup-record-mode";
 
+// If supplied, will enable Perfetto startup tracing and stream the
+// output to the given file.
+// TODO(oysteine): Remove once Perfetto starts early enough after
+// process startup to be able to replace the legacy startup tracing.
+const char kPerfettoOutputFile[] = "perfetto-output-file";
+
 // Sends a pretty-printed version of tracing info to the console.
 const char kTraceToConsole[]                = "trace-to-console";
 
diff --git a/components/tracing/common/tracing_switches.h b/components/tracing/common/tracing_switches.h
index 96468105..6304a24 100644
--- a/components/tracing/common/tracing_switches.h
+++ b/components/tracing/common/tracing_switches.h
@@ -17,6 +17,7 @@
 TRACING_EXPORT extern const char kTraceStartupDuration[];
 TRACING_EXPORT extern const char kTraceStartupFile[];
 TRACING_EXPORT extern const char kTraceStartupRecordMode[];
+TRACING_EXPORT extern const char kPerfettoOutputFile[];
 TRACING_EXPORT extern const char kTraceToConsole[];
 TRACING_EXPORT extern const char kTraceUploadURL[];
 
diff --git a/components/url_pattern_index/BUILD.gn b/components/url_pattern_index/BUILD.gn
index 14f90fd..59636fb 100644
--- a/components/url_pattern_index/BUILD.gn
+++ b/components/url_pattern_index/BUILD.gn
@@ -14,6 +14,8 @@
     "url_pattern.h",
     "url_pattern_index.cc",
     "url_pattern_index.h",
+    "url_rule_util.cc",
+    "url_rule_util.h",
   ]
 
   public_deps = [
@@ -44,17 +46,6 @@
   ]
 }
 
-static_library("util") {
-  sources = [
-    "url_rule_util.cc",
-    "url_rule_util.h",
-  ]
-  deps = [
-    ":url_pattern_index",
-    "//base",
-  ]
-}
-
 source_set("unit_tests") {
   testonly = true
   sources = [
@@ -69,7 +60,6 @@
   deps = [
     ":test_support",
     ":url_pattern_index",
-    ":util",
     "//base",
     "//testing/gtest",
     "//third_party/protobuf:protobuf_lite",
diff --git a/components/url_pattern_index/url_pattern_index.cc b/components/url_pattern_index/url_pattern_index.cc
index 273d421..a2d96a8 100644
--- a/components/url_pattern_index/url_pattern_index.cc
+++ b/components/url_pattern_index/url_pattern_index.cc
@@ -17,8 +17,10 @@
 #include "base/optional.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/string_util.h"
+#include "base/trace_event/trace_event.h"
 #include "components/url_pattern_index/ngram_extractor.h"
 #include "components/url_pattern_index/url_pattern.h"
+#include "components/url_pattern_index/url_rule_util.h"
 #include "url/gurl.h"
 #include "url/origin.h"
 #include "url/url_constants.h"
@@ -793,9 +795,15 @@
     return nullptr;
   }
 
-  return FindMatchInFlatUrlPatternIndex(
+  auto* rule = FindMatchInFlatUrlPatternIndex(
       *flat_index_, UrlPattern::UrlInfo(url), first_party_origin, element_type,
       activation_type, is_third_party, disable_generic_rules, strategy);
+  if (rule) {
+    TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("loading"),
+                 "UrlPatternIndexMatcher::FindMatch", "pattern",
+                 FlatUrlRuleToFilterlistString(rule));
+  }
+  return rule;
 }
 
 }  // namespace url_pattern_index
diff --git a/components/viz/service/display/display.cc b/components/viz/service/display/display.cc
index 4778c227..6c690622 100644
--- a/components/viz/service/display/display.cc
+++ b/components/viz/service/display/display.cc
@@ -90,6 +90,8 @@
   if (client_) {
     if (auto* context = output_surface_->context_provider())
       context->RemoveObserver(this);
+    if (skia_output_surface_)
+      skia_output_surface_->RemoveContextLostObserver(this);
     if (scheduler_)
       surface_manager_->RemoveObserver(scheduler_.get());
   }
@@ -122,6 +124,9 @@
   // it could miss a callback before setting this.
   if (auto* context = output_surface_->context_provider())
     context->AddObserver(this);
+
+  if (skia_output_surface_)
+    skia_output_surface_->AddContextLostObserver(this);
 }
 
 void Display::AddObserver(DisplayObserver* observer) {
diff --git a/components/viz/service/display/gl_renderer.cc b/components/viz/service/display/gl_renderer.cc
index 0095043a..154cb06 100644
--- a/components/viz/service/display/gl_renderer.cc
+++ b/components/viz/service/display/gl_renderer.cc
@@ -796,8 +796,15 @@
   gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
   gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 
-  gl_->CopyTexImage2D(GL_TEXTURE_2D, 0, GetFramebufferCopyTextureFormat(),
-                      window_rect.x(), window_rect.y(), window_rect.width(),
+  unsigned internalformat = GetFramebufferCopyTextureFormat();
+  // CopyTexImage2D requires inernalformat channels to be a subset of
+  // the channels of the source texture internalformat.
+  DCHECK(internalformat == GL_RGB || internalformat == GL_RGBA ||
+         internalformat == GL_BGRA_EXT);
+  if (internalformat == GL_BGRA_EXT)
+    internalformat = GL_RGBA;
+  gl_->CopyTexImage2D(GL_TEXTURE_2D, 0, internalformat, window_rect.x(),
+                      window_rect.y(), window_rect.width(),
                       window_rect.height(), 0);
   gl_->BindTexture(GL_TEXTURE_2D, 0);
   return texture_id;
diff --git a/components/viz/service/display/skia_output_surface.h b/components/viz/service/display/skia_output_surface.h
index f87a564..32d25265 100644
--- a/components/viz/service/display/skia_output_surface.h
+++ b/components/viz/service/display/skia_output_surface.h
@@ -14,6 +14,7 @@
 
 namespace viz {
 
+class ContextLostObserver;
 class CopyOutputRequest;
 struct ResourceMetadata;
 
@@ -95,6 +96,12 @@
                           const gfx::Rect& copy_rect,
                           std::unique_ptr<CopyOutputRequest> request) = 0;
 
+  // Add context lost observer.
+  virtual void AddContextLostObserver(ContextLostObserver* observer) = 0;
+
+  // Remove context lost observer.
+  virtual void RemoveContextLostObserver(ContextLostObserver* observer) = 0;
+
  private:
   DISALLOW_COPY_AND_ASSIGN(SkiaOutputSurface);
 };
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl.cc b/components/viz/service/display_embedder/skia_output_surface_impl.cc
index 9cdd4a5..4b6fe65 100644
--- a/components/viz/service/display_embedder/skia_output_surface_impl.cc
+++ b/components/viz/service/display_embedder/skia_output_surface_impl.cc
@@ -9,6 +9,7 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "components/viz/common/frame_sinks/begin_frame_source.h"
 #include "components/viz/common/frame_sinks/copy_output_request.h"
+#include "components/viz/common/gpu/context_lost_observer.h"
 #include "components/viz/common/resources/resource_format_utils.h"
 #include "components/viz/service/display/output_surface_client.h"
 #include "components/viz/service/display/output_surface_frame.h"
@@ -559,6 +560,16 @@
       sequence_id, std::move(callback), std::vector<gpu::SyncToken>()));
 }
 
+void SkiaOutputSurfaceImpl::AddContextLostObserver(
+    ContextLostObserver* observer) {
+  observers_.AddObserver(observer);
+}
+
+void SkiaOutputSurfaceImpl::RemoveContextLostObserver(
+    ContextLostObserver* observer) {
+  observers_.RemoveObserver(observer);
+}
+
 void SkiaOutputSurfaceImpl::InitializeOnGpuThread(base::WaitableEvent* event) {
   base::ScopedClosureRunner scoped_runner(
       base::BindOnce(&base::WaitableEvent::Signal, base::Unretained(event)));
@@ -566,12 +577,14 @@
       &SkiaOutputSurfaceImpl::DidSwapBuffersComplete, weak_ptr_);
   auto buffer_presented_callback =
       base::BindRepeating(&SkiaOutputSurfaceImpl::BufferPresented, weak_ptr_);
+  auto context_lost_callback =
+      base::BindRepeating(&SkiaOutputSurfaceImpl::ContextLost, weak_ptr_);
   impl_on_gpu_ = std::make_unique<SkiaOutputSurfaceImplOnGpu>(
       gpu_service_, surface_handle_,
       CreateSafeCallback(client_thread_task_runner_,
                          did_swap_buffer_complete_callback),
-      CreateSafeCallback(client_thread_task_runner_,
-                         buffer_presented_callback));
+      CreateSafeCallback(client_thread_task_runner_, buffer_presented_callback),
+      CreateSafeCallback(client_thread_task_runner_, context_lost_callback));
   capabilities_ = impl_on_gpu_->capabilities();
 }
 
@@ -614,6 +627,12 @@
   }
 }
 
+void SkiaOutputSurfaceImpl::ContextLost() {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  for (auto& observer : observers_)
+    observer.OnContextLost();
+}
+
 void SkiaOutputSurfaceImpl::SetNeedsSwapSizeNotifications(
     bool needs_swap_size_notifications) {
   needs_swap_size_notifications_ = needs_swap_size_notifications;
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl.h b/components/viz/service/display_embedder/skia_output_surface_impl.h
index 54122d6..e645ce7 100644
--- a/components/viz/service/display_embedder/skia_output_surface_impl.h
+++ b/components/viz/service/display_embedder/skia_output_surface_impl.h
@@ -6,6 +6,7 @@
 #define COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SKIA_OUTPUT_SURFACE_IMPL_H_
 
 #include "base/macros.h"
+#include "base/observer_list.h"
 #include "base/optional.h"
 #include "base/threading/thread_checker.h"
 #include "components/viz/service/display/skia_output_surface.h"
@@ -91,6 +92,8 @@
   void CopyOutput(RenderPassId id,
                   const gfx::Rect& copy_rect,
                   std::unique_ptr<CopyOutputRequest> request) override;
+  void AddContextLostObserver(ContextLostObserver* observer) override;
+  void RemoveContextLostObserver(ContextLostObserver* observer) override;
 
  private:
   template <class T>
@@ -101,6 +104,7 @@
   void DidSwapBuffersComplete(gpu::SwapBuffersCompleteParams params,
                               const gfx::Size& pixel_size);
   void BufferPresented(const gfx::PresentationFeedback& feedback);
+  void ContextLost();
 
   uint64_t sync_fence_release_ = 0;
   GpuServiceImpl* const gpu_service_;
@@ -131,6 +135,8 @@
   // Whether to send OutputSurfaceClient::DidSwapWithSize notifications.
   bool needs_swap_size_notifications_ = false;
 
+  base::ObserverList<ContextLostObserver>::Unchecked observers_;
+
   THREAD_CHECKER(thread_checker_);
 
   base::WeakPtr<SkiaOutputSurfaceImpl> weak_ptr_;
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
index a2e0614..a80c020 100644
--- a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
+++ b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
@@ -6,11 +6,13 @@
 
 #include "base/atomic_sequence_num.h"
 #include "base/callback_helpers.h"
+#include "base/optional.h"
 #include "base/synchronization/waitable_event.h"
 #include "components/viz/common/frame_sinks/copy_output_request.h"
 #include "components/viz/service/display/output_surface_frame.h"
 #include "components/viz/service/gl/gpu_service_impl.h"
 #include "gpu/command_buffer/common/swap_buffers_complete_params.h"
+#include "gpu/command_buffer/service/gr_shader_cache.h"
 #include "gpu/command_buffer/service/mailbox_manager.h"
 #include "gpu/command_buffer/service/scheduler.h"
 #include "gpu/command_buffer/service/shared_image_representation.h"
@@ -19,6 +21,7 @@
 #include "gpu/command_buffer/service/texture_base.h"
 #include "gpu/command_buffer/service/texture_manager.h"
 #include "gpu/config/gpu_preferences.h"
+#include "gpu/ipc/common/gpu_client_ids.h"
 #include "gpu/ipc/common/gpu_surface_lookup.h"
 #include "gpu/ipc/service/image_transport_surface.h"
 #include "gpu/vulkan/buildflags.h"
@@ -45,13 +48,15 @@
     GpuServiceImpl* gpu_service,
     gpu::SurfaceHandle surface_handle,
     const DidSwapBufferCompleteCallback& did_swap_buffer_complete_callback,
-    const BufferPresentedCallback& buffer_presented_callback)
+    const BufferPresentedCallback& buffer_presented_callback,
+    const ContextLostCallback& context_lost_callback)
     : command_buffer_id_(gpu::CommandBufferId::FromUnsafeValue(
           g_next_command_buffer_id.GetNext() + 1)),
       gpu_service_(gpu_service),
       surface_handle_(surface_handle),
       did_swap_buffer_complete_callback_(did_swap_buffer_complete_callback),
       buffer_presented_callback_(buffer_presented_callback),
+      context_lost_callback_(context_lost_callback),
       weak_ptr_factory_(this) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   weak_ptr_ = weak_ptr_factory_.GetWeakPtr();
@@ -95,10 +100,8 @@
   }
 
   if (!gpu_service_->is_using_vulkan()) {
-    if (!gl_context_->MakeCurrent(gl_surface_.get())) {
-      LOG(FATAL) << "Failed to make current.";
-      // TODO(penghuang): Handle the failure.
-    }
+    if (!MakeCurrent())
+      return;
     gl::GLSurface::ColorSpace surface_color_space =
         color_space == gfx::ColorSpace::CreateSCRGBLinear()
             ? gl::GLSurface::ColorSpace::SCRGB_LINEAR
@@ -108,8 +111,8 @@
       LOG(FATAL) << "Failed to resize.";
       // TODO(penghuang): Handle the failure.
     }
-    DCHECK(gl_context_->IsCurrent(gl_surface_.get()));
-    DCHECK(gr_context_);
+    DCHECK(gl_context()->IsCurrent(gl_surface_.get()));
+    DCHECK(gr_context());
 
     SkSurfaceProps surface_props =
         SkSurfaceProps(0, SkSurfaceProps::kLegacyFontHost_InitType);
@@ -123,7 +126,7 @@
                                         framebuffer_info);
 
     sk_surface_ = SkSurface::MakeFromBackendRenderTarget(
-        gr_context_, render_target, kBottomLeft_GrSurfaceOrigin,
+        gr_context(), render_target, kBottomLeft_GrSurfaceOrigin,
         kBGRA_8888_SkColorType, nullptr, &surface_props);
     DCHECK(sk_surface_);
   } else {
@@ -176,14 +179,17 @@
   DCHECK(ddl);
   DCHECK(sk_surface_);
 
-  if (!gpu_service_->is_using_vulkan() &&
-      !gl_context_->MakeCurrent(gl_surface_.get())) {
-    LOG(FATAL) << "Failed to make current.";
-    // TODO(penghuang): Handle the failure.
-  }
+  if (!MakeCurrent())
+    return;
 
-  sk_surface_->draw(ddl.get());
-  gr_context_->flush();
+  {
+    base::Optional<gpu::raster::GrShaderCache::ScopedCacheUse> cache_use;
+    if (gpu_service_->gr_shader_cache())
+      cache_use.emplace(gpu_service_->gr_shader_cache(),
+                        gpu::kInProcessCommandBufferClientId);
+    sk_surface_->draw(ddl.get());
+    gr_context()->flush();
+  }
   sync_point_client_state_->ReleaseFenceSync(sync_fence_release);
 }
 
@@ -192,10 +198,8 @@
   DCHECK(sk_surface_);
   base::TimeTicks swap_start, swap_end;
   if (!gpu_service_->is_using_vulkan()) {
-    if (!gl_context_->MakeCurrent(gl_surface_.get())) {
-      LOG(FATAL) << "Failed to make current.";
-      // TODO(penghuang): Handle the failure.
-    }
+    if (!MakeCurrent())
+      return;
     swap_start = base::TimeTicks::Now();
     OnSwapBuffers();
     gl_surface_->SwapBuffers(frame.need_presentation_feedback
@@ -241,11 +245,8 @@
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   DCHECK(ddl);
 
-  if (!gpu_service_->is_using_vulkan() &&
-      !gl_context_->MakeCurrent(gl_surface_.get())) {
-    LOG(FATAL) << "Failed to make current.";
-    // TODO(penghuang): Handle the failure.
-  }
+  if (!MakeCurrent())
+    return;
 
   auto& surface = offscreen_surfaces_[id];
   SkSurfaceCharacterization characterization;
@@ -253,12 +254,18 @@
   // the SkSurfaceCharacterization::operator!= is implemented in Skia.
   if (!surface || !surface->characterize(&characterization) ||
       characterization != ddl->characterization()) {
-    surface = SkSurface::MakeRenderTarget(gr_context_, ddl->characterization(),
+    surface = SkSurface::MakeRenderTarget(gr_context(), ddl->characterization(),
                                           SkBudgeted::kNo);
     DCHECK(surface);
   }
-  surface->draw(ddl.get());
-  surface->flush();
+  {
+    base::Optional<gpu::raster::GrShaderCache::ScopedCacheUse> cache_use;
+    if (gpu_service_->gr_shader_cache())
+      cache_use.emplace(gpu_service_->gr_shader_cache(),
+                        gpu::kInProcessCommandBufferClientId);
+    surface->draw(ddl.get());
+    gr_context()->flush();
+  }
   sync_point_client_state_->ReleaseFenceSync(sync_fence_release);
 }
 
@@ -318,17 +325,10 @@
     return;
   }
 
-  // Legacy mailbox path. TODO: Remove this once everything goes through
-  // SharedImages.
-  if (gpu_service_->is_using_vulkan()) {
-    // TODO(https://crbug.com/838899): Use SkSurface as raster decoder target.
-    // NOTIMPLEMENTED();
-    return;
-  }
   auto* mailbox_manager = gpu_service_->mailbox_manager();
   auto* texture_base = mailbox_manager->ConsumeTexture(metadata.mailbox);
   if (!texture_base) {
-    DLOG(ERROR) << "Failed to full fill the promise texture.";
+    DLOG(ERROR) << "Failed to fulfill the promise texture.";
     return;
   }
   BindOrCopyTextureIfNecessary(texture_base);
@@ -347,13 +347,13 @@
   *backend_texture =
       surface->getBackendTexture(SkSurface::kFlushRead_BackendHandleAccess);
   DLOG_IF(ERROR, !backend_texture->isValid())
-      << "Failed to full fill the promise texture created from RenderPassId:"
+      << "Failed to fulfill the promise texture created from RenderPassId:"
       << id;
 }
 
 sk_sp<GrContextThreadSafeProxy>
 SkiaOutputSurfaceImplOnGpu::GetGrContextThreadSafeProxy() {
-  return gr_context_->threadSafeProxy();
+  return gr_context()->threadSafeProxy();
 }
 
 #if defined(OS_WIN)
@@ -414,27 +414,21 @@
   }
   DCHECK(gl_surface_);
 
-  gl::GLContext* gl_context = nullptr;
-  if (!gpu_service_->GetGrContextForGLSurface(gl_surface_.get(), &gr_context_,
-                                              &gl_context)) {
+  context_state_ = gpu_service_->GetContextStateForGLSurface(gl_surface_.get());
+  if (!context_state_) {
     LOG(FATAL) << "Failed to create GrContext";
     // TODO(penghuang): handle the failure.
   }
-  gl_context_ = gl_context;
-  DCHECK(gr_context_);
-  DCHECK(gl_context_);
 
-  if (!gl_context_->MakeCurrent(gl_surface_.get())) {
-    LOG(FATAL) << "Failed to make current.";
-    // TODO(penghuang): Handle the failure.
-  }
+  if (!MakeCurrent())
+    return;
 
-  gl_version_info_ = gl_context_->GetVersionInfo();
+  gl_version_info_ = gl_context()->GetVersionInfo();
 
   capabilities_.flipped_output_surface = gl_surface_->FlipsVertically();
 
   // Get stencil bits from the default frame buffer.
-  auto* current_gl = gl_context_->GetCurrentGL();
+  auto* current_gl = gl_context()->GetCurrentGL();
   const auto* version = current_gl->Version;
   auto* api = current_gl->Api;
   GLint stencil_bits = 0;
@@ -450,8 +444,8 @@
 }
 
 void SkiaOutputSurfaceImplOnGpu::InitializeForVulkan() {
-  gr_context_ = gpu_service_->GetGrContextForVulkan();
-  DCHECK(gr_context_);
+  context_state_ = gpu_service_->GetContextStateForVulkan();
+  DCHECK(context_state_);
 }
 
 void SkiaOutputSurfaceImplOnGpu::BindOrCopyTextureIfNecessary(
@@ -506,7 +500,7 @@
                                         vulkan_surface_->size().height(), 0, 0,
                                         vk_image_info);
     sk_surface = SkSurface::MakeFromBackendRenderTarget(
-        gr_context_, render_target, kTopLeft_GrSurfaceOrigin,
+        gr_context(), render_target, kTopLeft_GrSurfaceOrigin,
         kBGRA_8888_SkColorType, nullptr, &surface_props);
   } else {
     auto backend = sk_surface->getBackendRenderTarget(
@@ -518,4 +512,17 @@
 #endif
 }
 
+bool SkiaOutputSurfaceImplOnGpu::MakeCurrent() {
+  if (!gpu_service_->is_using_vulkan()) {
+    if (context_state_->context_lost ||
+        !gl_context()->MakeCurrent(gl_surface_.get())) {
+      LOG(ERROR) << "Failed to make current.";
+      context_state_->context_lost = true;
+      context_lost_callback_.Run();
+      return false;
+    }
+  }
+  return true;
+}
+
 }  // namespace viz
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h
index 03eeba2..69b36626 100644
--- a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h
+++ b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h
@@ -14,6 +14,7 @@
 #include "components/viz/service/display/output_surface_frame.h"
 #include "components/viz/service/display/resource_metadata.h"
 #include "gpu/command_buffer/common/sync_token.h"
+#include "gpu/command_buffer/service/raster_decoder_context_state.h"
 #include "gpu/ipc/common/surface_handle.h"
 #include "gpu/ipc/in_process_command_buffer.h"
 #include "gpu/ipc/service/image_transport_surface_delegate.h"
@@ -51,11 +52,13 @@
                                    const gfx::Size& pixel_size)>;
   using BufferPresentedCallback =
       base::RepeatingCallback<void(const gfx::PresentationFeedback& feedback)>;
+  using ContextLostCallback = base::RepeatingCallback<void()>;
   SkiaOutputSurfaceImplOnGpu(
       GpuServiceImpl* gpu_service,
       gpu::SurfaceHandle surface_handle,
       const DidSwapBufferCompleteCallback& did_swap_buffer_complete_callback,
-      const BufferPresentedCallback& buffer_presented_callback);
+      const BufferPresentedCallback& buffer_presented_callback,
+      const ContextLostCallback& context_lost_callback);
   ~SkiaOutputSurfaceImplOnGpu() override;
 
   gpu::CommandBufferId command_buffer_id() const { return command_buffer_id_; }
@@ -126,17 +129,25 @@
 
   void CreateSkSurfaceForVulkan();
 
+  // Make context current for GL, and return false if the context is lost.
+  // It will do nothing when Vulkan is used.
+  bool MakeCurrent();
+
+  GrContext* gr_context() { return context_state_->gr_context; }
+  gl::GLContext* gl_context() { return context_state_->context.get(); }
+
   const gpu::CommandBufferId command_buffer_id_;
   GpuServiceImpl* const gpu_service_;
   const gpu::SurfaceHandle surface_handle_;
   DidSwapBufferCompleteCallback did_swap_buffer_complete_callback_;
   BufferPresentedCallback buffer_presented_callback_;
+  ContextLostCallback context_lost_callback_;
+
   scoped_refptr<gpu::SyncPointClientState> sync_point_client_state_;
   gpu::GpuPreferences gpu_preferences_;
   scoped_refptr<gl::GLSurface> gl_surface_;
   sk_sp<SkSurface> sk_surface_;
-  GrContext* gr_context_ = nullptr;
-  scoped_refptr<gl::GLContext> gl_context_;
+  scoped_refptr<gpu::raster::RasterDecoderContextState> context_state_;
   const gl::GLVersionInfo* gl_version_info_ = nullptr;
   OutputSurface::Capabilities capabilities_;
 
diff --git a/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc b/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc
index 082034f..e2ef5d4 100644
--- a/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc
+++ b/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc
@@ -507,7 +507,7 @@
 
   oracle_.RecordCapture(utilization);
   const int64_t frame_number = next_capture_frame_number_++;
-  TRACE_EVENT_ASYNC_BEGIN2("gpu.capture", "Capture", frame.get(),
+  TRACE_EVENT_ASYNC_BEGIN2("gpu.capture", "Capture", oracle_frame_number,
                            "frame_number", frame_number, "trigger",
                            VideoCaptureOracle::EventAsString(event));
 
@@ -673,18 +673,13 @@
   // also rewrites the media timestamp in terms of the smooth flow of the
   // original source content.
   base::TimeTicks media_ticks;
-  const bool should_deliver_frame =
-      oracle_.CompleteCapture(oracle_frame_number, !!frame, &media_ticks);
-  DCHECK(frame || !should_deliver_frame);
+  if (!oracle_.CompleteCapture(oracle_frame_number, !!frame, &media_ticks)) {
+    // The following is used by
+    // chrome/browser/extension/api/cast_streaming/performance_test.cc, in
+    // addition to the usual runtime tracing.
+    TRACE_EVENT_ASYNC_END1("gpu.capture", "Capture", oracle_frame_number,
+                           "success", false);
 
-  // The following is used by
-  // chrome/browser/extension/api/cast_streaming/performance_test.cc, in
-  // addition to the usual runtime tracing.
-  TRACE_EVENT_ASYNC_END2("gpu.capture", "Capture", frame.get(), "success",
-                         should_deliver_frame, "timestamp",
-                         (media_ticks - base::TimeTicks()).InMicroseconds());
-
-  if (!should_deliver_frame) {
     // Mark the whole source as dirty, since this frame may have contained
     // updated content that will not be delivered.
     dirty_rect_ = kMaxRect;
@@ -698,6 +693,13 @@
   }
   frame->set_timestamp(media_ticks - *first_frame_media_ticks_);
 
+  // The following is used by
+  // chrome/browser/extension/api/cast_streaming/performance_test.cc, in
+  // addition to the usual runtime tracing.
+  TRACE_EVENT_ASYNC_END2("gpu.capture", "Capture", oracle_frame_number,
+                         "success", true, "time_delta",
+                         frame->timestamp().InMicroseconds());
+
   // Clone a handle to the shared memory backing the populated video frame, to
   // send to the consumer. The handle is READ_WRITE because the consumer is free
   // to modify the content further (so long as it undoes its changes before the
diff --git a/components/viz/service/gl/gpu_service_impl.cc b/components/viz/service/gl/gpu_service_impl.cc
index 7a7d21a..6fa3d5a 100644
--- a/components/viz/service/gl/gpu_service_impl.cc
+++ b/components/viz/service/gl/gpu_service_impl.cc
@@ -21,6 +21,7 @@
 #include "components/viz/common/gpu/vulkan_in_process_context_provider.h"
 #include "gpu/command_buffer/client/gpu_memory_buffer_manager.h"
 #include "gpu/command_buffer/service/gpu_switches.h"
+#include "gpu/command_buffer/service/raster_decoder_context_state.h"
 #include "gpu/command_buffer/service/scheduler.h"
 #include "gpu/command_buffer/service/sync_point_manager.h"
 #include "gpu/config/dx_diag_node.h"
@@ -120,16 +121,6 @@
 
 }  // namespace
 
-struct GpuServiceImpl::GrContextAndGLContext {
-  GrContextAndGLContext() = default;
-  GrContextAndGLContext(GrContextAndGLContext&& other) = default;
-  ~GrContextAndGLContext() = default;
-  GrContextAndGLContext& operator=(GrContextAndGLContext&& other) = default;
-
-  scoped_refptr<gl::GLContext> gl_context;
-  sk_sp<GrContext> gr_context;
-};
-
 GpuServiceImpl::GpuServiceImpl(
     const gpu::GPUInfo& gpu_info,
     std::unique_ptr<gpu::GpuWatchdogThread> watchdog_thread,
@@ -194,20 +185,6 @@
     scheduler_->DestroySequence(skia_output_surface_sequence_id_);
   }
 
-  for (auto& key_and_data : contexts_for_gl_) {
-    auto& data = key_and_data.second;
-    if (!data.gr_context)
-      continue;
-    if (!data.gl_context ||
-        !data.gl_context->MakeCurrent(
-            gpu_channel_manager_->default_offscreen_surface())) {
-      LOG(ERROR) << "Failed to make current.";
-      data.gr_context->abandonContext();
-    }
-    data.gr_context = nullptr;
-  }
-  contexts_for_gl_.clear();
-
   media_gpu_channel_manager_.reset();
   gpu_channel_manager_.reset();
   owned_sync_point_manager_.reset();
@@ -280,14 +257,16 @@
   skia_output_surface_sequence_id_ =
       scheduler_->CreateSequence(gpu::SchedulingPriority::kHigh);
 
+  GrContext* vulkan_gr_context =
+      is_using_vulkan() ? vulkan_context_provider()->GetGrContext() : nullptr;
   // Defer creation of the render thread. This is to prevent it from handling
   // IPC messages before the sandbox has been enabled and all other necessary
   // initialization has succeeded.
-  gpu_channel_manager_.reset(new gpu::GpuChannelManager(
+  gpu_channel_manager_ = std::make_unique<gpu::GpuChannelManager>(
       gpu_preferences_, this, watchdog_thread_.get(), main_runner_, io_runner_,
       scheduler_.get(), sync_point_manager_, gpu_memory_buffer_factory_.get(),
       gpu_feature_info_, std::move(activity_flags),
-      std::move(default_offscreen_surface)));
+      std::move(default_offscreen_surface), vulkan_gr_context);
 
   media_gpu_channel_manager_.reset(
       new media::MediaGpuChannelManager(gpu_channel_manager_.get()));
@@ -311,57 +290,27 @@
   (*gpu_host_)->DisableGpuCompositing();
 }
 
-bool GpuServiceImpl::GetGrContextForGLSurface(gl::GLSurface* surface,
-                                              GrContext** gr_context,
-                                              gl::GLContext** gl_context) {
+scoped_refptr<gpu::raster::RasterDecoderContextState>
+GpuServiceImpl::GetContextStateForGLSurface(gl::GLSurface* surface) {
   DCHECK(main_runner_->BelongsToCurrentThread());
   DCHECK(!is_using_vulkan());
-  DCHECK(surface);
-  DCHECK(gr_context && !*gr_context);
-  DCHECK(gl_context && !*gl_context);
-
-  auto& data = contexts_for_gl_[surface->GetCompatibilityKey()];
-  if (!data.gr_context) {
-    DCHECK(!data.gl_context);
-
-    gl::GLContextAttribs attribs;
-    // TODO(penghuang) set attribs.
-    data.gl_context = gl::init::CreateGLContext(
-        gpu_channel_manager_->share_group(), surface, attribs);
-    DCHECK(data.gl_context);
-    gpu_feature_info_.ApplyToGLContext(data.gl_context.get());
-    if (!data.gl_context->MakeCurrent(surface)) {
-      LOG(FATAL) << "Failed to make current.";
-      // TODO(penghuang): handle the failure.
-    }
-
-    const auto* gl_version_info = data.gl_context->GetVersionInfo();
-    const bool use_version_es2 = false;
-    auto native_interface =
-        gl::init::CreateGrGLInterface(*gl_version_info, use_version_es2);
-    DCHECK(native_interface);
-
-    GrContextOptions options;
-    options.fExplicitlyAllocateGPUResources = GrContextOptions::Enable::kYes;
-    options.fUseGLBufferDataNullHint = GrContextOptions::Enable::kYes;
-    data.gr_context = GrContext::MakeGL(std::move(native_interface), options);
-    DCHECK(data.gr_context);
-  }
-
-  *gr_context = data.gr_context.get();
-  *gl_context = data.gl_context.get();
-  return !!gr_context;
+  gpu::ContextResult result;
+  auto context_state =
+      gpu_channel_manager_->GetRasterDecoderContextState(&result);
+  // TODO(penghuang): https://crbug.com/899740 Support GLSurface which is not
+  // compatible.
+  DCHECK_EQ(surface->GetCompatibilityKey(),
+            context_state->surface->GetCompatibilityKey());
+  DCHECK(!context_state->use_virtualized_gl_contexts);
+  return context_state;
 }
 
-GrContext* GpuServiceImpl::GetGrContextForVulkan() {
+scoped_refptr<gpu::raster::RasterDecoderContextState>
+GpuServiceImpl::GetContextStateForVulkan() {
   DCHECK(main_runner_->BelongsToCurrentThread());
   DCHECK(is_using_vulkan());
-#if BUILDFLAG(ENABLE_VULKAN)
-  return vulkan_context_provider_->GetGrContext();
-#else
-  NOTREACHED();
-  return nullptr;
-#endif
+  gpu::ContextResult result;
+  return gpu_channel_manager_->GetRasterDecoderContextState(&result);
 }
 
 gpu::ImageFactory* GpuServiceImpl::gpu_image_factory() {
diff --git a/components/viz/service/gl/gpu_service_impl.h b/components/viz/service/gl/gpu_service_impl.h
index 664ef05..b41a21d4 100644
--- a/components/viz/service/gl/gpu_service_impl.h
+++ b/components/viz/service/gl/gpu_service_impl.h
@@ -32,8 +32,6 @@
 #include "third_party/skia/include/core/SkRefCnt.h"
 #include "ui/gfx/native_widget_types.h"
 
-class GrContext;
-
 #if defined(OS_CHROMEOS)
 namespace arc {
 class ProtectedBufferManager;
@@ -52,6 +50,12 @@
 class MediaGpuChannelManager;
 }
 
+namespace gpu {
+namespace raster {
+struct RasterDecoderContextState;
+}  // namespace raster
+}  // namespace gpu
+
 namespace viz {
 
 class VulkanContextProvider;
@@ -85,12 +89,10 @@
       base::WaitableEvent* shutdown_event = nullptr);
   void Bind(mojom::GpuServiceRequest request);
 
-  // Get a GrContext and a GLContext for a given GL surface.
-  bool GetGrContextForGLSurface(gl::GLSurface* surface,
-                                GrContext** gr_context,
-                                gl::GLContext** gl_context);
-
-  GrContext* GetGrContextForVulkan();
+  scoped_refptr<gpu::raster::RasterDecoderContextState>
+  GetContextStateForGLSurface(gl::GLSurface* surface);
+  scoped_refptr<gpu::raster::RasterDecoderContextState>
+  GetContextStateForVulkan();
 
   // Notifies the GpuHost to stop using GPU compositing. This should be called
   // in response to an error in the GPU process that occurred after
@@ -125,6 +127,10 @@
     return gpu_channel_manager_->share_group();
   }
 
+  gpu::raster::GrShaderCache* gr_shader_cache() {
+    return gpu_channel_manager_->gr_shader_cache();
+  }
+
   gpu::SyncPointManager* sync_point_manager() { return sync_point_manager_; }
   gpu::Scheduler* scheduler() { return scheduler_.get(); }
 
@@ -291,10 +297,6 @@
   // sequence id for running tasks from SkiaOutputSurface;
   gpu::SequenceId skia_output_surface_sequence_id_;
 
-  // GL and Gr contexts used by Skia only.
-  struct GrContextAndGLContext;
-  base::flat_map<unsigned long, GrContextAndGLContext> contexts_for_gl_;
-
 #if BUILDFLAG(ENABLE_VULKAN)
   gpu::VulkanImplementation* vulkan_implementation_;
   scoped_refptr<VulkanContextProvider> vulkan_context_provider_;
diff --git a/content/browser/browser_child_process_host_impl.cc b/content/browser/browser_child_process_host_impl.cc
index 0d338c2..bc62dfa 100644
--- a/content/browser/browser_child_process_host_impl.cc
+++ b/content/browser/browser_child_process_host_impl.cc
@@ -316,9 +316,9 @@
   data_.metrics_name = metrics_name;
 }
 
-void BrowserChildProcessHostImpl::SetHandle(base::ProcessHandle handle) {
+void BrowserChildProcessHostImpl::SetProcess(base::Process process) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  data_.SetHandle(handle);
+  data_.SetProcess(std::move(process));
 }
 
 service_manager::mojom::ServiceRequest
@@ -360,8 +360,8 @@
   if (!child_process_) {
     // If the delegate doesn't use Launch() helper.
     ChildProcessTerminationInfo info;
-    info.status =
-        base::GetTerminationStatus(data_.GetHandle(), &info.exit_code);
+    info.status = base::GetTerminationStatus(data_.GetProcess().Handle(),
+                                             &info.exit_code);
     return info;
   }
   return child_process_->GetChildTerminationInfo(known_dead);
@@ -438,7 +438,7 @@
   // early exit watcher so GetTerminationStatus can close the process handle.
   early_exit_watcher_.StopWatching();
 #endif
-  if (child_process_.get() || data_.GetHandle()) {
+  if (child_process_.get() || data_.GetProcess().IsValid()) {
     ChildProcessTerminationInfo info =
         GetTerminationInfo(true /* known_dead */);
 #if defined(OS_ANDROID)
@@ -605,7 +605,7 @@
   early_exit_watcher_.StartWatchingOnce(process.Handle(), this);
 #endif
 
-  data_.SetHandle(process.Handle());
+  data_.SetProcess(process.Duplicate());
   delegate_->OnProcessLaunched();
 
   if (is_channel_connected_) {
diff --git a/content/browser/browser_child_process_host_impl.h b/content/browser/browser_child_process_host_impl.h
index 39c277f11..87f50b63 100644
--- a/content/browser/browser_child_process_host_impl.h
+++ b/content/browser/browser_child_process_host_impl.h
@@ -80,7 +80,7 @@
       override;
   void SetName(const base::string16& name) override;
   void SetMetricsName(const std::string& metrics_name) override;
-  void SetHandle(base::ProcessHandle handle) override;
+  void SetProcess(base::Process process) override;
   service_manager::mojom::ServiceRequest TakeInProcessServiceRequest() override;
 
   // ChildProcessHostDelegate implementation:
diff --git a/content/browser/devtools/devtools_http_handler.cc b/content/browser/devtools/devtools_http_handler.cc
index baa7d79..53a3e87 100644
--- a/content/browser/devtools/devtools_http_handler.cc
+++ b/content/browser/devtools/devtools_http_handler.cc
@@ -17,7 +17,6 @@
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted_memory.h"
-#include "base/message_loop/message_loop.h"
 #include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
@@ -308,11 +307,12 @@
 // messages sent to a DebuggerShell instance.
 class DevToolsAgentHostClientImpl : public DevToolsAgentHostClient {
  public:
-  DevToolsAgentHostClientImpl(base::MessageLoop* message_loop,
-                              ServerWrapper* server_wrapper,
-                              int connection_id,
-                              scoped_refptr<DevToolsAgentHost> agent_host)
-      : message_loop_(message_loop),
+  DevToolsAgentHostClientImpl(
+      scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+      ServerWrapper* server_wrapper,
+      int connection_id,
+      scoped_refptr<DevToolsAgentHost> agent_host)
+      : task_runner_(std::move(task_runner)),
         server_wrapper_(server_wrapper),
         connection_id_(connection_id),
         agent_host_(agent_host) {
@@ -337,7 +337,7 @@
     DispatchProtocolMessage(agent_host, message);
 
     agent_host_ = nullptr;
-    message_loop_->task_runner()->PostTask(
+    task_runner_->PostTask(
         FROM_HERE,
         base::BindOnce(&ServerWrapper::Close, base::Unretained(server_wrapper_),
                        connection_id_));
@@ -347,10 +347,10 @@
                                const std::string& message) override {
     DCHECK_CURRENTLY_ON(BrowserThread::UI);
     DCHECK(agent_host == agent_host_.get());
-    message_loop_->task_runner()->PostTask(
-        FROM_HERE, base::BindOnce(&ServerWrapper::SendOverWebSocket,
-                                  base::Unretained(server_wrapper_),
-                                  connection_id_, message));
+    task_runner_->PostTask(FROM_HERE,
+                           base::BindOnce(&ServerWrapper::SendOverWebSocket,
+                                          base::Unretained(server_wrapper_),
+                                          connection_id_, message));
   }
 
   void OnMessage(const std::string& message) {
@@ -360,7 +360,7 @@
   }
 
  private:
-  base::MessageLoop* const message_loop_;
+  const scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
   ServerWrapper* const server_wrapper_;
   const int connection_id_;
   scoped_refptr<DevToolsAgentHost> agent_host_;
@@ -736,7 +736,7 @@
             base::Bind(&DevToolsSocketFactory::CreateForTethering,
                        base::Unretained(socket_factory_.get())));
     connection_to_client_[connection_id].reset(new DevToolsAgentHostClientImpl(
-        thread_->message_loop(), server_wrapper_.get(), connection_id,
+        thread_->task_runner(), server_wrapper_.get(), connection_id,
         browser_agent));
     AcceptWebSocket(connection_id, request);
     return;
@@ -757,7 +757,7 @@
   }
 
   connection_to_client_[connection_id].reset(new DevToolsAgentHostClientImpl(
-      thread_->message_loop(), server_wrapper_.get(), connection_id, agent));
+      thread_->task_runner(), server_wrapper_.get(), connection_id, agent));
 
   AcceptWebSocket(connection_id, request);
 }
@@ -789,8 +789,7 @@
   base::Thread::Options options;
   options.message_loop_type = base::MessageLoop::TYPE_IO;
   if (thread->StartWithOptions(options)) {
-    base::TaskRunner* task_runner = thread->task_runner().get();
-    task_runner->PostTask(
+    thread->task_runner()->PostTask(
         FROM_HERE,
         base::BindOnce(&StartServerOnHandlerThread, weak_factory_.GetWeakPtr(),
                        std::move(thread), std::move(socket_factory),
diff --git a/content/browser/devtools/protocol/system_info_handler.cc b/content/browser/devtools/protocol/system_info_handler.cc
index def5f6b..76e7415 100644
--- a/content/browser/devtools/protocol/system_info_handler.cc
+++ b/content/browser/devtools/protocol/system_info_handler.cc
@@ -5,7 +5,6 @@
 #include "content/browser/devtools/protocol/system_info_handler.h"
 
 #include <stdint.h>
-
 #include <utility>
 
 #include "base/bind.h"
@@ -16,7 +15,9 @@
 #include "content/browser/gpu/compositor_util.h"
 #include "content/browser/gpu/gpu_data_manager_impl.h"
 #include "content/browser/gpu/gpu_process_host.h"
+#include "content/public/browser/browser_child_process_host.h"
 #include "content/public/browser/browser_task_traits.h"
+#include "content/public/browser/render_process_host.h"
 #include "gpu/config/gpu_feature_type.h"
 #include "gpu/config/gpu_info.h"
 #include "gpu/config/gpu_switches.h"
@@ -232,5 +233,65 @@
   new SystemInfoHandlerGpuObserver(std::move(callback));
 }
 
+namespace {
+
+std::unique_ptr<base::ProcessMetrics> CreateProcessMetrics(
+    base::ProcessHandle handle) {
+#if defined(OS_MACOSX)
+  return base::ProcessMetrics::CreateProcessMetrics(
+      handle, content::BrowserChildProcessHost::GetPortProvider());
+#else
+  return base::ProcessMetrics::CreateProcessMetrics(handle);
+#endif
+}
+
+std::unique_ptr<protocol::SystemInfo::ProcessInfo> MakeProcessInfo(
+    const base::Process& process,
+    const String& process_type) {
+  std::unique_ptr<base::ProcessMetrics> pm =
+      CreateProcessMetrics(process.Handle());
+  base::TimeDelta cpu_usage = pm->GetCumulativeCPUUsage();
+
+  return SystemInfo::ProcessInfo::Create()
+      .SetId(process.Pid())
+      .SetType(process_type)
+      .SetCpuTime(cpu_usage.InSecondsF())
+      .Build();
+}
+
+void AddBrowserProcessInfo(
+    protocol::Array<protocol::SystemInfo::ProcessInfo>* process_info) {
+  process_info->addItem(
+      MakeProcessInfo(base::Process::Current(),
+                      protocol::SystemInfo::ProcessTypeEnum::Browser));
+}
+
+void AddRendererProcessInfo(
+    protocol::Array<protocol::SystemInfo::ProcessInfo>* process_info) {
+  for (RenderProcessHost::iterator it(RenderProcessHost::AllHostsIterator());
+       !it.IsAtEnd(); it.Advance()) {
+    RenderProcessHost* host = it.GetCurrentValue();
+    if (host->GetProcess().IsValid()) {
+      process_info->addItem(MakeProcessInfo(
+          host->GetProcess(), protocol::SystemInfo::ProcessTypeEnum::Renderer));
+    }
+  }
+}
+
+}  // namespace
+
+Response SystemInfoHandler::GetProcessInfo(
+    std::unique_ptr<protocol::Array<protocol::SystemInfo::ProcessInfo>>*
+        process_info) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+  *process_info = protocol::Array<SystemInfo::ProcessInfo>::create();
+
+  AddBrowserProcessInfo(process_info->get());
+  AddRendererProcessInfo(process_info->get());
+
+  return Response::OK();
+}
+
 }  // namespace protocol
 }  // namespace content
diff --git a/content/browser/devtools/protocol/system_info_handler.h b/content/browser/devtools/protocol/system_info_handler.h
index dbb64ae2..45f671fb 100644
--- a/content/browser/devtools/protocol/system_info_handler.h
+++ b/content/browser/devtools/protocol/system_info_handler.h
@@ -26,6 +26,9 @@
   void Wire(UberDispatcher* dispatcher) override;
 
   void GetInfo(std::unique_ptr<GetInfoCallback> callback) override;
+  Response GetProcessInfo(
+      std::unique_ptr<protocol::Array<protocol::SystemInfo::ProcessInfo>>*
+          process_info) override;
 
  private:
   friend class SystemInfoHandlerGpuObserver;
diff --git a/content/browser/histogram_controller.cc b/content/browser/histogram_controller.cc
index 1c52b9e..0963415 100644
--- a/content/browser/histogram_controller.cc
+++ b/content/browser/histogram_controller.cc
@@ -154,8 +154,8 @@
     // In some cases, there may be no child process of the given type (for
     // example, the GPU process may not exist and there may instead just be a
     // GPU thread in the browser process). If that's the case, then the process
-    // handle will be base::kNullProcessHandle and we shouldn't ask it for data.
-    if (!data.IsHandleValid())
+    // will be invalid and we shouldn't ask it for data.
+    if (!data.GetProcess().IsValid())
       continue;
 
     if (auto* child_histogram_fetcher =
diff --git a/content/browser/ppapi_plugin_process_host.cc b/content/browser/ppapi_plugin_process_host.cc
index 3c2cf89..ed82bb98 100644
--- a/content/browser/ppapi_plugin_process_host.cc
+++ b/content/browser/ppapi_plugin_process_host.cc
@@ -523,8 +523,8 @@
   sent_requests_.pop();
 
   const ChildProcessData& data = process_->GetData();
-  client->OnPpapiChannelOpened(channel_handle,
-                               base::GetProcId(data.GetHandle()), data.id);
+  client->OnPpapiChannelOpened(channel_handle, data.GetProcess().Pid(),
+                               data.id);
 }
 
 }  // namespace content
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 2ce81d4..dae3544 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -295,7 +295,7 @@
 RenderProcessHostImpl::CreateStoragePartitionServiceFunction
     g_create_storage_partition = nullptr;
 
-base::MessageLoop* g_in_process_thread;
+base::Thread* g_in_process_thread;
 
 const RenderProcessHostFactory* g_render_process_host_factory_ = nullptr;
 const char kSiteProcessMapKeyName[] = "content_site_process_map";
@@ -1407,9 +1407,9 @@
     filter_->Disable();
 }
 
-base::MessageLoop*
-RenderProcessHostImpl::GetInProcessRendererThreadForTesting() {
-  return g_in_process_thread;
+scoped_refptr<base::SingleThreadTaskRunner>
+RenderProcessHostImpl::GetInProcessRendererThreadTaskRunnerForTesting() {
+  return g_in_process_thread->task_runner();
 }
 
 // static
@@ -1688,6 +1688,7 @@
   // Make sure to clean up the in-process renderer before the channel, otherwise
   // it may still run and have its IPCs fail, causing asserts.
   in_process_renderer_.reset();
+  g_in_process_thread = nullptr;
 
   ChildProcessSecurityPolicyImpl::GetInstance()->Remove(GetID());
 
@@ -1821,7 +1822,7 @@
 
     in_process_renderer_->StartWithOptions(options);
 
-    g_in_process_thread = in_process_renderer_->message_loop();
+    g_in_process_thread = in_process_renderer_.get();
 
     // Make sure any queued messages on the channel are flushed in the case
     // where we aren't launching a child process.
diff --git a/content/browser/renderer_host/render_process_host_impl.h b/content/browser/renderer_host/render_process_host_impl.h
index f11aa82..4c6760c 100644
--- a/content/browser/renderer_host/render_process_host_impl.h
+++ b/content/browser/renderer_host/render_process_host_impl.h
@@ -70,7 +70,6 @@
 
 namespace base {
 class CommandLine;
-class MessageLoop;
 class SharedPersistentMemoryAllocator;
 }
 
@@ -352,7 +351,8 @@
     kMaxValue = kRefusedBySiteInstance
   };
 
-  static base::MessageLoop* GetInProcessRendererThreadForTesting();
+  static scoped_refptr<base::SingleThreadTaskRunner>
+  GetInProcessRendererThreadTaskRunnerForTesting();
 
   // This forces a renderer that is running "in process" to shut down.
   static void ShutDownInProcessRenderer();
diff --git a/content/browser/service_manager/service_manager_context.cc b/content/browser/service_manager/service_manager_context.cc
index 37dafa0..f32ccd3 100644
--- a/content/browser/service_manager/service_manager_context.cc
+++ b/content/browser/service_manager/service_manager_context.cc
@@ -787,7 +787,7 @@
   auto iter = g_active_process_groups.Get().find(process_group_name);
   if (iter == g_active_process_groups.Get().end() || !iter->second)
     return false;
-  return iter->second->GetData().IsHandleValid();
+  return iter->second->GetData().GetProcess().IsValid();
 }
 
 // static
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 7fc1ad54..fd677b0 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -5417,7 +5417,7 @@
     browser_plugin_embedder_.reset();
 }
 
-WebContentsImpl* WebContentsImpl::GetOuterWebContents() {
+WebContentsImpl* WebContentsImpl::GetOuterWebContents() const {
   if (GuestMode::IsCrossProcessFrameGuest(this))
     return node_.outer_web_contents();
 
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index aa5700d..c7e5a55a 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -360,7 +360,7 @@
   void AttachToOuterWebContentsFrame(
       std::unique_ptr<WebContents> current_web_contents,
       RenderFrameHost* outer_contents_frame) override;
-  WebContentsImpl* GetOuterWebContents() override;
+  WebContentsImpl* GetOuterWebContents() const override;
   WebContentsImpl* GetOutermostWebContents() override;
   void DidChangeVisibleSecurityState() override;
   void NotifyPreferencesChanged() override;
diff --git a/content/browser/webauth/authenticator_impl.cc b/content/browser/webauth/authenticator_impl.cc
index b6e957e0..00cbfdb9 100644
--- a/content/browser/webauth/authenticator_impl.cc
+++ b/content/browser/webauth/authenticator_impl.cc
@@ -345,11 +345,17 @@
   }
 }
 
+enum class AttestationErasureOption {
+  kIncludeAttestation,
+  kEraseAttestationButIncludeAaguid,
+  kEraseAttestationAndAaguid,
+};
+
 blink::mojom::MakeCredentialAuthenticatorResponsePtr
 CreateMakeCredentialResponse(
     const std::string& client_data_json,
     device::AuthenticatorMakeCredentialResponse response_data,
-    bool preserve_attestation) {
+    AttestationErasureOption attestation_erasure) {
   auto response = blink::mojom::MakeCredentialAuthenticatorResponse::New();
   auto common_info = blink::mojom::CommonCredentialInfo::New();
   common_info->client_data_json.assign(client_data_json.begin(),
@@ -391,8 +397,17 @@
     }
   }
 
-  if (!preserve_attestation) {
-    response_data.EraseAttestationStatement();
+  switch (attestation_erasure) {
+    case AttestationErasureOption::kIncludeAttestation:
+      break;
+    case AttestationErasureOption::kEraseAttestationButIncludeAaguid:
+      response_data.EraseAttestationStatement(
+          device::AttestationObject::AAGUID::kInclude);
+      break;
+    case AttestationErasureOption::kEraseAttestationAndAaguid:
+      response_data.EraseAttestationStatement(
+          device::AttestationObject::AAGUID::kErase);
+      break;
   }
   response->attestation_object =
       response_data.GetCBOREncodedAttestationObject();
@@ -853,13 +868,24 @@
         return;
       }
 
-      const bool include_attestation = response_data->IsSelfAttestation();
+      AttestationErasureOption attestation_erasure =
+          AttestationErasureOption::kEraseAttestationAndAaguid;
+      if (response_data->IsSelfAttestation()) {
+        attestation_erasure = AttestationErasureOption::kIncludeAttestation;
+      } else if (transport_used == device::FidoTransportProtocol::kInternal) {
+        // Contrary to what the WebAuthn spec says, for internal (platform)
+        // authenticators we do not erase the AAGUID from authenticatorData,
+        // even if requested attestationConveyancePreference is "none".
+        attestation_erasure =
+            AttestationErasureOption::kEraseAttestationButIncludeAaguid;
+      }
+
       InvokeCallbackAndCleanup(
           std::move(make_credential_response_callback_),
           blink::mojom::AuthenticatorStatus::SUCCESS,
           CreateMakeCredentialResponse(std::move(client_data_json_),
                                        std::move(*response_data),
-                                       include_attestation),
+                                       attestation_erasure),
           Focus::kDoCheck);
       return;
   }
@@ -891,14 +917,15 @@
 
   UMA_HISTOGRAM_ENUMERATION("WebAuthentication.AttestationPromptResult",
                             AttestationPromptResult::kAllowed);
-  bool include_attestation = true;
+  AttestationErasureOption attestation_erasure =
+      AttestationErasureOption::kIncludeAttestation;
 
   // The check for IsAttestationCertificateInappropriatelyIdentifying is
   // performed after the permissions prompt, even though we know the answer
-  // before, because this still effectively discloses the make & model of the
-  // authenticator: If an RP sees a "none" attestation from Chrome after
-  // requesting direct attestation then it knows that it was one of the tokens
-  // with inappropriate certs.
+  // before, because this still effectively discloses the make & model of
+  // the authenticator: If an RP sees a "none" attestation from Chrome after
+  // requesting direct attestation then it knows that it was one of the
+  // tokens with inappropriate certs.
   if (response_data.IsAttestationCertificateInappropriatelyIdentifying() &&
       !request_delegate_->ShouldPermitIndividualAttestation(
           relying_party_id_)) {
@@ -910,14 +937,14 @@
     // The only way to get the underlying attestation will be to list the RP ID
     // in the enterprise policy, because that enables the individual attestation
     // bit in the register request and permits individual attestation generally.
-    include_attestation = false;
+    attestation_erasure = AttestationErasureOption::kEraseAttestationAndAaguid;
   }
 
   InvokeCallbackAndCleanup(std::move(make_credential_response_callback_),
                            blink::mojom::AuthenticatorStatus::SUCCESS,
                            CreateMakeCredentialResponse(
                                std::move(client_data_json_),
-                               std::move(response_data), include_attestation),
+                               std::move(response_data), attestation_erasure),
                            Focus::kDoCheck);
 }
 
@@ -1115,4 +1142,4 @@
 #endif
 }
 
-}  // namespace content
\ No newline at end of file
+}  // namespace content
diff --git a/content/browser/webauth/authenticator_impl_unittest.cc b/content/browser/webauth/authenticator_impl_unittest.cc
index e62dba6..dc9137d 100644
--- a/content/browser/webauth/authenticator_impl_unittest.cc
+++ b/content/browser/webauth/authenticator_impl_unittest.cc
@@ -55,6 +55,7 @@
 using blink::mojom::AuthenticatorSelectionCriteria;
 using blink::mojom::AuthenticatorSelectionCriteriaPtr;
 using blink::mojom::AuthenticatorStatus;
+using blink::mojom::AuthenticatorTransport;
 using blink::mojom::GetAssertionAuthenticatorResponsePtr;
 using blink::mojom::MakeCredentialAuthenticatorResponsePtr;
 using blink::mojom::PublicKeyCredentialCreationOptions;
@@ -70,9 +71,8 @@
 using blink::mojom::PublicKeyCredentialType;
 using blink::mojom::PublicKeyCredentialUserEntity;
 using blink::mojom::PublicKeyCredentialUserEntityPtr;
-using blink::mojom::AuthenticatorTransport;
-using cbor::Value;
 using cbor::Reader;
+using cbor::Value;
 
 namespace {
 
@@ -1104,8 +1104,10 @@
 enum class AttestationType {
   ANY,
   NONE,
+  NONE_WITH_NONZERO_AAGUID,
   U2F,
   SELF,
+  SELF_WITH_NONZERO_AAGUID,
 };
 
 class TestAuthenticatorRequestDelegate
@@ -1263,6 +1265,14 @@
       ASSERT_TRUE(attestation_value->is_map());
       const auto& attestation = attestation_value->GetMap();
 
+      base::Optional<device::AuthenticatorData> auth_data = base::nullopt;
+      const auto auth_data_it = attestation.find(Value("authData"));
+      if (auth_data_it != attestation.end() &&
+          auth_data_it->second.is_bytestring()) {
+        auth_data = device::AuthenticatorData::DecodeAuthenticatorData(
+            auth_data_it->second.GetBytestring());
+      }
+
       switch (test.expected_attestation) {
         case AttestationType::ANY:
           ASSERT_STREQ("", test.expected_certificate_substring);
@@ -1271,6 +1281,13 @@
         case AttestationType::NONE:
           ASSERT_STREQ("", test.expected_certificate_substring);
           ExpectMapHasKeyWithStringValue(attestation, "fmt", "none");
+          EXPECT_TRUE(auth_data->attested_data()->IsAaguidZero());
+          break;
+
+        case AttestationType::NONE_WITH_NONZERO_AAGUID:
+          ASSERT_STREQ("", test.expected_certificate_substring);
+          ExpectMapHasKeyWithStringValue(attestation, "fmt", "none");
+          EXPECT_FALSE(auth_data->attested_data()->IsAaguidZero());
           break;
 
         case AttestationType::U2F:
@@ -1281,7 +1298,7 @@
           }
           break;
 
-        case AttestationType::SELF:
+        case AttestationType::SELF: {
           ASSERT_STREQ("", test.expected_certificate_substring);
           ExpectMapHasKeyWithStringValue(attestation, "fmt", "packed");
 
@@ -1297,21 +1314,28 @@
                       attestation_statement.end());
           ASSERT_TRUE(attestation_statement.find(Value("ecdaaKeyId")) ==
                       attestation_statement.end());
-
-          // The AAGUID should be all zero.
-          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 =
-              auth_data_it->second.GetBytestring();
-          base::Optional<device::AuthenticatorData> parsed_auth_data =
-              device::AuthenticatorData::DecodeAuthenticatorData(auth_data);
-          ASSERT_TRUE(parsed_auth_data);
-          const base::Optional<device::AttestedCredentialData>& cred_data(
-              parsed_auth_data->attested_data());
-          ASSERT_TRUE(cred_data);
-          EXPECT_TRUE(cred_data->IsAaguidZero());
+          EXPECT_TRUE(auth_data->attested_data()->IsAaguidZero());
           break;
+        }
+        case AttestationType::SELF_WITH_NONZERO_AAGUID: {
+          ASSERT_STREQ("", test.expected_certificate_substring);
+          ExpectMapHasKeyWithStringValue(attestation, "fmt", "packed");
+
+          // A self-attestation should not include an X.509 chain nor ECDAA key.
+          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();
+
+          ASSERT_TRUE(attestation_statement.find(Value("x5c")) ==
+                      attestation_statement.end());
+          ASSERT_TRUE(attestation_statement.find(Value("ecdaaKeyId")) ==
+                      attestation_statement.end());
+          EXPECT_FALSE(auth_data->attested_data()->IsAaguidZero());
+          break;
+        }
       }
     }
   }
@@ -1354,8 +1378,8 @@
         << "', but expected to find '" << expected << "'";
   }
 
-  // Asserts that the webauthn attestation CBOR map in
-  // |attestation| contains a single X.509 certificate containing |substring|.
+  // Asserts that the webauthn attestation CBOR map in |attestation| contains a
+  // single X.509 certificate containing |substring|.
   static void ExpectCertificateContainingSubstring(
       const Value::MapValue& attestation,
       const std::string& substring) {
@@ -1488,8 +1512,8 @@
           IndividualAttestation::NOT_REQUESTED, AttestationConsent::GRANTED,
           AuthenticatorStatus::SUCCESS,
           // If individual attestation was not requested then the attestation
-          // certificate will be removed, even if consent is given, because
-          // the consent isn't to be tracked.
+          // certificate will be removed, even if consent is given, because the
+          // consent isn't to be tracked.
           AttestationType::NONE, "",
       },
       {
@@ -1497,8 +1521,8 @@
           IndividualAttestation::NOT_REQUESTED, AttestationConsent::GRANTED,
           AuthenticatorStatus::SUCCESS,
           // If individual attestation was not requested then the attestation
-          // certificate will be removed, even if consent is given, because
-          // the consent isn't to be tracked.
+          // certificate will be removed, even if consent is given, because the
+          // consent isn't to be tracked.
           AttestationType::NONE, "",
       },
 
@@ -1517,6 +1541,49 @@
   RunTestCases(kTests);
 }
 
+// Test attestation erasure for an authenticator that uses self-attestation
+// (which requires a zero AAGUID), but has a non-zero AAGUID. This mirrors the
+// behavior of the Touch ID platform authenticator.
+TEST_F(AuthenticatorContentBrowserClientTest,
+       PlatformAuthenticatorAttestation) {
+  virtual_device_.SetSupportedProtocol(device::ProtocolVersion::kCtap);
+  virtual_device_.mutable_state()->transport =
+      device::FidoTransportProtocol::kInternal;
+  virtual_device_.mutable_state()->self_attestation = true;
+  virtual_device_.mutable_state()->non_zero_aaguid_with_self_attestation = true;
+  NavigateAndCommit(GURL("https://example.com"));
+
+  const std::vector<TestCase> kTests = {
+      {
+          // Self-attestation is defined as having a zero AAGUID, but
+          // |non_zero_aaguid_with_self_attestation| is set above. Thus, if no
+          // attestation is requested, the self-attestation will be removed but,
+          // because the transport is kInternal, the AAGUID will be preserved.
+          AttestationConveyancePreference::NONE,
+          IndividualAttestation::NOT_REQUESTED, AttestationConsent::DENIED,
+          AuthenticatorStatus::SUCCESS,
+          AttestationType::NONE_WITH_NONZERO_AAGUID, "",
+      },
+      {
+          // If attestation is requested, but denied, we'll still fail the
+          // request.
+          AttestationConveyancePreference::DIRECT,
+          IndividualAttestation::NOT_REQUESTED, AttestationConsent::DENIED,
+          AuthenticatorStatus::NOT_ALLOWED_ERROR, AttestationType::ANY, "",
+      },
+      {
+          // If attestation is requested and granted, the self attestation
+          // will be returned.
+          AttestationConveyancePreference::DIRECT,
+          IndividualAttestation::NOT_REQUESTED, AttestationConsent::GRANTED,
+          AuthenticatorStatus::SUCCESS,
+          AttestationType::SELF_WITH_NONZERO_AAGUID, "",
+      },
+  };
+
+  RunTestCases(kTests);
+}
+
 TEST_F(AuthenticatorContentBrowserClientTest, Ctap2SelfAttestation) {
   virtual_device_.SetSupportedProtocol(device::ProtocolVersion::kCtap);
   virtual_device_.mutable_state()->self_attestation = true;
@@ -1538,8 +1605,8 @@
           AuthenticatorStatus::NOT_ALLOWED_ERROR, AttestationType::ANY, "",
       },
       {
-          // If attestation is requested and granted, the self attestation
-          // will be returned.
+          // If attestation is requested and granted, the self attestation will
+          // be returned.
           AttestationConveyancePreference::DIRECT,
           IndividualAttestation::NOT_REQUESTED, AttestationConsent::GRANTED,
           AuthenticatorStatus::SUCCESS, AttestationType::SELF, "",
@@ -1558,8 +1625,8 @@
 
   const std::vector<TestCase> kTests = {
       {
-          // Since the virtual device is configured to set a non-zero AAGUID
-          // the self-attestation should still be replaced with a "none"
+          // Since the virtual device is configured to set a non-zero AAGUID the
+          // self-attestation should still be replaced with a "none"
           // attestation.
           AttestationConveyancePreference::NONE,
           IndividualAttestation::NOT_REQUESTED, AttestationConsent::DENIED,
diff --git a/content/child/child_process.h b/content/child/child_process.h
index 11c5e200..ff74b61 100644
--- a/content/child/child_process.h
+++ b/content/child/child_process.h
@@ -54,7 +54,6 @@
   // Takes ownership of the pointer.
   void set_main_thread(ChildThreadImpl* thread);
 
-  base::MessageLoop* io_message_loop() { return io_thread_.message_loop(); }
   base::SingleThreadTaskRunner* io_task_runner() {
     return io_thread_.task_runner().get();
   }
diff --git a/content/child/service_factory.cc b/content/child/service_factory.cc
index 5ef1e49..3091031 100644
--- a/content/child/service_factory.cc
+++ b/content/child/service_factory.cc
@@ -15,6 +15,12 @@
 ServiceFactory::ServiceFactory() {}
 ServiceFactory::~ServiceFactory() {}
 
+bool ServiceFactory::HandleServiceRequest(
+    const std::string& name,
+    service_manager::mojom::ServiceRequest request) {
+  return false;
+}
+
 void ServiceFactory::CreateService(
     service_manager::mojom::ServiceRequest request,
     const std::string& name,
@@ -36,17 +42,20 @@
   }
 
   auto it = services_.find(name);
-  if (it == services_.end()) {
-    // DCHECK in developer builds to make these errors easier to identify.
-    // Otherwise they result only in cryptic browser error messages.
-    NOTREACHED() << "Unable to start service \"" << name << "\". Did you "
-                 << "forget to register the service in the utility process's"
-                 << "ServiceFactory?";
-    OnLoadFailed();
+  if (it != services_.end()) {
+    it->second->BindServiceRequest(std::move(request));
     return;
   }
 
-  it->second->BindServiceRequest(std::move(request));
+  if (HandleServiceRequest(name, std::move(request)))
+    return;
+
+  // DCHECK in developer builds to make these errors easier to identify.
+  // Otherwise they result only in cryptic browser error messages.
+  NOTREACHED() << "Unable to start service \"" << name << "\". Did you "
+               << "forget to register the service in the utility process's"
+               << "ServiceFactory?";
+  OnLoadFailed();
 }
 
 }  // namespace content
diff --git a/content/child/service_factory.h b/content/child/service_factory.h
index 8b71f4f9..5dae5f7 100644
--- a/content/child/service_factory.h
+++ b/content/child/service_factory.h
@@ -30,6 +30,9 @@
   ~ServiceFactory() override;
 
   virtual void RegisterServices(ServiceMap* services) = 0;
+  virtual bool HandleServiceRequest(
+      const std::string& name,
+      service_manager::mojom::ServiceRequest request);
   virtual void OnServiceQuit() {}
 
   // service_manager::mojom::ServiceFactory:
diff --git a/content/public/android/java/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityImpl.java b/content/public/android/java/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityImpl.java
index 70c745903..cd9a2e2 100644
--- a/content/public/android/java/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityImpl.java
@@ -946,7 +946,9 @@
 
     @CalledByNative
     private void handleSliderChanged(int id) {
-        sendAccessibilityEvent(id, AccessibilityEvent.TYPE_VIEW_SCROLLED);
+        // Sending a TYPE_VIEW_SELECTED event triggers talkback to report new
+        // slider value
+        sendAccessibilityEvent(id, AccessibilityEvent.TYPE_VIEW_SELECTED);
     }
 
     @CalledByNative
diff --git a/content/public/browser/browser_child_process_host.h b/content/public/browser/browser_child_process_host.h
index d3e1193..b034936 100644
--- a/content/public/browser/browser_child_process_host.h
+++ b/content/public/browser/browser_child_process_host.h
@@ -8,7 +8,7 @@
 #include "base/environment.h"
 #include "base/memory/shared_memory.h"
 #include "base/process/kill.h"
-#include "base/process/process_handle.h"
+#include "base/process/process.h"
 #include "base/strings/string16.h"
 #include "build/build_config.h"
 #include "content/common/content_export.h"
@@ -86,12 +86,11 @@
   // Sets the name of the process used for metrics reporting.
   virtual void SetMetricsName(const std::string& metrics_name) = 0;
 
-  // Set the handle of the process. BrowserChildProcessHost will do this when
-  // the Launch method is used to start the process. However if the owner
-  // of this object doesn't call Launch and starts the process in another way,
-  // they need to call this method so that the process handle is associated with
-  // this object.
-  virtual void SetHandle(base::ProcessHandle handle) = 0;
+  // Set the process. BrowserChildProcessHost will do this when the Launch
+  // method is used to start the process. However if the owner of this object
+  // doesn't call Launch and starts the process in another way, they need to
+  // call this method so that the process is associated with this object.
+  virtual void SetProcess(base::Process process) = 0;
 
   // Takes the ServiceRequest pipe away from this host. Use this only if you
   // intend to forego process launch and use the ServiceRequest in-process
diff --git a/content/public/browser/child_process_data.cc b/content/public/browser/child_process_data.cc
index 69399bd6..e8f16b5 100644
--- a/content/public/browser/child_process_data.cc
+++ b/content/public/browser/child_process_data.cc
@@ -4,43 +4,12 @@
 
 #include "content/public/browser/child_process_data.h"
 
-#if defined(OS_WIN)
-#include <Windows.h>
-#endif
-
 namespace content {
 
-#if defined(OS_WIN)
-void ChildProcessData::SetHandle(base::ProcessHandle process) {
-  HANDLE handle_to_set;
-  if (process == base::kNullProcessHandle) {
-    handle_to_set = base::kNullProcessHandle;
-  } else {
-    BOOL result =
-        ::DuplicateHandle(::GetCurrentProcess(), process, ::GetCurrentProcess(),
-                          &handle_to_set, 0, FALSE, DUPLICATE_SAME_ACCESS);
-    auto err = GetLastError();
-    CHECK(result) << process << " " << err;
-  }
-  handle_ = base::win::ScopedHandle(handle_to_set);
-}
-#endif
-
 ChildProcessData::ChildProcessData(int process_type)
-    : process_type(process_type), id(0), handle_(base::kNullProcessHandle) {}
+    : process_type(process_type) {}
 
-ChildProcessData::ChildProcessData(ChildProcessData&& rhs)
-    : process_type(rhs.process_type),
-      name(rhs.name),
-      metrics_name(rhs.metrics_name),
-      id(rhs.id) {
-#if defined(OS_WIN)
-  handle_.Set(rhs.handle_.Take());
-#else
-  handle_ = rhs.handle_;
-  rhs.handle_ = base::kNullProcessHandle;
-#endif
-}
+ChildProcessData::ChildProcessData(ChildProcessData&& rhs) = default;
 
 ChildProcessData::~ChildProcessData() {}
 
@@ -49,11 +18,7 @@
   result.name = name;
   result.metrics_name = metrics_name;
   result.id = id;
-#if defined(OS_WIN)
-  result.SetHandle(handle_.Get());
-#else
-  result.SetHandle(handle_);
-#endif
+  result.SetProcess(process_.Duplicate());
   return result;
 }
 
diff --git a/content/public/browser/child_process_data.h b/content/public/browser/child_process_data.h
index 3e8d6760..5848f90 100644
--- a/content/public/browser/child_process_data.h
+++ b/content/public/browser/child_process_data.h
@@ -7,13 +7,8 @@
 
 #include "base/process/process.h"
 #include "base/strings/string16.h"
-#include "build/build_config.h"
 #include "content/common/content_export.h"
 
-#if defined(OS_WIN)
-#include "base/win/scoped_handle.h"
-#endif
-
 namespace content {
 
 // Holds information about a child process.
@@ -32,18 +27,11 @@
   // The unique identifier for this child process. This identifier is NOT a
   // process ID, and will be unique for all types of child process for
   // one run of the browser.
-  int id;
+  int id = 0;
 
-#if defined(OS_WIN)
-  base::ProcessHandle GetHandle() const { return handle_.Get(); }
-  // Will duplicate the handle and assume ownership of the duplicate.
-  void SetHandle(base::ProcessHandle process);
-#else
-  base::ProcessHandle GetHandle() const { return handle_; }
-  void SetHandle(base::ProcessHandle process) { handle_ = process; }
-#endif
-
-  bool IsHandleValid() const { return GetHandle() != base::kNullProcessHandle; }
+  const base::Process& GetProcess() const { return process_; }
+  // Since base::Process is non-copyable, the caller has to provide a rvalue.
+  void SetProcess(base::Process process) { process_ = std::move(process); }
 
   explicit ChildProcessData(int process_type);
   ~ChildProcessData();
@@ -55,16 +43,8 @@
   ChildProcessData Duplicate() const;
 
  private:
-// The handle to the process. May have value kNullProcessHandle if no process
-// exists - either because it hasn't been started yet or it's running in the
-// current process.
-#if defined(OS_WIN)
-  // Must be a scoped handle on Windows holding a duplicated handle or else
-  // there are no guarantees the handle will still be valid when used.
-  base::win::ScopedHandle handle_;
-#else
-  base::ProcessHandle handle_;
-#endif
+  // May be invalid if the process isn't started or is the current process.
+  base::Process process_;
 };
 
 }  // namespace content
diff --git a/content/public/browser/guest_mode.cc b/content/public/browser/guest_mode.cc
index 7e8a6dd..5d8e746 100644
--- a/content/public/browser/guest_mode.cc
+++ b/content/public/browser/guest_mode.cc
@@ -14,9 +14,10 @@
 namespace content {
 
 // static
-bool GuestMode::IsCrossProcessFrameGuest(WebContents* web_contents) {
+bool GuestMode::IsCrossProcessFrameGuest(const WebContents* web_contents) {
   BrowserPluginGuest* browser_plugin_guest =
-      static_cast<WebContentsImpl*>(web_contents)->GetBrowserPluginGuest();
+      static_cast<const WebContentsImpl*>(web_contents)
+          ->GetBrowserPluginGuest();
 
   if (!browser_plugin_guest ||
       !browser_plugin_guest->can_use_cross_process_frames()) {
diff --git a/content/public/browser/guest_mode.h b/content/public/browser/guest_mode.h
index 058f280..47dd5e3 100644
--- a/content/public/browser/guest_mode.h
+++ b/content/public/browser/guest_mode.h
@@ -16,7 +16,7 @@
  public:
   // Returns true if |web_contents| is an inner WebContents based on cross
   // process frames.
-  static bool IsCrossProcessFrameGuest(WebContents* web_contents);
+  static bool IsCrossProcessFrameGuest(const WebContents* web_contents);
 
  private:
   GuestMode();
diff --git a/content/public/browser/web_contents.h b/content/public/browser/web_contents.h
index c3b7c35..e3befb2 100644
--- a/content/public/browser/web_contents.h
+++ b/content/public/browser/web_contents.h
@@ -535,7 +535,7 @@
 
   // Returns the outer WebContents of this WebContents if any.
   // Otherwise, return nullptr.
-  virtual WebContents* GetOuterWebContents() = 0;
+  virtual WebContents* GetOuterWebContents() const = 0;
 
   // Returns the root WebContents of the WebContents tree. Always returns
   // non-null value.
diff --git a/content/public/test/browser_test_base.cc b/content/public/test/browser_test_base.cc
index 7283df0..c795143 100644
--- a/content/public/test/browser_test_base.cc
+++ b/content/public/test/browser_test_base.cc
@@ -458,16 +458,15 @@
   CHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
       switches::kSingleProcess));
 
-  scoped_refptr<MessageLoopRunner> runner = new MessageLoopRunner;
+  scoped_refptr<base::SingleThreadTaskRunner> renderer_task_runner =
+      RenderProcessHostImpl::GetInProcessRendererThreadTaskRunnerForTesting();
+  CHECK(renderer_task_runner);
 
-  base::MessageLoop* renderer_loop =
-      RenderProcessHostImpl::GetInProcessRendererThreadForTesting();
-  CHECK(renderer_loop);
-
-  renderer_loop->task_runner()->PostTask(
+  base::RunLoop run_loop;
+  renderer_task_runner->PostTask(
       FROM_HERE,
-      base::BindOnce(&RunTaskOnRendererThread, task, runner->QuitClosure()));
-  runner->Run();
+      base::BindOnce(&RunTaskOnRendererThread, task, run_loop.QuitClosure()));
+  run_loop.Run();
 }
 
 void BrowserTestBase::EnablePixelOutput() { enable_pixel_output_ = true; }
diff --git a/content/renderer/media/stream/media_stream_constraints_util.cc b/content/renderer/media/stream/media_stream_constraints_util.cc
index bbcd6b96..3652c2c 100644
--- a/content/renderer/media/stream/media_stream_constraints_util.cc
+++ b/content/renderer/media/stream/media_stream_constraints_util.cc
@@ -259,13 +259,18 @@
     const blink::WebMediaTrackConstraintSet& basic_constraint_set,
     const media_constraints::ResolutionSet& resolution_set,
     const media_constraints::NumericRangeSet<double>& frame_rate_set,
-    const media::VideoCaptureFormat& source_format) {
-  media_constraints::ResolutionSet::Point resolution =
-      resolution_set.SelectClosestPointToIdeal(
-          basic_constraint_set, source_format.frame_size.height(),
-          source_format.frame_size.width());
-  int track_max_height = static_cast<int>(std::round(resolution.height()));
-  int track_max_width = static_cast<int>(std::round(resolution.width()));
+    const media::VideoCaptureFormat& source_format,
+    bool enable_rescale) {
+  base::Optional<gfx::Size> target_resolution;
+  if (enable_rescale) {
+    media_constraints::ResolutionSet::Point resolution =
+        resolution_set.SelectClosestPointToIdeal(
+            basic_constraint_set, source_format.frame_size.height(),
+            source_format.frame_size.width());
+    int track_target_height = static_cast<int>(std::round(resolution.height()));
+    int track_target_width = static_cast<int>(std::round(resolution.width()));
+    target_resolution = gfx::Size(track_target_width, track_target_height);
+  }
   double track_min_aspect_ratio =
       std::max(resolution_set.min_aspect_ratio(),
                static_cast<double>(resolution_set.min_width()) /
@@ -290,9 +295,9 @@
   if (track_max_frame_rate >= source_format.frame_rate)
     track_max_frame_rate = 0.0;
 
-  return VideoTrackAdapterSettings(
-      gfx::Size(track_max_width, track_max_height), track_min_aspect_ratio,
-      track_max_aspect_ratio, track_max_frame_rate);
+  return VideoTrackAdapterSettings(target_resolution, track_min_aspect_ratio,
+                                   track_max_aspect_ratio,
+                                   track_max_frame_rate);
 }
 
 double NumericConstraintFitnessDistance(double value1, double value2) {
diff --git a/content/renderer/media/stream/media_stream_constraints_util.h b/content/renderer/media/stream/media_stream_constraints_util.h
index 1abf655..ca74d75 100644
--- a/content/renderer/media/stream/media_stream_constraints_util.h
+++ b/content/renderer/media/stream/media_stream_constraints_util.h
@@ -230,7 +230,7 @@
 // Method to get boolean value of constraint with |name| from constraints.
 // Returns true if the constraint is specified in either mandatory or optional
 // constraints.
-bool CONTENT_EXPORT GetConstraintValueAsBoolean(
+CONTENT_EXPORT bool GetConstraintValueAsBoolean(
     const blink::WebMediaConstraints& constraints,
     const blink::BooleanConstraint blink::WebMediaTrackConstraintSet::*picker,
     bool* value);
@@ -238,17 +238,17 @@
 // Method to get int value of constraint with |name| from constraints.
 // Returns true if the constraint is specified in either mandatory or Optional
 // constraints.
-bool CONTENT_EXPORT GetConstraintValueAsInteger(
+CONTENT_EXPORT bool GetConstraintValueAsInteger(
     const blink::WebMediaConstraints& constraints,
     const blink::LongConstraint blink::WebMediaTrackConstraintSet::*picker,
     int* value);
 
-bool CONTENT_EXPORT GetConstraintMinAsInteger(
+CONTENT_EXPORT bool GetConstraintMinAsInteger(
     const blink::WebMediaConstraints& constraints,
     const blink::LongConstraint blink::WebMediaTrackConstraintSet::*picker,
     int* value);
 
-bool CONTENT_EXPORT GetConstraintMaxAsInteger(
+CONTENT_EXPORT bool GetConstraintMaxAsInteger(
     const blink::WebMediaConstraints& constraints,
     const blink::LongConstraint blink::WebMediaTrackConstraintSet::*picker,
     int* value);
@@ -256,17 +256,17 @@
 // Method to get double precision value of constraint with |name| from
 // constraints. Returns true if the constraint is specified in either mandatory
 // or Optional constraints.
-bool CONTENT_EXPORT GetConstraintValueAsDouble(
+CONTENT_EXPORT bool GetConstraintValueAsDouble(
     const blink::WebMediaConstraints& constraints,
     const blink::DoubleConstraint blink::WebMediaTrackConstraintSet::*picker,
     double* value);
 
-bool CONTENT_EXPORT GetConstraintMinAsDouble(
+CONTENT_EXPORT bool GetConstraintMinAsDouble(
     const blink::WebMediaConstraints& constraints,
     const blink::DoubleConstraint blink::WebMediaTrackConstraintSet::*picker,
     double* value);
 
-bool CONTENT_EXPORT GetConstraintMaxAsDouble(
+CONTENT_EXPORT bool GetConstraintMaxAsDouble(
     const blink::WebMediaConstraints& constraints,
     const blink::DoubleConstraint blink::WebMediaTrackConstraintSet::*picker,
     double* value);
@@ -274,7 +274,7 @@
 // Method to get std::string value of constraint with |name| from constraints.
 // Returns true if the constraint is specified in either mandatory or Optional
 // constraints.
-bool CONTENT_EXPORT GetConstraintValueAsString(
+CONTENT_EXPORT bool GetConstraintValueAsString(
     const blink::WebMediaConstraints& constraints,
     const blink::StringConstraint blink::WebMediaTrackConstraintSet::*picker,
     std::string* value);
@@ -322,30 +322,34 @@
 // This function selects track settings from a set of candidate resolutions and
 // frame rates, given the source video-capture format and ideal values.
 // The output are settings for a VideoTrackAdapter, which can adjust the
-// resolution and frame rate of the source, and consist of maximum (or
-// target) width, height and frame rate, and minimum and maximum aspect ratio.
+// resolution and frame rate of the source, and consist of
+// target width, height and frame rate, and minimum and maximum aspect ratio.
 // * Minimum and maximum aspect ratios are taken from |resolution_set| and are
 //   not affected by ideal values.
 // * The selected frame rate is always the value within the |frame_rate_set|
-//   range that is closest to the ideal frame rate (or the source frame rate
-//   if no ideal is supplied). If the chosen frame rate is greater than or equal
-//   to the source's frame rate, a value of 0.0 is returned, which means that
-//   there will be no frame-rate adjustment.
-// * Width and height are selected using the
-//   ResolutionSet::SelectClosestPointToIdeal function, using ideal values from
+//   range that is closest to the ideal frame rate (or closest to the source
+//   frame rate if no ideal is supplied). If the chosen frame rate is greater
+//   than or equal to the source's frame rate, a value of 0.0 is returned, which
+//   means that there will be no frame-rate adjustment.
+// * If |enable_rescale| is false, no target width and height are computed.
+// * If |enable_rescale| is true, the target width and height are selected using
+//   the ResolutionSet::SelectClosestPointToIdeal function, using ideal values
+//   for the width, height and aspectRatio properties from
 //   |basic_constraint_set| and using the source's width and height as the
 //   default resolution. The width and height returned by
 //   SelectClosestPointToIdeal are rounded to the nearest int. For more details,
 //   see the documentation for ResolutionSet::SelectClosestPointToIdeal.
 // Note that this function ignores the min/max/exact values from
-// |basic_constraint_set|. Only its ideal values are used.
+// |basic_constraint_set|. Only the ideal values for the width, height,
+// aspectRatio and frameRate are used.
 // This function has undefined behavior if any of |resolution_set| or
 // |frame_rate_set| are empty.
-VideoTrackAdapterSettings CONTENT_EXPORT SelectVideoTrackAdapterSettings(
+CONTENT_EXPORT VideoTrackAdapterSettings SelectVideoTrackAdapterSettings(
     const blink::WebMediaTrackConstraintSet& basic_constraint_set,
     const media_constraints::ResolutionSet& resolution_set,
     const media_constraints::NumericRangeSet<double>& frame_rate_set,
-    const media::VideoCaptureFormat& source_format);
+    const media::VideoCaptureFormat& source_format,
+    bool enable_rescale);
 
 // Generic distance function between two values for numeric constraints. Based
 // on the fitness-distance function described in
@@ -360,7 +364,7 @@
 
 // This method computes capabilities for a video source based on the given
 // |formats|. |facing_mode| is valid only in case of video device capture.
-blink::WebMediaStreamSource::Capabilities CONTENT_EXPORT
+CONTENT_EXPORT blink::WebMediaStreamSource::Capabilities
 ComputeCapabilitiesForVideoSource(
     const blink::WebString& device_id,
     const media::VideoCaptureFormats& formats,
diff --git a/content/renderer/media/stream/media_stream_constraints_util_unittest.cc b/content/renderer/media/stream/media_stream_constraints_util_unittest.cc
index 5f81668..a7a53cf2 100644
--- a/content/renderer/media/stream/media_stream_constraints_util_unittest.cc
+++ b/content/renderer/media/stream/media_stream_constraints_util_unittest.cc
@@ -10,6 +10,8 @@
 #include "content/renderer/media/stream/mock_constraint_factory.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+namespace content {
+
 namespace {
 
 const int kSourceHeight = 1000;
@@ -18,15 +20,21 @@
     static_cast<double>(kSourceWidth) / static_cast<double>(kSourceHeight);
 constexpr double kSourceFrameRate = 100.0;
 
-media::VideoCaptureFormat SourceFormat() {
-  return media::VideoCaptureFormat(gfx::Size(kSourceWidth, kSourceHeight),
-                                   kSourceFrameRate, media::PIXEL_FORMAT_I420);
+VideoTrackAdapterSettings SelectTrackSettings(
+    const blink::WebMediaTrackConstraintSet& basic_constraint_set,
+    const media_constraints::ResolutionSet& resolution_set,
+    const media_constraints::NumericRangeSet<double>& frame_rate_set,
+    bool enable_rescale = true) {
+  media::VideoCaptureFormat source_format(
+      gfx::Size(kSourceWidth, kSourceHeight), kSourceFrameRate,
+      media::PIXEL_FORMAT_I420);
+  return SelectVideoTrackAdapterSettings(basic_constraint_set, resolution_set,
+                                         frame_rate_set, source_format,
+                                         enable_rescale);
 }
 
 }  // namespace
 
-namespace content {
-
 class MediaStreamConstraintsUtilTest : public testing::Test {
  protected:
   using DoubleRangeSet = media_constraints::NumericRangeSet<double>;
@@ -124,9 +132,9 @@
   // No ideal values.
   {
     MockConstraintFactory constraint_factory;
-    auto result = SelectVideoTrackAdapterSettings(
+    auto result = SelectTrackSettings(
         constraint_factory.CreateWebMediaConstraints().Basic(), resolution_set,
-        frame_rate_set, SourceFormat());
+        frame_rate_set);
     EXPECT_EQ(kSourceHeight, result.target_height());
     EXPECT_EQ(kSourceWidth, result.target_width());
     EXPECT_EQ(0.0, result.min_aspect_ratio());
@@ -139,9 +147,9 @@
     const int kIdealHeight = 400;
     MockConstraintFactory constraint_factory;
     constraint_factory.basic().height.SetIdeal(kIdealHeight);
-    auto result = SelectVideoTrackAdapterSettings(
+    auto result = SelectTrackSettings(
         constraint_factory.CreateWebMediaConstraints().Basic(), resolution_set,
-        frame_rate_set, SourceFormat());
+        frame_rate_set);
     EXPECT_EQ(kIdealHeight, result.target_height());
     EXPECT_EQ(std::round(kIdealHeight * kSourceAspectRatio),
               result.target_width());
@@ -155,9 +163,9 @@
     const int kIdealWidth = 400;
     MockConstraintFactory constraint_factory;
     constraint_factory.basic().width.SetIdeal(kIdealWidth);
-    auto result = SelectVideoTrackAdapterSettings(
+    auto result = SelectTrackSettings(
         constraint_factory.CreateWebMediaConstraints().Basic(), resolution_set,
-        frame_rate_set, SourceFormat());
+        frame_rate_set);
     EXPECT_EQ(std::round(kIdealWidth / kSourceAspectRatio),
               result.target_height());
     EXPECT_EQ(kIdealWidth, result.target_width());
@@ -171,9 +179,9 @@
     const double kIdealAspectRatio = 2.0;
     MockConstraintFactory constraint_factory;
     constraint_factory.basic().aspect_ratio.SetIdeal(kIdealAspectRatio);
-    auto result = SelectVideoTrackAdapterSettings(
+    auto result = SelectTrackSettings(
         constraint_factory.CreateWebMediaConstraints().Basic(), resolution_set,
-        frame_rate_set, SourceFormat());
+        frame_rate_set);
     EXPECT_EQ(kSourceHeight, result.target_height());
     EXPECT_EQ(std::round(kSourceHeight * kIdealAspectRatio),
               result.target_width());
@@ -187,9 +195,9 @@
     const double kIdealFrameRate = 33;
     MockConstraintFactory constraint_factory;
     constraint_factory.basic().frame_rate.SetIdeal(kIdealFrameRate);
-    auto result = SelectVideoTrackAdapterSettings(
+    auto result = SelectTrackSettings(
         constraint_factory.CreateWebMediaConstraints().Basic(), resolution_set,
-        frame_rate_set, SourceFormat());
+        frame_rate_set);
     EXPECT_EQ(kSourceHeight, result.target_height());
     EXPECT_EQ(kSourceWidth, result.target_width());
     EXPECT_EQ(0.0, result.min_aspect_ratio());
@@ -209,9 +217,9 @@
     // Ideal aspect ratio is ignored if ideal width and height are supplied.
     constraint_factory.basic().aspect_ratio.SetIdeal(kIdealAspectRatio);
     constraint_factory.basic().frame_rate.SetIdeal(kIdealFrameRate);
-    auto result = SelectVideoTrackAdapterSettings(
+    auto result = SelectTrackSettings(
         constraint_factory.CreateWebMediaConstraints().Basic(), resolution_set,
-        frame_rate_set, SourceFormat());
+        frame_rate_set);
     EXPECT_EQ(kIdealHeight, result.target_height());
     EXPECT_EQ(kIdealWidth, result.target_width());
     EXPECT_EQ(0.0, result.min_aspect_ratio());
@@ -221,6 +229,9 @@
 }
 
 TEST_F(MediaStreamConstraintsUtilTest, VideoTrackAdapterSettingsConstrained) {
+  // Constraints are expressed by the limits in |resolution_set| and
+  // |frame_rate_set|. WebMediaTrackConstraints objects in this test are used
+  // only to express ideal values.
   const int kMinHeight = 500;
   const int kMaxHeight = 1200;
   const int kMinWidth = 1000;
@@ -236,9 +247,9 @@
   // No ideal values.
   {
     MockConstraintFactory constraint_factory;
-    auto result = SelectVideoTrackAdapterSettings(
+    auto result = SelectTrackSettings(
         constraint_factory.CreateWebMediaConstraints().Basic(), resolution_set,
-        frame_rate_set, SourceFormat());
+        frame_rate_set);
     EXPECT_EQ(kSourceHeight, result.target_height());
     EXPECT_EQ(kSourceWidth, result.target_width());
     EXPECT_EQ(kMinAspectRatio, result.min_aspect_ratio());
@@ -253,9 +264,9 @@
                   "kIdealHeight must be less than kMinHeight");
     MockConstraintFactory constraint_factory;
     constraint_factory.basic().height.SetIdeal(kIdealHeight);
-    auto result = SelectVideoTrackAdapterSettings(
+    auto result = SelectTrackSettings(
         constraint_factory.CreateWebMediaConstraints().Basic(), resolution_set,
-        frame_rate_set, SourceFormat());
+        frame_rate_set);
     EXPECT_EQ(kMinHeight, result.target_height());
     // kMinWidth > kMinHeight * kNativeAspectRatio
     EXPECT_EQ(kMinWidth, result.target_width());
@@ -273,9 +284,9 @@
                   "kIdealHeight must be less than kMaxHeight");
     MockConstraintFactory constraint_factory;
     constraint_factory.basic().height.SetIdeal(kIdealHeight);
-    auto result = SelectVideoTrackAdapterSettings(
+    auto result = SelectTrackSettings(
         constraint_factory.CreateWebMediaConstraints().Basic(), resolution_set,
-        frame_rate_set, SourceFormat());
+        frame_rate_set);
     EXPECT_EQ(kIdealHeight, result.target_height());
     EXPECT_EQ(std::round(kIdealHeight * kSourceAspectRatio),
               result.target_width());
@@ -291,9 +302,9 @@
                   "kIdealHeight must be greater than kMaxHeight");
     MockConstraintFactory constraint_factory;
     constraint_factory.basic().height.SetIdeal(kIdealHeight);
-    auto result = SelectVideoTrackAdapterSettings(
+    auto result = SelectTrackSettings(
         constraint_factory.CreateWebMediaConstraints().Basic(), resolution_set,
-        frame_rate_set, SourceFormat());
+        frame_rate_set);
     EXPECT_EQ(kMaxHeight, result.target_height());
     EXPECT_EQ(std::round(kMaxHeight * kSourceAspectRatio),
               result.target_width());
@@ -309,9 +320,9 @@
                   "kIdealWidth must be less than kMinWidth");
     MockConstraintFactory constraint_factory;
     constraint_factory.basic().width.SetIdeal(kIdealWidth);
-    auto result = SelectVideoTrackAdapterSettings(
+    auto result = SelectTrackSettings(
         constraint_factory.CreateWebMediaConstraints().Basic(), resolution_set,
-        frame_rate_set, SourceFormat());
+        frame_rate_set);
     EXPECT_EQ(std::round(kMinWidth / kSourceAspectRatio),
               result.target_height());
     EXPECT_EQ(kMinWidth, result.target_width());
@@ -329,9 +340,9 @@
                   "kIdealWidth must be less than kMaxWidth");
     MockConstraintFactory constraint_factory;
     constraint_factory.basic().width.SetIdeal(kIdealWidth);
-    auto result = SelectVideoTrackAdapterSettings(
+    auto result = SelectTrackSettings(
         constraint_factory.CreateWebMediaConstraints().Basic(), resolution_set,
-        frame_rate_set, SourceFormat());
+        frame_rate_set);
     EXPECT_EQ(std::round(kIdealWidth / kSourceAspectRatio),
               result.target_height());
     EXPECT_EQ(kIdealWidth, result.target_width());
@@ -347,9 +358,9 @@
                   "kIdealWidth must be greater than kMaxWidth");
     MockConstraintFactory constraint_factory;
     constraint_factory.basic().width.SetIdeal(kIdealWidth);
-    auto result = SelectVideoTrackAdapterSettings(
+    auto result = SelectTrackSettings(
         constraint_factory.CreateWebMediaConstraints().Basic(), resolution_set,
-        frame_rate_set, SourceFormat());
+        frame_rate_set);
     // kMaxHeight < kMaxWidth / kNativeAspectRatio
     EXPECT_EQ(kMaxHeight, result.target_height());
     EXPECT_EQ(kMaxWidth, result.target_width());
@@ -365,9 +376,9 @@
                   "kIdealAspectRatio must be less than kMinAspectRatio");
     MockConstraintFactory constraint_factory;
     constraint_factory.basic().aspect_ratio.SetIdeal(kIdealAspectRatio);
-    auto result = SelectVideoTrackAdapterSettings(
+    auto result = SelectTrackSettings(
         constraint_factory.CreateWebMediaConstraints().Basic(), resolution_set,
-        frame_rate_set, SourceFormat());
+        frame_rate_set);
     // Desired point is (kNativeWidth/kMinAspectRatio, kNativeWidth), but it
     // is outside the size constraints. Closest to that while maintaining the
     // same aspect ratio is (kMaxHeight, kMaxHeight * kMinAspectRatio).
@@ -387,9 +398,9 @@
                   "kIdealAspectRatio must be less than kMaxAspectRatio");
     MockConstraintFactory constraint_factory;
     constraint_factory.basic().aspect_ratio.SetIdeal(kIdealAspectRatio);
-    auto result = SelectVideoTrackAdapterSettings(
+    auto result = SelectTrackSettings(
         constraint_factory.CreateWebMediaConstraints().Basic(), resolution_set,
-        frame_rate_set, SourceFormat());
+        frame_rate_set);
     EXPECT_EQ(std::round(kSourceWidth / kIdealAspectRatio),
               result.target_height());
     EXPECT_EQ(kSourceWidth, result.target_width());
@@ -405,9 +416,9 @@
                   "kIdealAspectRatio must be greater than kMaxAspectRatio");
     MockConstraintFactory constraint_factory;
     constraint_factory.basic().aspect_ratio.SetIdeal(kIdealAspectRatio);
-    auto result = SelectVideoTrackAdapterSettings(
+    auto result = SelectTrackSettings(
         constraint_factory.CreateWebMediaConstraints().Basic(), resolution_set,
-        frame_rate_set, SourceFormat());
+        frame_rate_set);
     EXPECT_EQ(kSourceHeight, result.target_height());
     EXPECT_EQ(std::round(kSourceHeight * kMaxAspectRatio),
               result.target_width());
@@ -423,9 +434,9 @@
                   "kIdealFrameRate must be less than kMinFrameRate");
     MockConstraintFactory constraint_factory;
     constraint_factory.basic().frame_rate.SetIdeal(kIdealFrameRate);
-    auto result = SelectVideoTrackAdapterSettings(
+    auto result = SelectTrackSettings(
         constraint_factory.CreateWebMediaConstraints().Basic(), resolution_set,
-        frame_rate_set, SourceFormat());
+        frame_rate_set);
     EXPECT_EQ(kSourceHeight, result.target_height());
     EXPECT_EQ(kSourceWidth, result.target_width());
     EXPECT_EQ(kMinAspectRatio, result.min_aspect_ratio());
@@ -442,9 +453,9 @@
                   "kIdealFrameRate must be less than kMaxFrameRate");
     MockConstraintFactory constraint_factory;
     constraint_factory.basic().frame_rate.SetIdeal(kIdealFrameRate);
-    auto result = SelectVideoTrackAdapterSettings(
+    auto result = SelectTrackSettings(
         constraint_factory.CreateWebMediaConstraints().Basic(), resolution_set,
-        frame_rate_set, SourceFormat());
+        frame_rate_set);
     EXPECT_EQ(kSourceHeight, result.target_height());
     EXPECT_EQ(kSourceWidth, result.target_width());
     EXPECT_EQ(kMinAspectRatio, result.min_aspect_ratio());
@@ -459,9 +470,9 @@
                   "kIdealFrameRate must be greater than kMaxFrameRate");
     MockConstraintFactory constraint_factory;
     constraint_factory.basic().frame_rate.SetIdeal(kIdealFrameRate);
-    auto result = SelectVideoTrackAdapterSettings(
+    auto result = SelectTrackSettings(
         constraint_factory.CreateWebMediaConstraints().Basic(), resolution_set,
-        frame_rate_set, SourceFormat());
+        frame_rate_set);
     EXPECT_EQ(kSourceHeight, result.target_height());
     EXPECT_EQ(kSourceWidth, result.target_width());
     EXPECT_EQ(kMinAspectRatio, result.min_aspect_ratio());
@@ -490,9 +501,9 @@
     constraint_factory.basic().height.SetIdeal(kIdealHeight);
     constraint_factory.basic().width.SetIdeal(kIdealWidth);
     constraint_factory.basic().frame_rate.SetIdeal(kIdealFrameRate);
-    auto result = SelectVideoTrackAdapterSettings(
+    auto result = SelectTrackSettings(
         constraint_factory.CreateWebMediaConstraints().Basic(), resolution_set,
-        frame_rate_set, SourceFormat());
+        frame_rate_set);
     EXPECT_EQ(kIdealHeight, result.target_height());
     EXPECT_EQ(kIdealWidth, result.target_width());
     EXPECT_EQ(kMinAspectRatio, result.min_aspect_ratio());
@@ -515,9 +526,9 @@
     constraint_factory.basic().height.SetIdeal(kIdealHeight);
     constraint_factory.basic().width.SetIdeal(kIdealWidth);
     constraint_factory.basic().frame_rate.SetIdeal(kIdealFrameRate);
-    auto result = SelectVideoTrackAdapterSettings(
+    auto result = SelectTrackSettings(
         constraint_factory.CreateWebMediaConstraints().Basic(), resolution_set,
-        frame_rate_set, SourceFormat());
+        frame_rate_set);
     EXPECT_EQ(kMaxHeight, result.target_height());
     EXPECT_EQ(kMaxWidth, result.target_width());
     EXPECT_EQ(kMinAspectRatio, result.min_aspect_ratio());
@@ -529,9 +540,9 @@
   {
     DoubleRangeSet frame_rate_set(kMinFrameRate, kSourceFrameRate);
     MockConstraintFactory constraint_factory;
-    auto result = SelectVideoTrackAdapterSettings(
+    auto result = SelectTrackSettings(
         constraint_factory.CreateWebMediaConstraints().Basic(), resolution_set,
-        frame_rate_set, SourceFormat());
+        frame_rate_set);
     EXPECT_EQ(kSourceHeight, result.target_height());
     EXPECT_EQ(kSourceWidth, result.target_width());
     EXPECT_EQ(kMinAspectRatio, result.min_aspect_ratio());
@@ -548,9 +559,9 @@
     static_assert(kHighFrameRate > kSourceFrameRate,
                   "kIdealFrameRate must be greater than kSourceFrameRate");
     MockConstraintFactory constraint_factory;
-    auto result = SelectVideoTrackAdapterSettings(
+    auto result = SelectTrackSettings(
         constraint_factory.CreateWebMediaConstraints().Basic(), resolution_set,
-        frame_rate_set, SourceFormat());
+        frame_rate_set);
     EXPECT_EQ(kSourceHeight, result.target_height());
     EXPECT_EQ(kSourceWidth, result.target_width());
     EXPECT_EQ(kMinAspectRatio, result.min_aspect_ratio());
@@ -568,9 +579,9 @@
 
   {
     MockConstraintFactory constraint_factory;
-    auto result = SelectVideoTrackAdapterSettings(
+    auto result = SelectTrackSettings(
         constraint_factory.CreateWebMediaConstraints().Basic(), resolution_set,
-        frame_rate_set, SourceFormat());
+        frame_rate_set);
     EXPECT_EQ(kSourceHeight, result.target_height());
     EXPECT_EQ(kSourceWidth, result.target_width());
     EXPECT_EQ(0.0, result.min_aspect_ratio());
@@ -580,9 +591,9 @@
 
   {
     MockConstraintFactory constraint_factory;
-    auto result = SelectVideoTrackAdapterSettings(
+    auto result = SelectTrackSettings(
         constraint_factory.CreateWebMediaConstraints().Basic(), resolution_set,
-        frame_rate_set, SourceFormat());
+        frame_rate_set);
     EXPECT_EQ(kSourceHeight, result.target_height());
     EXPECT_EQ(kSourceWidth, result.target_width());
     EXPECT_EQ(0.0, result.min_aspect_ratio());
@@ -602,9 +613,9 @@
     // Ideal aspect ratio is ignored if ideal width and height are supplied.
     constraint_factory.basic().aspect_ratio.SetIdeal(kIdealAspectRatio);
     constraint_factory.basic().frame_rate.SetIdeal(kIdealFrameRate);
-    auto result = SelectVideoTrackAdapterSettings(
+    auto result = SelectTrackSettings(
         constraint_factory.CreateWebMediaConstraints().Basic(), resolution_set,
-        frame_rate_set, SourceFormat());
+        frame_rate_set);
     EXPECT_EQ(kIdealHeight, result.target_height());
     EXPECT_EQ(kIdealWidth, result.target_width());
     EXPECT_EQ(0.0, result.min_aspect_ratio());
@@ -613,4 +624,103 @@
   }
 }
 
+TEST_F(MediaStreamConstraintsUtilTest,
+       VideoTrackAdapterSettingsRescalingDisabledUnconstrained) {
+  ResolutionSet resolution_set;
+  DoubleRangeSet frame_rate_set;
+
+  // No ideal values.
+  {
+    MockConstraintFactory constraint_factory;
+    auto result = SelectTrackSettings(
+        constraint_factory.CreateWebMediaConstraints().Basic(), resolution_set,
+        frame_rate_set, false /* enable_rescale */);
+    // No target resolution since rescaling is disabled.
+    EXPECT_FALSE(result.target_size());
+    // Min/Max aspect ratio are the system limits.
+    EXPECT_EQ(0.0, result.min_aspect_ratio());
+    EXPECT_EQ(HUGE_VAL, result.max_aspect_ratio());
+    // No max frame rate since there is no ideal or max value.
+    EXPECT_EQ(0.0, result.max_frame_rate());
+  }
+
+  // Ideals supplied.
+  {
+    const int kIdealHeight = 400;
+    const int kIdealWidth = 600;
+    const int kIdealAspectRatio = 2.0;
+    const double kIdealFrameRate = 33;
+    MockConstraintFactory constraint_factory;
+    // Ideal height, width and aspectRatio are ignored if rescaling is disabled.
+    constraint_factory.basic().height.SetIdeal(kIdealHeight);
+    constraint_factory.basic().width.SetIdeal(kIdealWidth);
+    constraint_factory.basic().aspect_ratio.SetIdeal(kIdealAspectRatio);
+    constraint_factory.basic().frame_rate.SetIdeal(kIdealFrameRate);
+    auto result = SelectTrackSettings(
+        constraint_factory.CreateWebMediaConstraints().Basic(), resolution_set,
+        frame_rate_set, false /* enable_rescale */);
+    // No target resolution since rescaling is disabled.
+    EXPECT_FALSE(result.target_size());
+    // Min/Max aspect ratio are the system limits.
+    EXPECT_EQ(0.0, result.min_aspect_ratio());
+    EXPECT_EQ(HUGE_VAL, result.max_aspect_ratio());
+    // Max frame rate corresponds to the ideal value.
+    EXPECT_EQ(kIdealFrameRate, result.max_frame_rate());
+  }
+}
+
+TEST_F(MediaStreamConstraintsUtilTest,
+       VideoTrackAdapterSettingsRescalingDisabledConstrained) {
+  // Constraints are expressed by the limits in |resolution_set| and
+  // |frame_rate_set|. WebMediaTrackConstraints objects in this test are used
+  // only to express ideal values.
+  const int kMinHeight = 500;
+  const int kMaxHeight = 1200;
+  const int kMinWidth = 1000;
+  const int kMaxWidth = 2000;
+  constexpr double kMinAspectRatio = 1.0;
+  constexpr double kMaxAspectRatio = 2.0;
+  constexpr double kMinFrameRate = 20.0;
+  constexpr double kMaxFrameRate = 44.0;
+  ResolutionSet resolution_set(kMinHeight, kMaxHeight, kMinWidth, kMaxWidth,
+                               kMinAspectRatio, kMaxAspectRatio);
+  DoubleRangeSet frame_rate_set(kMinFrameRate, kMaxFrameRate);
+
+  // No ideal values.
+  {
+    MockConstraintFactory constraint_factory;
+    auto result = SelectTrackSettings(
+        constraint_factory.CreateWebMediaConstraints().Basic(), resolution_set,
+        frame_rate_set, false /* enable_rescale */);
+    // No target size since rescaling is disabled.
+    EXPECT_FALSE(result.target_size());
+    // Min/Max aspect ratio and max frame rate come from the constraints
+    // expressed in |resolution_set| and |frame_rate_set|.
+    EXPECT_EQ(kMinAspectRatio, result.min_aspect_ratio());
+    EXPECT_EQ(kMaxAspectRatio, result.max_aspect_ratio());
+    EXPECT_EQ(kMaxFrameRate, result.max_frame_rate());
+  }
+
+  // Ideal values supplied.
+  {
+    const int kIdealHeight = 900;
+    const int kIdealWidth = 1600;
+    constexpr double kIdealFrameRate = 35.0;
+    MockConstraintFactory constraint_factory;
+    constraint_factory.basic().height.SetIdeal(kIdealHeight);
+    constraint_factory.basic().width.SetIdeal(kIdealWidth);
+    constraint_factory.basic().frame_rate.SetIdeal(kIdealFrameRate);
+    auto result = SelectTrackSettings(
+        constraint_factory.CreateWebMediaConstraints().Basic(), resolution_set,
+        frame_rate_set, false /* enable_rescale */);
+    // No target size since rescaling is disabled, despite ideal values.
+    EXPECT_FALSE(result.target_size());
+    // Min/Max aspect ratio and max frame rate come from the constraints
+    // expressed in |resolution_set| and |frame_rate_set|.
+    EXPECT_EQ(kMinAspectRatio, result.min_aspect_ratio());
+    EXPECT_EQ(kMaxAspectRatio, result.max_aspect_ratio());
+    EXPECT_EQ(kIdealFrameRate, result.max_frame_rate());
+  }
+}
+
 }  // namespace content
diff --git a/content/renderer/media/stream/media_stream_constraints_util_video_content.cc b/content/renderer/media/stream/media_stream_constraints_util_video_content.cc
index 273a64b..2cfb4e5 100644
--- a/content/renderer/media/stream/media_stream_constraints_util_video_content.cc
+++ b/content/renderer/media/stream/media_stream_constraints_util_video_content.cc
@@ -314,7 +314,8 @@
 
   auto track_adapter_settings = SelectVideoTrackAdapterSettings(
       basic_constraint_set, candidates.resolution_set(),
-      candidates.frame_rate_set(), capture_params.requested_format);
+      candidates.frame_rate_set(), capture_params.requested_format,
+      true /* enable_rescale */);
 
   return VideoCaptureSettings(std::move(device_id), capture_params,
                               noise_reduction, track_adapter_settings,
diff --git a/content/renderer/media/stream/media_stream_constraints_util_video_device.cc b/content/renderer/media/stream/media_stream_constraints_util_video_device.cc
index d5396569..7e065c4 100644
--- a/content/renderer/media/stream/media_stream_constraints_util_video_device.cc
+++ b/content/renderer/media/stream/media_stream_constraints_util_video_device.cc
@@ -429,7 +429,7 @@
   auto track_adapter_settings = SelectVideoTrackAdapterSettings(
       basic_constraint_set, candidate_format.resolution_set(),
       candidate_format.constrained_frame_rate(),
-      capture_params.requested_format);
+      capture_params.requested_format, true /* enable_rescale */);
 
   return VideoCaptureSettings(device->device_id, capture_params,
                               noise_reduction, track_adapter_settings,
diff --git a/content/shell/browser/layout_test/devtools_protocol_test_bindings.cc b/content/shell/browser/layout_test/devtools_protocol_test_bindings.cc
index 4119b4c7..1abc320 100644
--- a/content/shell/browser/layout_test/devtools_protocol_test_bindings.cc
+++ b/content/shell/browser/layout_test/devtools_protocol_test_bindings.cc
@@ -33,7 +33,9 @@
 DevToolsProtocolTestBindings::DevToolsProtocolTestBindings(
     WebContents* devtools)
     : WebContentsObserver(devtools),
-      agent_host_(DevToolsAgentHost::CreateForDiscovery()) {
+      agent_host_(DevToolsAgentHost::CreateForBrowser(
+          nullptr,
+          DevToolsAgentHost::CreateServerSocketCallback())) {
   agent_host_->AttachClient(this);
 }
 
diff --git a/content/test/renderer_audio_output_stream_factory_context_impl_unittest.cc b/content/test/renderer_audio_output_stream_factory_context_impl_unittest.cc
index cca3c08..cbbb54229 100644
--- a/content/test/renderer_audio_output_stream_factory_context_impl_unittest.cc
+++ b/content/test/renderer_audio_output_stream_factory_context_impl_unittest.cc
@@ -235,8 +235,7 @@
 
   base::Thread renderer_side_ipc_thread("Renderer IPC thread");
   ASSERT_TRUE(renderer_side_ipc_thread.Start());
-  auto renderer_ipc_task_runner =
-      renderer_side_ipc_thread.message_loop()->task_runner();
+  auto renderer_ipc_task_runner = renderer_side_ipc_thread.task_runner();
 
   // Bind |stream_factory| to |renderer_ipc_task_runner|.
   mojom::RendererAudioOutputStreamFactory* factory_ptr;
diff --git a/content/utility/utility_service_factory.cc b/content/utility/utility_service_factory.cc
index aa667dd..e3b80b1 100644
--- a/content/utility/utility_service_factory.cc
+++ b/content/utility/utility_service_factory.cc
@@ -107,11 +107,6 @@
 }
 #endif  // BUILDFLAG(ENABLE_LIBRARY_CDMS)
 
-std::unique_ptr<service_manager::Service> CreateDataDecoderService() {
-  content::UtilityThread::Get()->EnsureBlinkInitialized();
-  return data_decoder::DataDecoderService::Create();
-}
-
 std::unique_ptr<service_manager::Service> CreateVizService() {
   return std::make_unique<viz::Service>();
 }
@@ -168,11 +163,6 @@
 #endif  // BUILDFLAG(ENABLE_CROS_LIBASSISTANT)
 #endif
 
-  service_manager::EmbeddedServiceInfo data_decoder_info;
-  data_decoder_info.factory = base::Bind(&CreateDataDecoderService);
-  services->insert(
-      std::make_pair(data_decoder::mojom::kServiceName, data_decoder_info));
-
   service_manager::EmbeddedServiceInfo viz_info;
   viz_info.factory = base::Bind(&CreateVizService);
   services->insert(std::make_pair(viz::mojom::kVizServiceName, viz_info));
@@ -189,6 +179,26 @@
   }
 }
 
+bool UtilityServiceFactory::HandleServiceRequest(
+    const std::string& name,
+    service_manager::mojom::ServiceRequest request) {
+  if (name == data_decoder::mojom::kServiceName) {
+    content::UtilityThread::Get()->EnsureBlinkInitialized();
+    running_service_ =
+        std::make_unique<data_decoder::DataDecoderService>(std::move(request));
+  }
+
+  if (running_service_) {
+    // If we actually started a service for this request, make sure its
+    // self-termination results in full process termination.
+    running_service_->set_termination_closure(base::BindOnce(
+        &UtilityServiceFactory::OnServiceQuit, base::Unretained(this)));
+    return true;
+  }
+
+  return false;
+}
+
 void UtilityServiceFactory::OnServiceQuit() {
   UtilityThread::Get()->ReleaseProcess();
 }
diff --git a/content/utility/utility_service_factory.h b/content/utility/utility_service_factory.h
index 639f286..ff278d4 100644
--- a/content/utility/utility_service_factory.h
+++ b/content/utility/utility_service_factory.h
@@ -28,6 +28,9 @@
       const std::string& name,
       service_manager::mojom::PIDReceiverPtr pid_receiver) override;
   void RegisterServices(ServiceMap* services) override;
+  bool HandleServiceRequest(
+      const std::string& name,
+      service_manager::mojom::ServiceRequest request) override;
   void OnServiceQuit() override;
 
  private:
@@ -41,6 +44,8 @@
   std::unique_ptr<service_manager::BinderRegistry> network_registry_;
   std::unique_ptr<service_manager::BinderRegistry> audio_registry_;
 
+  std::unique_ptr<service_manager::Service> running_service_;
+
   DISALLOW_COPY_AND_ASSIGN(UtilityServiceFactory);
 };
 
diff --git a/dbus/test_service.cc b/dbus/test_service.cc
index 06f8b9a..2fb05c1 100644
--- a/dbus/test_service.cc
+++ b/dbus/test_service.cc
@@ -69,9 +69,9 @@
 }
 
 void TestService::ShutdownAndBlock() {
-  message_loop()->task_runner()->PostTask(
-      FROM_HERE, base::Bind(&TestService::ShutdownAndBlockInternal,
-                            base::Unretained(this)));
+  task_runner()->PostTask(FROM_HERE,
+                          base::Bind(&TestService::ShutdownAndBlockInternal,
+                                     base::Unretained(this)));
 }
 
 bool TestService::HasDBusThread() {
@@ -86,13 +86,13 @@
 }
 
 void TestService::SendTestSignal(const std::string& message) {
-  message_loop()->task_runner()->PostTask(
-      FROM_HERE, base::Bind(&TestService::SendTestSignalInternal,
-                            base::Unretained(this), message));
+  task_runner()->PostTask(FROM_HERE,
+                          base::Bind(&TestService::SendTestSignalInternal,
+                                     base::Unretained(this), message));
 }
 
 void TestService::SendTestSignalFromRoot(const std::string& message) {
-  message_loop()->task_runner()->PostTask(
+  task_runner()->PostTask(
       FROM_HERE, base::Bind(&TestService::SendTestSignalFromRootInternal,
                             base::Unretained(this), message));
 }
@@ -119,9 +119,9 @@
 }
 
 void TestService::RequestOwnership(base::Callback<void(bool)> callback) {
-  message_loop()->task_runner()->PostTask(
-      FROM_HERE, base::Bind(&TestService::RequestOwnershipInternal,
-                            base::Unretained(this), callback));
+  task_runner()->PostTask(FROM_HERE,
+                          base::Bind(&TestService::RequestOwnershipInternal,
+                                     base::Unretained(this), callback));
 }
 
 void TestService::RequestOwnershipInternal(
@@ -314,9 +314,10 @@
 void TestService::AsyncEcho(MethodCall* method_call,
                             ExportedObject::ResponseSender response_sender) {
   // Schedule a call to Echo() to send an asynchronous response after we return.
-  message_loop()->task_runner()->PostDelayedTask(
-      FROM_HERE, base::Bind(&TestService::Echo, base::Unretained(this),
-                            method_call, response_sender),
+  task_runner()->PostDelayedTask(
+      FROM_HERE,
+      base::Bind(&TestService::Echo, base::Unretained(this), method_call,
+                 response_sender),
       TestTimeouts::tiny_timeout());
 }
 
@@ -630,9 +631,9 @@
 }
 
 void TestService::AddObject(const ObjectPath& object_path) {
-  message_loop()->task_runner()->PostTask(
-      FROM_HERE, base::Bind(&TestService::AddObjectInternal,
-                            base::Unretained(this), object_path));
+  task_runner()->PostTask(FROM_HERE,
+                          base::Bind(&TestService::AddObjectInternal,
+                                     base::Unretained(this), object_path));
 }
 
 void TestService::AddObjectInternal(const ObjectPath& object_path) {
@@ -654,9 +655,9 @@
 }
 
 void TestService::RemoveObject(const ObjectPath& object_path) {
-  message_loop()->task_runner()->PostTask(
-      FROM_HERE, base::Bind(&TestService::RemoveObjectInternal,
-                            base::Unretained(this), object_path));
+  task_runner()->PostTask(FROM_HERE,
+                          base::Bind(&TestService::RemoveObjectInternal,
+                                     base::Unretained(this), object_path));
 }
 
 void TestService::RemoveObjectInternal(const ObjectPath& object_path) {
@@ -673,7 +674,7 @@
 }
 
 void TestService::SendPropertyChangedSignal(const std::string& name) {
-  message_loop()->task_runner()->PostTask(
+  task_runner()->PostTask(
       FROM_HERE, base::Bind(&TestService::SendPropertyChangedSignalInternal,
                             base::Unretained(this), name));
 }
@@ -702,7 +703,7 @@
 }
 
 void TestService::SendPropertyInvalidatedSignal() {
-  message_loop()->task_runner()->PostTask(
+  task_runner()->PostTask(
       FROM_HERE, base::Bind(&TestService::SendPropertyInvalidatedSignalInternal,
                             base::Unretained(this)));
 }
diff --git a/device/bluetooth/dbus/bluetooth_adapter_client.cc b/device/bluetooth/dbus/bluetooth_adapter_client.cc
index 2829a2d..587c6ef 100644
--- a/device/bluetooth/dbus/bluetooth_adapter_client.cc
+++ b/device/bluetooth/dbus/bluetooth_adapter_client.cc
@@ -95,6 +95,31 @@
   writer->CloseContainer(&struct_writer);
 }
 
+BluetoothAdapterClient::Error ErrorResponseToError(
+    dbus::ErrorResponse* response) {
+  BluetoothAdapterClient::Error error(BluetoothAdapterClient::kNoResponseError,
+                                      "");
+  if (response) {
+    dbus::MessageReader reader(response);
+    error.name = response->GetErrorName();
+    reader.PopString(&error.message);
+  }
+
+  return error;
+}
+
+void OnResponseAdapter(
+    const base::Closure& callback,
+    BluetoothAdapterClient::ErrorCallback error_callback,
+    const base::Optional<BluetoothAdapterClient::Error>& error) {
+  if (!error) {
+    callback.Run();
+    return;
+  }
+
+  std::move(error_callback).Run(error->name, error->message);
+}
+
 }  // namespace
 
 BluetoothAdapterClient::DiscoveryFilter::DiscoveryFilter() = default;
@@ -124,6 +149,10 @@
     uuids.reset();
 }
 
+BluetoothAdapterClient::Error::Error(const std::string& name,
+                                     const std::string& message)
+    : name(name), message(message) {}
+
 const char BluetoothAdapterClient::kNoResponseError[] =
     "org.chromium.Error.NoResponse";
 const char BluetoothAdapterClient::kUnknownAdapterError[] =
@@ -206,25 +235,21 @@
 
   // BluetoothAdapterClient override.
   void StartDiscovery(const dbus::ObjectPath& object_path,
-                      const base::Closure& callback,
-                      ErrorCallback error_callback) override {
+                      ResponseCallback callback) override {
     dbus::MethodCall method_call(bluetooth_adapter::kBluetoothAdapterInterface,
                                  bluetooth_adapter::kStartDiscovery);
 
     dbus::ObjectProxy* object_proxy =
         object_manager_->GetObjectProxy(object_path);
     if (!object_proxy) {
-      std::move(error_callback).Run(kUnknownAdapterError, "");
+      std::move(callback).Run(Error(kUnknownAdapterError, ""));
       return;
     }
 
-    object_proxy->CallMethodWithErrorCallback(
+    object_proxy->CallMethodWithErrorResponse(
         &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
-        base::BindOnce(&BluetoothAdapterClientImpl::OnSuccess,
-                       weak_ptr_factory_.GetWeakPtr(), callback),
-        base::BindOnce(&BluetoothAdapterClientImpl::OnError,
-                       weak_ptr_factory_.GetWeakPtr(),
-                       std::move(error_callback)));
+        base::BindOnce(&BluetoothAdapterClientImpl::OnResponse,
+                       weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
   }
 
   // BluetoothAdapterClient override.
@@ -541,6 +566,17 @@
     std::move(error_callback).Run(error_name, error_message);
   }
 
+  void OnResponse(ResponseCallback callback,
+                  dbus::Response* response,
+                  dbus::ErrorResponse* error_response) {
+    if (response) {
+      std::move(callback).Run(base::nullopt);
+      return;
+    }
+
+    std::move(callback).Run(ErrorResponseToError(error_response));
+  }
+
   dbus::ObjectManager* object_manager_;
 
   // List of observers interested in event notifications from us.
@@ -563,4 +599,11 @@
   return new BluetoothAdapterClientImpl;
 }
 
+void BluetoothAdapterClient::StartDiscovery(const dbus::ObjectPath& object_path,
+                                            const base::Closure& callback,
+                                            ErrorCallback error_callback) {
+  StartDiscovery(object_path, base::BindOnce(&OnResponseAdapter, callback,
+                                             std::move(error_callback)));
+}
+
 }  // namespace bluez
diff --git a/device/bluetooth/dbus/bluetooth_adapter_client.h b/device/bluetooth/dbus/bluetooth_adapter_client.h
index 03ff66d..6580764 100644
--- a/device/bluetooth/dbus/bluetooth_adapter_client.h
+++ b/device/bluetooth/dbus/bluetooth_adapter_client.h
@@ -12,6 +12,7 @@
 
 #include "base/callback_forward.h"
 #include "base/macros.h"
+#include "base/optional.h"
 #include "dbus/object_path.h"
 #include "dbus/property.h"
 #include "device/bluetooth/bluetooth_export.h"
@@ -47,6 +48,14 @@
     DISALLOW_COPY_AND_ASSIGN(DiscoveryFilter);
   };
 
+  // Represent an error sent through DBus.
+  struct Error {
+    Error(const std::string& name, const std::string& message);
+
+    std::string name;
+    std::string message;
+  };
+
   // Structure of properties associated with bluetooth adapters.
   struct Properties : public dbus::PropertySet {
     // The Bluetooth device address of the adapter. Read-only.
@@ -147,10 +156,18 @@
                                   const std::string& error_message)>
       ErrorCallback;
 
+  // Callback used by adapter methods to indicate that a response was
+  // received with an optional Error in case an error occurred.
+  using ResponseCallback =
+      base::OnceCallback<void(const base::Optional<Error>&)>;
+
   // Starts a device discovery on the adapter with object path |object_path|.
   virtual void StartDiscovery(const dbus::ObjectPath& object_path,
-                              const base::Closure& callback,
-                              ErrorCallback error_callback) = 0;
+                              ResponseCallback callback) = 0;
+  // DEPRECATED: Use StartDiscovery() above.
+  void StartDiscovery(const dbus::ObjectPath& object_path,
+                      const base::Closure& callback,
+                      ErrorCallback error_callback);
 
   // Cancels any previous device discovery on the adapter with object path
   // |object_path|.
diff --git a/device/bluetooth/dbus/fake_bluetooth_adapter_client.cc b/device/bluetooth/dbus/fake_bluetooth_adapter_client.cc
index 573019b5..d515d141 100644
--- a/device/bluetooth/dbus/fake_bluetooth_adapter_client.cc
+++ b/device/bluetooth/dbus/fake_bluetooth_adapter_client.cc
@@ -134,18 +134,17 @@
 
 void FakeBluetoothAdapterClient::StartDiscovery(
     const dbus::ObjectPath& object_path,
-    const base::Closure& callback,
-    ErrorCallback error_callback) {
+    ResponseCallback callback) {
   if (object_path != dbus::ObjectPath(kAdapterPath)) {
     PostDelayedTask(
-        base::BindOnce(std::move(error_callback), kNoResponseError, ""));
+        base::BindOnce(std::move(callback), Error(kNoResponseError, "")));
     return;
   }
 
   ++discovering_count_;
   VLOG(1) << "StartDiscovery: " << object_path.value() << ", "
           << "count is now " << discovering_count_;
-  PostDelayedTask(callback);
+  PostDelayedTask(base::BindOnce(std::move(callback), base::nullopt));
 
   if (discovering_count_ == 1) {
     properties_->discovering.ReplaceValue(true);
diff --git a/device/bluetooth/dbus/fake_bluetooth_adapter_client.h b/device/bluetooth/dbus/fake_bluetooth_adapter_client.h
index 59adc33..9acc716 100644
--- a/device/bluetooth/dbus/fake_bluetooth_adapter_client.h
+++ b/device/bluetooth/dbus/fake_bluetooth_adapter_client.h
@@ -49,8 +49,7 @@
   std::vector<dbus::ObjectPath> GetAdapters() override;
   Properties* GetProperties(const dbus::ObjectPath& object_path) override;
   void StartDiscovery(const dbus::ObjectPath& object_path,
-                      const base::Closure& callback,
-                      ErrorCallback error_callback) override;
+                      ResponseCallback callback) override;
   void StopDiscovery(const dbus::ObjectPath& object_path,
                      const base::Closure& callback,
                      ErrorCallback error_callback) override;
diff --git a/device/fido/attestation_object.cc b/device/fido/attestation_object.cc
index 8bec23e..552223a 100644
--- a/device/fido/attestation_object.cc
+++ b/device/fido/attestation_object.cc
@@ -29,17 +29,22 @@
   return authenticator_data_.GetCredentialId();
 }
 
-void AttestationObject::EraseAttestationStatement() {
+void AttestationObject::EraseAttestationStatement(
+    AttestationObject::AAGUID erase_aaguid) {
   attestation_statement_ = std::make_unique<NoneAttestationStatement>();
-  authenticator_data_.DeleteDeviceAaguid();
+  if (erase_aaguid == AAGUID::kErase) {
+    authenticator_data_.DeleteDeviceAaguid();
+  }
 
 // Attested credential data is optional section within authenticator data. But
 // if present, the first 16 bytes of it represents a device AAGUID which must
-// be set to zeros for none attestation statement format.
+// be set to zeros for none attestation statement format, unless explicitly
+// requested otherwise (we make an exception for platform authenticators).
 #if DCHECK_IS_ON()
   if (!authenticator_data_.attested_data())
     return;
-  DCHECK(authenticator_data_.attested_data()->IsAaguidZero());
+  DCHECK(erase_aaguid == AAGUID::kInclude ||
+         authenticator_data_.attested_data()->IsAaguidZero());
 #endif
 }
 
diff --git a/device/fido/attestation_object.h b/device/fido/attestation_object.h
index 36f463d8..2eba61f 100644
--- a/device/fido/attestation_object.h
+++ b/device/fido/attestation_object.h
@@ -36,10 +36,16 @@
 
   std::vector<uint8_t> GetCredentialId() const;
 
-  // Replaces the attestation statement with a “none” attestation and replaces
-  // device AAGUID with zero bytes as specified for step 20.3 in
+  enum class AAGUID {
+    kErase,
+    kInclude,
+  };
+
+  // Replaces the attestation statement with a “none” attestation, and replaces
+  // device AAGUID with zero bytes (unless |erase_aaguid| is kInclude) as
+  // specified for step 20.3 in
   // https://w3c.github.io/webauthn/#createCredential.
-  void EraseAttestationStatement();
+  void EraseAttestationStatement(AAGUID erase_aaguid);
 
   // Returns true if the attestation is a "self" attestation, i.e. is just the
   // private key signing itself to show that it is fresh. See
diff --git a/device/fido/authenticator_make_credential_response.cc b/device/fido/authenticator_make_credential_response.cc
index 7efafaf..04863377 100644
--- a/device/fido/authenticator_make_credential_response.cc
+++ b/device/fido/authenticator_make_credential_response.cc
@@ -78,8 +78,9 @@
   return attestation_object_.SerializeToCBOREncodedBytes();
 }
 
-void AuthenticatorMakeCredentialResponse::EraseAttestationStatement() {
-  attestation_object_.EraseAttestationStatement();
+void AuthenticatorMakeCredentialResponse::EraseAttestationStatement(
+    AttestationObject::AAGUID erase_aaguid) {
+  attestation_object_.EraseAttestationStatement(erase_aaguid);
 }
 
 bool AuthenticatorMakeCredentialResponse::IsSelfAttestation() {
diff --git a/device/fido/authenticator_make_credential_response.h b/device/fido/authenticator_make_credential_response.h
index 0f9c581c..56cc57d2 100644
--- a/device/fido/authenticator_make_credential_response.h
+++ b/device/fido/authenticator_make_credential_response.h
@@ -44,10 +44,10 @@
 
   std::vector<uint8_t> GetCBOREncodedAttestationObject() const;
 
-  // Replaces the attestation statement with a “none” attestation and removes
-  // AAGUID from authenticator data section.
+  // Replaces the attestation statement with a “none” attestation, and removes
+  // AAGUID from authenticator data section unless |preserve_aaguid| is true.
   // https://w3c.github.io/webauthn/#createCredential
-  void EraseAttestationStatement();
+  void EraseAttestationStatement(AttestationObject::AAGUID erase_aaguid);
 
   // Returns true if the attestation is a "self" attestation, i.e. is just the
   // private key signing itself to show that it is fresh and the AAGUID is zero.
diff --git a/device/fido/ctap_response_fuzzer.cc b/device/fido/ctap_response_fuzzer.cc
index 4f251e6..c3abf10 100644
--- a/device/fido/ctap_response_fuzzer.cc
+++ b/device/fido/ctap_response_fuzzer.cc
@@ -35,14 +35,14 @@
   auto response = device::ReadCTAPMakeCredentialResponse(
       FidoTransportProtocol::kUsbHumanInterfaceDevice, input);
   if (response)
-    response->EraseAttestationStatement();
+    response->EraseAttestationStatement(AttestationObject::AAGUID::kErase);
 
   response = device::AuthenticatorMakeCredentialResponse::
       CreateFromU2fRegisterResponse(
           FidoTransportProtocol::kUsbHumanInterfaceDevice,
           relying_party_id_hash, input);
   if (response)
-    response->EraseAttestationStatement();
+    response->EraseAttestationStatement(AttestationObject::AAGUID::kErase);
 
   device::ReadCTAPGetAssertionResponse(input);
   std::vector<uint8_t> u2f_response_data(data, data + size);
diff --git a/device/fido/ctap_response_unittest.cc b/device/fido/ctap_response_unittest.cc
index be87a09..8feeffa 100644
--- a/device/fido/ctap_response_unittest.cc
+++ b/device/fido/ctap_response_unittest.cc
@@ -373,7 +373,8 @@
       FidoTransportProtocol::kUsbHumanInterfaceDevice,
       test_data::kTestMakeCredentialResponse);
   ASSERT_TRUE(make_credential_response);
-  make_credential_response->EraseAttestationStatement();
+  make_credential_response->EraseAttestationStatement(
+      AttestationObject::AAGUID::kErase);
   EXPECT_THAT(make_credential_response->GetCBOREncodedAttestationObject(),
               ::testing::ElementsAreArray(test_data::kNoneAttestationResponse));
 }
diff --git a/device/fido/mac/util.mm b/device/fido/mac/util.mm
index 999a7487..bd891c44 100644
--- a/device/fido/mac/util.mm
+++ b/device/fido/mac/util.mm
@@ -31,11 +31,12 @@
 using cbor::Writer;
 using cbor::Value;
 
-// WebAuthn requires an all-zero AAGUID for authenticators using
-// self-attestation.
-constexpr std::array<uint8_t, 16> kAaguid = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                                             0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                                             0x00, 0x00, 0x00, 0x00};
+// The Touch ID authenticator AAGUID value. Despite using self-attestation,
+// Chrome will return this non-zero AAGUID for all MakeCredential
+// responses coming from the Touch ID platform authenticator.
+constexpr std::array<uint8_t, 16> kAaguid = {0xad, 0xce, 0x00, 0x02, 0x35, 0xbc,
+                                             0xc6, 0x0a, 0x64, 0x8b, 0x0b, 0x25,
+                                             0xf1, 0xf0, 0x55, 0x03};
 
 // SecKeyRefToECPublicKey converts a SecKeyRef for a public key into an
 // equivalent |ECPublicKey| instance. It returns |nullptr| if the key cannot be
diff --git a/device/fido/virtual_fido_device.cc b/device/fido/virtual_fido_device.cc
index 05bf3065..755e5390 100644
--- a/device/fido/virtual_fido_device.cc
+++ b/device/fido/virtual_fido_device.cc
@@ -173,8 +173,7 @@
 }
 
 FidoTransportProtocol VirtualFidoDevice::DeviceTransport() const {
-  // Virtual device are injected as HID devices.
-  return FidoTransportProtocol::kUsbHumanInterfaceDevice;
+  return state_->transport;
 }
 
 }  // namespace device
diff --git a/device/fido/virtual_fido_device.h b/device/fido/virtual_fido_device.h
index 06a65f7..782eee3 100644
--- a/device/fido/virtual_fido_device.h
+++ b/device/fido/virtual_fido_device.h
@@ -89,6 +89,9 @@
     // zero, in violation of the rules for self-attestation.
     bool non_zero_aaguid_with_self_attestation = false;
 
+    FidoTransportProtocol transport =
+        FidoTransportProtocol::kUsbHumanInterfaceDevice;
+
     // Adds a registration for the specified credential ID with the application
     // parameter set to be valid for the given relying party ID (which would
     // typically be a domain, e.g. "example.com").
diff --git a/device/gamepad/gamepad_provider.cc b/device/gamepad/gamepad_provider.cc
index 8b7b1b0..1078b56 100644
--- a/device/gamepad/gamepad_provider.cc
+++ b/device/gamepad/gamepad_provider.cc
@@ -144,8 +144,7 @@
     base::AutoLock lock(is_paused_lock_);
     is_paused_ = true;
   }
-  base::MessageLoop* polling_loop = polling_thread_->message_loop();
-  polling_loop->task_runner()->PostTask(
+  polling_thread_->task_runner()->PostTask(
       FROM_HERE,
       base::BindOnce(&GamepadProvider::SendPauseHint, Unretained(this), true));
 }
@@ -158,11 +157,10 @@
     is_paused_ = false;
   }
 
-  base::MessageLoop* polling_loop = polling_thread_->message_loop();
-  polling_loop->task_runner()->PostTask(
+  polling_thread_->task_runner()->PostTask(
       FROM_HERE,
       base::BindOnce(&GamepadProvider::SendPauseHint, Unretained(this), false));
-  polling_loop->task_runner()->PostTask(
+  polling_thread_->task_runner()->PostTask(
       FROM_HERE,
       base::BindOnce(&GamepadProvider::ScheduleDoPoll, Unretained(this)));
 }
diff --git a/extensions/browser/image_sanitizer_unittest.cc b/extensions/browser/image_sanitizer_unittest.cc
index 1210977..c01f403 100644
--- a/extensions/browser/image_sanitizer_unittest.cc
+++ b/extensions/browser/image_sanitizer_unittest.cc
@@ -18,6 +18,7 @@
 #include "build/build_config.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "services/data_decoder/public/cpp/test_data_decoder_service.h"
+#include "services/data_decoder/public/mojom/constants.mojom.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace extensions {
@@ -72,12 +73,19 @@
  protected:
   void InitTestDataDecoderService(
       std::unique_ptr<service_manager::Service> service) {
-    if (!service)
-      service = data_decoder::DataDecoderService::Create();
-    connector_factory_ =
-        service_manager::TestConnectorFactory::CreateForUniqueService(
-            std::move(service));
-    connector_ = connector_factory_->CreateConnector();
+    if (service) {
+      test_data_decoder_service_ = std::move(service);
+    } else {
+      test_data_decoder_service_ =
+          std::make_unique<data_decoder::DataDecoderService>(
+              RegisterDataDecoder());
+    }
+    connector_ = connector_factory_.CreateConnector();
+  }
+
+  service_manager::mojom::ServiceRequest RegisterDataDecoder() {
+    return connector_factory_.RegisterInstance(
+        data_decoder::mojom::kServiceName);
   }
 
   void CreateValidImage(const base::FilePath::StringPieceType& file_name) {
@@ -150,9 +158,10 @@
       ImageSanitizer::ImageDecodedCallback image_decoded_callback,
       ImageSanitizer::SanitizationDoneCallback done_callback) {
     sanitizer_ = ImageSanitizer::CreateAndStart(
-        connector_.get(), service_manager::Identity(), temp_dir_.GetPath(),
-        image_relative_paths, std::move(image_decoded_callback),
-        std::move(done_callback));
+        connector_.get(),
+        service_manager::Identity(data_decoder::mojom::kServiceName),
+        temp_dir_.GetPath(), image_relative_paths,
+        std::move(image_decoded_callback), std::move(done_callback));
   }
 
   bool WriteBase64DataToFile(const std::string& base64_data,
@@ -183,8 +192,9 @@
   }
 
   content::TestBrowserThreadBundle thread_bundle_;
-  std::unique_ptr<service_manager::TestConnectorFactory> connector_factory_;
+  service_manager::TestConnectorFactory connector_factory_;
   std::unique_ptr<service_manager::Connector> connector_;
+  std::unique_ptr<service_manager::Service> test_data_decoder_service_;
   ImageSanitizer::Status last_status_ = ImageSanitizer::Status::kSuccess;
   base::FilePath last_reported_path_;
   base::OnceClosure done_callback_;
@@ -335,7 +345,7 @@
 TEST_F(ImageSanitizerTest, DataDecoderServiceCrashes) {
   InitTestDataDecoderService(
       std::make_unique<data_decoder::CrashyDataDecoderService>(
-          /*crash_json=*/false, /*crash_image=*/true));
+          RegisterDataDecoder(), /*crash_json=*/false, /*crash_image=*/true));
   constexpr base::FilePath::CharType kGoodPngName[] =
       FILE_PATH_LITERAL("good.png");
   CreateValidImage(kGoodPngName);
diff --git a/extensions/browser/json_file_sanitizer_unittest.cc b/extensions/browser/json_file_sanitizer_unittest.cc
index 5fceb224..2404df9 100644
--- a/extensions/browser/json_file_sanitizer_unittest.cc
+++ b/extensions/browser/json_file_sanitizer_unittest.cc
@@ -13,6 +13,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "services/data_decoder/public/cpp/test_data_decoder_service.h"
+#include "services/data_decoder/public/mojom/constants.mojom.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace extensions {
@@ -52,7 +53,8 @@
 
   void CreateAndStartSanitizer(const std::set<base::FilePath>& file_paths) {
     sanitizer_ = JsonFileSanitizer::CreateAndStart(
-        test_data_decoder_service_.connector(), service_manager::Identity(),
+        test_data_decoder_service_.connector(),
+        service_manager::Identity(data_decoder::mojom::kServiceName),
         file_paths,
         base::BindOnce(&JsonFileSanitizerTest::SanitizationDone,
                        base::Unretained(this)));
diff --git a/extensions/browser/sandboxed_unpacker_unittest.cc b/extensions/browser/sandboxed_unpacker_unittest.cc
index 8f611ef..cc37e25 100644
--- a/extensions/browser/sandboxed_unpacker_unittest.cc
+++ b/extensions/browser/sandboxed_unpacker_unittest.cc
@@ -18,6 +18,7 @@
 #include "base/values.h"
 #include "components/crx_file/id_util.h"
 #include "components/services/unzip/public/cpp/test_unzip_service.h"
+#include "components/services/unzip/public/interfaces/constants.mojom.h"
 #include "components/services/unzip/unzip_service.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/test/test_browser_thread_bundle.h"
@@ -34,7 +35,9 @@
 #include "extensions/test/test_extensions_client.h"
 #include "services/data_decoder/data_decoder_service.h"
 #include "services/data_decoder/public/cpp/test_data_decoder_service.h"
+#include "services/data_decoder/public/mojom/constants.mojom.h"
 #include "services/service_manager/public/cpp/connector.h"
+#include "services/service_manager/public/cpp/service_context.h"
 #include "services/service_manager/public/cpp/test/test_connector_factory.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -156,20 +159,23 @@
   }
 
   void InitSanboxedUnpacker(
-      std::unique_ptr<service_manager::Service> data_decode_service,
+      std::unique_ptr<service_manager::Service> data_decoder_service,
       std::unique_ptr<service_manager::Service> unzip_service) {
-    service_manager::TestConnectorFactory::NameToServiceMap services;
-    if (!data_decode_service)
-      data_decode_service = data_decoder::DataDecoderService::Create();
+    if (data_decoder_service) {
+      data_decoder_service_ = std::move(data_decoder_service);
+    } else {
+      data_decoder_service_ =
+          std::make_unique<data_decoder::DataDecoderService>(
+              RegisterDataDecoder());
+    }
+
     if (!unzip_service)
       unzip_service = unzip::UnzipService::CreateService();
-    services.insert(
-        std::make_pair("data_decoder", std::move(data_decode_service)));
-    services.insert(std::make_pair("unzip_service", std::move(unzip_service)));
-    test_connector_factory_ =
-        service_manager::TestConnectorFactory::CreateForServices(
-            std::move(services));
-    connector_ = test_connector_factory_->CreateConnector();
+    unzip_service_context_ = std::make_unique<service_manager::ServiceContext>(
+        std::move(unzip_service),
+        test_connector_factory_.RegisterInstance(unzip::mojom::kServiceName));
+
+    connector_ = test_connector_factory_.CreateConnector();
 
     sandboxed_unpacker_ =
         new SandboxedUnpacker(connector_->Clone(), Manifest::INTERNAL,
@@ -177,6 +183,11 @@
                               base::ThreadTaskRunnerHandle::Get(), client_);
   }
 
+  service_manager::mojom::ServiceRequest RegisterDataDecoder() {
+    return test_connector_factory_.RegisterInstance(
+        data_decoder::mojom::kServiceName);
+  }
+
   void TearDown() override {
     // Need to destruct SandboxedUnpacker before the message loop since
     // it posts a task to it.
@@ -264,9 +275,12 @@
   scoped_refptr<SandboxedUnpacker> sandboxed_unpacker_;
   std::unique_ptr<content::InProcessUtilityThreadHelper>
       in_process_utility_thread_helper_;
-  std::unique_ptr<service_manager::TestConnectorFactory>
-      test_connector_factory_;
+
+  service_manager::TestConnectorFactory test_connector_factory_;
   std::unique_ptr<service_manager::Connector> connector_;
+
+  std::unique_ptr<service_manager::Service> data_decoder_service_;
+  std::unique_ptr<service_manager::ServiceContext> unzip_service_context_;
 };
 
 TEST_F(SandboxedUnpackerTest, EmptyDefaultLocale) {
@@ -469,9 +483,10 @@
 }
 
 TEST_F(SandboxedUnpackerTest, JsonParserFails) {
-  InitSanboxedUnpacker(std::make_unique<data_decoder::CrashyDataDecoderService>(
-                           /*crash_json=*/true, /*crash_image=*/false),
-                       /*unzip_service=*/nullptr);
+  InitSanboxedUnpacker(
+      std::make_unique<data_decoder::CrashyDataDecoderService>(
+          RegisterDataDecoder(), /*crash_json=*/true, /*crash_image=*/false),
+      /*unzip_service=*/nullptr);
   SetupUnpacker("good_package.crx", "");
   EXPECT_FALSE(InstallSucceeded());
   EXPECT_FALSE(GetInstallErrorMessage().empty());
@@ -480,9 +495,10 @@
 }
 
 TEST_F(SandboxedUnpackerTest, ImageDecoderFails) {
-  InitSanboxedUnpacker(std::make_unique<data_decoder::CrashyDataDecoderService>(
-                           /*crash_json=*/false, /*crash_image=*/true),
-                       /*unzip_service=*/nullptr);
+  InitSanboxedUnpacker(
+      std::make_unique<data_decoder::CrashyDataDecoderService>(
+          RegisterDataDecoder(), /*crash_json=*/false, /*crash_image=*/true),
+      /*unzip_service=*/nullptr);
   SetupUnpacker("good_package.crx", "");
   EXPECT_FALSE(InstallSucceeded());
   EXPECT_FALSE(GetInstallErrorMessage().empty());
diff --git a/gpu/BUILD.gn b/gpu/BUILD.gn
index 7b017d4e..13d4a13f 100644
--- a/gpu/BUILD.gn
+++ b/gpu/BUILD.gn
@@ -511,6 +511,7 @@
     "//ipc:test_support",
     "//mojo/core/embedder",
     "//mojo/public/cpp/bindings",
+    "//mojo/public/cpp/test_support:test_utils",
     "//net:test_support",
     "//skia",
     "//testing/gmock",
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index f1ab171..b452571 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -37,6 +37,7 @@
 #include "gpu/command_buffer/common/debug_marker_manager.h"
 #include "gpu/command_buffer/common/gles2_cmd_format.h"
 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
+#include "gpu/command_buffer/common/gpu_memory_buffer_support.h"
 #include "gpu/command_buffer/common/mailbox.h"
 #include "gpu/command_buffer/common/sync_token.h"
 #include "gpu/command_buffer/service/buffer_manager.h"
@@ -3068,23 +3069,22 @@
 
   DCHECK(format == GL_RGB || format == GL_RGBA);
   bool is_cleared = false;
+  gfx::BufferFormat buffer_format = gfx::BufferFormat::RGBA_8888;
+  if (format == GL_RGB) {
+#if defined(USE_OZONE)
+    // BGRX format is preferred for Ozone as it matches the format used by the
+    // buffer queue and is as a result guaranteed to work on all devices.
+    // TODO(reveman): Define this format in one place instead of having to
+    // duplicate BGRX_8888.
+    buffer_format = gfx::BufferFormat::BGRX_8888;
+#else
+    buffer_format = gfx::BufferFormat::RGBX_8888;
+#endif
+  }
+  DCHECK_EQ(format, gpu::InternalFormatForGpuMemoryBufferFormat(buffer_format));
   scoped_refptr<gl::GLImage> image =
       decoder_->GetContextGroup()->image_factory()->CreateAnonymousImage(
-          size,
-          format == GL_RGB
-              ?
-#if defined(USE_OZONE)
-              // BGRX format is preferred for Ozone as it matches the format
-              // used by the buffer queue and is as a result guaranteed to work
-              // on all devices.
-              // TODO(reveman): Define this format in one place instead of
-              // having to duplicate BGRX_8888.
-              gfx::BufferFormat::BGRX_8888
-#else
-              gfx::BufferFormat::RGBX_8888
-#endif
-              : gfx::BufferFormat::RGBA_8888,
-          gfx::BufferUsage::SCANOUT, format, &is_cleared);
+          size, buffer_format, gfx::BufferUsage::SCANOUT, &is_cleared);
   if (!image || !image->BindTexImage(Target()))
     return false;
 
@@ -17592,23 +17592,18 @@
   }
 
   gfx::BufferFormat buffer_format;
-  GLint untyped_format;
   switch (internal_format) {
     case GL_RGBA8_OES:
       buffer_format = gfx::BufferFormat::RGBA_8888;
-      untyped_format = GL_RGBA;
       break;
     case GL_BGRA8_EXT:
       buffer_format = gfx::BufferFormat::BGRA_8888;
-      untyped_format = GL_BGRA_EXT;
       break;
     case GL_RGBA16F_EXT:
       buffer_format = gfx::BufferFormat::RGBA_F16;
-      untyped_format = GL_RGBA;
       break;
     case GL_R8_EXT:
       buffer_format = gfx::BufferFormat::R_8;
-      untyped_format = GL_RED_EXT;
       break;
     default:
       LOCAL_SET_GL_ERROR(GL_INVALID_ENUM, "glTexStorage2DImageCHROMIUM",
@@ -17628,7 +17623,7 @@
   scoped_refptr<gl::GLImage> image =
       GetContextGroup()->image_factory()->CreateAnonymousImage(
           gfx::Size(width, height), buffer_format, gfx::BufferUsage::SCANOUT,
-          untyped_format, &is_cleared);
+          &is_cleared);
   if (!image || !image->BindTexImage(target)) {
     LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glTexStorage2DImageCHROMIUM",
                        "Failed to create or bind GL Image");
diff --git a/gpu/command_buffer/service/gr_cache_controller_unittest.cc b/gpu/command_buffer/service/gr_cache_controller_unittest.cc
index 467ffe9..04d5c61 100644
--- a/gpu/command_buffer/service/gr_cache_controller_unittest.cc
+++ b/gpu/command_buffer/service/gr_cache_controller_unittest.cc
@@ -49,7 +49,7 @@
     gl::init::ShutdownGL(false);
   }
 
-  GrContext* gr_context() { return context_state_->gr_context.get(); }
+  GrContext* gr_context() { return context_state_->gr_context; }
 
  protected:
   scoped_refptr<RasterDecoderContextState> context_state_;
diff --git a/gpu/command_buffer/service/image_factory.cc b/gpu/command_buffer/service/image_factory.cc
index cefffee..385c8f2 100644
--- a/gpu/command_buffer/service/image_factory.cc
+++ b/gpu/command_buffer/service/image_factory.cc
@@ -20,7 +20,6 @@
     const gfx::Size& size,
     gfx::BufferFormat format,
     gfx::BufferUsage usage,
-    unsigned internalformat,
     bool* is_cleared) {
   NOTREACHED();
   return nullptr;
diff --git a/gpu/command_buffer/service/image_factory.h b/gpu/command_buffer/service/image_factory.h
index 76cd6d8..339ad39e 100644
--- a/gpu/command_buffer/service/image_factory.h
+++ b/gpu/command_buffer/service/image_factory.h
@@ -28,7 +28,6 @@
       gfx::GpuMemoryBufferHandle handle,
       const gfx::Size& size,
       gfx::BufferFormat format,
-      unsigned internalformat,
       int client_id,
       SurfaceHandle surface_handle) = 0;
 
@@ -39,7 +38,6 @@
       const gfx::Size& size,
       gfx::BufferFormat format,
       gfx::BufferUsage usage,
-      unsigned internalformat,
       bool* is_cleared);
 
   // An image can only be bound to a texture with the appropriate type.
diff --git a/gpu/command_buffer/service/raster_decoder.cc b/gpu/command_buffer/service/raster_decoder.cc
index 3dc4b14..fecca12 100644
--- a/gpu/command_buffer/service/raster_decoder.cc
+++ b/gpu/command_buffer/service/raster_decoder.cc
@@ -492,7 +492,7 @@
 
   gl::GLApi* api() const { return state_.api(); }
   GrContext* gr_context() const {
-    return raster_decoder_context_state_->gr_context.get();
+    return raster_decoder_context_state_->gr_context;
   }
   ServiceTransferCache* transfer_cache() {
     return raster_decoder_context_state_->transfer_cache.get();
@@ -2414,7 +2414,6 @@
   }
 
   DCHECK(GLSupportsFormat(texture_metadata.format()));
-  GLint untyped_format = viz::GLDataFormat(texture_metadata.format());
 
   if (!GetContextGroup()->image_factory()) {
     LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glTexStorage2DImage",
@@ -2426,7 +2425,7 @@
   scoped_refptr<gl::GLImage> image =
       GetContextGroup()->image_factory()->CreateAnonymousImage(
           gfx::Size(width, height), buffer_format, gfx::BufferUsage::SCANOUT,
-          untyped_format, &is_cleared);
+          &is_cleared);
 
   ScopedTextureBinder binder(&state_, texture_manager(), texture_ref,
                              texture_metadata.target(), gr_context());
diff --git a/gpu/command_buffer/service/raster_decoder_context_state.cc b/gpu/command_buffer/service/raster_decoder_context_state.cc
index 9b12cb99..3fad5d903 100644
--- a/gpu/command_buffer/service/raster_decoder_context_state.cc
+++ b/gpu/command_buffer/service/raster_decoder_context_state.cc
@@ -22,10 +22,13 @@
     scoped_refptr<gl::GLShareGroup> share_group,
     scoped_refptr<gl::GLSurface> surface,
     scoped_refptr<gl::GLContext> context,
-    bool use_virtualized_gl_contexts)
+    bool use_virtualized_gl_contexts,
+    GrContext* vulkan_gr_context)
     : share_group(std::move(share_group)),
       surface(std::move(surface)),
       context(std::move(context)),
+      gr_context(vulkan_gr_context),
+      use_vulkan_gr_context(!!gr_context),
       use_virtualized_gl_contexts(use_virtualized_gl_contexts) {
   if (base::ThreadTaskRunnerHandle::IsSet()) {
     base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
@@ -45,52 +48,54 @@
     GrContextOptions::PersistentCache* cache,
     GpuProcessActivityFlags* activity_flags,
     gl::ProgressReporter* progress_reporter) {
-  DCHECK(context->IsCurrent(surface.get()));
+  if (!use_vulkan_gr_context) {
+    DCHECK(context->IsCurrent(surface.get()));
 
-  sk_sp<GrGLInterface> interface(gl::init::CreateGrGLInterface(
-      *context->GetVersionInfo(), workarounds.use_es2_for_oopr,
-      progress_reporter));
-  if (!interface) {
-    LOG(ERROR) << "OOP raster support disabled: GrGLInterface creation "
-                  "failed.";
-    return;
+    sk_sp<GrGLInterface> interface(gl::init::CreateGrGLInterface(
+        *context->GetVersionInfo(), workarounds.use_es2_for_oopr,
+        progress_reporter));
+    if (!interface) {
+      LOG(ERROR) << "OOP raster support disabled: GrGLInterface creation "
+                    "failed.";
+      return;
+    }
+
+    if (activity_flags && cache) {
+      // |activity_flags| is safe to capture here since it must outlive the
+      // this context state.
+      interface->fFunctions.fProgramBinary =
+          [activity_flags](GrGLuint program, GrGLenum binaryFormat,
+                           void* binary, GrGLsizei length) {
+            GpuProcessActivityFlags::ScopedSetFlag scoped_set_flag(
+                activity_flags, ActivityFlagsBase::FLAG_LOADING_PROGRAM_BINARY);
+            glProgramBinary(program, binaryFormat, binary, length);
+          };
+    }
+
+    // If you make any changes to the GrContext::Options here that could
+    // affect text rendering, make sure to match the capabilities initialized
+    // in GetCapabilities and ensuring these are also used by the
+    // PaintOpBufferSerializer.
+    GrContextOptions options;
+    options.fDriverBugWorkarounds =
+        GrDriverBugWorkarounds(workarounds.ToIntSet());
+    size_t max_resource_cache_bytes = 0u;
+    raster::DetermineGrCacheLimitsFromAvailableMemory(
+        &max_resource_cache_bytes, &glyph_cache_max_texture_bytes);
+    options.fGlyphCacheTextureMaximumBytes = glyph_cache_max_texture_bytes;
+    options.fPersistentCache = cache;
+    options.fAvoidStencilBuffers = workarounds.avoid_stencil_buffers;
+    owned_gr_context = GrContext::MakeGL(std::move(interface), options);
+    gr_context = owned_gr_context.get();
+    if (!gr_context) {
+      LOG(ERROR) << "OOP raster support disabled: GrContext creation "
+                    "failed.";
+    } else {
+      constexpr int kMaxGaneshResourceCacheCount = 16384;
+      gr_context->setResourceCacheLimits(kMaxGaneshResourceCacheCount,
+                                         max_resource_cache_bytes);
+    }
   }
-
-  if (activity_flags && cache) {
-    // |activity_flags| is safe to capture here since it must outlive the
-    // this context state.
-    interface->fFunctions.fProgramBinary =
-        [activity_flags](GrGLuint program, GrGLenum binaryFormat, void* binary,
-                         GrGLsizei length) {
-          GpuProcessActivityFlags::ScopedSetFlag scoped_set_flag(
-              activity_flags, ActivityFlagsBase::FLAG_LOADING_PROGRAM_BINARY);
-          glProgramBinary(program, binaryFormat, binary, length);
-        };
-  }
-
-  // If you make any changes to the GrContext::Options here that could
-  // affect text rendering, make sure to match the capabilities initialized
-  // in GetCapabilities and ensuring these are also used by the
-  // PaintOpBufferSerializer.
-  GrContextOptions options;
-  options.fDriverBugWorkarounds =
-      GrDriverBugWorkarounds(workarounds.ToIntSet());
-  size_t max_resource_cache_bytes = 0u;
-  raster::DetermineGrCacheLimitsFromAvailableMemory(
-      &max_resource_cache_bytes, &glyph_cache_max_texture_bytes);
-  options.fGlyphCacheTextureMaximumBytes = glyph_cache_max_texture_bytes;
-  options.fPersistentCache = cache;
-  options.fAvoidStencilBuffers = workarounds.avoid_stencil_buffers;
-  gr_context = GrContext::MakeGL(std::move(interface), options);
-  if (!gr_context) {
-    LOG(ERROR) << "OOP raster support disabled: GrContext creation "
-                  "failed.";
-  } else {
-    constexpr int kMaxGaneshResourceCacheCount = 16384;
-    gr_context->setResourceCacheLimits(kMaxGaneshResourceCacheCount,
-                                       max_resource_cache_bytes);
-  }
-
   transfer_cache = std::make_unique<ServiceTransferCache>();
 }
 
@@ -98,7 +103,7 @@
     const base::trace_event::MemoryDumpArgs& args,
     base::trace_event::ProcessMemoryDump* pmd) {
   if (gr_context)
-    DumpGrMemoryStatistics(gr_context.get(), pmd, base::nullopt);
+    DumpGrMemoryStatistics(gr_context, pmd, base::nullopt);
   return true;
 }
 
diff --git a/gpu/command_buffer/service/raster_decoder_context_state.h b/gpu/command_buffer/service/raster_decoder_context_state.h
index 28321e47..1d8d006 100644
--- a/gpu/command_buffer/service/raster_decoder_context_state.h
+++ b/gpu/command_buffer/service/raster_decoder_context_state.h
@@ -33,7 +33,8 @@
   RasterDecoderContextState(scoped_refptr<gl::GLShareGroup> share_group,
                             scoped_refptr<gl::GLSurface> surface,
                             scoped_refptr<gl::GLContext> context,
-                            bool use_virtualized_gl_contexts);
+                            bool use_virtualized_gl_contexts,
+                            GrContext* vulkan_gr_context = nullptr);
   void InitializeGrContext(const GpuDriverBugWorkarounds& workarounds,
                            GrContextOptions::PersistentCache* cache,
                            GpuProcessActivityFlags* activity_flags = nullptr,
@@ -44,9 +45,11 @@
   scoped_refptr<gl::GLShareGroup> share_group;
   scoped_refptr<gl::GLSurface> surface;
   scoped_refptr<gl::GLContext> context;
-  sk_sp<GrContext> gr_context;
+  GrContext* gr_context;
+  sk_sp<GrContext> owned_gr_context;
   std::unique_ptr<ServiceTransferCache> transfer_cache;
-  bool use_virtualized_gl_contexts = false;
+  const bool use_vulkan_gr_context = false;
+  const bool use_virtualized_gl_contexts = false;
   bool context_lost = false;
   size_t glyph_cache_max_texture_bytes = 0u;
 
diff --git a/gpu/command_buffer/service/shared_image_backing_factory_gl_texture.cc b/gpu/command_buffer/service/shared_image_backing_factory_gl_texture.cc
index 70d999f3..d3cd62b2 100644
--- a/gpu/command_buffer/service/shared_image_backing_factory_gl_texture.cc
+++ b/gpu/command_buffer/service/shared_image_backing_factory_gl_texture.cc
@@ -352,7 +352,8 @@
             feature_info.get(), gl_format);
       }
     }
-    if (!info.enabled || !enable_scanout_images)
+    if (!info.enabled || !enable_scanout_images ||
+        !IsGpuMemoryBufferFormatSupported(format))
       continue;
     gfx::BufferFormat buffer_format = viz::BufferFormat(format);
     switch (buffer_format) {
@@ -366,6 +367,8 @@
     }
     info.allow_scanout = true;
     info.buffer_format = buffer_format;
+    DCHECK_EQ(info.gl_format,
+              gpu::InternalFormatForGpuMemoryBufferFormat(buffer_format));
     if (base::ContainsValue(gpu_preferences.texture_target_exception_list,
                             gfx::BufferUsageAndFormat(gfx::BufferUsage::SCANOUT,
                                                       buffer_format)))
@@ -448,7 +451,7 @@
     bool is_cleared = false;
     image = image_factory_->CreateAnonymousImage(
         size, format_info.buffer_format, gfx::BufferUsage::SCANOUT,
-        format_info.gl_format, &is_cleared);
+        &is_cleared);
     if (!image || !image->BindTexImage(target)) {
       LOG(ERROR) << "CreateSharedImage: Failed to create image";
       api->glBindTextureFn(target, old_texture_binding);
diff --git a/gpu/command_buffer/service/shared_image_backing_factory_gl_texture_unittest.cc b/gpu/command_buffer/service/shared_image_backing_factory_gl_texture_unittest.cc
index d9c3e0c..67b0ac99 100644
--- a/gpu/command_buffer/service/shared_image_backing_factory_gl_texture_unittest.cc
+++ b/gpu/command_buffer/service/shared_image_backing_factory_gl_texture_unittest.cc
@@ -60,7 +60,7 @@
     return GetParam() && gles2::PassthroughCommandDecoderSupported();
   }
 
-  GrContext* gr_context() { return context_state_->gr_context.get(); }
+  GrContext* gr_context() { return context_state_->gr_context; }
 
  protected:
   scoped_refptr<gl::GLSurface> surface_;
diff --git a/gpu/command_buffer/service/wrapped_sk_image.cc b/gpu/command_buffer/service/wrapped_sk_image.cc
index ad25b6db..0680d58 100644
--- a/gpu/command_buffer/service/wrapped_sk_image.cc
+++ b/gpu/command_buffer/service/wrapped_sk_image.cc
@@ -77,7 +77,7 @@
         image_->getBackendTexture(/*flushPendingGrContextIO=*/true);
     DCHECK(gr_texture.isValid());
     return SkSurface::MakeFromBackendTextureAsRenderTarget(
-        context_state_->gr_context.get(), gr_texture, kTopLeft_GrSurfaceOrigin,
+        context_state_->gr_context, gr_texture, kTopLeft_GrSurfaceOrigin,
         final_msaa_count, color_type, /*colorSpace=*/nullptr, &surface_props);
   }
 
@@ -119,7 +119,7 @@
     size_t stride = info.minRowBytes();
     estimated_size_ = info.computeByteSize(stride);
 
-    auto surface = SkSurface::MakeRenderTarget(context_state_->gr_context.get(),
+    auto surface = SkSurface::MakeRenderTarget(context_state_->gr_context,
                                                SkBudgeted::kNo, info);
     if (!surface)
       return false;
diff --git a/gpu/command_buffer/tests/gl_manager.cc b/gpu/command_buffer/tests/gl_manager.cc
index 5423983..4f94d0c 100644
--- a/gpu/command_buffer/tests/gl_manager.cc
+++ b/gpu/command_buffer/tests/gl_manager.cc
@@ -532,11 +532,9 @@
     if (gpu_memory_buffer->GetType() == gfx::NATIVE_PIXMAP) {
       gfx::GpuMemoryBufferHandle handle = gpu_memory_buffer->CloneHandle();
       gfx::BufferFormat format = gpu_memory_buffer->GetFormat();
-      unsigned internalformat =
-          gpu::InternalFormatForGpuMemoryBufferFormat(format);
       gl_image = gpu_memory_buffer_factory_->AsImageFactory()
                      ->CreateImageForGpuMemoryBuffer(
-                         std::move(handle), size, format, internalformat,
+                         std::move(handle), size, format,
                          gpu::kInProcessCommandBufferClientId,
                          gpu::kNullSurfaceHandle);
       if (!gl_image)
diff --git a/gpu/command_buffer/tests/texture_image_factory.cc b/gpu/command_buffer/tests/texture_image_factory.cc
index 509fb80..f37ed61 100644
--- a/gpu/command_buffer/tests/texture_image_factory.cc
+++ b/gpu/command_buffer/tests/texture_image_factory.cc
@@ -55,7 +55,6 @@
     gfx::GpuMemoryBufferHandle handle,
     const gfx::Size& size,
     gfx::BufferFormat format,
-    unsigned internalformat,
     int client_id,
     SurfaceHandle surface_handle) {
   return nullptr;
@@ -69,7 +68,6 @@
     const gfx::Size& size,
     gfx::BufferFormat format,
     gfx::BufferUsage usage,
-    unsigned internalformat,
     bool* is_cleared) {
   *is_cleared = true;
   return new TextureImage(size);
diff --git a/gpu/command_buffer/tests/texture_image_factory.h b/gpu/command_buffer/tests/texture_image_factory.h
index 0bd5671a..60987375 100644
--- a/gpu/command_buffer/tests/texture_image_factory.h
+++ b/gpu/command_buffer/tests/texture_image_factory.h
@@ -17,14 +17,12 @@
       gfx::GpuMemoryBufferHandle handle,
       const gfx::Size& size,
       gfx::BufferFormat format,
-      unsigned internalformat,
       int client_id,
       SurfaceHandle surface_handle) override;
   bool SupportsCreateAnonymousImage() const override;
   scoped_refptr<gl::GLImage> CreateAnonymousImage(const gfx::Size& size,
                                                   gfx::BufferFormat format,
                                                   gfx::BufferUsage usage,
-                                                  unsigned internalformat,
                                                   bool* is_cleared) override;
   unsigned RequiredTextureType() override;
   bool SupportsFormatRGB() override;
diff --git a/gpu/ipc/DEPS b/gpu/ipc/DEPS
index 62e28091..b82b151b 100644
--- a/gpu/ipc/DEPS
+++ b/gpu/ipc/DEPS
@@ -1,4 +1,5 @@
 include_rules = [
+  "+components/viz/common/features.h",
   "+components/viz/common/resources/resource_format.h",
 ]
 
diff --git a/gpu/ipc/common/gpu_memory_buffer_impl_test_template.h b/gpu/ipc/common/gpu_memory_buffer_impl_test_template.h
index 80d18660..5899c54 100644
--- a/gpu/ipc/common/gpu_memory_buffer_impl_test_template.h
+++ b/gpu/ipc/common/gpu_memory_buffer_impl_test_template.h
@@ -14,10 +14,14 @@
 #include <memory>
 
 #include "base/bind.h"
+#include "base/message_loop/message_loop.h"
 #include "build/build_config.h"
 #include "gpu/ipc/common/gpu_memory_buffer_support.h"
+#include "mojo/public/cpp/base/shared_memory_mojom_traits.h"
+#include "mojo/public/cpp/test_support/test_utils.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gfx/buffer_format_util.h"
+#include "ui/gfx/mojo/buffer_types_struct_traits.h"
 
 #if defined(OS_WIN)
 #include "ui/gl/init/gl_factory.h"
@@ -245,12 +249,59 @@
   }
 }
 
+TYPED_TEST_P(GpuMemoryBufferImplTest, SerializeAndDeserialize) {
+  base::MessageLoop message_loop;
+  const gfx::Size kBufferSize(8, 8);
+  const gfx::GpuMemoryBufferType kBufferType = TypeParam::kBufferType;
+
+  for (auto format : gfx::GetBufferFormatsForTesting()) {
+    gfx::BufferUsage usages[] = {
+        gfx::BufferUsage::GPU_READ,
+        gfx::BufferUsage::SCANOUT,
+        gfx::BufferUsage::SCANOUT_CAMERA_READ_WRITE,
+        gfx::BufferUsage::CAMERA_AND_CPU_READ_WRITE,
+        gfx::BufferUsage::SCANOUT_CPU_READ_WRITE,
+        gfx::BufferUsage::SCANOUT_VDA_WRITE,
+        gfx::BufferUsage::GPU_READ_CPU_READ_WRITE,
+        gfx::BufferUsage::GPU_READ_CPU_READ_WRITE_PERSISTENT};
+    for (auto usage : usages) {
+      if (!TestFixture::gpu_memory_buffer_support()->IsConfigurationSupported(
+              TypeParam::kBufferType, format, usage))
+        continue;
+
+      bool destroyed = false;
+      gfx::GpuMemoryBufferHandle handle;
+      GpuMemoryBufferImpl::DestructionCallback destroy_callback =
+          TestFixture::CreateGpuMemoryBuffer(kBufferSize, format, usage,
+                                             &handle, &destroyed);
+
+      gfx::GpuMemoryBufferHandle output_handle;
+      mojo::test::SerializeAndDeserialize<gfx::mojom::GpuMemoryBufferHandle>(
+          &handle, &output_handle);
+      EXPECT_EQ(output_handle.type, kBufferType);
+
+      std::unique_ptr<GpuMemoryBufferImpl> buffer(
+          TestFixture::gpu_memory_buffer_support()
+              ->CreateGpuMemoryBufferImplFromHandle(std::move(output_handle),
+                                                    kBufferSize, format, usage,
+                                                    destroy_callback));
+      ASSERT_TRUE(buffer);
+      EXPECT_EQ(buffer->GetFormat(), format);
+
+      // Check if destruction callback is executed when deleting the buffer.
+      buffer.reset();
+      ASSERT_TRUE(destroyed);
+    }
+  }
+}
+
 // The GpuMemoryBufferImplTest test case verifies behavior that is expected
 // from a GpuMemoryBuffer implementation in order to be conformant.
 REGISTER_TYPED_TEST_CASE_P(GpuMemoryBufferImplTest,
                            CreateFromHandle,
                            Map,
-                           PersistentMap);
+                           PersistentMap,
+                           SerializeAndDeserialize);
 
 TYPED_TEST_CASE_P(GpuMemoryBufferImplCreateTest);
 
diff --git a/gpu/ipc/in_process_command_buffer.cc b/gpu/ipc/in_process_command_buffer.cc
index 50aced5..59e9925 100644
--- a/gpu/ipc/in_process_command_buffer.cc
+++ b/gpu/ipc/in_process_command_buffer.cc
@@ -28,6 +28,7 @@
 #include "base/trace_event/memory_dump_manager.h"
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
+#include "components/viz/common/features.h"
 #include "gpu/command_buffer/client/gpu_control_client.h"
 #include "gpu/command_buffer/client/gpu_memory_buffer_manager.h"
 #include "gpu/command_buffer/client/shared_image_interface.h"
@@ -386,6 +387,19 @@
   use_virtualized_gl_context_ |=
       context_group_->feature_info()->workarounds().use_virtualized_gl_contexts;
 
+  const auto& gpu_feature_info = task_executor_->gpu_feature_info();
+  const bool use_oop_rasterization =
+      gpu_feature_info.status_values[GPU_FEATURE_TYPE_OOP_RASTERIZATION] ==
+      gpu::kGpuFeatureStatusEnabled;
+
+  // With OOP-R, SkiaRenderer and Skia DDL, we will only have one GLContext
+  // and share it with RasterDecoders and DisplayCompositor. So it is not
+  // necessary to use virtualized gl context anymore.
+  // TODO(penghuang): Make virtualized gl context work with SkiaRenderer + DDL +
+  // OOPR. https://crbug.com/838899
+  if (features::IsUsingSkiaDeferredDisplayList() && use_oop_rasterization)
+    use_virtualized_gl_context_ = false;
+
   // TODO(sunnyps): Should this use ScopedCrashKey instead?
   crash_keys::gpu_gl_context_is_virtual.Set(use_virtualized_gl_context_ ? "1"
                                                                         : "0");
@@ -995,14 +1009,14 @@
     return;
   }
 
-  unsigned internalformat = gpu::InternalFormatForGpuMemoryBufferFormat(format);
-
   switch (handle.type) {
     case gfx::SHARED_MEMORY_BUFFER: {
       if (!base::IsValueInRangeForNumericType<size_t>(handle.stride)) {
         LOG(ERROR) << "Invalid stride for image.";
         return;
       }
+      unsigned internalformat =
+          gpu::InternalFormatForGpuMemoryBufferFormat(format);
       scoped_refptr<gl::GLImageSharedMemory> image(
           new gl::GLImageSharedMemory(size, internalformat));
       if (!image->Initialize(handle.region, handle.id, format, handle.offset,
@@ -1022,8 +1036,8 @@
 
       scoped_refptr<gl::GLImage> image =
           image_factory_->CreateImageForGpuMemoryBuffer(
-              std::move(handle), size, format, internalformat,
-              kInProcessCommandBufferClientId, kNullSurfaceHandle);
+              std::move(handle), size, format, kInProcessCommandBufferClientId,
+              kNullSurfaceHandle);
       if (!image.get()) {
         LOG(ERROR) << "Failed to create image for buffer.";
         return;
diff --git a/gpu/ipc/service/gles2_command_buffer_stub.cc b/gpu/ipc/service/gles2_command_buffer_stub.cc
index d80cbca..8ff9ef4d 100644
--- a/gpu/ipc/service/gles2_command_buffer_stub.cc
+++ b/gpu/ipc/service/gles2_command_buffer_stub.cc
@@ -19,6 +19,7 @@
 #include "base/time/time.h"
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
+#include "components/viz/common/features.h"
 #include "gpu/command_buffer/common/constants.h"
 #include "gpu/command_buffer/common/gpu_memory_buffer_support.h"
 #include "gpu/command_buffer/common/mailbox.h"
@@ -123,6 +124,19 @@
   // only a single context. See crbug.com/510243 for details.
   use_virtualized_gl_context_ |= manager->mailbox_manager()->UsesSync();
 
+  const auto& gpu_feature_info = manager->gpu_feature_info();
+  const bool use_oop_rasterization =
+      gpu_feature_info.status_values[GPU_FEATURE_TYPE_OOP_RASTERIZATION] ==
+      gpu::kGpuFeatureStatusEnabled;
+
+  // With OOP-R, SkiaRenderer and Skia DDL, we will only have one GLContext
+  // and share it with RasterDecoders and DisplayCompositor. So it is not
+  // necessary to use virtualized gl context anymore.
+  // TODO(penghuang): Make virtualized gl context work with SkiaRenderer + DDL +
+  // OOPR. https://crbug.com/838899
+  if (features::IsUsingSkiaDeferredDisplayList() && use_oop_rasterization)
+    use_virtualized_gl_context_ = false;
+
   bool offscreen = (surface_handle_ == kNullSurfaceHandle);
   gl::GLSurface* default_surface = manager->default_offscreen_surface();
   // On low-spec Android devices, the default offscreen surface is
diff --git a/gpu/ipc/service/gpu_channel.cc b/gpu/ipc/service/gpu_channel.cc
index e0c20d4c..3e00904 100644
--- a/gpu/ipc/service/gpu_channel.cc
+++ b/gpu/ipc/service/gpu_channel.cc
@@ -725,11 +725,12 @@
     const gfx::Size& size,
     gfx::BufferFormat format,
     SurfaceHandle surface_handle) {
-  unsigned internalformat = gpu::InternalFormatForGpuMemoryBufferFormat(format);
   switch (handle.type) {
     case gfx::SHARED_MEMORY_BUFFER: {
       if (!base::IsValueInRangeForNumericType<size_t>(handle.stride))
         return nullptr;
+      unsigned internalformat =
+          gpu::InternalFormatForGpuMemoryBufferFormat(format);
       scoped_refptr<gl::GLImageSharedMemory> image(
           new gl::GLImageSharedMemory(size, internalformat));
       if (!image->Initialize(handle.region, handle.id, format, handle.offset,
@@ -747,8 +748,7 @@
       return manager->gpu_memory_buffer_factory()
           ->AsImageFactory()
           ->CreateImageForGpuMemoryBuffer(std::move(handle), size, format,
-                                          internalformat, client_id_,
-                                          surface_handle);
+                                          client_id_, surface_handle);
     }
   }
 }
diff --git a/gpu/ipc/service/gpu_channel_manager.cc b/gpu/ipc/service/gpu_channel_manager.cc
index 6f66fa2..39d421b 100644
--- a/gpu/ipc/service/gpu_channel_manager.cc
+++ b/gpu/ipc/service/gpu_channel_manager.cc
@@ -16,6 +16,7 @@
 #include "base/sys_info.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
+#include "components/viz/common/features.h"
 #include "gpu/command_buffer/common/sync_token.h"
 #include "gpu/command_buffer/service/feature_info.h"
 #include "gpu/command_buffer/service/gpu_tracer.h"
@@ -61,7 +62,8 @@
     GpuMemoryBufferFactory* gpu_memory_buffer_factory,
     const GpuFeatureInfo& gpu_feature_info,
     GpuProcessActivityFlags activity_flags,
-    scoped_refptr<gl::GLSurface> default_offscreen_surface)
+    scoped_refptr<gl::GLSurface> default_offscreen_surface,
+    GrContext* vulkan_gr_context)
     : task_runner_(task_runner),
       io_task_runner_(io_task_runner),
       gpu_preferences_(gpu_preferences),
@@ -82,6 +84,7 @@
       memory_pressure_listener_(
           base::Bind(&GpuChannelManager::HandleMemoryPressure,
                      base::Unretained(this))),
+      vulkan_gr_context_(vulkan_gr_context),
       weak_factory_(this) {
   DCHECK(task_runner->BelongsToCurrentThread());
   DCHECK(io_task_runner);
@@ -365,6 +368,18 @@
   // only a single context. See crbug.com/510243 for details.
   use_virtualized_gl_contexts |= mailbox_manager_->UsesSync();
 
+  const bool use_oop_rasterization =
+      gpu_feature_info_.status_values[GPU_FEATURE_TYPE_OOP_RASTERIZATION] ==
+      gpu::kGpuFeatureStatusEnabled;
+
+  // With OOP-R, SkiaRenderer and Skia DDL, we will only have one GLContext
+  // and share it with RasterDecoders and DisplayCompositor. So it is not
+  // necessary to use virtualized gl context anymore.
+  // TODO(penghuang): Make virtualized gl context work with SkiaRenderer + DDL +
+  // OOPR. https://crbug.com/838899
+  if (features::IsUsingSkiaDeferredDisplayList() && use_oop_rasterization)
+    use_virtualized_gl_contexts = false;
+
   const bool use_passthrough_decoder =
       gles2::PassthroughCommandDecoderSupported() &&
       gpu_preferences_.use_passthrough_cmd_decoder;
@@ -416,9 +431,10 @@
     return nullptr;
   }
 
+  // TODO(penghuang): https://crbug.com/899735 Handle device lost for Vulkan.
   raster_decoder_context_state_ = new raster::RasterDecoderContextState(
       std::move(share_group), std::move(surface), std::move(context),
-      use_virtualized_gl_contexts);
+      use_virtualized_gl_contexts, vulkan_gr_context_);
   const bool enable_raster_transport =
       gpu_feature_info_.status_values[GPU_FEATURE_TYPE_OOP_RASTERIZATION] ==
       gpu::kGpuFeatureStatusEnabled;
diff --git a/gpu/ipc/service/gpu_channel_manager.h b/gpu/ipc/service/gpu_channel_manager.h
index 73409b05..e0b60d571 100644
--- a/gpu/ipc/service/gpu_channel_manager.h
+++ b/gpu/ipc/service/gpu_channel_manager.h
@@ -37,6 +37,8 @@
 #include "ui/gl/gl_surface.h"
 #include "url/gurl.h"
 
+class GrContext;
+
 namespace gl {
 class GLShareGroup;
 }
@@ -76,7 +78,8 @@
                     GpuMemoryBufferFactory* gpu_memory_buffer_factory,
                     const GpuFeatureInfo& gpu_feature_info,
                     GpuProcessActivityFlags activity_flags,
-                    scoped_refptr<gl::GLSurface> default_offscreen_surface);
+                    scoped_refptr<gl::GLSurface> default_offscreen_surface,
+                    GrContext* vulkan_gr_context = nullptr);
   ~GpuChannelManager() override;
 
   GpuChannelManagerDelegate* delegate() const { return delegate_; }
@@ -238,6 +241,10 @@
   scoped_refptr<raster::RasterDecoderContextState>
       raster_decoder_context_state_;
 
+  // With --enable-vulkan, the vulkan_gr_context_ will be set from
+  // viz::GpuServiceImpl. The raster decoders will use it for rasterization.
+  GrContext* vulkan_gr_context_;
+
   // Member variables should appear before the WeakPtrFactory, to ensure
   // that any WeakPtrs to Controller are invalidated before its members
   // variable's destructors are executed, rendering them invalid.
diff --git a/gpu/ipc/service/gpu_memory_buffer_factory_android_hardware_buffer.cc b/gpu/ipc/service/gpu_memory_buffer_factory_android_hardware_buffer.cc
index 459ef53..483aedf3 100644
--- a/gpu/ipc/service/gpu_memory_buffer_factory_android_hardware_buffer.cc
+++ b/gpu/ipc/service/gpu_memory_buffer_factory_android_hardware_buffer.cc
@@ -64,7 +64,6 @@
     gfx::GpuMemoryBufferHandle handle,
     const gfx::Size& size,
     gfx::BufferFormat format,
-    unsigned internalformat,
     int client_id,
     SurfaceHandle surface_handle) {
   // We should only end up in this code path if the memory buffer has a valid
diff --git a/gpu/ipc/service/gpu_memory_buffer_factory_android_hardware_buffer.h b/gpu/ipc/service/gpu_memory_buffer_factory_android_hardware_buffer.h
index 3309e1c..f2e33f4 100644
--- a/gpu/ipc/service/gpu_memory_buffer_factory_android_hardware_buffer.h
+++ b/gpu/ipc/service/gpu_memory_buffer_factory_android_hardware_buffer.h
@@ -42,7 +42,6 @@
       gfx::GpuMemoryBufferHandle handle,
       const gfx::Size& size,
       gfx::BufferFormat format,
-      unsigned internalformat,
       int client_id,
       SurfaceHandle surface_handle) override;
   unsigned RequiredTextureType() override;
diff --git a/gpu/ipc/service/gpu_memory_buffer_factory_dxgi.cc b/gpu/ipc/service/gpu_memory_buffer_factory_dxgi.cc
index 79e15e1..f373a08 100644
--- a/gpu/ipc/service/gpu_memory_buffer_factory_dxgi.cc
+++ b/gpu/ipc/service/gpu_memory_buffer_factory_dxgi.cc
@@ -102,7 +102,6 @@
     gfx::GpuMemoryBufferHandle handle,
     const gfx::Size& size,
     gfx::BufferFormat format,
-    unsigned internalformat,
     int client_id,
     SurfaceHandle surface_handle) {
   if (handle.type != gfx::DXGI_SHARED_HANDLE)
diff --git a/gpu/ipc/service/gpu_memory_buffer_factory_dxgi.h b/gpu/ipc/service/gpu_memory_buffer_factory_dxgi.h
index c2cf970..38c196e 100644
--- a/gpu/ipc/service/gpu_memory_buffer_factory_dxgi.h
+++ b/gpu/ipc/service/gpu_memory_buffer_factory_dxgi.h
@@ -50,7 +50,6 @@
       gfx::GpuMemoryBufferHandle handle,
       const gfx::Size& size,
       gfx::BufferFormat format,
-      unsigned internalformat,
       int client_id,
       SurfaceHandle surface_handle) override;
   unsigned RequiredTextureType() override;
diff --git a/gpu/ipc/service/gpu_memory_buffer_factory_io_surface.cc b/gpu/ipc/service/gpu_memory_buffer_factory_io_surface.cc
index 7d43155..c3ae7805 100644
--- a/gpu/ipc/service/gpu_memory_buffer_factory_io_surface.cc
+++ b/gpu/ipc/service/gpu_memory_buffer_factory_io_surface.cc
@@ -8,6 +8,7 @@
 
 #include "base/debug/dump_without_crashing.h"
 #include "base/logging.h"
+#include "gpu/command_buffer/common/gpu_memory_buffer_support.h"
 #include "ui/gfx/buffer_format_util.h"
 #include "ui/gfx/mac/io_surface.h"
 #include "ui/gl/gl_bindings.h"
@@ -108,7 +109,6 @@
     gfx::GpuMemoryBufferHandle handle,
     const gfx::Size& size,
     gfx::BufferFormat format,
-    unsigned internalformat,
     int client_id,
     SurfaceHandle surface_handle) {
   base::AutoLock lock(io_surfaces_lock_);
@@ -121,6 +121,7 @@
     return scoped_refptr<gl::GLImage>();
   }
 
+  unsigned internalformat = gpu::InternalFormatForGpuMemoryBufferFormat(format);
   scoped_refptr<gl::GLImageIOSurface> image(
       gl::GLImageIOSurface::Create(size, internalformat));
   if (!image->Initialize(it->second.get(), handle.id, format)) {
@@ -135,7 +136,6 @@
 GpuMemoryBufferFactoryIOSurface::CreateAnonymousImage(const gfx::Size& size,
                                                       gfx::BufferFormat format,
                                                       gfx::BufferUsage usage,
-                                                      unsigned internalformat,
                                                       bool* is_cleared) {
   bool should_clear = false;
   base::ScopedCFTypeRef<IOSurfaceRef> io_surface(
@@ -167,6 +167,7 @@
     LOG(ERROR) << "Failed to create IOSurface mach port.";
   }
 
+  unsigned internalformat = gpu::InternalFormatForGpuMemoryBufferFormat(format);
   scoped_refptr<gl::GLImageIOSurface> image(
       gl::GLImageIOSurface::Create(size, internalformat));
   // Use an invalid GMB id so that we can differentiate between anonymous and
diff --git a/gpu/ipc/service/gpu_memory_buffer_factory_io_surface.h b/gpu/ipc/service/gpu_memory_buffer_factory_io_surface.h
index 62e3ed21..1ec67a3 100644
--- a/gpu/ipc/service/gpu_memory_buffer_factory_io_surface.h
+++ b/gpu/ipc/service/gpu_memory_buffer_factory_io_surface.h
@@ -51,14 +51,12 @@
       gfx::GpuMemoryBufferHandle handle,
       const gfx::Size& size,
       gfx::BufferFormat format,
-      unsigned internalformat,
       int client_id,
       SurfaceHandle surface_handle) override;
   bool SupportsCreateAnonymousImage() const override;
   scoped_refptr<gl::GLImage> CreateAnonymousImage(const gfx::Size& size,
                                                   gfx::BufferFormat format,
                                                   gfx::BufferUsage usage,
-                                                  unsigned internalformat,
                                                   bool* is_cleared) override;
   unsigned RequiredTextureType() override;
   bool SupportsFormatRGB() override;
diff --git a/gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap.cc b/gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap.cc
index 2900b61..8d9f8923 100644
--- a/gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap.cc
+++ b/gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap.cc
@@ -4,6 +4,7 @@
 
 #include "gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap.h"
 
+#include "gpu/command_buffer/common/gpu_memory_buffer_support.h"
 #include "ui/gfx/buffer_format_util.h"
 #include "ui/gfx/client_native_pixmap.h"
 #include "ui/gfx/linux/native_pixmap_dmabuf.h"
@@ -82,7 +83,6 @@
     gfx::GpuMemoryBufferHandle handle,
     const gfx::Size& size,
     gfx::BufferFormat format,
-    unsigned internalformat,
     int client_id,
     SurfaceHandle surface_handle) {
   DCHECK_EQ(handle.type, gfx::NATIVE_PIXMAP);
@@ -123,6 +123,7 @@
     }
   }
 
+  unsigned internalformat = gpu::InternalFormatForGpuMemoryBufferFormat(format);
   scoped_refptr<gl::GLImageNativePixmap> image(
       new gl::GLImageNativePixmap(size, internalformat));
   if (!image->Initialize(pixmap.get(), format)) {
@@ -147,7 +148,6 @@
     const gfx::Size& size,
     gfx::BufferFormat format,
     gfx::BufferUsage usage,
-    unsigned internalformat,
     bool* is_cleared) {
   scoped_refptr<gfx::NativePixmap> pixmap;
 #if defined(USE_OZONE)
@@ -163,6 +163,7 @@
                << gfx::BufferFormatToString(format);
     return nullptr;
   }
+  unsigned internalformat = gpu::InternalFormatForGpuMemoryBufferFormat(format);
   scoped_refptr<gl::GLImageNativePixmap> image(
       new gl::GLImageNativePixmap(size, internalformat));
   if (!image->Initialize(pixmap.get(), format)) {
diff --git a/gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap.h b/gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap.h
index 69745d2..c9486a0 100644
--- a/gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap.h
+++ b/gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap.h
@@ -46,14 +46,12 @@
       gfx::GpuMemoryBufferHandle handle,
       const gfx::Size& size,
       gfx::BufferFormat format,
-      unsigned internalformat,
       int client_id,
       SurfaceHandle surface_handle) override;
   bool SupportsCreateAnonymousImage() const override;
   scoped_refptr<gl::GLImage> CreateAnonymousImage(const gfx::Size& size,
                                                   gfx::BufferFormat format,
                                                   gfx::BufferUsage usage,
-                                                  unsigned internalformat,
                                                   bool* is_cleared) override;
   unsigned RequiredTextureType() override;
 
diff --git a/gpu/vulkan/BUILD.gn b/gpu/vulkan/BUILD.gn
index 12f00c4a..3e8862d 100644
--- a/gpu/vulkan/BUILD.gn
+++ b/gpu/vulkan/BUILD.gn
@@ -48,10 +48,6 @@
       "//ui/gfx",
     ]
 
-    if (use_x11) {
-      deps += [ "//third_party/angle/third_party/vulkan-validation-layers:vulkan_validation_layers" ]
-    }
-
     data_deps = []
     if (is_fuchsia) {
       data_deps += [ "//third_party/fuchsia-sdk:vulkan_layers" ]
diff --git a/gpu/vulkan/vulkan_instance.cc b/gpu/vulkan/vulkan_instance.cc
index 749484c..b612179 100644
--- a/gpu/vulkan/vulkan_instance.cc
+++ b/gpu/vulkan/vulkan_instance.cc
@@ -113,7 +113,9 @@
   }
 
   std::unordered_set<std::string> desired_layers({
-#if defined(USE_X11) && !defined(USE_OZONE)
+#if !defined(USE_X11) && !defined(USE_OZONE)
+    // TODO(crbug.com/843346): Make validation work in combination with
+    // VK_KHR_xlib_surface or switch to VK_KHR_xcb_surface.
     "VK_LAYER_LUNARG_standard_validation",
 #endif
   });
diff --git a/ios/build/bots/scripts/test_runner.py b/ios/build/bots/scripts/test_runner.py
index 6a9cec35..7e5421e 100644
--- a/ios/build/bots/scripts/test_runner.py
+++ b/ios/build/bots/scripts/test_runner.py
@@ -941,12 +941,25 @@
       Args:
         cert_path: Path to the certificate to copy to all emulators
     '''
+
+    # TODO(crbug.com/892381): Remove this debug logging
+    print 'ERICALE copy_trusted_certificate DEBUG START'
+    simLocs = glob.glob(
+        '{}/Library/Developer/CoreSimulator/Devices/*/data/Library/'.
+        format(os.path.expanduser('~')))
+    for loc in simLocs:
+      print loc
+      print subprocess.check_output(['ls', '-lsr', loc])
+      print "--"
+    print 'ERICALE copy_trusted_certificate DEBUG END'
+
     trustStores = glob.glob(
-        '{}/Library/Developer/CoreSimulator/Devices/*/data/Library/Keychains/{}'.
-        format(os.path.expanduser('~'), 'TrustStore.sqlite3'))
+        '{}/Library/Developer/CoreSimulator/Devices/*/data/Library'.
+        format(os.path.expanduser('~')))
     for trustStore in trustStores:
       print 'Copying TrustStore to {}'.format(trustStore)
-      shutil.copy(cert_path, trustStore)
+      os.makedirs(trustStore + "/Keychains/",exist_ok=True)
+      shutil.copy(cert_path, trustStore + "/Keychains/TrustStore.sqlite3")
 
 
 class WprProxySimulatorTestRunner(SimulatorTestRunner):
diff --git a/ios/build/bots/tests/eg_tests.json b/ios/build/bots/tests/eg_tests.json
index e6249baa..b54249e 100644
--- a/ios/build/bots/tests/eg_tests.json
+++ b/ios/build/bots/tests/eg_tests.json
@@ -24,9 +24,6 @@
     },
     {
       "app": "ios_chrome_reading_list_egtests",
-      "test args": [
-        "--enable-reading-list"
-      ],
       "xctest": true
     },
     {
diff --git a/ios/chrome/browser/autofill/automation/automation_action.mm b/ios/chrome/browser/autofill/automation/automation_action.mm
index aa0fa32..c9feb0b 100644
--- a/ios/chrome/browser/autofill/automation/automation_action.mm
+++ b/ios/chrome/browser/autofill/automation/automation_action.mm
@@ -112,6 +112,18 @@
 @interface AutomationActionSelectDropdown : AutomationAction
 @end
 
+// An action that loads a web page.
+// This is recorded in tandem with the actions that cause loads to
+// occur (i.e. clicking on a link); therefore, this action is
+// a no-op when replaying.
+// We assume this action has a format resembling:
+// {
+//   "url": "www.google.com",
+//   "type": "loadPage"
+// }
+@interface AutomationActionLoadPage : AutomationAction
+@end
+
 @implementation AutomationAction
 
 + (instancetype)actionWithValueDictionary:
@@ -134,6 +146,7 @@
     @"autofill" : [AutomationActionAutofill class],
     @"validateField" : [AutomationActionValidateField class],
     @"select" : [AutomationActionSelectDropdown class],
+    @"loadPage" : [AutomationActionLoadPage class],
     // More to come.
   };
 
@@ -247,6 +260,14 @@
 
 @end
 
+@implementation AutomationActionLoadPage
+
+- (void)execute {
+  // loadPage is a no-op action - perform nothing
+}
+
+@end
+
 @implementation AutomationActionWaitFor
 
 - (void)execute {
diff --git a/ios/chrome/browser/ui/BUILD.gn b/ios/chrome/browser/ui/BUILD.gn
index 933da7e4..5ed8e7f 100644
--- a/ios/chrome/browser/ui/BUILD.gn
+++ b/ios/chrome/browser/ui/BUILD.gn
@@ -337,7 +337,7 @@
     "//ios/chrome/browser/ui/infobars",
     "//ios/chrome/browser/ui/infobars:public",
     "//ios/chrome/browser/ui/keyboard",
-    "//ios/chrome/browser/ui/location_bar:toolbar_model_delegate",
+    "//ios/chrome/browser/ui/location_bar:location_bar_model_delegate",
     "//ios/chrome/browser/ui/main:tab_switcher",
     "//ios/chrome/browser/ui/main_content:main_content_ui",
     "//ios/chrome/browser/ui/main_content:main_content_ui_broadcasting_util",
@@ -496,7 +496,7 @@
     "//ios/chrome/browser/tabs",
     "//ios/chrome/browser/tabs:tabs_internal",
     "//ios/chrome/browser/ui/commands",
-    "//ios/chrome/browser/ui/location_bar:toolbar_model_delegate",
+    "//ios/chrome/browser/ui/location_bar:location_bar_model_delegate",
     "//ios/chrome/browser/ui/omnibox:omnibox_internal",
     "//ios/chrome/browser/ui/toolbar",
     "//ios/chrome/browser/ui/util",
diff --git a/ios/chrome/browser/ui/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view_controller.mm
index 5e38623..cbcca70 100644
--- a/ios/chrome/browser/ui/browser_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view_controller.mm
@@ -38,7 +38,7 @@
 #include "components/feature_engagement/public/tracker.h"
 #include "components/image_fetcher/ios/ios_image_data_fetcher_wrapper.h"
 #import "components/language/ios/browser/ios_language_detection_tab_helper.h"
-#include "components/omnibox/browser/toolbar_model_impl.h"
+#include "components/omnibox/browser/location_bar_model_impl.h"
 #include "components/prefs/pref_service.h"
 #include "components/reading_list/core/reading_list_model.h"
 #include "components/search_engines/search_engines_pref_names.h"
@@ -157,7 +157,7 @@
 #import "ios/chrome/browser/ui/infobars/infobar_coordinator.h"
 #import "ios/chrome/browser/ui/infobars/infobar_positioner.h"
 #import "ios/chrome/browser/ui/key_commands_provider.h"
-#include "ios/chrome/browser/ui/location_bar/toolbar_model_delegate_ios.h"
+#include "ios/chrome/browser/ui/location_bar/location_bar_model_delegate_ios.h"
 #import "ios/chrome/browser/ui/location_bar_notification_names.h"
 #import "ios/chrome/browser/ui/main_content/main_content_ui.h"
 #import "ios/chrome/browser/ui/main_content/main_content_ui_broadcasting_util.h"
@@ -448,8 +448,8 @@
 
   // Facade objects used by |_toolbarCoordinator|.
   // Must outlive |_toolbarCoordinator|.
-  std::unique_ptr<ToolbarModelDelegateIOS> _toolbarModelDelegate;
-  std::unique_ptr<ToolbarModel> _toolbarModel;
+  std::unique_ptr<LocationBarModelDelegateIOS> _locationBarModelDelegate;
+  std::unique_ptr<LocationBarModel> _locationBarModel;
 
   // Controller for edge swipe gestures for page and tab navigation.
   SideSwipeController* _sideSwipeController;
@@ -1805,8 +1805,8 @@
     self.toolbarInterface = nil;
     [_toolbarUIUpdater stopUpdating];
     _toolbarUIUpdater = nil;
-    _toolbarModelDelegate = nil;
-    _toolbarModel = nil;
+    _locationBarModelDelegate = nil;
+    _locationBarModel = nil;
     self.helper = nil;
     [self.tabStripCoordinator stop];
     self.tabStripCoordinator = nil;
@@ -2090,7 +2090,7 @@
 // Create the UI elements.  May or may not have valid browser state & tab model.
 - (void)buildToolbarAndTabStrip {
   DCHECK([self isViewLoaded]);
-  DCHECK(!_toolbarModelDelegate);
+  DCHECK(!_locationBarModelDelegate);
 
   // Initialize the prerender service before creating the toolbar controller.
   PrerenderService* prerenderService =
@@ -2099,11 +2099,11 @@
     prerenderService->SetDelegate(self);
   }
 
-  // Create the toolbar model and controller.
-  _toolbarModelDelegate.reset(
-      new ToolbarModelDelegateIOS([_model webStateList]));
-  _toolbarModel = std::make_unique<ToolbarModelImpl>(
-      _toolbarModelDelegate.get(), kMaxURLDisplayChars);
+  // Create the location bar model and controller.
+  _locationBarModelDelegate.reset(
+      new LocationBarModelDelegateIOS([_model webStateList]));
+  _locationBarModel = std::make_unique<LocationBarModelImpl>(
+      _locationBarModelDelegate.get(), kMaxURLDisplayChars);
   self.helper = [_dependencyFactory newBrowserViewControllerHelper];
 
   PrimaryToolbarCoordinator* topToolbarCoordinator =
@@ -2348,7 +2348,7 @@
 // both browser state and tab model are valid.
 - (void)addUIFunctionalityForModelAndBrowserState {
   DCHECK(_browserState);
-  DCHECK(_toolbarModel);
+  DCHECK(_locationBarModel);
   DCHECK(_model);
   DCHECK([self isViewLoaded]);
 
@@ -2420,7 +2420,7 @@
       initWithBaseViewController:self
                     browserState:_browserState
                       dispatcher:self.dispatcher];
-  [_paymentRequestManager setToolbarModel:_toolbarModel.get()];
+  [_paymentRequestManager setLocationBarModel:_locationBarModel.get()];
   [_paymentRequestManager setActiveWebState:[_model currentTab].webState];
 }
 
@@ -3101,12 +3101,9 @@
 #pragma mark - Private Methods: Recent Tabs
 
 - (void)createRecentTabsCoordinator {
-  // Always use the regular BrowserState since the incognito one doesn't have a
-  // SignIn manager.
-  RecentTabsCoordinator* recentTabsCoordinator = [[RecentTabsCoordinator alloc]
-      initWithBaseViewController:self
-                    browserState:_browserState
-                                     ->GetOriginalChromeBrowserState()];
+  RecentTabsCoordinator* recentTabsCoordinator =
+      [[RecentTabsCoordinator alloc] initWithBaseViewController:self
+                                                   browserState:_browserState];
   recentTabsCoordinator.loader = self;
   recentTabsCoordinator.dispatcher = self.dispatcher;
   self.recentTabsCoordinator = recentTabsCoordinator;
@@ -4502,8 +4499,8 @@
   }
 }
 
-- (ToolbarModel*)toolbarModel {
-  return _toolbarModel.get();
+- (LocationBarModel*)locationBarModel {
+  return _locationBarModel.get();
 }
 
 #pragma mark - BrowserCommands
diff --git a/ios/chrome/browser/ui/browser_view_controller_helper_unittest.mm b/ios/chrome/browser/ui/browser_view_controller_helper_unittest.mm
index 042cd8d..3bff3bdd 100644
--- a/ios/chrome/browser/ui/browser_view_controller_helper_unittest.mm
+++ b/ios/chrome/browser/ui/browser_view_controller_helper_unittest.mm
@@ -11,7 +11,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "components/bookmarks/browser/bookmark_model.h"
 #include "components/bookmarks/test/bookmark_test_helpers.h"
-#include "components/omnibox/browser/test_toolbar_model.h"
+#include "components/omnibox/browser/test_location_bar_model.h"
 #include "ios/chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
 #import "ios/chrome/browser/ui/toolbar/test/toolbar_test_navigation_manager.h"
@@ -80,7 +80,7 @@
 
 TEST_F(BrowserViewControllerHelperTest, TestisWebStateBookmarked) {
   // Set the curent tab to |kWebUrl| and create a bookmark for |kWebUrl|, then
-  // verify that the toolbar model indicates that the URL is bookmarked.
+  // verify that the location bar model indicates that the URL is bookmarked.
   web_state_->SetCurrentURL(GURL(kWebUrl));
   bookmarks::BookmarkModel* bookmark_model =
       ios::BookmarkModelFactory::GetForBrowserState(
@@ -92,8 +92,8 @@
                              base::UTF8ToUTF16(kWebUrl), GURL(kWebUrl));
   EXPECT_TRUE([helper_ isWebStateBookmarked:web_state_.get()]);
 
-  // Remove the bookmark and verify the toolbar model indicates that the URL is
-  // not bookmarked.
+  // Remove the bookmark and verify the location bar model indicates that the
+  // URL is not bookmarked.
   bookmark_model->Remove(node);
   EXPECT_FALSE([helper_ isWebStateBookmarked:web_state_.get()]);
 }
diff --git a/ios/chrome/browser/ui/browser_view_controller_unittest.mm b/ios/chrome/browser/ui/browser_view_controller_unittest.mm
index 19951798..1a4e7c2 100644
--- a/ios/chrome/browser/ui/browser_view_controller_unittest.mm
+++ b/ios/chrome/browser/ui/browser_view_controller_unittest.mm
@@ -12,7 +12,7 @@
 #include "base/path_service.h"
 #include "base/strings/sys_string_conversions.h"
 #include "components/bookmarks/test/bookmark_test_helpers.h"
-#include "components/omnibox/browser/test_toolbar_model.h"
+#include "components/omnibox/browser/test_location_bar_model.h"
 #include "components/prefs/testing_pref_service.h"
 #include "components/search_engines/template_url_service.h"
 #include "components/sessions/core/tab_restore_service.h"
@@ -354,7 +354,7 @@
        TestLocationBarBeganEdit_whenPageLoadIsInProgress) {
   OCMockObject* tabMock = static_cast<OCMockObject*>(tab_);
 
-  // Have the TestToolbarModel indicate that a page load is in progress.
+  // Have the TestLocationBarModel indicate that a page load is in progress.
   id partialMock = OCMPartialMock(bvcHelper_);
   OCMExpect([partialMock isToolbarLoading:static_cast<web::WebState*>(
                                               [OCMArg anyPointer])])
diff --git a/ios/chrome/browser/ui/location_bar/BUILD.gn b/ios/chrome/browser/ui/location_bar/BUILD.gn
index 7bd02c34..c820bc8 100644
--- a/ios/chrome/browser/ui/location_bar/BUILD.gn
+++ b/ios/chrome/browser/ui/location_bar/BUILD.gn
@@ -82,11 +82,11 @@
       [ "//ios/chrome/browser/ui/omnibox:omnibox_internal" ]
 }
 
-source_set("toolbar_model_delegate") {
+source_set("location_bar_model_delegate") {
   configs += [ "//build/config/compiler:enable_arc" ]
   sources = [
-    "toolbar_model_delegate_ios.h",
-    "toolbar_model_delegate_ios.mm",
+    "location_bar_model_delegate_ios.h",
+    "location_bar_model_delegate_ios.mm",
   ]
   deps = [
     "//base",
diff --git a/ios/chrome/browser/ui/location_bar/location_bar_coordinator.mm b/ios/chrome/browser/ui/location_bar/location_bar_coordinator.mm
index 0e884b9..2790bcfc 100644
--- a/ios/chrome/browser/ui/location_bar/location_bar_coordinator.mm
+++ b/ios/chrome/browser/ui/location_bar/location_bar_coordinator.mm
@@ -146,8 +146,8 @@
   self.omniboxPopupCoordinator.webStateList = self.webStateList;
   [self.omniboxPopupCoordinator start];
 
-  self.mediator =
-      [[LocationBarMediator alloc] initWithToolbarModel:[self toolbarModel]];
+  self.mediator = [[LocationBarMediator alloc]
+      initWithLocationBarModel:[self locationBarModel]];
   self.mediator.webStateList = self.webStateList;
   self.mediator.consumer = self;
 
@@ -293,8 +293,8 @@
   return self.webStateList->GetActiveWebState();
 }
 
-- (ToolbarModel*)toolbarModel {
-  return [self.delegate toolbarModel];
+- (LocationBarModel*)locationBarModel {
+  return [self.delegate locationBarModel];
 }
 
 #pragma mark - LocationBarViewControllerDelegate
diff --git a/ios/chrome/browser/ui/location_bar/location_bar_coordinator_unittest.mm b/ios/chrome/browser/ui/location_bar/location_bar_coordinator_unittest.mm
index c838761..cb544973 100644
--- a/ios/chrome/browser/ui/location_bar/location_bar_coordinator_unittest.mm
+++ b/ios/chrome/browser/ui/location_bar/location_bar_coordinator_unittest.mm
@@ -8,7 +8,7 @@
 #include <string>
 #include <vector>
 
-#include "components/omnibox/browser/test_toolbar_model.h"
+#include "components/omnibox/browser/test_location_bar_model.h"
 #include "components/variations/variations_http_header_provider.h"
 #include "ios/chrome/browser/autocomplete/autocomplete_classifier_factory.h"
 #include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
@@ -34,7 +34,7 @@
 @end
 
 @implementation TestToolbarCoordinatorDelegate {
-  std::unique_ptr<ToolbarModel> _model;
+  std::unique_ptr<LocationBarModel> _model;
 }
 
 - (void)locationBarDidBecomeFirstResponder {
@@ -44,9 +44,9 @@
 - (void)locationBarBeganEdit {
 }
 
-- (ToolbarModel*)toolbarModel {
+- (LocationBarModel*)locationBarModel {
   if (!_model) {
-    _model = std::make_unique<TestToolbarModel>();
+    _model = std::make_unique<TestLocationBarModel>();
   }
 
   return _model.get();
diff --git a/ios/chrome/browser/ui/location_bar/location_bar_mediator.h b/ios/chrome/browser/ui/location_bar/location_bar_mediator.h
index 4d4986e3..0420c78 100644
--- a/ios/chrome/browser/ui/location_bar/location_bar_mediator.h
+++ b/ios/chrome/browser/ui/location_bar/location_bar_mediator.h
@@ -9,12 +9,12 @@
 
 @protocol LocationBarConsumer;
 class WebStateList;
-class ToolbarModel;
+class LocationBarModel;
 
 // A mediator object that updates the mediator when the web state changes.
 @interface LocationBarMediator : NSObject
 
-- (instancetype)initWithToolbarModel:(ToolbarModel*)toolbarModel
+- (instancetype)initWithLocationBarModel:(LocationBarModel*)locationBarModel
     NS_DESIGNATED_INITIALIZER;
 - (instancetype)init NS_UNAVAILABLE;
 
@@ -22,9 +22,9 @@
 // state.
 @property(nonatomic, assign) WebStateList* webStateList;
 
-// The toolbar model used by this mediator to extract the current URL and the
-// security state.
-@property(nonatomic, assign, readonly) ToolbarModel* toolbarModel;
+// The location bar model used by this mediator to extract the current URL and
+// the security state.
+@property(nonatomic, assign, readonly) LocationBarModel* locationBarModel;
 
 // The consumer for this object. This can change during the lifetime of this
 // object and may be nil.
diff --git a/ios/chrome/browser/ui/location_bar/location_bar_mediator.mm b/ios/chrome/browser/ui/location_bar/location_bar_mediator.mm
index 287b099..898c67a 100644
--- a/ios/chrome/browser/ui/location_bar/location_bar_mediator.mm
+++ b/ios/chrome/browser/ui/location_bar/location_bar_mediator.mm
@@ -6,7 +6,7 @@
 
 #include "base/memory/ptr_util.h"
 #include "base/strings/sys_string_conversions.h"
-#include "components/omnibox/browser/toolbar_model.h"
+#include "components/omnibox/browser/location_bar_model.h"
 #include "components/security_state/core/security_state_ui.h"
 #include "ios/chrome/browser/chrome_url_constants.h"
 #include "ios/chrome/browser/ssl/ios_security_state_tab_helper.h"
@@ -41,13 +41,13 @@
 @synthesize consumer = _consumer;
 @synthesize webState = _webState;
 @synthesize webStateList = _webStateList;
-@synthesize toolbarModel = _toolbarModel;
+@synthesize locationBarModel = _locationBarModel;
 
-- (instancetype)initWithToolbarModel:(ToolbarModel*)toolbarModel {
-  DCHECK(toolbarModel);
+- (instancetype)initWithLocationBarModel:(LocationBarModel*)locationBarModel {
+  DCHECK(locationBarModel);
   self = [super init];
   if (self) {
-    _toolbarModel = toolbarModel;
+    _locationBarModel = locationBarModel;
     _webStateObserver = std::make_unique<web::WebStateObserverBridge>(self);
     _webStateListObserver = std::make_unique<WebStateListObserverBridge>(self);
   }
@@ -192,32 +192,32 @@
 }
 
 - (void)notifyConsumerOfChangedSecurityIcon {
-  [self.consumer
-      updateLocationIcon:[self currentLocationIcon]
-      securityStatusText:base::SysUTF16ToNSString(
-                             self.toolbarModel->GetSecureAccessibilityText())];
+  [self.consumer updateLocationIcon:[self currentLocationIcon]
+                 securityStatusText:base::SysUTF16ToNSString(
+                                        self.locationBarModel
+                                            ->GetSecureAccessibilityText())];
 }
 
 #pragma mark Location helpers
 
 - (NSString*)currentLocationString {
-  base::string16 string = self.toolbarModel->GetURLForDisplay();
+  base::string16 string = self.locationBarModel->GetURLForDisplay();
   return base::SysUTF16ToNSString(string);
 }
 
 #pragma mark Security status icon helpers
 
 - (UIImage*)currentLocationIcon {
-  if (!self.toolbarModel->ShouldDisplayURL()) {
+  if (!self.locationBarModel->ShouldDisplayURL()) {
     return nil;
   }
 
-  if (self.toolbarModel->IsOfflinePage()) {
+  if (self.locationBarModel->IsOfflinePage()) {
     return [self imageForOfflinePage];
   }
 
   return GetLocationBarSecurityIconForSecurityState(
-      self.toolbarModel->GetSecurityLevel(true));
+      self.locationBarModel->GetSecurityLevel(true));
 }
 
 // Returns a location icon for offline pages.
diff --git a/ios/chrome/browser/ui/location_bar/toolbar_model_delegate_ios.h b/ios/chrome/browser/ui/location_bar/location_bar_model_delegate_ios.h
similarity index 62%
rename from ios/chrome/browser/ui/location_bar/toolbar_model_delegate_ios.h
rename to ios/chrome/browser/ui/location_bar/location_bar_model_delegate_ios.h
index 4c22130..5d8e3977 100644
--- a/ios/chrome/browser/ui/location_bar/toolbar_model_delegate_ios.h
+++ b/ios/chrome/browser/ui/location_bar/location_bar_model_delegate_ios.h
@@ -2,11 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef IOS_CHROME_BROWSER_UI_LOCATION_BAR_TOOLBAR_MODEL_DELEGATE_IOS_H_
-#define IOS_CHROME_BROWSER_UI_LOCATION_BAR_TOOLBAR_MODEL_DELEGATE_IOS_H_
+#ifndef IOS_CHROME_BROWSER_UI_LOCATION_BAR_LOCATION_BAR_MODEL_DELEGATE_IOS_H_
+#define IOS_CHROME_BROWSER_UI_LOCATION_BAR_LOCATION_BAR_MODEL_DELEGATE_IOS_H_
 
 #include "base/macros.h"
-#include "components/omnibox/browser/toolbar_model_delegate.h"
+#include "components/omnibox/browser/location_bar_model_delegate.h"
 
 class WebStateList;
 
@@ -15,15 +15,15 @@
 class WebState;
 }  // namespace web
 
-// Implementation of ToolbarModelDelegate which uses an instance of
+// Implementation of LocationBarModelDelegate which uses an instance of
 // TabModel in order to fulfill its duties.
-class ToolbarModelDelegateIOS : public ToolbarModelDelegate {
+class LocationBarModelDelegateIOS : public LocationBarModelDelegate {
  public:
-  // |web_state_list| must outlive this ToolbarModelDelegateIOS object.
-  explicit ToolbarModelDelegateIOS(WebStateList* web_state_list);
-  ~ToolbarModelDelegateIOS() override;
+  // |web_state_list| must outlive this LocationBarModelDelegateIOS object.
+  explicit LocationBarModelDelegateIOS(WebStateList* web_state_list);
+  ~LocationBarModelDelegateIOS() override;
 
-  // ToolbarModelDelegate implementation:
+  // LocationBarModelDelegate implementation:
   base::string16 FormattedStringWithEquivalentMeaning(
       const GURL& url,
       const base::string16& formatted_url) const override;
@@ -46,7 +46,7 @@
 
   WebStateList* web_state_list_;  // weak
 
-  DISALLOW_COPY_AND_ASSIGN(ToolbarModelDelegateIOS);
+  DISALLOW_COPY_AND_ASSIGN(LocationBarModelDelegateIOS);
 };
 
-#endif  // IOS_CHROME_BROWSER_UI_LOCATION_BAR_TOOLBAR_MODEL_DELEGATE_IOS_H_
+#endif  // IOS_CHROME_BROWSER_UI_LOCATION_BAR_LOCATION_BAR_MODEL_DELEGATE_IOS_H_
diff --git a/ios/chrome/browser/ui/location_bar/toolbar_model_delegate_ios.mm b/ios/chrome/browser/ui/location_bar/location_bar_model_delegate_ios.mm
similarity index 79%
rename from ios/chrome/browser/ui/location_bar/toolbar_model_delegate_ios.mm
rename to ios/chrome/browser/ui/location_bar/location_bar_model_delegate_ios.mm
index ceb59ef2..f846b8c 100644
--- a/ios/chrome/browser/ui/location_bar/toolbar_model_delegate_ios.mm
+++ b/ios/chrome/browser/ui/location_bar/location_bar_model_delegate_ios.mm
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#import "ios/chrome/browser/ui/location_bar/toolbar_model_delegate_ios.h"
+#import "ios/chrome/browser/ui/location_bar/location_bar_model_delegate_ios.h"
 
 #include "base/logging.h"
 #include "components/omnibox/browser/autocomplete_classifier.h"
@@ -24,30 +24,32 @@
 #error "This file requires ARC support."
 #endif
 
-ToolbarModelDelegateIOS::ToolbarModelDelegateIOS(WebStateList* web_state_list)
+LocationBarModelDelegateIOS::LocationBarModelDelegateIOS(
+    WebStateList* web_state_list)
     : web_state_list_(web_state_list) {}
 
-ToolbarModelDelegateIOS::~ToolbarModelDelegateIOS() {}
+LocationBarModelDelegateIOS::~LocationBarModelDelegateIOS() {}
 
-web::WebState* ToolbarModelDelegateIOS::GetActiveWebState() const {
+web::WebState* LocationBarModelDelegateIOS::GetActiveWebState() const {
   return web_state_list_->GetActiveWebState();
 }
 
-web::NavigationItem* ToolbarModelDelegateIOS::GetNavigationItem() const {
+web::NavigationItem* LocationBarModelDelegateIOS::GetNavigationItem() const {
   web::WebState* web_state = GetActiveWebState();
   web::NavigationManager* navigation_manager =
       web_state ? web_state->GetNavigationManager() : nullptr;
   return navigation_manager ? navigation_manager->GetVisibleItem() : nullptr;
 }
 
-base::string16 ToolbarModelDelegateIOS::FormattedStringWithEquivalentMeaning(
+base::string16
+LocationBarModelDelegateIOS::FormattedStringWithEquivalentMeaning(
     const GURL& url,
     const base::string16& formatted_url) const {
   return AutocompleteInput::FormattedStringWithEquivalentMeaning(
       url, formatted_url, AutocompleteSchemeClassifierImpl(), nullptr);
 }
 
-bool ToolbarModelDelegateIOS::GetURL(GURL* url) const {
+bool LocationBarModelDelegateIOS::GetURL(GURL* url) const {
   DCHECK(url);
   web::NavigationItem* item = GetNavigationItem();
   if (!item)
@@ -56,7 +58,7 @@
   return true;
 }
 
-bool ToolbarModelDelegateIOS::ShouldDisplayURL() const {
+bool LocationBarModelDelegateIOS::ShouldDisplayURL() const {
   web::NavigationItem* item = GetNavigationItem();
   if (item) {
     GURL url = item->GetURL();
@@ -72,7 +74,7 @@
   return true;
 }
 
-security_state::SecurityLevel ToolbarModelDelegateIOS::GetSecurityLevel()
+security_state::SecurityLevel LocationBarModelDelegateIOS::GetSecurityLevel()
     const {
   web::WebState* web_state = GetActiveWebState();
   // If there is no active WebState (which can happen during toolbar
@@ -85,15 +87,15 @@
   return result.security_level;
 }
 
-scoped_refptr<net::X509Certificate> ToolbarModelDelegateIOS::GetCertificate()
-    const {
+scoped_refptr<net::X509Certificate>
+LocationBarModelDelegateIOS::GetCertificate() const {
   web::NavigationItem* item = GetNavigationItem();
   if (item)
     return item->GetSSL().certificate;
   return scoped_refptr<net::X509Certificate>();
 }
 
-bool ToolbarModelDelegateIOS::FailsMalwareCheck() const {
+bool LocationBarModelDelegateIOS::FailsMalwareCheck() const {
   web::WebState* web_state = GetActiveWebState();
   // If there is no active WebState (which can happen during toolbar
   // initialization), so nothing can fail.
@@ -106,11 +108,12 @@
          security_state::MALICIOUS_CONTENT_STATUS_NONE;
 }
 
-const gfx::VectorIcon* ToolbarModelDelegateIOS::GetVectorIconOverride() const {
+const gfx::VectorIcon* LocationBarModelDelegateIOS::GetVectorIconOverride()
+    const {
   return nullptr;
 }
 
-bool ToolbarModelDelegateIOS::IsOfflinePage() const {
+bool LocationBarModelDelegateIOS::IsOfflinePage() const {
   web::WebState* web_state = GetActiveWebState();
   if (!web_state)
     return false;
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_controller.mm b/ios/chrome/browser/ui/ntp/new_tab_page_controller.mm
index ed37720..23fe33c0 100644
--- a/ios/chrome/browser/ui/ntp/new_tab_page_controller.mm
+++ b/ios/chrome/browser/ui/ntp/new_tab_page_controller.mm
@@ -42,7 +42,7 @@
   // Delegate to focus and blur the omnibox.
   __weak id<OmniboxFocuser> _focuser;
 
-  // Delegate to fetch the ToolbarModel and current web state from.
+  // Delegate to fetch the LocationBarModel and current web state from.
   __weak id<NewTabPageControllerDelegate> _toolbarDelegate;
 
   TabModel* _tabModel;
diff --git a/ios/chrome/browser/ui/omnibox/location_bar_delegate.h b/ios/chrome/browser/ui/omnibox/location_bar_delegate.h
index 854772d..223184a 100644
--- a/ios/chrome/browser/ui/omnibox/location_bar_delegate.h
+++ b/ios/chrome/browser/ui/omnibox/location_bar_delegate.h
@@ -7,7 +7,7 @@
 
 #import <Foundation/Foundation.h>
 
-class ToolbarModel;
+class LocationBarModel;
 
 namespace web {
 class WebState;
@@ -19,7 +19,7 @@
 - (void)locationBarHasResignedFirstResponder;
 - (void)locationBarBeganEdit;
 - (web::WebState*)webState;
-- (ToolbarModel*)toolbarModel;
+- (LocationBarModel*)locationBarModel;
 @end
 
 #endif  // IOS_SHARED_CHROME_BROWSER_UI_OMNIBOX_LOCATION_BAR_DELEGATE_H_
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_view_ios.h b/ios/chrome/browser/ui/omnibox/omnibox_view_ios.h
index c793228..d62d68e 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_view_ios.h
+++ b/ios/chrome/browser/ui/omnibox/omnibox_view_ios.h
@@ -8,8 +8,8 @@
 #import <UIKit/UIKit.h>
 
 #include <memory>
+#include "components/omnibox/browser/location_bar_model.h"
 #include "components/omnibox/browser/omnibox_view.h"
-#include "components/omnibox/browser/toolbar_model.h"
 #import "ios/chrome/browser/ui/omnibox/omnibox_left_image_consumer.h"
 #import "ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.h"
 #include "ios/chrome/browser/ui/omnibox/popup/omnibox_popup_provider.h"
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_view_ios.mm b/ios/chrome/browser/ui/omnibox/omnibox_view_ios.mm
index 91298ca..94c02fd8 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_view_ios.mm
+++ b/ios/chrome/browser/ui/omnibox/omnibox_view_ios.mm
@@ -17,9 +17,9 @@
 #include "base/strings/sys_string_conversions.h"
 #include "components/omnibox/browser/autocomplete_input.h"
 #include "components/omnibox/browser/autocomplete_match.h"
+#include "components/omnibox/browser/location_bar_model.h"
 #include "components/omnibox/browser/omnibox_edit_model.h"
 #include "components/omnibox/browser/omnibox_popup_model.h"
-#include "components/omnibox/browser/toolbar_model.h"
 #include "ios/chrome/browser/autocomplete/autocomplete_scheme_classifier_impl.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/ui/omnibox/chrome_omnibox_client_ios.h"
@@ -720,7 +720,7 @@
     return;
 
   const security_state::SecurityLevel security_level =
-      controller()->GetToolbarModel()->GetSecurityLevel(false);
+      controller()->GetLocationBarModel()->GetSecurityLevel(false);
 
   if ((security_level == security_state::NONE) ||
       (security_level == security_state::HTTP_SHOW_WARNING)) {
@@ -944,7 +944,7 @@
       return IDR_IOS_OMNIBOX_OFFLINE;
     }
     return GetIconForSecurityState(
-        controller()->GetToolbarModel()->GetSecurityLevel(false));
+        controller()->GetLocationBarModel()->GetSecurityLevel(false));
   }
   return GetIconForAutocompleteMatchType(
       model() ? model()->CurrentMatch(nullptr).type
diff --git a/ios/chrome/browser/ui/omnibox/web_omnibox_edit_controller_impl.h b/ios/chrome/browser/ui/omnibox/web_omnibox_edit_controller_impl.h
index 6d6cf27e..10f6859 100644
--- a/ios/chrome/browser/ui/omnibox/web_omnibox_edit_controller_impl.h
+++ b/ios/chrome/browser/ui/omnibox/web_omnibox_edit_controller_impl.h
@@ -37,8 +37,8 @@
                             base::TimeTicks match_selection_timestamp) override;
   void OnInputInProgress(bool in_progress) override;
   void OnChanged() override;
-  ToolbarModel* GetToolbarModel() override;
-  const ToolbarModel* GetToolbarModel() const override;
+  LocationBarModel* GetLocationBarModel() override;
+  const LocationBarModel* GetLocationBarModel() const override;
 
  private:
   __weak id<LocationBarDelegate> delegate_;
diff --git a/ios/chrome/browser/ui/omnibox/web_omnibox_edit_controller_impl.mm b/ios/chrome/browser/ui/omnibox/web_omnibox_edit_controller_impl.mm
index 5e16e46..21c08713 100644
--- a/ios/chrome/browser/ui/omnibox/web_omnibox_edit_controller_impl.mm
+++ b/ios/chrome/browser/ui/omnibox/web_omnibox_edit_controller_impl.mm
@@ -4,7 +4,7 @@
 
 #include "ios/chrome/browser/ui/omnibox/web_omnibox_edit_controller_impl.h"
 
-#include "components/omnibox/browser/toolbar_model.h"
+#include "components/omnibox/browser/location_bar_model.h"
 #import "ios/chrome/browser/ui/location_bar/location_bar_url_loader.h"
 #import "ios/chrome/browser/ui/omnibox/location_bar_delegate.h"
 #include "url/gurl.h"
@@ -49,8 +49,8 @@
 }
 
 void WebOmniboxEditControllerImpl::OnInputInProgress(bool in_progress) {
-  if ([delegate_ toolbarModel])
-    [delegate_ toolbarModel]->set_input_in_progress(in_progress);
+  if ([delegate_ locationBarModel])
+    [delegate_ locationBarModel]->set_input_in_progress(in_progress);
   // TODO(crbug.com/818649): see if this is really used.
   if (in_progress)
     [delegate_ locationBarBeganEdit];
@@ -62,10 +62,11 @@
   // TODO(crbug.com/818645): update the security icon in LocationBarMediator.
 }
 
-ToolbarModel* WebOmniboxEditControllerImpl::GetToolbarModel() {
-  return [delegate_ toolbarModel];
+LocationBarModel* WebOmniboxEditControllerImpl::GetLocationBarModel() {
+  return [delegate_ locationBarModel];
 }
 
-const ToolbarModel* WebOmniboxEditControllerImpl::GetToolbarModel() const {
-  return [delegate_ toolbarModel];
+const LocationBarModel* WebOmniboxEditControllerImpl::GetLocationBarModel()
+    const {
+  return [delegate_ locationBarModel];
 }
diff --git a/ios/chrome/browser/ui/omnibox_perftest.mm b/ios/chrome/browser/ui/omnibox_perftest.mm
index ce658f86..062c834c5 100644
--- a/ios/chrome/browser/ui/omnibox_perftest.mm
+++ b/ios/chrome/browser/ui/omnibox_perftest.mm
@@ -8,13 +8,13 @@
 
 #import "base/test/ios/wait_util.h"
 #include "base/time/time.h"
-#include "components/omnibox/browser/test_toolbar_model.h"
-#include "components/omnibox/browser/toolbar_model_impl.h"
+#include "components/omnibox/browser/location_bar_model_impl.h"
+#include "components/omnibox/browser/test_location_bar_model.h"
 #include "ios/chrome/browser/autocomplete/autocomplete_classifier_factory.h"
 #include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
 #include "ios/chrome/browser/search_engines/template_url_service_factory.h"
 #import "ios/chrome/browser/ui/commands/command_dispatcher.h"
-#include "ios/chrome/browser/ui/location_bar/toolbar_model_delegate_ios.h"
+#include "ios/chrome/browser/ui/location_bar/location_bar_model_delegate_ios.h"
 #import "ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.h"
 #import "ios/chrome/browser/ui/toolbar/primary_toolbar_coordinator.h"
 #import "ios/chrome/browser/ui/toolbar/toolbar_coordinator_delegate.h"
@@ -95,17 +95,17 @@
                                     WebStateOpener());
 
     // Creates the Toolbar for testing and sizes it to the width of the screen.
-    toolbar_model_delegate_.reset(
-        new ToolbarModelDelegateIOS(web_state_list_.get()));
-    toolbar_model_ = std::make_unique<ToolbarModelImpl>(
-        toolbar_model_delegate_.get(), kMaxURLDisplayChars);
+    location_bar_model_delegate_.reset(
+        new LocationBarModelDelegateIOS(web_state_list_.get()));
+    location_bar_model_ = std::make_unique<LocationBarModelImpl>(
+        location_bar_model_delegate_.get(), kMaxURLDisplayChars);
 
     // The OCMOCK_VALUE macro doesn't like std::unique_ptr, but it works just
     // fine if a temporary variable is used.
-    ToolbarModel* model_for_mock = toolbar_model_.get();
+    LocationBarModel* model_for_mock = location_bar_model_.get();
     id toolbarDelegate = OCMProtocolMock(@protocol(ToolbarCoordinatorDelegate));
     [[[toolbarDelegate stub] andReturnValue:OCMOCK_VALUE(model_for_mock)]
-        toolbarModel];
+        locationBarModel];
 
     CommandDispatcher* dispatcher = [[CommandDispatcher alloc] init];
 
@@ -227,8 +227,8 @@
   std::unique_ptr<TestChromeBrowserState> chrome_browser_state_;
   FakeWebStateListDelegate web_state_list_delegate_;
   std::unique_ptr<WebStateList> web_state_list_;
-  std::unique_ptr<ToolbarModelDelegateIOS> toolbar_model_delegate_;
-  std::unique_ptr<ToolbarModel> toolbar_model_;
+  std::unique_ptr<LocationBarModelDelegateIOS> location_bar_model_delegate_;
+  std::unique_ptr<LocationBarModel> location_bar_model_;
   PrimaryToolbarCoordinator* coordinator_;
   UIWindow* window_;
   KeyboardAppearanceListener* keyboard_listener_;
diff --git a/ios/chrome/browser/ui/payments/payment_request_manager.h b/ios/chrome/browser/ui/payments/payment_request_manager.h
index 74e1346b..45aec993 100644
--- a/ios/chrome/browser/ui/payments/payment_request_manager.h
+++ b/ios/chrome/browser/ui/payments/payment_request_manager.h
@@ -17,7 +17,7 @@
 extern NSString* const kNotSupportedError;
 
 @protocol ApplicationCommands;
-class ToolbarModel;
+class LocationBarModel;
 
 namespace ios {
 class ChromeBrowserState;
@@ -33,8 +33,8 @@
 // interface.
 @interface PaymentRequestManager : NSObject
 
-// ToolbarModel that is used for grabbing security info.
-@property(nonatomic, assign) ToolbarModel* toolbarModel;
+// LocationBarModel that is used for grabbing security info.
+@property(nonatomic, assign) LocationBarModel* locationBarModel;
 
 // The WebState being observed for invocations of the Payment Request API.
 // Should outlive this instance. May be nullptr.
diff --git a/ios/chrome/browser/ui/payments/payment_request_manager.mm b/ios/chrome/browser/ui/payments/payment_request_manager.mm
index 960982f..94e4553 100644
--- a/ios/chrome/browser/ui/payments/payment_request_manager.mm
+++ b/ios/chrome/browser/ui/payments/payment_request_manager.mm
@@ -24,7 +24,7 @@
 #include "components/autofill/core/browser/credit_card.h"
 #include "components/autofill/core/browser/personal_data_manager.h"
 #include "components/autofill/ios/browser/autofill_driver_ios.h"
-#include "components/omnibox/browser/toolbar_model.h"
+#include "components/omnibox/browser/location_bar_model.h"
 #include "components/payments/core/can_make_payment_query.h"
 #include "components/payments/core/features.h"
 #include "components/payments/core/journey_logger.h"
@@ -268,7 +268,7 @@
 
 @implementation PaymentRequestManager
 
-@synthesize toolbarModel = _toolbarModel;
+@synthesize locationBarModel = _locationBarModel;
 @synthesize browserState = _browserState;
 @synthesize enabled = _enabled;
 @synthesize activeWebState = _activeWebState;
@@ -956,7 +956,7 @@
     return NO;
   }
 
-  if (!self.toolbarModel) {
+  if (!self.locationBarModel) {
     return NO;
   }
 
@@ -982,7 +982,7 @@
   // If the scheme is cryptographic, the SSL certificate must also be valid.
   return !security_state::IsSchemeCryptographic(lastCommittedURL) ||
          security_state::IsSslCertificateValid(
-             self.toolbarModel->GetSecurityLevel(true));
+             self.locationBarModel->GetSecurityLevel(true));
 }
 
 #pragma mark - PaymentRequestUIDelegate
diff --git a/ios/chrome/browser/ui/recent_tabs/recent_tabs_coordinator.mm b/ios/chrome/browser/ui/recent_tabs/recent_tabs_coordinator.mm
index 5cd15c5..ddc3a0c2 100644
--- a/ios/chrome/browser/ui/recent_tabs/recent_tabs_coordinator.mm
+++ b/ios/chrome/browser/ui/recent_tabs/recent_tabs_coordinator.mm
@@ -6,6 +6,7 @@
 
 #include "base/ios/block_types.h"
 #include "base/mac/foundation_util.h"
+#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/ui/commands/application_commands.h"
 #import "ios/chrome/browser/ui/recent_tabs/recent_tabs_mediator.h"
 #import "ios/chrome/browser/ui/recent_tabs/recent_tabs_presentation_delegate.h"
@@ -57,10 +58,13 @@
   recentTabsTableViewController.navigationItem.rightBarButtonItem =
       dismissButton;
 
-  // Initialize and configure RecentTabsMediator.
+  // Initialize and configure RecentTabsMediator. Make sure to use the
+  // OriginalChromeBrowserState since the mediator services need a SignIn
+  // manager which is not present in an OffTheRecord BrowserState.
   DCHECK(!self.mediator);
   self.mediator = [[RecentTabsMediator alloc] init];
-  self.mediator.browserState = self.browserState;
+  self.mediator.browserState =
+      self.browserState->GetOriginalChromeBrowserState();
   // Set the consumer first before calling [self.mediator initObservers] and
   // then [self.mediator configureConsumer].
   self.mediator.consumer = recentTabsTableViewController;
diff --git a/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.mm b/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.mm
index 5aaf976..e5e399e 100644
--- a/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.mm
+++ b/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.mm
@@ -114,6 +114,8 @@
 // Handles displaying the context menu for all form factors.
 @property(nonatomic, strong) ContextMenuCoordinator* contextMenuCoordinator;
 @property(nonatomic, strong) SigninPromoViewMediator* signinPromoViewMediator;
+// YES if this ViewController is being presented on incognito mode.
+@property(nonatomic, assign, getter=isIncognito) BOOL incognito;
 @end
 
 @implementation RecentTabsTableViewController : ChromeTableViewController
@@ -173,6 +175,18 @@
   [super viewWillDisappear:animated];
 }
 
+#pragma mark - Setters & Getters
+// Some RecentTabs services depend on objects not present in the OffTheRecord
+// BrowserState, in order to prevent crashes set |_browserState| to
+// |browserState|->OriginalChromeBrowserState. While doing this check if
+// incognito or not so that pages are loaded accordingly.
+- (void)setBrowserState:(ios::ChromeBrowserState*)browserState {
+  if (browserState) {
+    _browserState = browserState->GetOriginalChromeBrowserState();
+    _incognito = browserState->IsOffTheRecord();
+  }
+}
+
 #pragma mark - TableViewModel
 
 - (void)loadModel {
@@ -1045,7 +1059,7 @@
     OpenNewTabCommand* command =
         [[OpenNewTabCommand alloc] initWithURL:tab->virtual_url
                                       referrer:web::Referrer()
-                                   inIncognito:NO
+                                   inIncognito:[self isIncognito]
                                   inBackground:YES
                                       appendTo:kLastTab];
 
diff --git a/ios/chrome/browser/ui/sad_tab/sad_tab_legacy_coordinator.h b/ios/chrome/browser/ui/sad_tab/sad_tab_legacy_coordinator.h
index ed7a1fc..033b33e2 100644
--- a/ios/chrome/browser/ui/sad_tab/sad_tab_legacy_coordinator.h
+++ b/ios/chrome/browser/ui/sad_tab/sad_tab_legacy_coordinator.h
@@ -10,6 +10,7 @@
 #import "ios/chrome/browser/web/sad_tab_tab_helper_delegate.h"
 
 @protocol ApplicationCommands;
+@protocol BrowserCommands;
 
 // Coordinator that displays a SadTab view.
 @interface SadTabLegacyCoordinator : NSObject<SadTabTabHelperDelegate>
@@ -18,7 +19,7 @@
 @property(nonatomic, weak) UIViewController* baseViewController;
 
 // The dispatcher for this Coordinator.
-@property(nonatomic, weak) id<ApplicationCommands> dispatcher;
+@property(nonatomic, weak) id<ApplicationCommands, BrowserCommands> dispatcher;
 
 @end
 
diff --git a/ios/chrome/browser/ui/sad_tab/sad_tab_legacy_coordinator.mm b/ios/chrome/browser/ui/sad_tab/sad_tab_legacy_coordinator.mm
index 523dc14..d1ee9ebe 100644
--- a/ios/chrome/browser/ui/sad_tab/sad_tab_legacy_coordinator.mm
+++ b/ios/chrome/browser/ui/sad_tab/sad_tab_legacy_coordinator.mm
@@ -5,39 +5,51 @@
 #import "ios/chrome/browser/ui/sad_tab/sad_tab_legacy_coordinator.h"
 
 #import "ios/chrome/browser/ui/commands/application_commands.h"
+#import "ios/chrome/browser/ui/commands/browser_commands.h"
+#import "ios/chrome/browser/ui/commands/open_new_tab_command.h"
 #import "ios/chrome/browser/ui/sad_tab/sad_tab_view.h"
 #import "ios/chrome/browser/web/sad_tab_tab_helper.h"
+#include "ios/web/public/browser_state.h"
 #import "ios/web/public/navigation_manager.h"
 #import "ios/web/public/web_state/ui/crw_generic_content_view.h"
-#include "ios/web/public/web_state/web_state.h"
+#import "ios/web/public/web_state/web_state.h"
 
-@interface SadTabLegacyCoordinator ()<SadTabActionDelegate>
+@interface SadTabLegacyCoordinator ()<SadTabViewDelegate>
 @end
 
 @implementation SadTabLegacyCoordinator
 @synthesize baseViewController = _baseViewController;
 @synthesize dispatcher = _dispatcher;
 
-#pragma mark - SadTabActionDelegate
+#pragma mark - SadTabViewDelegate
 
-- (void)showReportAnIssue {
+- (void)sadTabViewShowReportAnIssue:(SadTabView*)sadTabView {
   [self.dispatcher showReportAnIssueFromViewController:self.baseViewController];
 }
 
+- (void)sadTabView:(SadTabView*)sadTabView
+    showSuggestionsPageWithURL:(const GURL&)URL {
+  OpenNewTabCommand* command = [OpenNewTabCommand commandWithURLFromChrome:URL];
+  [self.dispatcher openURLInNewTab:command];
+}
+
+- (void)sadTabViewReload:(SadTabView*)sadTabView {
+  [self.dispatcher reload];
+}
+
 #pragma mark - SadTabTabHelperDelegate
 
 - (void)sadTabTabHelper:(SadTabTabHelper*)tabHelper
     presentSadTabForWebState:(web::WebState*)webState
              repeatedFailure:(BOOL)repeatedFailure {
-  // Create a SadTabView so |webstate| presents it.
-  SadTabView* sadTabview = [[SadTabView alloc]
-           initWithMode:repeatedFailure ? SadTabViewMode::FEEDBACK
-                                        : SadTabViewMode::RELOAD
-      navigationManager:webState->GetNavigationManager()];
-  sadTabview.dispatcher = static_cast<id<ApplicationCommands>>(self.dispatcher);
-  sadTabview.actionDelegate = self;
+  SadTabViewMode mode =
+      repeatedFailure ? SadTabViewMode::FEEDBACK : SadTabViewMode::RELOAD;
+  SadTabView* sadTabView = [[SadTabView alloc]
+      initWithMode:mode
+      offTheRecord:webState->GetBrowserState()->IsOffTheRecord()];
+  sadTabView.delegate = self;
   CRWContentView* contentView =
-      [[CRWGenericContentView alloc] initWithView:sadTabview];
+      [[CRWGenericContentView alloc] initWithView:sadTabView];
   webState->ShowTransientContentView(contentView);
 }
 
diff --git a/ios/chrome/browser/ui/sad_tab/sad_tab_view.h b/ios/chrome/browser/ui/sad_tab/sad_tab_view.h
index 3781777..aa06415 100644
--- a/ios/chrome/browser/ui/sad_tab/sad_tab_view.h
+++ b/ios/chrome/browser/ui/sad_tab/sad_tab_view.h
@@ -11,6 +11,7 @@
 #include "ios/web/public/navigation_manager.h"
 
 @protocol ApplicationCommands;
+@class SadTabView;
 
 // Describes the mode of the Sad Tab, whether it should offer an attempt to
 // reload content, or whether it should offer a way to provide feedback.
@@ -19,21 +20,25 @@
   FEEDBACK,    // A mode which allows the user to provide feedback
 };
 
-// Protocol for actions from the SadTabView.
-@protocol SadTabActionDelegate
-// Shows reportAnIssue UI.
-- (void)showReportAnIssue;
+@protocol SadTabViewDelegate
+// Instructs the delegate to show Report An Issue UI.
+- (void)sadTabViewShowReportAnIssue:(SadTabView*)sadTabView;
+
+// Instructs the delegate to show Suggestions help page with the given URL.
+- (void)sadTabView:(SadTabView*)sadTabView
+    showSuggestionsPageWithURL:(const GURL&)URL;
+
+// Instructs the delegate to reload this page.
+- (void)sadTabViewReload:(SadTabView*)sadTabView;
+
 @end
 
-// The view used to show "sad tab" content to the user when WKWebView's renderer
+// The view used to show "sad tab" content to the user when WebState's renderer
 // process crashes.
 @interface SadTabView : UIView
 
-// Designated initializer. |navigationManager| allows the view to execute
-// actions such as a reload if necessary.
 - (instancetype)initWithMode:(SadTabViewMode)mode
-           navigationManager:(web::NavigationManager*)navigationManager
-    NS_DESIGNATED_INITIALIZER;
+                offTheRecord:(BOOL)offTheRecord NS_DESIGNATED_INITIALIZER;
 
 - (instancetype)init NS_UNAVAILABLE;
 - (instancetype)initWithFrame:(CGRect)frame NS_UNAVAILABLE;
@@ -42,11 +47,7 @@
 // Determines the type of Sad Tab information that will be displayed.
 @property(nonatomic, readonly) SadTabViewMode mode;
 
-// The dispatcher for this view.
-@property(nonatomic, weak) id<ApplicationCommands> dispatcher;
-
-// The delegate for actions from this view.
-@property(nonatomic, weak) id<SadTabActionDelegate> actionDelegate;
+@property(nonatomic, weak) id<SadTabViewDelegate> delegate;
 
 @end
 
diff --git a/ios/chrome/browser/ui/sad_tab/sad_tab_view.mm b/ios/chrome/browser/ui/sad_tab/sad_tab_view.mm
index 47d7d29..1d9072d 100644
--- a/ios/chrome/browser/ui/sad_tab/sad_tab_view.mm
+++ b/ios/chrome/browser/ui/sad_tab/sad_tab_view.mm
@@ -12,7 +12,6 @@
 #include "ios/chrome/browser/chrome_url_constants.h"
 #import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h"
 #import "ios/chrome/browser/ui/commands/application_commands.h"
-#import "ios/chrome/browser/ui/commands/open_new_tab_command.h"
 #import "ios/chrome/browser/ui/url_loader.h"
 #import "ios/chrome/browser/ui/util/label_link_controller.h"
 #include "ios/chrome/browser/ui/util/rtl_geometry.h"
@@ -59,6 +58,8 @@
 
 @interface SadTabView ()
 
+// YES if the SadTab UI is displayed in Off The Record browsing mode.
+@property(nonatomic, readonly, getter=isOffTheRecord) BOOL offTheRecord;
 // Container view that displays all other subviews.
 @property(nonatomic, readonly, strong) UIView* containerView;
 // Displays the Sad Tab face.
@@ -77,8 +78,6 @@
 // The bounds of |containerView|, with a height updated to CGFLOAT_MAX to allow
 // text to be laid out using as many lines as necessary.
 @property(nonatomic, readonly) CGRect containerBounds;
-// Allows this view to perform navigation actions such as reloading.
-@property(nonatomic, readonly) web::NavigationManager* navigationManager;
 
 // Subview layout methods.  Must be called in the following order, as subsequent
 // layouts reference the values set in previous functions.
@@ -115,7 +114,7 @@
                         forLinkText:(nonnull NSString*)linkText;
 
 // The action selector for |_actionButton|.
-- (void)handleActionButtonTapped:(id)sender;
+- (void)handleActionButtonTapped;
 
 // Returns the desired background color.
 + (UIColor*)sadTabBackgroundColor;
@@ -126,6 +125,7 @@
 
 @implementation SadTabView
 
+@synthesize offTheRecord = _offTheRecord;
 @synthesize imageView = _imageView;
 @synthesize containerView = _containerView;
 @synthesize titleLabel = _titleLabel;
@@ -134,16 +134,14 @@
 @synthesize footerLabelLinkController = _footerLabelLinkController;
 @synthesize actionButton = _actionButton;
 @synthesize mode = _mode;
-@synthesize navigationManager = _navigationManager;
-@synthesize dispatcher = _dispatcher;
-@synthesize actionDelegate = _actionDelegate;
+@synthesize delegate = _delegate;
 
 - (instancetype)initWithMode:(SadTabViewMode)mode
-           navigationManager:(web::NavigationManager*)navigationManager {
+                offTheRecord:(BOOL)offTheRecord {
   self = [super initWithFrame:CGRectZero];
   if (self) {
     _mode = mode;
-    _navigationManager = navigationManager;
+    _offTheRecord = offTheRecord;
     self.backgroundColor = [[self class] sadTabBackgroundColor];
   }
   return self;
@@ -228,17 +226,13 @@
           [[NSMutableAttributedString alloc]
               initWithString:feedbackIntroductionString];
 
-      BOOL isAlreadyInIncognitoMode =
-          _navigationManager
-              ? _navigationManager->GetBrowserState()->IsOffTheRecord()
-              : NO;
       NSMutableArray* stringsArray = [NSMutableArray
           arrayWithObjects:l10n_util::GetNSString(
                                IDS_SAD_TAB_RELOAD_RESTART_BROWSER),
                            l10n_util::GetNSString(
                                IDS_SAD_TAB_RELOAD_RESTART_DEVICE),
                            nil];
-      if (!isAlreadyInIncognitoMode) {
+      if (!self.offTheRecord) {
         NSString* incognitoSuggestionString =
             l10n_util::GetNSString(IDS_SAD_TAB_RELOAD_INCOGNITO);
         [stringsArray insertObject:incognitoSuggestionString atIndex:0];
@@ -308,9 +302,8 @@
   _footerLabelLinkController = [[LabelLinkController alloc]
       initWithLabel:label
              action:^(const GURL& URL) {
-               OpenNewTabCommand* command =
-                   [OpenNewTabCommand commandWithURLFromChrome:URL];
-               [weakSelf.dispatcher openURLInNewTab:command];
+               [weakSelf.delegate sadTabView:weakSelf
+                   showSuggestionsPageWithURL:URL];
              }];
 
   _footerLabelLinkController.linkFont =
@@ -408,7 +401,7 @@
     [_actionButton setTitleColor:[UIColor whiteColor]
                         forState:UIControlStateNormal];
     [_actionButton addTarget:self
-                      action:@selector(handleActionButtonTapped:)
+                      action:@selector(handleActionButtonTapped)
             forControlEvents:UIControlEventTouchUpInside];
   }
   return _actionButton;
@@ -556,20 +549,19 @@
 
 #pragma mark Util
 
-- (void)handleActionButtonTapped:(id)sender {
+- (void)handleActionButtonTapped {
   switch (self.mode) {
     case SadTabViewMode::RELOAD:
       UMA_HISTOGRAM_ENUMERATION(ui_metrics::kSadTabReloadHistogramKey,
                                 ui_metrics::SadTabEvent::BUTTON_CLICKED,
                                 ui_metrics::SadTabEvent::MAX_SAD_TAB_EVENT);
-      self.navigationManager->Reload(web::ReloadType::NORMAL, true);
+      [self.delegate sadTabViewReload:self];
       break;
     case SadTabViewMode::FEEDBACK: {
-      DCHECK(self.actionDelegate);
       UMA_HISTOGRAM_ENUMERATION(ui_metrics::kSadTabFeedbackHistogramKey,
                                 ui_metrics::SadTabEvent::BUTTON_CLICKED,
                                 ui_metrics::SadTabEvent::MAX_SAD_TAB_EVENT);
-      [self.actionDelegate showReportAnIssue];
+      [self.delegate sadTabViewShowReportAnIssue:self];
       break;
     }
   };
diff --git a/ios/chrome/browser/ui/settings/cells/version_item.mm b/ios/chrome/browser/ui/settings/cells/version_item.mm
index 32421f99..40cdfd4 100644
--- a/ios/chrome/browser/ui/settings/cells/version_item.mm
+++ b/ios/chrome/browser/ui/settings/cells/version_item.mm
@@ -61,6 +61,7 @@
     _textLabel.translatesAutoresizingMaskIntoConstraints = NO;
     _textLabel.font =
         [UIFont preferredFontForTextStyle:UIFontTextStyleFootnote];
+    _textLabel.numberOfLines = 0;
     _textLabel.textColor =
         UIColorFromRGB(kTableViewSecondaryLabelLightGrayTextColor);
     _textLabel.backgroundColor = [UIColor clearColor];
diff --git a/ios/chrome/browser/ui/toolbar/DEPS b/ios/chrome/browser/ui/toolbar/DEPS
index fe58721..cfa7db1 100644
--- a/ios/chrome/browser/ui/toolbar/DEPS
+++ b/ios/chrome/browser/ui/toolbar/DEPS
@@ -1,5 +1,5 @@
 specific_include_rules = {
-  "^toolbar_model_impl_ios\.mm$": [
+  "^location_bar_model_impl_ios\.mm$": [
     "+ios/web/web_state/ui/crw_web_controller.h",
   ],
   # web::HttpServer is deprecated in favor of net::EmbeddedTestServer.
diff --git a/ios/chrome/browser/ui/toolbar/toolbar_coordinator_delegate.h b/ios/chrome/browser/ui/toolbar/toolbar_coordinator_delegate.h
index 968025a7..77094f01 100644
--- a/ios/chrome/browser/ui/toolbar/toolbar_coordinator_delegate.h
+++ b/ios/chrome/browser/ui/toolbar/toolbar_coordinator_delegate.h
@@ -7,7 +7,7 @@
 
 #import <Foundation/Foundation.h>
 
-class ToolbarModel;
+class LocationBarModel;
 
 // Protocol receiving notification when the some events occur in the
 // ToolbarCoordinator
@@ -19,8 +19,8 @@
 - (void)locationBarDidResignFirstResponder;
 // Called when the location bar receives a key press.
 - (void)locationBarBeganEdit;
-// Returns the toolbar model.
-- (ToolbarModel*)toolbarModel;
+// Returns the location bar model.
+- (LocationBarModel*)locationBarModel;
 
 @end
 
diff --git a/ios/web/web_thread_impl.cc b/ios/web/web_thread_impl.cc
index e703cf3..e1f9459 100644
--- a/ios/web/web_thread_impl.cc
+++ b/ios/web/web_thread_impl.cc
@@ -132,23 +132,22 @@
   if (!target_thread_outlives_current)
     globals.lock.Acquire();
 
-  base::MessageLoop* message_loop =
-      globals.threads[identifier] ? globals.threads[identifier]->message_loop()
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner =
+      globals.threads[identifier] ? globals.threads[identifier]->task_runner()
                                   : nullptr;
-  if (message_loop) {
+  if (task_runner) {
     if (nestable) {
-      message_loop->task_runner()->PostDelayedTask(from_here, std::move(task),
-                                                   delay);
+      task_runner->PostDelayedTask(from_here, std::move(task), delay);
     } else {
-      message_loop->task_runner()->PostNonNestableDelayedTask(
-          from_here, std::move(task), delay);
+      task_runner->PostNonNestableDelayedTask(from_here, std::move(task),
+                                              delay);
     }
   }
 
   if (!target_thread_outlives_current)
     globals.lock.Release();
 
-  return !!message_loop;
+  return !!task_runner;
 }
 
 class WebThreadTaskExecutor : public base::TaskExecutor {
diff --git a/media/audio/audio_low_latency_input_output_unittest.cc b/media/audio/audio_low_latency_input_output_unittest.cc
index cb21008..4ed02ecc 100644
--- a/media/audio/audio_low_latency_input_output_unittest.cc
+++ b/media/audio/audio_low_latency_input_output_unittest.cc
@@ -12,11 +12,11 @@
 #include "base/environment.h"
 #include "base/files/file_util.h"
 #include "base/macros.h"
-#include "base/message_loop/message_loop.h"
 #include "base/path_service.h"
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
 #include "base/synchronization/lock.h"
+#include "base/test/scoped_task_environment.h"
 #include "base/test/test_timeouts.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
@@ -82,10 +82,13 @@
   ~AudioLowLatencyInputOutputTest() override { audio_manager_->Shutdown(); }
 
   AudioManager* audio_manager() { return audio_manager_.get(); }
-  base::MessageLoopForUI* message_loop() { return &message_loop_; }
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner() {
+    return task_environment_.GetMainThreadTaskRunner();
+  }
 
  private:
-  base::MessageLoopForUI message_loop_;
+  base::test::ScopedTaskEnvironment task_environment_{
+      base::test::ScopedTaskEnvironment::MainThreadType::UI};
   std::unique_ptr<AudioManager> audio_manager_;
 
   DISALLOW_COPY_AND_ASSIGN(AudioLowLatencyInputOutputTest);
@@ -387,7 +390,7 @@
   // Wait for approximately 10 seconds. The user will hear their own voice
   // in loop back during this time. At the same time, delay recordings are
   // performed and stored in the output text file.
-  message_loop()->task_runner()->PostDelayedTask(
+  task_runner()->PostDelayedTask(
       FROM_HERE, base::RunLoop::QuitCurrentWhenIdleClosureDeprecated(),
       TestTimeouts::action_timeout());
   base::RunLoop().Run();
diff --git a/media/capture/mojom/video_capture_types.mojom b/media/capture/mojom/video_capture_types.mojom
index a09b3103..36f64e5 100644
--- a/media/capture/mojom/video_capture_types.mojom
+++ b/media/capture/mojom/video_capture_types.mojom
@@ -241,6 +241,7 @@
   VideoCaptureBufferType buffer_type;
   ResolutionChangePolicy resolution_change_policy;
   PowerLineFrequency power_line_frequency;
+  bool enable_face_detection;
 };
 
 // Contains one stride value per image plane. Stride means the number of bytes
diff --git a/media/capture/mojom/video_capture_types_mojom_traits.cc b/media/capture/mojom/video_capture_types_mojom_traits.cc
index 5baf263f..f35e8aa 100644
--- a/media/capture/mojom/video_capture_types_mojom_traits.cc
+++ b/media/capture/mojom/video_capture_types_mojom_traits.cc
@@ -1521,6 +1521,7 @@
     return false;
   if (!data.ReadPowerLineFrequency(&out->power_line_frequency))
     return false;
+  out->enable_face_detection = data.enable_face_detection();
   return true;
 }
 
diff --git a/media/capture/mojom/video_capture_types_mojom_traits.h b/media/capture/mojom/video_capture_types_mojom_traits.h
index 53d15b2..73f6709 100644
--- a/media/capture/mojom/video_capture_types_mojom_traits.h
+++ b/media/capture/mojom/video_capture_types_mojom_traits.h
@@ -136,6 +136,11 @@
     return params.power_line_frequency;
   }
 
+  static bool enable_face_detection(
+      const media::VideoCaptureParams& params) {
+    return params.enable_face_detection;
+  }
+
   static bool Read(media::mojom::VideoCaptureParamsDataView data,
                    media::VideoCaptureParams* out);
 };
diff --git a/media/capture/video/android/java/src/org/chromium/media/VideoCapture.java b/media/capture/video/android/java/src/org/chromium/media/VideoCapture.java
index c48be06..4f346ade 100644
--- a/media/capture/video/android/java/src/org/chromium/media/VideoCapture.java
+++ b/media/capture/video/android/java/src/org/chromium/media/VideoCapture.java
@@ -60,7 +60,8 @@
 
     // Allocate necessary resources for capture.
     @CalledByNative
-    public abstract boolean allocate(int width, int height, int frameRate);
+    public abstract boolean allocate(
+            int width, int height, int frameRate, boolean enableFaceDetection);
 
     // Success is indicated by returning true and a callback to
     // nativeOnStarted(), which may occur synchronously or asynchronously.
diff --git a/media/capture/video/android/java/src/org/chromium/media/VideoCaptureCamera.java b/media/capture/video/android/java/src/org/chromium/media/VideoCaptureCamera.java
index c75f116..c0c17aba 100644
--- a/media/capture/video/android/java/src/org/chromium/media/VideoCaptureCamera.java
+++ b/media/capture/video/android/java/src/org/chromium/media/VideoCaptureCamera.java
@@ -289,7 +289,7 @@
     }
 
     @Override
-    public boolean allocate(int width, int height, int frameRate) {
+    public boolean allocate(int width, int height, int frameRate, boolean enableFaceDetection) {
         Log.d(TAG, "allocate: requested (%d x %d) @%dfps", width, height, frameRate);
         try {
             mCamera = android.hardware.Camera.open(mId);
diff --git a/media/capture/video/android/java/src/org/chromium/media/VideoCaptureCamera2.java b/media/capture/video/android/java/src/org/chromium/media/VideoCaptureCamera2.java
index 8c8b32b..6b9e7ac6 100644
--- a/media/capture/video/android/java/src/org/chromium/media/VideoCaptureCamera2.java
+++ b/media/capture/video/android/java/src/org/chromium/media/VideoCaptureCamera2.java
@@ -936,6 +936,7 @@
     private boolean mRedEyeReduction;
     private int mFillLightMode = AndroidFillLightMode.OFF;
     private boolean mTorch;
+    private boolean mEnableFaceDetection;
 
     // Service function to grab CameraCharacteristics and handle exceptions.
     private static CameraCharacteristics getCameraCharacteristics(int id) {
@@ -1011,6 +1012,14 @@
 
         configureCommonCaptureSettings(mPreviewRequestBuilder);
 
+        // Overwrite settings to enable face detection.
+        if (mEnableFaceDetection) {
+            mPreviewRequestBuilder.set(
+                    CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_USE_SCENE_MODE);
+            mPreviewRequestBuilder.set(CaptureRequest.CONTROL_SCENE_MODE,
+                    CameraMetadata.CONTROL_SCENE_MODE_FACE_PRIORITY);
+        }
+
         List<Surface> surfaceList = new ArrayList<Surface>(1);
         // TODO(mcasas): release this Surface when not needed, https://crbug.com/643884.
         surfaceList.add(mImageReader.getSurface());
@@ -1336,7 +1345,7 @@
     }
 
     @Override
-    public boolean allocate(int width, int height, int frameRate) {
+    public boolean allocate(int width, int height, int frameRate, boolean enableFaceDetection) {
         Log.d(TAG, "allocate: requested (%d x %d) @%dfps", width, height, frameRate);
         nativeDCheckCurrentlyOnIncomingTaskRunner(mNativeVideoCaptureDeviceAndroid);
         synchronized (mCameraStateLock) {
@@ -1389,6 +1398,8 @@
         mInvertDeviceOrientationReadings =
                 cameraCharacteristics.get(CameraCharacteristics.LENS_FACING)
                 == CameraCharacteristics.LENS_FACING_BACK;
+
+        mEnableFaceDetection = enableFaceDetection;
         return true;
     }
 
diff --git a/media/capture/video/android/video_capture_device_android.cc b/media/capture/video/android/video_capture_device_android.cc
index e1ebe0a6..31f1c08 100644
--- a/media/capture/video/android/video_capture_device_android.cc
+++ b/media/capture/video/android/video_capture_device_android.cc
@@ -135,7 +135,7 @@
   jboolean ret = Java_VideoCapture_allocate(
       env, j_capture_, params.requested_format.frame_size.width(),
       params.requested_format.frame_size.height(),
-      params.requested_format.frame_rate);
+      params.requested_format.frame_rate, params.enable_face_detection);
   if (!ret) {
     SetErrorState(media::VideoCaptureError::kAndroidFailedToAllocate, FROM_HERE,
                   "failed to allocate");
diff --git a/media/capture/video_capture_types.cc b/media/capture/video_capture_types.cc
index 6cd3063b..323ef60 100644
--- a/media/capture/video_capture_types.cc
+++ b/media/capture/video_capture_types.cc
@@ -72,7 +72,8 @@
 VideoCaptureParams::VideoCaptureParams()
     : buffer_type(VideoCaptureBufferType::kSharedMemory),
       resolution_change_policy(ResolutionChangePolicy::FIXED_RESOLUTION),
-      power_line_frequency(PowerLineFrequency::FREQUENCY_DEFAULT) {}
+      power_line_frequency(PowerLineFrequency::FREQUENCY_DEFAULT),
+      enable_face_detection(false) {}
 
 bool VideoCaptureParams::IsValid() const {
   return requested_format.IsValid() &&
diff --git a/media/capture/video_capture_types.h b/media/capture/video_capture_types.h
index d298f71..107034f 100644
--- a/media/capture/video_capture_types.h
+++ b/media/capture/video_capture_types.h
@@ -292,6 +292,12 @@
 
   // User-specified power line frequency.
   PowerLineFrequency power_line_frequency;
+
+  // Flag indicating if face detection should be enabled. This is for
+  // allowing the driver to apply appropriate settings for optimal
+  // exposures around the face area. Currently only applicable on
+  // Android platform with Camera2 driver support.
+  bool enable_face_detection;
 };
 
 }  // namespace media
diff --git a/media/cast/test/cast_benchmarks.cc b/media/cast/test/cast_benchmarks.cc
index 15a88cb..de31683f 100644
--- a/media/cast/test/cast_benchmarks.cc
+++ b/media/cast/test/cast_benchmarks.cc
@@ -652,7 +652,6 @@
       SearchVector v = ab.blend(ac, x == y ? 1.0 : static_cast<double>(y) / x);
       thread_num++;
       (*threads)[thread_num % threads->size()]
-          ->message_loop()
           ->task_runner()
           ->PostTask(FROM_HERE,
                      base::Bind(&CastBenchmark::BinarySearch,
@@ -682,7 +681,7 @@
       a.bitrate.grade = 1.0;
       a.latency.grade = 1.0;
       a.packet_drop.grade = 1.0;
-      threads[0]->message_loop()->task_runner()->PostTask(
+      threads[0]->task_runner()->PostTask(
           FROM_HERE,
           base::BindOnce(base::IgnoreResult(&CastBenchmark::RunOnePoint),
                          base::Unretained(this), a, 1.0));
diff --git a/media/cast/test/utility/udp_proxy.cc b/media/cast/test/utility/udp_proxy.cc
index 12bbf07..394c80e4 100644
--- a/media/cast/test/utility/udp_proxy.cc
+++ b/media/cast/test/utility/udp_proxy.cc
@@ -16,6 +16,7 @@
 #include "base/rand_util.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/threading/thread.h"
+#include "base/threading/thread_restrictions.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/default_tick_clock.h"
 #include "net/base/io_buffer.h"
@@ -693,6 +694,7 @@
         from_dest_pipe_(std::move(from_dest_pipe)),
         blocked_(false),
         weak_factory_(this) {
+    base::ScopedAllowBlockingForTesting allow_blocking;
     proxy_thread_.StartWithOptions(
         base::Thread::Options(base::MessageLoop::TYPE_IO, 0));
     base::WaitableEvent start_event(
@@ -708,6 +710,7 @@
   }
 
   ~UDPProxyImpl() final {
+    base::ScopedAllowBlockingForTesting allow_blocking;
     base::WaitableEvent stop_event(
         base::WaitableEvent::ResetPolicy::AUTOMATIC,
         base::WaitableEvent::InitialState::NOT_SIGNALED);
diff --git a/media/gpu/android/codec_allocator.cc b/media/gpu/android/codec_allocator.cc
index 2545a1f..bb99093 100644
--- a/media/gpu/android/codec_allocator.cc
+++ b/media/gpu/android/codec_allocator.cc
@@ -152,9 +152,11 @@
     // Register the hang detector to observe the thread's MessageLoop.
     thread->thread.task_runner()->PostTask(
         FROM_HERE,
-        base::BindOnce(&base::MessageLoop::AddTaskObserver,
-                       base::Unretained(thread->thread.message_loop()),
-                       &thread->hang_detector));
+        base::BindOnce(
+            [](base::MessageLoop::TaskObserver* observer) {
+              base::MessageLoopCurrent::Get()->AddTaskObserver(observer);
+            },
+            base::Unretained(&thread->hang_detector)));
   }
 
   clients_.insert(client);
diff --git a/media/gpu/v4l2/v4l2_image_processor.cc b/media/gpu/v4l2/v4l2_image_processor.cc
index 81734f9..9fdffb2 100644
--- a/media/gpu/v4l2/v4l2_image_processor.cc
+++ b/media/gpu/v4l2/v4l2_image_processor.cc
@@ -571,7 +571,7 @@
   // * device_poll_thread_ is running normally
   // * device_poll_thread_ scheduled us, but then a DestroyTask() shut it down,
   //   in which case we should early-out.
-  if (!device_poll_thread_.message_loop())
+  if (!device_poll_thread_.task_runner())
     return;
 
   Dequeue();
diff --git a/media/gpu/v4l2/v4l2_video_decode_accelerator.cc b/media/gpu/v4l2/v4l2_video_decode_accelerator.cc
index 99fe241..bf609b65 100644
--- a/media/gpu/v4l2/v4l2_video_decode_accelerator.cc
+++ b/media/gpu/v4l2/v4l2_video_decode_accelerator.cc
@@ -1232,7 +1232,7 @@
   // * device_poll_thread_ scheduled us, but then a ResetTask() or DestroyTask()
   //   shut it down, in which case we're either in kResetting or kError states
   //   respectively, and we should have early-outed already.
-  DCHECK(device_poll_thread_.message_loop());
+  DCHECK(device_poll_thread_.task_runner());
   // Queue the DevicePollTask() now.
   device_poll_thread_.task_runner()->PostTask(
       FROM_HERE, base::BindOnce(&V4L2VideoDecodeAccelerator::DevicePollTask,
diff --git a/media/gpu/v4l2/v4l2_video_encode_accelerator.cc b/media/gpu/v4l2/v4l2_video_encode_accelerator.cc
index 20a69a23..4c29b7c 100644
--- a/media/gpu/v4l2/v4l2_video_encode_accelerator.cc
+++ b/media/gpu/v4l2/v4l2_video_encode_accelerator.cc
@@ -593,7 +593,7 @@
   // * device_poll_thread_ scheduled us, but then a DestroyTask() shut it down,
   //   in which case we're in kError state, and we should have early-outed
   //   already.
-  DCHECK(device_poll_thread_.message_loop());
+  DCHECK(device_poll_thread_.task_runner());
   // Queue the DevicePollTask() now.
   device_poll_thread_.task_runner()->PostTask(
       FROM_HERE, base::BindOnce(&V4L2VideoEncodeAccelerator::DevicePollTask,
diff --git a/media/gpu/vaapi/vaapi_video_decode_accelerator.h b/media/gpu/vaapi/vaapi_video_decode_accelerator.h
index 793a712..3e1e84b 100644
--- a/media/gpu/vaapi/vaapi_video_decode_accelerator.h
+++ b/media/gpu/vaapi/vaapi_video_decode_accelerator.h
@@ -263,7 +263,7 @@
 
   base::Thread decoder_thread_;
   // Use this to post tasks to |decoder_thread_| instead of
-  // |decoder_thread_.message_loop()| because the latter will be NULL once
+  // |decoder_thread_.task_runner()| because the latter will be NULL once
   // |decoder_thread_.Stop()| returns.
   scoped_refptr<base::SingleThreadTaskRunner> decoder_thread_task_runner_;
 
diff --git a/media/renderers/paint_canvas_video_renderer.cc b/media/renderers/paint_canvas_video_renderer.cc
index e360c0a..93de42e1 100644
--- a/media/renderers/paint_canvas_video_renderer.cc
+++ b/media/renderers/paint_canvas_video_renderer.cc
@@ -207,6 +207,7 @@
 
   gpu::gles2::GLES2Interface* gl = context_3d.gl;
   unsigned source_texture = 0;
+  gfx::ColorSpace color_space_for_skia;
   if (mailbox_holder.texture_target != GL_TEXTURE_2D) {
     // TODO(dcastagna): At the moment Skia doesn't support targets different
     // than GL_TEXTURE_2D.  Avoid this copy once
@@ -221,6 +222,7 @@
     gl->WaitSyncTokenCHROMIUM(mailbox_holder.sync_token.GetConstData());
     source_texture =
         gl->CreateAndConsumeTextureCHROMIUM(mailbox_holder.mailbox.name);
+    color_space_for_skia = video_frame->ColorSpace();
   }
   GrGLTextureInfo source_texture_info;
   source_texture_info.fID = source_texture;
@@ -235,7 +237,8 @@
       GrMipMapped::kNo, source_texture_info);
   return SkImage::MakeFromAdoptedTexture(
       context_3d.gr_context, source_backend_texture, kTopLeft_GrSurfaceOrigin,
-      kRGBA_8888_SkColorType);
+      kRGBA_8888_SkColorType, kPremul_SkAlphaType,
+      color_space_for_skia.ToSkColorSpace());
 }
 
 void VideoFrameCopyTextureOrSubTexture(gpu::gles2::GLES2Interface* gl,
diff --git a/mojo/public/js/mojo_bindings_resources.grd b/mojo/public/js/mojo_bindings_resources.grd
index fd2be00b..57f2a9b 100644
--- a/mojo/public/js/mojo_bindings_resources.grd
+++ b/mojo/public/js/mojo_bindings_resources.grd
@@ -7,7 +7,7 @@
     <output filename="grit/mojo_bindings_resources_map.h"
         type="gzipped_resource_map_header" />
     <output filename="grit/mojo_bindings_resources_map.cc"
-        type="gzipped_resource_file_map_source" />
+        type="gzipped_resource_map_source" />
     <output filename="mojo_bindings_resources.pak" type="data_package" />
   </outputs>
   <translations />
diff --git a/net/BUILD.gn b/net/BUILD.gn
index d843ae4e..a229e0e 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -4970,21 +4970,19 @@
     "third_party/http2/http2_structures_test_util.cc",
     "third_party/http2/http2_structures_test_util.h",
     "third_party/http2/platform/api/http2_string_utils_test.cc",
-    "third_party/http2/platform/api/random_util_helper.h",
-    "third_party/http2/platform/impl/random_util_helper_impl.cc",
-    "third_party/http2/platform/impl/random_util_helper_impl.h",
     "third_party/http2/test_tools/frame_parts.cc",
     "third_party/http2/test_tools/frame_parts.h",
     "third_party/http2/test_tools/frame_parts_collector.cc",
     "third_party/http2/test_tools/frame_parts_collector.h",
     "third_party/http2/test_tools/frame_parts_collector_listener.cc",
     "third_party/http2/test_tools/frame_parts_collector_listener.h",
+    "third_party/http2/test_tools/http2_random.cc",
+    "third_party/http2/test_tools/http2_random.h",
+    "third_party/http2/test_tools/http2_random_test.cc",
     "third_party/http2/tools/failure.cc",
     "third_party/http2/tools/failure.h",
     "third_party/http2/tools/http2_frame_builder.cc",
     "third_party/http2/tools/http2_frame_builder.h",
-    "third_party/http2/tools/http2_random.cc",
-    "third_party/http2/tools/http2_random.h",
     "third_party/http2/tools/random_decoder_test.cc",
     "third_party/http2/tools/random_decoder_test.h",
     "third_party/http2/tools/random_util.cc",
diff --git a/net/android/java/src/org/chromium/net/AndroidNetworkLibrary.java b/net/android/java/src/org/chromium/net/AndroidNetworkLibrary.java
index 5072bd02..ce9dfc9f 100644
--- a/net/android/java/src/org/chromium/net/AndroidNetworkLibrary.java
+++ b/net/android/java/src/org/chromium/net/AndroidNetworkLibrary.java
@@ -27,6 +27,7 @@
 import org.chromium.base.VisibleForTesting;
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.CalledByNativeUnchecked;
+import org.chromium.base.annotations.MainDex;
 import org.chromium.base.compat.ApiHelperForM;
 
 import java.io.FileDescriptor;
@@ -51,8 +52,8 @@
 /**
  * This class implements net utilities required by the net component.
  */
+@MainDex
 class AndroidNetworkLibrary {
-
     private static final String TAG = "AndroidNetworkLibrary";
 
     // Cached Method for LinkProperties.isPrivateDnsActive().
diff --git a/net/base/network_change_notifier_win.cc b/net/base/network_change_notifier_win.cc
index c53df99..882a71b 100644
--- a/net/base/network_change_notifier_win.cc
+++ b/net/base/network_change_notifier_win.cc
@@ -11,7 +11,6 @@
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/macros.h"
-#include "base/message_loop/message_loop.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/single_thread_task_runner.h"
 #include "base/task_runner_util.h"
@@ -210,8 +209,7 @@
   // Unretained is safe in this call because this object owns the thread and the
   // thread is stopped in this object's destructor.
   base::PostTaskAndReplyWithResult(
-      dns_config_service_thread_->message_loop()->task_runner().get(),
-      FROM_HERE,
+      dns_config_service_thread_->task_runner().get(), FROM_HERE,
       base::Bind(&NetworkChangeNotifierWin::RecomputeCurrentConnectionType,
                  base::Unretained(this)),
       reply_callback);
diff --git a/net/cookies/cookie_store_test_callbacks.cc b/net/cookies/cookie_store_test_callbacks.cc
index 5e711d0a..091ae4da 100644
--- a/net/cookies/cookie_store_test_callbacks.cc
+++ b/net/cookies/cookie_store_test_callbacks.cc
@@ -8,29 +8,31 @@
 #include "base/message_loop/message_loop.h"
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread.h"
+#include "base/threading/thread_task_runner_handle.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace net {
 
 CookieCallback::CookieCallback(base::Thread* run_in_thread)
-    : run_in_thread_(run_in_thread), run_in_loop_(NULL) {}
+    : run_in_thread_(run_in_thread) {}
 
 CookieCallback::CookieCallback()
-    : run_in_thread_(NULL), run_in_loop_(base::MessageLoop::current()) {}
+    : run_in_thread_(NULL),
+      run_in_task_runner_(base::ThreadTaskRunnerHandle::Get()) {}
 
 CookieCallback::~CookieCallback() = default;
 
 void CookieCallback::CallbackEpilogue() {
-  base::MessageLoop* expected_loop = NULL;
+  scoped_refptr<base::SingleThreadTaskRunner> expected_task_runner;
   if (run_in_thread_) {
-    DCHECK(!run_in_loop_);
-    expected_loop = run_in_thread_->message_loop();
-  } else if (run_in_loop_) {
-    expected_loop = run_in_loop_;
+    DCHECK(!run_in_task_runner_);
+    expected_task_runner = run_in_thread_->task_runner();
+  } else if (run_in_task_runner_) {
+    expected_task_runner = run_in_task_runner_;
   }
-  ASSERT_TRUE(expected_loop != NULL);
+  ASSERT_TRUE(expected_task_runner);
 
-  EXPECT_EQ(expected_loop, base::MessageLoop::current());
+  EXPECT_TRUE(expected_task_runner->BelongsToCurrentThread());
   loop_to_quit_.Quit();
 }
 
diff --git a/net/cookies/cookie_store_test_callbacks.h b/net/cookies/cookie_store_test_callbacks.h
index d126ea715..5a95d34 100644
--- a/net/cookies/cookie_store_test_callbacks.h
+++ b/net/cookies/cookie_store_test_callbacks.h
@@ -8,12 +8,13 @@
 #include <string>
 #include <vector>
 
+#include "base/memory/scoped_refptr.h"
 #include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
 #include "net/cookies/canonical_cookie.h"
 #include "net/cookies/cookie_store.h"
 
 namespace base {
-class MessageLoop;
 class Thread;
 }
 
@@ -43,7 +44,7 @@
 
  private:
   base::Thread* run_in_thread_;
-  base::MessageLoop* run_in_loop_;
+  scoped_refptr<base::SingleThreadTaskRunner> run_in_task_runner_;
   base::RunLoop loop_to_quit_;
 };
 
diff --git a/net/dns/dns_config_overrides.cc b/net/dns/dns_config_overrides.cc
index 037e59a8..ba6a485 100644
--- a/net/dns/dns_config_overrides.cc
+++ b/net/dns/dns_config_overrides.cc
@@ -30,8 +30,38 @@
   return !(*this == other);
 }
 
+// static
+DnsConfigOverrides
+DnsConfigOverrides::CreateOverridingEverythingWithDefaults() {
+  DnsConfig defaults;
+
+  DnsConfigOverrides overrides;
+  overrides.nameservers = defaults.nameservers;
+  overrides.search = defaults.search;
+  overrides.hosts = defaults.hosts;
+  overrides.append_to_multi_label_name = defaults.append_to_multi_label_name;
+  overrides.randomize_ports = defaults.randomize_ports;
+  overrides.ndots = defaults.ndots;
+  overrides.timeout = defaults.timeout;
+  overrides.attempts = defaults.attempts;
+  overrides.rotate = defaults.rotate;
+  overrides.use_local_ipv6 = defaults.use_local_ipv6;
+  overrides.dns_over_https_servers = defaults.dns_over_https_servers;
+
+  return overrides;
+}
+
+bool DnsConfigOverrides::OverridesEverything() const {
+  return nameservers && search && hosts && append_to_multi_label_name &&
+         randomize_ports && ndots && timeout && attempts && rotate &&
+         use_local_ipv6 && dns_over_https_servers;
+}
+
 DnsConfig DnsConfigOverrides::ApplyOverrides(const DnsConfig& config) const {
-  DnsConfig overridden(config);
+  DnsConfig overridden;
+
+  if (!OverridesEverything())
+    overridden = config;
 
   if (nameservers)
     overridden.nameservers = nameservers.value();
diff --git a/net/dns/dns_config_overrides.h b/net/dns/dns_config_overrides.h
index 6b2913a..3873b15 100644
--- a/net/dns/dns_config_overrides.h
+++ b/net/dns/dns_config_overrides.h
@@ -28,11 +28,20 @@
   bool operator==(const DnsConfigOverrides& other) const;
   bool operator!=(const DnsConfigOverrides& other) const;
 
+  // Creation method that initializes all values with the defaults from
+  // DnsConfig. Guarantees the result of OverridesEverything() will be |true|.
+  static DnsConfigOverrides CreateOverridingEverythingWithDefaults();
+
   // Creates a new DnsConfig where any field with an overriding value in |this|
   // is replaced with that overriding value. Any field without an overriding
   // value (|base::nullopt|) will be copied as-is from |config|.
   DnsConfig ApplyOverrides(const DnsConfig& config) const;
 
+  // Returns |true| if the overriding configuration is comprehensive and would
+  // override everything in a base DnsConfig. This is the case if all Optional
+  // fields have a value.
+  bool OverridesEverything() const;
+
   // Overriding values. See same-named fields in DnsConfig for explanations.
   base::Optional<std::vector<IPEndPoint>> nameservers;
   base::Optional<std::vector<std::string>> search;
diff --git a/net/dns/host_resolver_impl.cc b/net/dns/host_resolver_impl.cc
index 3cbf2d2..bab65ea 100644
--- a/net/dns/host_resolver_impl.cc
+++ b/net/dns/host_resolver_impl.cc
@@ -2186,7 +2186,10 @@
   dns_client_ = std::move(dns_client);
   if (dns_client_ && !dns_client_->GetConfig() &&
       num_dns_failures_ < kMaximumDnsFailures) {
-    DnsConfig dns_config = GetBaseDnsConfig();
+    DnsConfig dns_config;
+    // Skip retrieving the base config if all values will be overridden.
+    if (!dns_config_overrides_.OverridesEverything())
+      dns_config = GetBaseDnsConfig();
     DnsConfig overridden_config =
         dns_config_overrides_.ApplyOverrides(dns_config);
     dns_client_->SetConfig(overridden_config);
@@ -2345,7 +2348,7 @@
     return;
 
   dns_config_overrides_ = overrides;
-  if (dns_client_.get() && dns_client_->GetConfig())
+  if (dns_client_.get())
     UpdateDNSConfig(true);
 }
 
@@ -2875,8 +2878,9 @@
 }
 
 void HostResolverImpl::OnDNSChanged() {
-  // Ignore changes if we're using a test config.
-  if (test_base_config_)
+  // Ignore changes if we're using a test config or if we have overriding
+  // configuration that overrides everything from the base config.
+  if (test_base_config_ || dns_config_overrides_.OverridesEverything())
     return;
 
   UpdateDNSConfig(true);
@@ -2892,16 +2896,22 @@
 }
 
 void HostResolverImpl::UpdateDNSConfig(bool config_changed) {
-  DnsConfig dns_config = GetBaseDnsConfig();
+  DnsConfig dns_config;
 
-  if (net_log_) {
-    net_log_->AddGlobalEntry(NetLogEventType::DNS_CONFIG_CHANGED,
-                             base::Bind(&NetLogDnsConfigCallback, &dns_config));
+  // Skip retrieving the base config if all values will be overridden.
+  if (!dns_config_overrides_.OverridesEverything()) {
+    dns_config = GetBaseDnsConfig();
+
+    if (net_log_) {
+      net_log_->AddGlobalEntry(
+          NetLogEventType::DNS_CONFIG_CHANGED,
+          base::BindRepeating(&NetLogDnsConfigCallback, &dns_config));
+    }
+
+    // TODO(szym): Remove once http://crbug.com/137914 is resolved.
+    received_dns_config_ = dns_config.IsValid();
   }
 
-  // TODO(szym): Remove once http://crbug.com/137914 is resolved.
-  received_dns_config_ = dns_config.IsValid();
-
   dns_config = dns_config_overrides_.ApplyOverrides(dns_config);
 
   // Conservatively assume local IPv6 is needed when DnsConfig is not valid.
diff --git a/net/dns/host_resolver_impl_unittest.cc b/net/dns/host_resolver_impl_unittest.cc
index 50720d9..0649050 100644
--- a/net/dns/host_resolver_impl_unittest.cc
+++ b/net/dns/host_resolver_impl_unittest.cc
@@ -5819,6 +5819,9 @@
           DnsConfig::DnsOverHttpsServerConfig("dns.example.com", true)};
   overrides.dns_over_https_servers = dns_over_https_servers;
 
+  // This test is expected to test overriding all fields.
+  EXPECT_TRUE(overrides.OverridesEverything());
+
   resolver_->SetDnsConfigOverrides(overrides);
 
   const DnsConfig* overridden_config = dns_client_->GetConfig();
@@ -5835,6 +5838,31 @@
   EXPECT_EQ(dns_over_https_servers, overridden_config->dns_over_https_servers);
 }
 
+TEST_F(HostResolverImplDnsTest,
+       SetDnsConfigOverrides_OverrideEverythingCreation) {
+  DnsConfig original_config = CreateValidDnsConfig();
+  ChangeDnsConfig(original_config);
+
+  // Confirm pre-override state.
+  ASSERT_TRUE(original_config.Equals(*dns_client_->GetConfig()));
+  ASSERT_FALSE(original_config.Equals(DnsConfig()));
+
+  DnsConfigOverrides overrides =
+      DnsConfigOverrides::CreateOverridingEverythingWithDefaults();
+  EXPECT_TRUE(overrides.OverridesEverything());
+
+  // Ensure config is valid by setting a nameserver.
+  std::vector<IPEndPoint> nameservers = {CreateExpected("1.2.3.4", 50)};
+  overrides.nameservers = nameservers;
+  EXPECT_TRUE(overrides.OverridesEverything());
+
+  resolver_->SetDnsConfigOverrides(overrides);
+
+  DnsConfig expected;
+  expected.nameservers = nameservers;
+  EXPECT_TRUE(dns_client_->GetConfig()->Equals(DnsConfig(expected)));
+}
+
 TEST_F(HostResolverImplDnsTest, SetDnsConfigOverrides_PartialOverride) {
   DnsConfig original_config = CreateValidDnsConfig();
   ChangeDnsConfig(original_config);
@@ -5847,6 +5875,7 @@
       CreateExpected("192.168.0.2", 192)};
   overrides.nameservers = nameservers;
   overrides.rotate = true;
+  EXPECT_FALSE(overrides.OverridesEverything());
 
   resolver_->SetDnsConfigOverrides(overrides);
 
@@ -5906,12 +5935,59 @@
   EXPECT_TRUE(original_config.Equals(*dns_client_->GetConfig()));
 }
 
+// Test that even when using config overrides, a change to the base system
+// config cancels pending requests.
+TEST_F(HostResolverImplDnsTest, CancellationOnBaseConfigChange) {
+  DnsConfig original_config = CreateValidDnsConfig();
+  ChangeDnsConfig(original_config);
+
+  DnsConfigOverrides overrides;
+  overrides.nameservers.emplace({CreateExpected("123.123.123.123", 80)});
+  ASSERT_FALSE(overrides.OverridesEverything());
+  resolver_->SetDnsConfigOverrides(overrides);
+
+  ResolveHostResponseHelper response(resolver_->CreateRequest(
+      HostPortPair("4slow_ok", 80), NetLogWithSource(), base::nullopt));
+  ASSERT_FALSE(response.complete());
+
+  DnsConfig new_config = original_config;
+  new_config.attempts = 103;
+  ChangeDnsConfig(new_config);
+
+  EXPECT_THAT(response.result_error(), IsError(ERR_NETWORK_CHANGED));
+}
+
+// Test that when all configuration is overridden, system configuration changes
+// do not cancel requests.
+TEST_F(HostResolverImplDnsTest,
+       CancellationOnBaseConfigChange_OverridesEverything) {
+  DnsConfig original_config = CreateValidDnsConfig();
+  ChangeDnsConfig(original_config);
+
+  DnsConfigOverrides overrides =
+      DnsConfigOverrides::CreateOverridingEverythingWithDefaults();
+  overrides.nameservers.emplace({CreateExpected("123.123.123.123", 80)});
+  ASSERT_TRUE(overrides.OverridesEverything());
+  resolver_->SetDnsConfigOverrides(overrides);
+
+  ResolveHostResponseHelper response(resolver_->CreateRequest(
+      HostPortPair("4slow_ok", 80), NetLogWithSource(), base::nullopt));
+  ASSERT_FALSE(response.complete());
+
+  DnsConfig new_config = original_config;
+  new_config.attempts = 103;
+  ChangeDnsConfig(new_config);
+
+  dns_client_->CompleteDelayedTransactions();
+  EXPECT_THAT(response.result_error(), IsOk());
+}
+
 // Test that in-progress queries are cancelled on applying new DNS config
 // overrides, same as receiving a new DnsConfig from the system.
 TEST_F(HostResolverImplDnsTest, CancelQueriesOnSettingOverrides) {
   ChangeDnsConfig(CreateValidDnsConfig());
   ResolveHostResponseHelper response(resolver_->CreateRequest(
-      HostPortPair("ok", 80), NetLogWithSource(), base::nullopt));
+      HostPortPair("4slow_ok", 80), NetLogWithSource(), base::nullopt));
   ASSERT_FALSE(response.complete());
 
   DnsConfigOverrides overrides;
@@ -5929,11 +6005,12 @@
   resolver_->SetDnsConfigOverrides(overrides);
 
   ResolveHostResponseHelper response(resolver_->CreateRequest(
-      HostPortPair("ok", 80), NetLogWithSource(), base::nullopt));
+      HostPortPair("4slow_ok", 80), NetLogWithSource(), base::nullopt));
   ASSERT_FALSE(response.complete());
 
   resolver_->SetDnsConfigOverrides(overrides);
 
+  dns_client_->CompleteDelayedTransactions();
   EXPECT_THAT(response.result_error(), IsOk());
 }
 
@@ -5946,7 +6023,7 @@
   resolver_->SetDnsConfigOverrides(overrides);
 
   ResolveHostResponseHelper response(resolver_->CreateRequest(
-      HostPortPair("ok", 80), NetLogWithSource(), base::nullopt));
+      HostPortPair("4slow_ok", 80), NetLogWithSource(), base::nullopt));
   ASSERT_FALSE(response.complete());
 
   resolver_->SetDnsConfigOverrides(DnsConfigOverrides());
@@ -5959,11 +6036,12 @@
 TEST_F(HostResolverImplDnsTest, CancelQueriesOnClearingOverrides_NoOverrides) {
   ChangeDnsConfig(CreateValidDnsConfig());
   ResolveHostResponseHelper response(resolver_->CreateRequest(
-      HostPortPair("ok", 80), NetLogWithSource(), base::nullopt));
+      HostPortPair("4slow_ok", 80), NetLogWithSource(), base::nullopt));
   ASSERT_FALSE(response.complete());
 
   resolver_->SetDnsConfigOverrides(DnsConfigOverrides());
 
+  dns_client_->CompleteDelayedTransactions();
   EXPECT_THAT(response.result_error(), IsOk());
 }
 
diff --git a/net/quic/quic_chromium_client_session.cc b/net/quic/quic_chromium_client_session.cc
index a08abc8d..c990f38f 100644
--- a/net/quic/quic_chromium_client_session.cc
+++ b/net/quic/quic_chromium_client_session.cc
@@ -687,7 +687,10 @@
     base::SequencedTaskRunner* task_runner,
     std::unique_ptr<SocketPerformanceWatcher> socket_performance_watcher,
     NetLog* net_log)
-    : quic::QuicSpdyClientSessionBase(connection, push_promise_index, config),
+    : quic::QuicSpdyClientSessionBase(connection,
+                                      push_promise_index,
+                                      config,
+                                      connection->supported_versions()),
       session_key_(session_key),
       require_confirmation_(require_confirmation),
       migrate_session_early_v2_(migrate_session_early_v2),
diff --git a/net/quic/quic_chromium_client_stream_test.cc b/net/quic/quic_chromium_client_stream_test.cc
index 869042c..a305268 100644
--- a/net/quic/quic_chromium_client_stream_test.cc
+++ b/net/quic/quic_chromium_client_stream_test.cc
@@ -143,7 +143,8 @@
     quic::QuicClientPushPromiseIndex* push_promise_index)
     : quic::QuicSpdyClientSessionBase(connection,
                                       push_promise_index,
-                                      quic::test::DefaultQuicConfig()) {
+                                      quic::test::DefaultQuicConfig(),
+                                      connection->supported_versions()) {
   crypto_stream_.reset(new quic::test::MockQuicCryptoStream(this));
   Initialize();
   ON_CALL(*this, WritevData(_, _, _, _, _))
diff --git a/net/quic/quic_flags_list.h b/net/quic/quic_flags_list.h
index 5efeb24..f8da146e 100644
--- a/net/quic/quic_flags_list.h
+++ b/net/quic/quic_flags_list.h
@@ -83,9 +83,6 @@
 // Enables 3 new connection options to make PROBE_RTT more aggressive
 QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_bbr_less_probe_rtt, false)
 
-// If true, limit quic stream length to be below 2^62.
-QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_stream_too_long, true)
-
 // If true, enable QUIC v99.
 QUIC_FLAG(bool, FLAGS_quic_enable_version_99, false)
 
@@ -268,7 +265,7 @@
 // If true, dispatcher passes in a single version when creating a server
 // connection, such that version negotiation is not supported in connection.
 QUIC_FLAG(bool,
-          FLAGS_quic_restart_flag_quic_no_server_conn_ver_negotiation,
+          FLAGS_quic_restart_flag_quic_no_server_conn_ver_negotiation2,
           false)
 
 // If true, enable QUIC version 46 which adds CRYPTO frames.
@@ -293,3 +290,13 @@
 // If true, use common code for checking whether a new stream ID may be
 // allocated.
 QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_use_common_stream_check, false)
+
+// If true, QuicEpollClock::Now() will monotonically increase.
+QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_monotonic_epoll_clock, false)
+
+// If true, a client connection would be closed when a version negotiation
+// packet is received. It would be the higher layer's responsibility to do the
+// reconnection.
+QUIC_FLAG(bool,
+          FLAGS_quic_reloadable_flag_quic_no_client_conn_ver_negotiation,
+          false)
diff --git a/net/third_party/http2/decoder/decode_buffer_test.cc b/net/third_party/http2/decoder/decode_buffer_test.cc
index 007f844..b6cf4fd0 100644
--- a/net/third_party/http2/decoder/decode_buffer_test.cc
+++ b/net/third_party/http2/decoder/decode_buffer_test.cc
@@ -5,7 +5,7 @@
 #include "net/third_party/http2/decoder/decode_buffer.h"
 
 #include "base/logging.h"
-#include "net/third_party/http2/tools/http2_random.h"
+#include "net/third_party/http2/test_tools/http2_random.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace http2 {
diff --git a/net/third_party/http2/decoder/decode_http2_structures_test.cc b/net/third_party/http2/decoder/decode_http2_structures_test.cc
index 5f1c42a..5538bb8 100644
--- a/net/third_party/http2/decoder/decode_http2_structures_test.cc
+++ b/net/third_party/http2/decoder/decode_http2_structures_test.cc
@@ -16,8 +16,8 @@
 #include "net/third_party/http2/http2_structures_test_util.h"
 #include "net/third_party/http2/platform/api/http2_string.h"
 #include "net/third_party/http2/platform/api/http2_string_piece.h"
+#include "net/third_party/http2/test_tools/http2_random.h"
 #include "net/third_party/http2/tools/http2_frame_builder.h"
-#include "net/third_party/http2/tools/http2_random.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 using ::testing::AssertionResult;
diff --git a/net/third_party/http2/decoder/frame_decoder_state_test_util.cc b/net/third_party/http2/decoder/frame_decoder_state_test_util.cc
index 9cd9c9d..b7363df 100644
--- a/net/third_party/http2/decoder/frame_decoder_state_test_util.cc
+++ b/net/third_party/http2/decoder/frame_decoder_state_test_util.cc
@@ -8,14 +8,14 @@
 #include "net/third_party/http2/decoder/http2_structure_decoder_test_util.h"
 #include "net/third_party/http2/http2_structures.h"
 #include "net/third_party/http2/http2_structures_test_util.h"
-#include "net/third_party/http2/tools/http2_random.h"
+#include "net/third_party/http2/test_tools/http2_random.h"
 #include "net/third_party/http2/tools/random_decoder_test.h"
 
 namespace http2 {
 namespace test {
 
 // static
-void FrameDecoderStatePeer::Randomize(FrameDecoderState* p, RandomBase* rng) {
+void FrameDecoderStatePeer::Randomize(FrameDecoderState* p, Http2Random* rng) {
   VLOG(1) << "FrameDecoderStatePeer::Randomize";
   ::http2::test::Randomize(&p->frame_header_, rng);
   p->remaining_payload_ = rng->Rand32();
diff --git a/net/third_party/http2/decoder/frame_decoder_state_test_util.h b/net/third_party/http2/decoder/frame_decoder_state_test_util.h
index 54a703b..a118f1b 100644
--- a/net/third_party/http2/decoder/frame_decoder_state_test_util.h
+++ b/net/third_party/http2/decoder/frame_decoder_state_test_util.h
@@ -19,7 +19,7 @@
   // decode buffer to the payload decoder, which increases the likelihood of
   // detecting any use of prior states of the decoder on the decoding of
   // future payloads.
-  static void Randomize(FrameDecoderState* p, RandomBase* rng);
+  static void Randomize(FrameDecoderState* p, Http2Random* rng);
 
   // Inject a frame header into the FrameDecoderState.
   // PayloadDecoderBaseTest::StartDecoding calls this just after calling
diff --git a/net/third_party/http2/decoder/http2_frame_decoder_test.cc b/net/third_party/http2/decoder/http2_frame_decoder_test.cc
index f1d2e3c..b28232c 100644
--- a/net/third_party/http2/decoder/http2_frame_decoder_test.cc
+++ b/net/third_party/http2/decoder/http2_frame_decoder_test.cc
@@ -15,8 +15,8 @@
 #include "net/third_party/http2/platform/api/http2_string_piece.h"
 #include "net/third_party/http2/test_tools/frame_parts.h"
 #include "net/third_party/http2/test_tools/frame_parts_collector_listener.h"
+#include "net/third_party/http2/test_tools/http2_random.h"
 #include "net/third_party/http2/tools/failure.h"
-#include "net/third_party/http2/tools/http2_random.h"
 #include "net/third_party/http2/tools/random_decoder_test.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/net/third_party/http2/decoder/http2_structure_decoder_test_util.cc b/net/third_party/http2/decoder/http2_structure_decoder_test_util.cc
index 74e0f88..e24d70e 100644
--- a/net/third_party/http2/decoder/http2_structure_decoder_test_util.cc
+++ b/net/third_party/http2/decoder/http2_structure_decoder_test_util.cc
@@ -11,7 +11,7 @@
 
 // static
 void Http2StructureDecoderPeer::Randomize(Http2StructureDecoder* p,
-                                          RandomBase* rng) {
+                                          Http2Random* rng) {
   p->offset_ = rng->Rand32();
   for (size_t i = 0; i < sizeof p->buffer_; ++i) {
     p->buffer_[i] = rng->Rand8();
diff --git a/net/third_party/http2/decoder/http2_structure_decoder_test_util.h b/net/third_party/http2/decoder/http2_structure_decoder_test_util.h
index da65a26..8740896 100644
--- a/net/third_party/http2/decoder/http2_structure_decoder_test_util.h
+++ b/net/third_party/http2/decoder/http2_structure_decoder_test_util.h
@@ -7,7 +7,7 @@
 
 #include "net/third_party/http2/decoder/http2_structure_decoder.h"
 
-#include "net/third_party/http2/tools/http2_random.h"
+#include "net/third_party/http2/test_tools/http2_random.h"
 
 namespace http2 {
 namespace test {
@@ -15,7 +15,7 @@
 class Http2StructureDecoderPeer {
  public:
   // Overwrite the Http2StructureDecoder instance with random values.
-  static void Randomize(Http2StructureDecoder* p, RandomBase* rng);
+  static void Randomize(Http2StructureDecoder* p, Http2Random* rng);
 };
 
 }  // namespace test
diff --git a/net/third_party/http2/decoder/payload_decoders/altsvc_payload_decoder_test.cc b/net/third_party/http2/decoder/payload_decoders/altsvc_payload_decoder_test.cc
index b5f79e50..b31d605f 100644
--- a/net/third_party/http2/decoder/payload_decoders/altsvc_payload_decoder_test.cc
+++ b/net/third_party/http2/decoder/payload_decoders/altsvc_payload_decoder_test.cc
@@ -14,8 +14,8 @@
 #include "net/third_party/http2/platform/api/http2_string.h"
 #include "net/third_party/http2/test_tools/frame_parts.h"
 #include "net/third_party/http2/test_tools/frame_parts_collector.h"
+#include "net/third_party/http2/test_tools/http2_random.h"
 #include "net/third_party/http2/tools/http2_frame_builder.h"
-#include "net/third_party/http2/tools/http2_random.h"
 #include "net/third_party/http2/tools/random_decoder_test.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/net/third_party/http2/decoder/payload_decoders/data_payload_decoder_test.cc b/net/third_party/http2/decoder/payload_decoders/data_payload_decoder_test.cc
index 245f9f1..ba27b24 100644
--- a/net/third_party/http2/decoder/payload_decoders/data_payload_decoder_test.cc
+++ b/net/third_party/http2/decoder/payload_decoders/data_payload_decoder_test.cc
@@ -15,9 +15,9 @@
 #include "net/third_party/http2/platform/api/http2_string.h"
 #include "net/third_party/http2/test_tools/frame_parts.h"
 #include "net/third_party/http2/test_tools/frame_parts_collector.h"
+#include "net/third_party/http2/test_tools/http2_random.h"
 #include "net/third_party/http2/tools/failure.h"
 #include "net/third_party/http2/tools/http2_frame_builder.h"
-#include "net/third_party/http2/tools/http2_random.h"
 #include "net/third_party/http2/tools/random_decoder_test.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/net/third_party/http2/decoder/payload_decoders/goaway_payload_decoder_test.cc b/net/third_party/http2/decoder/payload_decoders/goaway_payload_decoder_test.cc
index 5648c91..fdba2529 100644
--- a/net/third_party/http2/decoder/payload_decoders/goaway_payload_decoder_test.cc
+++ b/net/third_party/http2/decoder/payload_decoders/goaway_payload_decoder_test.cc
@@ -14,8 +14,8 @@
 #include "net/third_party/http2/platform/api/http2_string.h"
 #include "net/third_party/http2/test_tools/frame_parts.h"
 #include "net/third_party/http2/test_tools/frame_parts_collector.h"
+#include "net/third_party/http2/test_tools/http2_random.h"
 #include "net/third_party/http2/tools/http2_frame_builder.h"
-#include "net/third_party/http2/tools/http2_random.h"
 #include "net/third_party/http2/tools/random_decoder_test.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/net/third_party/http2/decoder/payload_decoders/headers_payload_decoder_test.cc b/net/third_party/http2/decoder/payload_decoders/headers_payload_decoder_test.cc
index 4a70b13..252ad88 100644
--- a/net/third_party/http2/decoder/payload_decoders/headers_payload_decoder_test.cc
+++ b/net/third_party/http2/decoder/payload_decoders/headers_payload_decoder_test.cc
@@ -14,8 +14,8 @@
 #include "net/third_party/http2/platform/api/http2_string.h"
 #include "net/third_party/http2/test_tools/frame_parts.h"
 #include "net/third_party/http2/test_tools/frame_parts_collector.h"
+#include "net/third_party/http2/test_tools/http2_random.h"
 #include "net/third_party/http2/tools/http2_frame_builder.h"
-#include "net/third_party/http2/tools/http2_random.h"
 #include "net/third_party/http2/tools/random_decoder_test.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/net/third_party/http2/decoder/payload_decoders/ping_payload_decoder_test.cc b/net/third_party/http2/decoder/payload_decoders/ping_payload_decoder_test.cc
index dcac2f77..16e3e65 100644
--- a/net/third_party/http2/decoder/payload_decoders/ping_payload_decoder_test.cc
+++ b/net/third_party/http2/decoder/payload_decoders/ping_payload_decoder_test.cc
@@ -13,8 +13,8 @@
 #include "net/third_party/http2/http2_structures_test_util.h"
 #include "net/third_party/http2/test_tools/frame_parts.h"
 #include "net/third_party/http2/test_tools/frame_parts_collector.h"
+#include "net/third_party/http2/test_tools/http2_random.h"
 #include "net/third_party/http2/tools/http2_frame_builder.h"
-#include "net/third_party/http2/tools/http2_random.h"
 #include "net/third_party/http2/tools/random_decoder_test.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/net/third_party/http2/decoder/payload_decoders/priority_payload_decoder_test.cc b/net/third_party/http2/decoder/payload_decoders/priority_payload_decoder_test.cc
index 27167e0..3ef328474 100644
--- a/net/third_party/http2/decoder/payload_decoders/priority_payload_decoder_test.cc
+++ b/net/third_party/http2/decoder/payload_decoders/priority_payload_decoder_test.cc
@@ -13,8 +13,8 @@
 #include "net/third_party/http2/http2_structures_test_util.h"
 #include "net/third_party/http2/test_tools/frame_parts.h"
 #include "net/third_party/http2/test_tools/frame_parts_collector.h"
+#include "net/third_party/http2/test_tools/http2_random.h"
 #include "net/third_party/http2/tools/http2_frame_builder.h"
-#include "net/third_party/http2/tools/http2_random.h"
 #include "net/third_party/http2/tools/random_decoder_test.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/net/third_party/http2/decoder/payload_decoders/push_promise_payload_decoder_test.cc b/net/third_party/http2/decoder/payload_decoders/push_promise_payload_decoder_test.cc
index 381b922b..1e9887d 100644
--- a/net/third_party/http2/decoder/payload_decoders/push_promise_payload_decoder_test.cc
+++ b/net/third_party/http2/decoder/payload_decoders/push_promise_payload_decoder_test.cc
@@ -14,8 +14,8 @@
 #include "net/third_party/http2/platform/api/http2_string.h"
 #include "net/third_party/http2/test_tools/frame_parts.h"
 #include "net/third_party/http2/test_tools/frame_parts_collector.h"
+#include "net/third_party/http2/test_tools/http2_random.h"
 #include "net/third_party/http2/tools/http2_frame_builder.h"
-#include "net/third_party/http2/tools/http2_random.h"
 #include "net/third_party/http2/tools/random_decoder_test.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/net/third_party/http2/decoder/payload_decoders/rst_stream_payload_decoder_test.cc b/net/third_party/http2/decoder/payload_decoders/rst_stream_payload_decoder_test.cc
index ff9bf259..47389f4 100644
--- a/net/third_party/http2/decoder/payload_decoders/rst_stream_payload_decoder_test.cc
+++ b/net/third_party/http2/decoder/payload_decoders/rst_stream_payload_decoder_test.cc
@@ -14,8 +14,8 @@
 #include "net/third_party/http2/http2_structures_test_util.h"
 #include "net/third_party/http2/test_tools/frame_parts.h"
 #include "net/third_party/http2/test_tools/frame_parts_collector.h"
+#include "net/third_party/http2/test_tools/http2_random.h"
 #include "net/third_party/http2/tools/http2_frame_builder.h"
-#include "net/third_party/http2/tools/http2_random.h"
 #include "net/third_party/http2/tools/random_decoder_test.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/net/third_party/http2/decoder/payload_decoders/settings_payload_decoder_test.cc b/net/third_party/http2/decoder/payload_decoders/settings_payload_decoder_test.cc
index 9190c20..96aa42a 100644
--- a/net/third_party/http2/decoder/payload_decoders/settings_payload_decoder_test.cc
+++ b/net/third_party/http2/decoder/payload_decoders/settings_payload_decoder_test.cc
@@ -16,8 +16,8 @@
 #include "net/third_party/http2/http2_structures_test_util.h"
 #include "net/third_party/http2/test_tools/frame_parts.h"
 #include "net/third_party/http2/test_tools/frame_parts_collector.h"
+#include "net/third_party/http2/test_tools/http2_random.h"
 #include "net/third_party/http2/tools/http2_frame_builder.h"
-#include "net/third_party/http2/tools/http2_random.h"
 #include "net/third_party/http2/tools/random_decoder_test.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/net/third_party/http2/decoder/payload_decoders/unknown_payload_decoder_test.cc b/net/third_party/http2/decoder/payload_decoders/unknown_payload_decoder_test.cc
index 75d40cd..f4467e39 100644
--- a/net/third_party/http2/decoder/payload_decoders/unknown_payload_decoder_test.cc
+++ b/net/third_party/http2/decoder/payload_decoders/unknown_payload_decoder_test.cc
@@ -16,7 +16,7 @@
 #include "net/third_party/http2/platform/api/http2_string.h"
 #include "net/third_party/http2/test_tools/frame_parts.h"
 #include "net/third_party/http2/test_tools/frame_parts_collector.h"
-#include "net/third_party/http2/tools/http2_random.h"
+#include "net/third_party/http2/test_tools/http2_random.h"
 #include "net/third_party/http2/tools/random_decoder_test.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/net/third_party/http2/decoder/payload_decoders/window_update_payload_decoder_test.cc b/net/third_party/http2/decoder/payload_decoders/window_update_payload_decoder_test.cc
index 5c69f212..784a970 100644
--- a/net/third_party/http2/decoder/payload_decoders/window_update_payload_decoder_test.cc
+++ b/net/third_party/http2/decoder/payload_decoders/window_update_payload_decoder_test.cc
@@ -13,8 +13,8 @@
 #include "net/third_party/http2/http2_structures_test_util.h"
 #include "net/third_party/http2/test_tools/frame_parts.h"
 #include "net/third_party/http2/test_tools/frame_parts_collector.h"
+#include "net/third_party/http2/test_tools/http2_random.h"
 #include "net/third_party/http2/tools/http2_frame_builder.h"
-#include "net/third_party/http2/tools/http2_random.h"
 #include "net/third_party/http2/tools/random_decoder_test.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/net/third_party/http2/hpack/decoder/hpack_block_collector.cc b/net/third_party/http2/hpack/decoder/hpack_block_collector.cc
index 8e8d7b06..33eaaf7 100644
--- a/net/third_party/http2/hpack/decoder/hpack_block_collector.cc
+++ b/net/third_party/http2/hpack/decoder/hpack_block_collector.cc
@@ -8,7 +8,6 @@
 #include <memory>
 
 #include "base/logging.h"
-#include "base/rand_util.h"
 #include "net/third_party/http2/tools/failure.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -91,8 +90,8 @@
       HpackEntryCollector(type, name_huffman, name, value_huffman, value));
 }
 
-void HpackBlockCollector::ShuffleEntries(RandomBase* rng) {
-  base::RandomShuffle(entries_.begin(), entries_.end());
+void HpackBlockCollector::ShuffleEntries(Http2Random* rng) {
+  std::shuffle(entries_.begin(), entries_.end(), *rng);
 }
 
 void HpackBlockCollector::AppendToHpackBlockBuilder(
diff --git a/net/third_party/http2/hpack/decoder/hpack_block_collector.h b/net/third_party/http2/hpack/decoder/hpack_block_collector.h
index 1195b74..969cedeb 100644
--- a/net/third_party/http2/hpack/decoder/hpack_block_collector.h
+++ b/net/third_party/http2/hpack/decoder/hpack_block_collector.h
@@ -23,12 +23,11 @@
 #include "net/third_party/http2/hpack/tools/hpack_block_builder.h"
 #include "net/third_party/http2/platform/api/http2_string.h"
 #include "net/third_party/http2/platform/api/http2_string_piece.h"
+#include "net/third_party/http2/test_tools/http2_random.h"
 
 namespace http2 {
 namespace test {
 
-class RandomBase;
-
 class HpackBlockCollector : public HpackEntryDecoderListener {
  public:
   // Implementations of HpackEntryDecoderListener, forwarding to pending_entry_,
@@ -76,7 +75,7 @@
 
   // Shuffle the entries, in support of generating an HPACK block of entries
   // in some random order.
-  void ShuffleEntries(RandomBase* rng);
+  void ShuffleEntries(Http2Random* rng);
 
   // Serialize entries_ to the HpackBlockBuilder.
   void AppendToHpackBlockBuilder(HpackBlockBuilder* hbb) const;
diff --git a/net/third_party/http2/hpack/decoder/hpack_block_decoder_test.cc b/net/third_party/http2/hpack/decoder/hpack_block_decoder_test.cc
index 9bd94eb3..831311c 100644
--- a/net/third_party/http2/hpack/decoder/hpack_block_decoder_test.cc
+++ b/net/third_party/http2/hpack/decoder/hpack_block_decoder_test.cc
@@ -16,8 +16,8 @@
 #include "net/third_party/http2/hpack/tools/hpack_block_builder.h"
 #include "net/third_party/http2/hpack/tools/hpack_example.h"
 #include "net/third_party/http2/platform/api/http2_string_piece.h"
+#include "net/third_party/http2/test_tools/http2_random.h"
 #include "net/third_party/http2/tools/failure.h"
-#include "net/third_party/http2/tools/http2_random.h"
 #include "net/third_party/http2/tools/random_decoder_test.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/net/third_party/http2/hpack/decoder/hpack_decoder_tables_test.cc b/net/third_party/http2/hpack/decoder/hpack_decoder_tables_test.cc
index 121f5500..c66b8d9 100644
--- a/net/third_party/http2/hpack/decoder/hpack_decoder_tables_test.cc
+++ b/net/third_party/http2/hpack/decoder/hpack_decoder_tables_test.cc
@@ -11,8 +11,8 @@
 #include "base/logging.h"
 #include "net/third_party/http2/hpack/http2_hpack_constants.h"
 #include "net/third_party/http2/platform/api/http2_string.h"
+#include "net/third_party/http2/test_tools/http2_random.h"
 #include "net/third_party/http2/tools/failure.h"
-#include "net/third_party/http2/tools/http2_random.h"
 #include "net/third_party/http2/tools/random_util.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -51,7 +51,7 @@
 }
 
 template <class C>
-void ShuffleCollection(C* collection, RandomBase* r) {
+void ShuffleCollection(C* collection, Http2Random* r) {
   std::shuffle(collection->begin(), collection->end(), *r);
 }
 
@@ -84,10 +84,11 @@
     return static_table_.Lookup(index);
   }
 
-  RandomBase* RandomPtr() { return &random_; }
+  Http2Random* RandomPtr() { return &random_; }
+
+  Http2Random random_;
 
  private:
-  Http2Random random_;
   HpackDecoderStaticTable static_table_;
 };
 
@@ -250,10 +251,10 @@
   for (size_t limit : table_sizes) {
     ASSERT_TRUE(DynamicTableSizeUpdate(limit));
     for (int insert_count = 0; insert_count < 100; ++insert_count) {
-      Http2String name = GenerateHttp2HeaderName(
-          GenerateUniformInRange(2, 40, RandomPtr()), RandomPtr());
-      Http2String value = GenerateWebSafeString(
-          GenerateUniformInRange(2, 600, RandomPtr()), RandomPtr());
+      Http2String name =
+          GenerateHttp2HeaderName(random_.UniformInRange(2, 40), RandomPtr());
+      Http2String value =
+          GenerateWebSafeString(random_.UniformInRange(2, 600), RandomPtr());
       ASSERT_TRUE(Insert(name, value));
     }
     EXPECT_TRUE(VerifyStaticTableContents());
diff --git a/net/third_party/http2/hpack/decoder/hpack_decoder_test.cc b/net/third_party/http2/hpack/decoder/hpack_decoder_test.cc
index 1694f6e..efc1cf7 100644
--- a/net/third_party/http2/hpack/decoder/hpack_decoder_test.cc
+++ b/net/third_party/http2/hpack/decoder/hpack_decoder_test.cc
@@ -21,8 +21,8 @@
 #include "net/third_party/http2/hpack/tools/hpack_example.h"
 #include "net/third_party/http2/http2_constants.h"
 #include "net/third_party/http2/platform/api/http2_string.h"
+#include "net/third_party/http2/test_tools/http2_random.h"
 #include "net/third_party/http2/tools/failure.h"
-#include "net/third_party/http2/tools/http2_random.h"
 #include "net/third_party/http2/tools/random_util.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -145,8 +145,7 @@
     if (fragment_the_hpack_block_) {
       // See note in ctor regarding RNG.
       while (!block.empty()) {
-        size_t fragment_size =
-            GenerateRandomSizeSkewedLow(block.size(), &random_);
+        size_t fragment_size = random_.RandomSizeSkewedLow(block.size());
         DecodeBuffer db(block.substr(0, fragment_size));
         VERIFY_TRUE(decoder_.DecodeFragment(&db));
         VERIFY_EQ(0u, db.Remaining());
diff --git a/net/third_party/http2/hpack/decoder/hpack_entry_decoder_test.cc b/net/third_party/http2/hpack/decoder/hpack_entry_decoder_test.cc
index 5b7500e..9840bcf 100644
--- a/net/third_party/http2/hpack/decoder/hpack_entry_decoder_test.cc
+++ b/net/third_party/http2/hpack/decoder/hpack_entry_decoder_test.cc
@@ -10,8 +10,8 @@
 
 #include "net/third_party/http2/hpack/decoder/hpack_entry_collector.h"
 #include "net/third_party/http2/hpack/tools/hpack_block_builder.h"
+#include "net/third_party/http2/test_tools/http2_random.h"
 #include "net/third_party/http2/tools/failure.h"
-#include "net/third_party/http2/tools/http2_random.h"
 #include "net/third_party/http2/tools/random_decoder_test.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/net/third_party/http2/hpack/decoder/hpack_string_decoder_test.cc b/net/third_party/http2/hpack/decoder/hpack_string_decoder_test.cc
index ae0cb13..996895da 100644
--- a/net/third_party/http2/hpack/decoder/hpack_string_decoder_test.cc
+++ b/net/third_party/http2/hpack/decoder/hpack_string_decoder_test.cc
@@ -10,8 +10,8 @@
 #include "net/third_party/http2/hpack/decoder/hpack_string_decoder_listener.h"
 #include "net/third_party/http2/hpack/tools/hpack_block_builder.h"
 #include "net/third_party/http2/platform/api/http2_string_piece.h"
+#include "net/third_party/http2/test_tools/http2_random.h"
 #include "net/third_party/http2/tools/failure.h"
-#include "net/third_party/http2/tools/http2_random.h"
 #include "net/third_party/http2/tools/random_decoder_test.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/net/third_party/http2/hpack/huffman/hpack_huffman_transcoder_test.cc b/net/third_party/http2/hpack/huffman/hpack_huffman_transcoder_test.cc
index 419f81e..49183d3 100644
--- a/net/third_party/http2/hpack/huffman/hpack_huffman_transcoder_test.cc
+++ b/net/third_party/http2/hpack/huffman/hpack_huffman_transcoder_test.cc
@@ -13,7 +13,6 @@
 #include "net/third_party/http2/platform/api/http2_string.h"
 #include "net/third_party/http2/platform/api/http2_string_piece.h"
 #include "net/third_party/http2/platform/api/http2_string_utils.h"
-#include "net/third_party/http2/platform/api/random_util_helper.h"
 #include "net/third_party/http2/tools/random_decoder_test.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -97,7 +96,7 @@
   }
 
   Http2String RandomAsciiNonControlString(int length) {
-    return RandomString(RandomPtr(), length, ascii_non_control_set_);
+    return Random().RandStringWithAlphabet(length, ascii_non_control_set_);
   }
 
   Http2String RandomBytes(int length) { return Random().RandString(length); }
diff --git a/net/third_party/http2/http2_structures_test.cc b/net/third_party/http2/http2_structures_test.cc
index 05430ba..65b44a9 100644
--- a/net/third_party/http2/http2_structures_test.cc
+++ b/net/third_party/http2/http2_structures_test.cc
@@ -20,8 +20,8 @@
 
 #include "net/third_party/http2/http2_structures_test_util.h"
 #include "net/third_party/http2/platform/api/http2_string_utils.h"
+#include "net/third_party/http2/test_tools/http2_random.h"
 #include "net/third_party/http2/tools/failure.h"
-#include "net/third_party/http2/tools/http2_random.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/net/third_party/http2/http2_structures_test_util.cc b/net/third_party/http2/http2_structures_test_util.cc
index 4e17e7e..f4bb8b4 100644
--- a/net/third_party/http2/http2_structures_test_util.cc
+++ b/net/third_party/http2/http2_structures_test_util.cc
@@ -7,45 +7,45 @@
 #include "net/third_party/http2/http2_constants.h"
 #include "net/third_party/http2/http2_constants_test_util.h"
 #include "net/third_party/http2/http2_structures.h"
-#include "net/third_party/http2/tools/http2_random.h"
+#include "net/third_party/http2/test_tools/http2_random.h"
 
 namespace http2 {
 namespace test {
 
-void Randomize(Http2FrameHeader* p, RandomBase* rng) {
+void Randomize(Http2FrameHeader* p, Http2Random* rng) {
   p->payload_length = rng->Rand32() & 0xffffff;
   p->type = static_cast<Http2FrameType>(rng->Rand8());
   p->flags = static_cast<Http2FrameFlag>(rng->Rand8());
   p->stream_id = rng->Rand32() & StreamIdMask();
 }
-void Randomize(Http2PriorityFields* p, RandomBase* rng) {
+void Randomize(Http2PriorityFields* p, Http2Random* rng) {
   p->stream_dependency = rng->Rand32() & StreamIdMask();
   p->weight = rng->Rand8() + 1;
   p->is_exclusive = rng->OneIn(2);
 }
-void Randomize(Http2RstStreamFields* p, RandomBase* rng) {
+void Randomize(Http2RstStreamFields* p, Http2Random* rng) {
   p->error_code = static_cast<Http2ErrorCode>(rng->Rand32());
 }
-void Randomize(Http2SettingFields* p, RandomBase* rng) {
+void Randomize(Http2SettingFields* p, Http2Random* rng) {
   p->parameter = static_cast<Http2SettingsParameter>(rng->Rand16());
   p->value = rng->Rand32();
 }
-void Randomize(Http2PushPromiseFields* p, RandomBase* rng) {
+void Randomize(Http2PushPromiseFields* p, Http2Random* rng) {
   p->promised_stream_id = rng->Rand32() & StreamIdMask();
 }
-void Randomize(Http2PingFields* p, RandomBase* rng) {
+void Randomize(Http2PingFields* p, Http2Random* rng) {
   for (int ndx = 0; ndx < 8; ++ndx) {
     p->opaque_bytes[ndx] = rng->Rand8();
   }
 }
-void Randomize(Http2GoAwayFields* p, RandomBase* rng) {
+void Randomize(Http2GoAwayFields* p, Http2Random* rng) {
   p->last_stream_id = rng->Rand32() & StreamIdMask();
   p->error_code = static_cast<Http2ErrorCode>(rng->Rand32());
 }
-void Randomize(Http2WindowUpdateFields* p, RandomBase* rng) {
+void Randomize(Http2WindowUpdateFields* p, Http2Random* rng) {
   p->window_size_increment = rng->Rand32() & 0x7fffffff;
 }
-void Randomize(Http2AltSvcFields* p, RandomBase* rng) {
+void Randomize(Http2AltSvcFields* p, Http2Random* rng) {
   p->origin_length = rng->Rand16();
 }
 
diff --git a/net/third_party/http2/http2_structures_test_util.h b/net/third_party/http2/http2_structures_test_util.h
index 4ea8c945..318d50f 100644
--- a/net/third_party/http2/http2_structures_test_util.h
+++ b/net/third_party/http2/http2_structures_test_util.h
@@ -7,14 +7,13 @@
 
 #include "net/third_party/http2/http2_structures.h"
 #include "net/third_party/http2/platform/api/http2_string.h"
+#include "net/third_party/http2/test_tools/http2_random.h"
 #include "net/third_party/http2/tools/http2_frame_builder.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace http2 {
 namespace test {
 
-class RandomBase;
-
 template <class S>
 Http2String SerializeStructure(const S& s) {
   Http2FrameBuilder fb;
@@ -25,15 +24,15 @@
 
 // Randomize the members of out, in a manner that yields encodeable contents
 // (e.g. a "uint24" field has only the low 24 bits set).
-void Randomize(Http2FrameHeader* out, RandomBase* rng);
-void Randomize(Http2PriorityFields* out, RandomBase* rng);
-void Randomize(Http2RstStreamFields* out, RandomBase* rng);
-void Randomize(Http2SettingFields* out, RandomBase* rng);
-void Randomize(Http2PushPromiseFields* out, RandomBase* rng);
-void Randomize(Http2PingFields* out, RandomBase* rng);
-void Randomize(Http2GoAwayFields* out, RandomBase* rng);
-void Randomize(Http2WindowUpdateFields* out, RandomBase* rng);
-void Randomize(Http2AltSvcFields* out, RandomBase* rng);
+void Randomize(Http2FrameHeader* out, Http2Random* rng);
+void Randomize(Http2PriorityFields* out, Http2Random* rng);
+void Randomize(Http2RstStreamFields* out, Http2Random* rng);
+void Randomize(Http2SettingFields* out, Http2Random* rng);
+void Randomize(Http2PushPromiseFields* out, Http2Random* rng);
+void Randomize(Http2PingFields* out, Http2Random* rng);
+void Randomize(Http2GoAwayFields* out, Http2Random* rng);
+void Randomize(Http2WindowUpdateFields* out, Http2Random* rng);
+void Randomize(Http2AltSvcFields* out, Http2Random* rng);
 
 // Clear bits of header->flags that are known to be invalid for the
 // type. For unknown frame types, no change is made.
diff --git a/net/third_party/http2/platform/api/http2_reconstruct_object.h b/net/third_party/http2/platform/api/http2_reconstruct_object.h
index 329651b4..e84feb5 100644
--- a/net/third_party/http2/platform/api/http2_reconstruct_object.h
+++ b/net/third_party/http2/platform/api/http2_reconstruct_object.h
@@ -12,19 +12,19 @@
 namespace http2 {
 namespace test {
 
-class RandomBase;
+class Http2Random;
 
 // Reconstruct an object so that it is initialized as when it was first
 // constructed. Runs the destructor to handle objects that might own resources,
 // and runs the constructor with the provided arguments, if any.
 template <class T, class... Args>
-void Http2ReconstructObject(T* ptr, RandomBase* rng, Args&&... args) {
+void Http2ReconstructObject(T* ptr, Http2Random* rng, Args&&... args) {
   Http2ReconstructObjectImpl(ptr, rng, std::forward<Args>(args)...);
 }
 
 // This version applies default-initialization to the object.
 template <class T>
-void Http2DefaultReconstructObject(T* ptr, RandomBase* rng) {
+void Http2DefaultReconstructObject(T* ptr, Http2Random* rng) {
   Http2DefaultReconstructObjectImpl(ptr, rng);
 }
 
diff --git a/net/third_party/http2/platform/api/random_util_helper.h b/net/third_party/http2/platform/api/random_util_helper.h
deleted file mode 100644
index 189c344..0000000
--- a/net/third_party/http2/platform/api/random_util_helper.h
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright (c) 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 NET_THIRD_PARTY_HTTP2_PLATFORM_API_RANDOM_UTIL_HELPER_H_
-#define NET_THIRD_PARTY_HTTP2_PLATFORM_API_RANDOM_UTIL_HELPER_H_
-
-#include "net/third_party/http2/platform/impl/random_util_helper_impl.h"
-
-namespace http2 {
-
-namespace test {
-
-inline Http2String RandomString(RandomBase* random,
-                                int len,
-                                Http2StringPiece alphabet) {
-  return RandomStringImpl(random, len, alphabet);
-}
-
-}  // namespace test
-
-}  // namespace http2
-
-#endif  // NET_THIRD_PARTY_HTTP2_PLATFORM_API_RANDOM_UTIL_HELPER_H_
diff --git a/net/third_party/http2/platform/impl/http2_reconstruct_object_impl.h b/net/third_party/http2/platform/impl/http2_reconstruct_object_impl.h
index 4bac727..09e21d690 100644
--- a/net/third_party/http2/platform/impl/http2_reconstruct_object_impl.h
+++ b/net/third_party/http2/platform/impl/http2_reconstruct_object_impl.h
@@ -10,20 +10,20 @@
 namespace http2 {
 namespace test {
 
-class RandomBase;
+class Http2Random;
 
 // Reconstruct an object so that it is initialized as when it was first
 // constructed. Runs the destructor to handle objects that might own resources,
 // and runs the constructor with the provided arguments, if any.
 template <class T, class... Args>
-void Http2ReconstructObjectImpl(T* ptr, RandomBase* rng, Args&&... args) {
+void Http2ReconstructObjectImpl(T* ptr, Http2Random* rng, Args&&... args) {
   ptr->~T();
   ::new (ptr) T(std::forward<Args>(args)...);
 }
 
 // This version applies default-initialization to the object.
 template <class T>
-void Http2DefaultReconstructObjectImpl(T* ptr, RandomBase* rng) {
+void Http2DefaultReconstructObjectImpl(T* ptr, Http2Random* rng) {
   ptr->~T();
   ::new (ptr) T;
 }
diff --git a/net/third_party/http2/platform/impl/random_util_helper_impl.cc b/net/third_party/http2/platform/impl/random_util_helper_impl.cc
deleted file mode 100644
index 532710f..0000000
--- a/net/third_party/http2/platform/impl/random_util_helper_impl.cc
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright (c) 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 "net/third_party/http2/platform/impl/random_util_helper_impl.h"
-
-namespace http2 {
-namespace test {
-
-Http2String RandomStringImpl(RandomBase* random,
-                             int len,
-                             Http2StringPiece alphabet) {
-  Http2String random_string;
-  random_string.reserve(len);
-  for (int i = 0; i < len; ++i)
-    random_string.push_back(alphabet[random->Uniform(alphabet.size())]);
-  return random_string;
-}
-
-}  // namespace test
-}  // namespace http2
diff --git a/net/third_party/http2/platform/impl/random_util_helper_impl.h b/net/third_party/http2/platform/impl/random_util_helper_impl.h
deleted file mode 100644
index 5ca4dd5..0000000
--- a/net/third_party/http2/platform/impl/random_util_helper_impl.h
+++ /dev/null
@@ -1,21 +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 NET_THIRD_PARTY_HTTP2_PLATFORM_IMPL_RANDOM_UTIL_HELPER_IMPL_H_
-#define NET_THIRD_PARTY_HTTP2_PLATFORM_IMPL_RANDOM_UTIL_HELPER_IMPL_H_
-
-#include "net/third_party/http2/platform/api/http2_string.h"
-#include "net/third_party/http2/platform/api/http2_string_piece.h"
-#include "net/third_party/http2/tools/http2_random.h"
-
-namespace http2 {
-namespace test {
-
-Http2String RandomStringImpl(RandomBase* random,
-                             int len,
-                             Http2StringPiece alphabet);
-}  // namespace test
-}  // namespace http2
-
-#endif  // NET_THIRD_PARTY_HTTP2_PLATFORM_IMPL_RANDOM_UTIL_HELPER_IMPL_H_
diff --git a/net/third_party/http2/test_tools/http2_random.cc b/net/third_party/http2/test_tools/http2_random.cc
new file mode 100644
index 0000000..53cf4bb7a2
--- /dev/null
+++ b/net/third_party/http2/test_tools/http2_random.cc
@@ -0,0 +1,72 @@
+#include "net/third_party/http2/test_tools/http2_random.h"
+
+#include "base/logging.h"
+#include "net/third_party/http2/platform/api/http2_string_utils.h"
+#include "third_party/boringssl/src/include/openssl/chacha.h"
+#include "third_party/boringssl/src/include/openssl/rand.h"
+
+static const uint8_t kZeroNonce[12] = {0};
+
+namespace http2 {
+namespace test {
+
+Http2Random::Http2Random() {
+  RAND_bytes(key_, sizeof(key_));
+
+  LOG(INFO) << "Initialized test RNG with the following key: " << Key();
+}
+
+Http2Random::Http2Random(Http2StringPiece key) {
+  Http2String decoded_key = Http2HexDecode(key);
+  CHECK_EQ(sizeof(key_), decoded_key.size());
+  memcpy(key_, decoded_key.data(), sizeof(key_));
+}
+
+Http2String Http2Random::Key() const {
+  return Http2HexEncode(key_, sizeof(key_));
+}
+
+void Http2Random::FillRandom(void* buffer, size_t buffer_size) {
+  memset(buffer, 0, buffer_size);
+  uint8_t* buffer_u8 = reinterpret_cast<uint8_t*>(buffer);
+  CRYPTO_chacha_20(buffer_u8, buffer_u8, buffer_size, key_, kZeroNonce,
+                   counter_++);
+}
+
+Http2String Http2Random::RandString(int length) {
+  Http2String result;
+  result.resize(length);
+  FillRandom(&result[0], length);
+  return result;
+}
+
+uint64_t Http2Random::Rand64() {
+  union {
+    uint64_t number;
+    uint8_t bytes[sizeof(uint64_t)];
+  } result;
+  FillRandom(result.bytes, sizeof(result.bytes));
+  return result.number;
+}
+
+double Http2Random::RandDouble() {
+  union {
+    double f;
+    uint64_t i;
+  } value;
+  value.i = (1023ull << 52ull) | (Rand64() & 0xfffffffffffffu);
+  return value.f - 1.0;
+}
+
+Http2String Http2Random::RandStringWithAlphabet(int length,
+                                                Http2StringPiece alphabet) {
+  Http2String result;
+  result.resize(length);
+  for (int i = 0; i < length; i++) {
+    result[i] = alphabet[Uniform(alphabet.size())];
+  }
+  return result;
+}
+
+}  // namespace test
+}  // namespace http2
diff --git a/net/third_party/http2/test_tools/http2_random.h b/net/third_party/http2/test_tools/http2_random.h
new file mode 100644
index 0000000..ac3ef85
--- /dev/null
+++ b/net/third_party/http2/test_tools/http2_random.h
@@ -0,0 +1,84 @@
+#ifndef NET_THIRD_PARTY_HTTP2_TEST_TOOLS_HTTP2_RANDOM_H_
+#define NET_THIRD_PARTY_HTTP2_TEST_TOOLS_HTTP2_RANDOM_H_
+
+#include <cmath>
+#include <cstdint>
+#include <limits>
+#include <random>
+
+#include "net/third_party/http2/platform/api/http2_string.h"
+#include "net/third_party/http2/platform/api/http2_string_piece.h"
+
+namespace http2 {
+namespace test {
+
+// The random number generator used for unit tests.  Since the algorithm is
+// deterministic and fixed, this can be used to reproduce flakes in the unit
+// tests caused by specific random values.
+class Http2Random {
+ public:
+  Http2Random();
+
+  Http2Random(const Http2Random&) = delete;
+  Http2Random& operator=(const Http2Random&) = delete;
+
+  // Reproducible random number generation: by using the same key, the same
+  // sequence of results is obtained.
+  explicit Http2Random(Http2StringPiece key);
+  Http2String Key() const;
+
+  void FillRandom(void* buffer, size_t buffer_size);
+  Http2String RandString(int length);
+
+  // Returns a random 64-bit value.
+  uint64_t Rand64();
+
+  // Return a uniformly distrubted random number in [0, n).
+  int32_t Uniform(int32_t n) { return Rand64() % n; }
+  // Return a uniformly distrubted random number in [lo, hi).
+  size_t UniformInRange(size_t lo, size_t hi) {
+    return lo + Rand64() % (hi - lo);
+  }
+  // Return an integer of logarithmically random scale.
+  int32_t Skewed(int32_t max_log) {
+    const int32_t base = Rand32() % (max_log + 1);
+    const uint32_t mask = ((base < 32) ? (1u << base) : 0u) - 1u;
+    return Rand32() & mask;
+  }
+  // Return a random number in [0, max] range that skews low.
+  size_t RandomSizeSkewedLow(size_t max) {
+    return std::round(max * std::pow(RandDouble(), 2));
+  }
+
+  // Returns a random double between 0 and 1.
+  double RandDouble();
+  float RandFloat() { return RandDouble(); }
+
+  // Has 1/n chance of returning true.
+  bool OneIn(int n) { return Uniform(n) == 0; }
+
+  uint8_t Rand8() { return Rand64(); }
+  uint16_t Rand16() { return Rand64(); }
+  uint32_t Rand32() { return Rand64(); }
+
+  // Return a random string consisting of the characters from the specified
+  // alphabet.
+  Http2String RandStringWithAlphabet(int length, Http2StringPiece alphabet);
+
+  // STL UniformRandomNumberGenerator implementation.
+  using result_type = uint64_t;
+  static constexpr result_type min() { return 0; }
+  static constexpr result_type max() {
+    return std::numeric_limits<result_type>::max();
+  }
+  result_type operator()() { return Rand64(); }
+
+ private:
+  uint8_t key_[32];
+  uint32_t counter_ = 0;
+};
+
+}  // namespace test
+}  // namespace http2
+
+#endif  // NET_THIRD_PARTY_HTTP2_TEST_TOOLS_HTTP2_RANDOM_H_
diff --git a/net/third_party/http2/test_tools/http2_random_test.cc b/net/third_party/http2/test_tools/http2_random_test.cc
new file mode 100644
index 0000000..a748e9fd
--- /dev/null
+++ b/net/third_party/http2/test_tools/http2_random_test.cc
@@ -0,0 +1,94 @@
+#include "net/third_party/http2/test_tools/http2_random.h"
+
+#include <set>
+
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace http2 {
+namespace test {
+namespace {
+
+TEST(Http2RandomTest, ProducesDifferentNumbers) {
+  Http2Random random;
+  uint64_t value1 = random.Rand64();
+  uint64_t value2 = random.Rand64();
+  uint64_t value3 = random.Rand64();
+
+  EXPECT_NE(value1, value2);
+  EXPECT_NE(value2, value3);
+  EXPECT_NE(value3, value1);
+}
+
+TEST(Http2RandomTest, StartsWithDifferentKeys) {
+  Http2Random random1;
+  Http2Random random2;
+
+  EXPECT_NE(random1.Key(), random2.Key());
+  EXPECT_NE(random1.Rand64(), random2.Rand64());
+  EXPECT_NE(random1.Rand64(), random2.Rand64());
+  EXPECT_NE(random1.Rand64(), random2.Rand64());
+}
+
+TEST(Http2RandomTest, ReproducibleRandom) {
+  Http2Random random;
+  uint64_t value1 = random.Rand64();
+  uint64_t value2 = random.Rand64();
+
+  Http2Random clone_random(random.Key());
+  EXPECT_EQ(clone_random.Key(), random.Key());
+  EXPECT_EQ(value1, clone_random.Rand64());
+  EXPECT_EQ(value2, clone_random.Rand64());
+}
+
+TEST(Http2RandomTest, STLShuffle) {
+  Http2Random random;
+  const Http2String original = "abcdefghijklmonpqrsuvwxyz";
+
+  Http2String shuffled = original;
+  std::shuffle(shuffled.begin(), shuffled.end(), random);
+  EXPECT_NE(original, shuffled);
+}
+
+TEST(Http2RandomTest, RandFloat) {
+  Http2Random random;
+  for (int i = 0; i < 10000; i++) {
+    float value = random.RandFloat();
+    ASSERT_GE(value, 0.f);
+    ASSERT_LE(value, 1.f);
+  }
+}
+
+TEST(Http2RandomTest, RandStringWithAlphabet) {
+  Http2Random random;
+  Http2String str = random.RandStringWithAlphabet(1000, "xyz");
+  EXPECT_EQ(1000u, str.size());
+
+  std::set<char> characters(str.begin(), str.end());
+  EXPECT_THAT(characters, testing::ElementsAre('x', 'y', 'z'));
+}
+
+TEST(Http2RandomTest, SkewedLow) {
+  Http2Random random;
+  constexpr size_t kMax = 1234;
+  for (int i = 0; i < 10000; i++) {
+    size_t value = random.RandomSizeSkewedLow(kMax);
+    ASSERT_GE(value, 0u);
+    ASSERT_LE(value, kMax);
+  }
+}
+
+// Checks that SkewedLow() generates full range.  This is required, since in
+// some unit tests would infinitely loop.
+TEST(Http2RandomTest, SkewedLowFullRange) {
+  Http2Random random;
+  std::set<size_t> values;
+  for (int i = 0; i < 1000; i++) {
+    values.insert(random.RandomSizeSkewedLow(3));
+  }
+  EXPECT_THAT(values, testing::ElementsAre(0, 1, 2, 3));
+}
+
+}  // namespace
+}  // namespace test
+}  // namespace http2
diff --git a/net/third_party/http2/tools/http2_random.cc b/net/third_party/http2/tools/http2_random.cc
deleted file mode 100644
index ba62000..0000000
--- a/net/third_party/http2/tools/http2_random.cc
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/third_party/http2/tools/http2_random.h"
-
-#include <memory>
-
-#include "base/rand_util.h"
-
-namespace http2 {
-namespace test {
-
-bool Http2Random::OneIn(int n) {
-  return base::RandGenerator(n) == 0;
-}
-
-int32_t Http2Random::Uniform(int32_t n) {
-  return base::RandGenerator(n);
-}
-
-uint8_t Http2Random::Rand8() {
-  return base::RandGenerator(
-      static_cast<uint64_t>(std::numeric_limits<uint8_t>::max()) + 1);
-}
-
-uint16_t Http2Random::Rand16() {
-  return base::RandGenerator(
-      static_cast<uint64_t>(std::numeric_limits<uint16_t>::max()) + 1);
-}
-
-uint32_t Http2Random::Rand32() {
-  return base::RandGenerator(
-      static_cast<uint64_t>(std::numeric_limits<uint32_t>::max()) + 1);
-}
-
-uint64_t Http2Random::Rand64() {
-  return base::RandUint64();
-}
-
-int32_t Http2Random::Next() {
-  return Rand32();
-}
-
-int32_t Http2Random::Skewed(int max_log) {
-  const uint32_t base = Rand32() % (max_log + 1);
-  const uint32_t mask = ((base < 32) ? (1u << base) : 0u) - 1u;
-  return Rand32() & mask;
-}
-
-Http2String Http2Random::RandString(int length) {
-  std::unique_ptr<char[]> buffer(new char[length]);
-  base::RandBytes(buffer.get(), length);
-  return Http2String(buffer.get(), length);
-}
-
-}  // namespace test
-}  // namespace http2
diff --git a/net/third_party/http2/tools/http2_random.h b/net/third_party/http2/tools/http2_random.h
deleted file mode 100644
index 324b542e..0000000
--- a/net/third_party/http2/tools/http2_random.h
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_THIRD_PARTY_HTTP2_TOOLS_HTTP2_RANDOM_H_
-#define NET_THIRD_PARTY_HTTP2_TOOLS_HTTP2_RANDOM_H_
-
-#include <stdint.h>
-
-#include <limits>
-
-#include "net/third_party/http2/platform/api/http2_string.h"
-
-namespace http2 {
-namespace test {
-
-class RandomBase {
- public:
-  virtual ~RandomBase() {}
-  virtual bool OneIn(int n) = 0;
-  virtual int32_t Uniform(int32_t n) = 0;
-  virtual uint8_t Rand8() = 0;
-  virtual uint16_t Rand16() = 0;
-  virtual uint32_t Rand32() = 0;
-  virtual uint64_t Rand64() = 0;
-  virtual int32_t Next() = 0;
-  virtual int32_t Skewed(int max_log) = 0;
-  virtual Http2String RandString(int length) = 0;
-
-  // STL UniformRandomNumberGenerator implementation.
-  typedef uint32_t result_type;
-  static constexpr result_type min() { return 0; }
-  static constexpr result_type max() {
-    return std::numeric_limits<uint32_t>::max();
-  }
-  result_type operator()() { return Rand32(); }
-};
-
-// Http2Random holds no state: instances use the same base::RandGenerator
-// with a global state.
-class Http2Random : public RandomBase {
- public:
-  ~Http2Random() override {}
-  bool OneIn(int n) override;
-  int32_t Uniform(int32_t n) override;
-  uint8_t Rand8() override;
-  uint16_t Rand16() override;
-  uint32_t Rand32() override;
-  uint64_t Rand64() override;
-  int32_t Next() override;
-  int32_t Skewed(int max_log) override;
-  Http2String RandString(int length) override;
-};
-
-}  // namespace test
-}  // namespace http2
-
-#endif  // NET_THIRD_PARTY_HTTP2_TOOLS_HTTP2_RANDOM_H_
diff --git a/net/third_party/http2/tools/random_decoder_test.h b/net/third_party/http2/tools/random_decoder_test.h
index aec90bec..a9e9d81c 100644
--- a/net/third_party/http2/tools/random_decoder_test.h
+++ b/net/third_party/http2/tools/random_decoder_test.h
@@ -21,8 +21,8 @@
 #include "net/third_party/http2/decoder/decode_status.h"
 #include "net/third_party/http2/platform/api/http2_string.h"
 #include "net/third_party/http2/platform/api/http2_string_piece.h"
+#include "net/third_party/http2/test_tools/http2_random.h"
 #include "net/third_party/http2/tools/failure.h"
-#include "net/third_party/http2/tools/http2_random.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace http2 {
@@ -39,7 +39,7 @@
 // the enum type, but which fits into its storage.
 template <typename T,
           typename E = typename std::enable_if<std::is_enum<T>::value>::type>
-void CorruptEnum(T* out, RandomBase* rng) {
+void CorruptEnum(T* out, Http2Random* rng) {
   // Per cppreference.com, if the destination type of a static_cast is
   // smaller than the source type (i.e. type of r and uint32 below), the
   // resulting value is the smallest unsigned value equal to the source value
@@ -236,11 +236,11 @@
     return ValidateDoneAndOffset(offset, validator);
   }
 
-  // Expose |random_| as RandomBase so callers do not have to care about which
-  // sub-class of RandomBase is used, nor can they rely on the specific
+  // Expose |random_| as Http2Random so callers do not have to care about which
+  // sub-class of Http2Random is used, nor can they rely on the specific
   // sub-class that RandomDecoderTest uses.
-  RandomBase& Random() { return random_; }
-  RandomBase* RandomPtr() { return &random_; }
+  Http2Random& Random() { return random_; }
+  Http2Random* RandomPtr() { return &random_; }
 
   uint32_t RandStreamId();
 
diff --git a/net/third_party/http2/tools/random_util.cc b/net/third_party/http2/tools/random_util.cc
index f373c3f..6449b6b 100644
--- a/net/third_party/http2/tools/random_util.cc
+++ b/net/third_party/http2/tools/random_util.cc
@@ -6,80 +6,33 @@
 
 #include <cmath>
 
-#include "base/rand_util.h"
-#include "net/third_party/http2/platform/api/random_util_helper.h"
-#include "net/third_party/http2/tools/http2_random.h"
-
 namespace http2 {
 namespace test {
-namespace {
-
-const char kWebsafe64[] =
-    "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_";
-
-// Generate two independent standard normal random variables using the polar
-// method.
-void GenerateRandomSizeSkewedLowHelper(size_t max, size_t* x, size_t* y) {
-  double a, b, s;
-  do {
-    // Draw uniformly on [-1, 1).
-    a = 2 * base::RandDouble() - 1.0;
-    b = 2 * base::RandDouble() - 1.0;
-    s = a * a + b * b;
-  } while (s >= 1.0);
-  double t = std::sqrt(-2.0 * std::log(s) / s);
-  *x = static_cast<size_t>(a * t * max);
-  *y = static_cast<size_t>(b * t * max);
-}
-
-}  // anonymous namespace
-
-size_t GenerateUniformInRange(size_t lo, size_t hi, RandomBase* rng) {
-  if (lo + 1 >= hi) {
-    return lo;
-  }
-  return lo + rng->Rand64() % (hi - lo);
-}
 
 // Here "word" means something that starts with a lower-case letter, and has
 // zero or more additional characters that are numbers or lower-case letters.
-Http2String GenerateHttp2HeaderName(size_t len, RandomBase* rng) {
+Http2String GenerateHttp2HeaderName(size_t len, Http2Random* rng) {
   Http2StringPiece alpha_lc = "abcdefghijklmnopqrstuvwxyz";
   // If the name is short, just make it one word.
   if (len < 8) {
-    return RandomString(rng, len, alpha_lc);
+    return rng->RandStringWithAlphabet(len, alpha_lc);
   }
   // If the name is longer, ensure it starts with a word, and after that may
   // have any character in alphanumdash_lc. 4 is arbitrary, could be as low
   // as 1.
   Http2StringPiece alphanumdash_lc = "abcdefghijklmnopqrstuvwxyz0123456789-";
-  return RandomString(rng, 4, alpha_lc) +
-         RandomString(rng, len - 4, alphanumdash_lc);
+  return rng->RandStringWithAlphabet(4, alpha_lc) +
+         rng->RandStringWithAlphabet(len - 4, alphanumdash_lc);
 }
 
-Http2String GenerateWebSafeString(size_t len, RandomBase* rng) {
-  return RandomString(rng, len, kWebsafe64);
+Http2String GenerateWebSafeString(size_t len, Http2Random* rng) {
+  static const char* kWebsafe64 =
+      "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_";
+  return rng->RandStringWithAlphabet(len, kWebsafe64);
 }
 
-Http2String GenerateWebSafeString(size_t lo, size_t hi, RandomBase* rng) {
-  return GenerateWebSafeString(GenerateUniformInRange(lo, hi, rng), rng);
-}
-
-size_t GenerateRandomSizeSkewedLow(size_t max, RandomBase* rng) {
-  if (max == 0) {
-    return 0;
-  }
-  // Generate a random number with a Gaussian distribution, centered on zero;
-  // take the absolute, and then keep in range 0 to max.
-  for (int i = 0; i < 5; i++) {
-    size_t x, y;
-    GenerateRandomSizeSkewedLowHelper(max, &x, &y);
-    if (x <= max)
-      return x;
-    if (y <= max)
-      return y;
-  }
-  return rng->Uniform(max + 1);
+Http2String GenerateWebSafeString(size_t lo, size_t hi, Http2Random* rng) {
+  return GenerateWebSafeString(rng->UniformInRange(lo, hi), rng);
 }
 
 }  // namespace test
diff --git a/net/third_party/http2/tools/random_util.h b/net/third_party/http2/tools/random_util.h
index 4a38c68..90bb6ed 100644
--- a/net/third_party/http2/tools/random_util.h
+++ b/net/third_party/http2/tools/random_util.h
@@ -8,33 +8,20 @@
 #include <stddef.h>
 
 #include "net/third_party/http2/platform/api/http2_string.h"
-#include "net/third_party/http2/platform/api/http2_string_piece.h"
+#include "net/third_party/http2/test_tools/http2_random.h"
 
 namespace http2 {
 namespace test {
 
-class RandomBase;
-
-// Returns a random string of length |len|, each character drawn uniformly and
-// independently fom |alphabet|.
-Http2String RandomString(RandomBase* rng, int len, Http2StringPiece alphabet);
-
-// Returns a random integer in the range [lo, hi).
-size_t GenerateUniformInRange(size_t lo, size_t hi, RandomBase* rng);
-
 // Generate a string with the allowed character set for HTTP/2 / HPACK header
 // names.
-Http2String GenerateHttp2HeaderName(size_t len, RandomBase* rng);
+Http2String GenerateHttp2HeaderName(size_t len, Http2Random* rng);
 
 // Generate a string with the web-safe string character set of specified len.
-Http2String GenerateWebSafeString(size_t len, RandomBase* rng);
+Http2String GenerateWebSafeString(size_t len, Http2Random* rng);
 
 // Generate a string with the web-safe string character set of length [lo, hi).
-Http2String GenerateWebSafeString(size_t lo, size_t hi, RandomBase* rng);
-
-// Returns a random integer in the range [0, max], with a bias towards producing
-// lower numbers.
-size_t GenerateRandomSizeSkewedLow(size_t max, RandomBase* rng);
+Http2String GenerateWebSafeString(size_t lo, size_t hi, Http2Random* rng);
 
 }  // namespace test
 }  // namespace http2
diff --git a/net/third_party/quic/core/chlo_extractor.cc b/net/third_party/quic/core/chlo_extractor.cc
index b16aa05..b09dd611 100644
--- a/net/third_party/quic/core/chlo_extractor.cc
+++ b/net/third_party/quic/core/chlo_extractor.cc
@@ -29,7 +29,8 @@
 
   // QuicFramerVisitorInterface implementation
   void OnError(QuicFramer* framer) override {}
-  bool OnProtocolVersionMismatch(ParsedQuicVersion version) override;
+  bool OnProtocolVersionMismatch(ParsedQuicVersion version,
+                                 PacketHeaderFormat form) override;
   void OnPacket() override {}
   void OnPublicResetPacket(const QuicPublicResetPacket& packet) override {}
   void OnVersionNegotiationPacket(
@@ -97,7 +98,8 @@
       chlo_contains_tags_(false),
       connection_id_(0) {}
 
-bool ChloFramerVisitor::OnProtocolVersionMismatch(ParsedQuicVersion version) {
+bool ChloFramerVisitor::OnProtocolVersionMismatch(ParsedQuicVersion version,
+                                                  PacketHeaderFormat /*form*/) {
   if (!framer_->IsSupportedVersion(version)) {
     return false;
   }
diff --git a/net/third_party/quic/core/crypto/crypto_handshake_message.h b/net/third_party/quic/core/crypto/crypto_handshake_message.h
index 75f9060..d72abc3 100644
--- a/net/third_party/quic/core/crypto/crypto_handshake_message.h
+++ b/net/third_party/quic/core/crypto/crypto_handshake_message.h
@@ -146,7 +146,7 @@
   size_t minimum_size_;
 
   // The serialized form of the handshake message. This member is constructed
-  // lasily.
+  // lazily.
   mutable std::unique_ptr<QuicData> serialized_;
 };
 
diff --git a/net/third_party/quic/core/http/end_to_end_test.cc b/net/third_party/quic/core/http/end_to_end_test.cc
index 8ed9508..7300abc 100644
--- a/net/third_party/quic/core/http/end_to_end_test.cc
+++ b/net/third_party/quic/core/http/end_to_end_test.cc
@@ -524,7 +524,11 @@
     EXPECT_EQ(0u, client_stats.packets_discarded);
     // When doing 0-RTT with stateless rejects, the encrypted requests cause
     // a retranmission of the SREJ packets which are dropped by the client.
-    if (!BothSidesSupportStatelessRejects()) {
+    // When client starts with an unsupported version, the version negotiation
+    // packet sent by server for the old connection (respond for the connection
+    // close packet) will be dropped by the client.
+    if (!BothSidesSupportStatelessRejects() &&
+        !ServerSendsVersionNegotiation()) {
       EXPECT_EQ(0u, client_stats.packets_dropped);
     }
     if (!ClientSupportsIetfQuicNotSupportedByServer()) {
@@ -569,6 +573,14 @@
                    .transport_version <= QUIC_VERSION_43;
   }
 
+  // Returns true when client starts with an unsupported version, and client
+  // closes connection when version negotiation is received.
+  bool ServerSendsVersionNegotiation() {
+    return GetQuicReloadableFlag(quic_no_client_conn_ver_negotiation) &&
+           GetParam().client_supported_versions[0] !=
+               FilterSupportedVersions(GetParam().server_supported_versions)[0];
+  }
+
   bool SupportsIetfQuicWithTls(ParsedQuicVersion version) {
     return version.transport_version > QUIC_VERSION_43 &&
            version.handshake_protocol == PROTOCOL_TLS1_3;
@@ -655,7 +667,15 @@
 
   EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
   EXPECT_EQ("200", client_->response_headers()->find(":status")->second);
-  EXPECT_EQ(2, client_->client()->GetNumSentClientHellos());
+  int expected_num_client_hellos = 2;
+  if (ServerSendsVersionNegotiation()) {
+    ++expected_num_client_hellos;
+    if (BothSidesSupportStatelessRejects()) {
+      ++expected_num_client_hellos;
+    }
+  }
+  EXPECT_EQ(expected_num_client_hellos,
+            client_->client()->GetNumSentClientHellos());
 }
 
 TEST_P(EndToEndTest, SimpleRequestResponse) {
@@ -663,7 +683,15 @@
 
   EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
   EXPECT_EQ("200", client_->response_headers()->find(":status")->second);
-  EXPECT_EQ(2, client_->client()->GetNumSentClientHellos());
+  int expected_num_client_hellos = 2;
+  if (ServerSendsVersionNegotiation()) {
+    ++expected_num_client_hellos;
+    if (BothSidesSupportStatelessRejects()) {
+      ++expected_num_client_hellos;
+    }
+  }
+  EXPECT_EQ(expected_num_client_hellos,
+            client_->client()->GetNumSentClientHellos());
 }
 
 TEST_P(EndToEndTest, SimpleRequestResponseWithLargeReject) {
@@ -672,7 +700,11 @@
 
   EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
   EXPECT_EQ("200", client_->response_headers()->find(":status")->second);
-  EXPECT_EQ(3, client_->client()->GetNumSentClientHellos());
+  if (ServerSendsVersionNegotiation()) {
+    EXPECT_EQ(4, client_->client()->GetNumSentClientHellos());
+  } else {
+    EXPECT_EQ(3, client_->client()->GetNumSentClientHellos());
+  }
 }
 
 TEST_P(EndToEndTestWithTls, SimpleRequestResponsev6) {
@@ -977,22 +1009,32 @@
   // torn down after the reject.  The number of hellos on the latest
   // session is 1.
   const int expected_num_hellos_latest_session =
-      BothSidesSupportStatelessRejects() ? 1 : 2;
+      (BothSidesSupportStatelessRejects() && !ServerSendsVersionNegotiation())
+          ? 1
+          : 2;
   EXPECT_EQ(expected_num_hellos_latest_session,
             client_->client()->client_session()->GetNumSentClientHellos());
-  EXPECT_EQ(2, client_->client()->GetNumSentClientHellos());
+  if (ServerSendsVersionNegotiation()) {
+    EXPECT_EQ(3, client_->client()->GetNumSentClientHellos());
+  } else {
+    EXPECT_EQ(2, client_->client()->GetNumSentClientHellos());
+  }
 
   client_->Disconnect();
 
   // The 0-RTT handshake should succeed.
   client_->Connect();
-  client_->WaitForInitialResponse();
+  EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
   ASSERT_TRUE(client_->client()->connected());
   EXPECT_EQ(kFooResponseBody,
             client_->SendCustomSynchronousRequest(headers, body));
 
   EXPECT_EQ(1, client_->client()->client_session()->GetNumSentClientHellos());
-  EXPECT_EQ(1, client_->client()->GetNumSentClientHellos());
+  if (ServerSendsVersionNegotiation()) {
+    EXPECT_EQ(2, client_->client()->GetNumSentClientHellos());
+  } else {
+    EXPECT_EQ(1, client_->client()->GetNumSentClientHellos());
+  }
 
   client_->Disconnect();
 
@@ -1002,6 +1044,7 @@
   StartServer();
 
   client_->Connect();
+  EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
   ASSERT_TRUE(client_->client()->connected());
   EXPECT_EQ(kFooResponseBody,
             client_->SendCustomSynchronousRequest(headers, body));
@@ -1012,7 +1055,11 @@
   // latest session is 1.
   EXPECT_EQ(expected_num_hellos_latest_session,
             client_->client()->client_session()->GetNumSentClientHellos());
-  EXPECT_EQ(2, client_->client()->GetNumSentClientHellos());
+  if (ServerSendsVersionNegotiation()) {
+    EXPECT_EQ(3, client_->client()->GetNumSentClientHellos());
+  } else {
+    EXPECT_EQ(2, client_->client()->GetNumSentClientHellos());
+  }
 
   VerifyCleanConnection(false);
 }
@@ -1029,21 +1076,31 @@
   // torn down after the reject.  The number of hellos on that second
   // latest session is 1.
   const int expected_num_hellos_latest_session =
-      BothSidesSupportStatelessRejects() ? 1 : 2;
+      (BothSidesSupportStatelessRejects() && !ServerSendsVersionNegotiation())
+          ? 1
+          : 2;
   EXPECT_EQ(expected_num_hellos_latest_session,
             client_->client()->client_session()->GetNumSentClientHellos());
-  EXPECT_EQ(2, client_->client()->GetNumSentClientHellos());
+  if (ServerSendsVersionNegotiation()) {
+    EXPECT_EQ(3, client_->client()->GetNumSentClientHellos());
+  } else {
+    EXPECT_EQ(2, client_->client()->GetNumSentClientHellos());
+  }
 
   client_->Disconnect();
 
   // The 0-RTT handshake should succeed.
   client_->Connect();
-  client_->WaitForInitialResponse();
+  EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
   ASSERT_TRUE(client_->client()->connected());
   EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
 
   EXPECT_EQ(1, client_->client()->client_session()->GetNumSentClientHellos());
-  EXPECT_EQ(1, client_->client()->GetNumSentClientHellos());
+  if (ServerSendsVersionNegotiation()) {
+    EXPECT_EQ(2, client_->client()->GetNumSentClientHellos());
+  } else {
+    EXPECT_EQ(1, client_->client()->GetNumSentClientHellos());
+  }
 
   client_->Disconnect();
 
@@ -1053,6 +1110,7 @@
   StartServer();
 
   client_->Connect();
+  EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
   ASSERT_TRUE(client_->client()->connected());
   EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
   // In the non-stateless case, the same session is used for both
@@ -1062,7 +1120,11 @@
   // latest session is 1.
   EXPECT_EQ(expected_num_hellos_latest_session,
             client_->client()->client_session()->GetNumSentClientHellos());
-  EXPECT_EQ(2, client_->client()->GetNumSentClientHellos());
+  if (ServerSendsVersionNegotiation()) {
+    EXPECT_EQ(3, client_->client()->GetNumSentClientHellos());
+  } else {
+    EXPECT_EQ(2, client_->client()->GetNumSentClientHellos());
+  }
 
   VerifyCleanConnection(false);
 }
@@ -1087,22 +1149,32 @@
   // torn down after the reject.  The number of hellos on the latest
   // session is 1.
   const int expected_num_hellos_latest_session =
-      BothSidesSupportStatelessRejects() ? 1 : 2;
+      (BothSidesSupportStatelessRejects() && !ServerSendsVersionNegotiation())
+          ? 1
+          : 2;
   EXPECT_EQ(expected_num_hellos_latest_session,
             client_->client()->client_session()->GetNumSentClientHellos());
-  EXPECT_EQ(2, client_->client()->GetNumSentClientHellos());
+  if (ServerSendsVersionNegotiation()) {
+    EXPECT_EQ(3, client_->client()->GetNumSentClientHellos());
+  } else {
+    EXPECT_EQ(2, client_->client()->GetNumSentClientHellos());
+  }
 
   client_->Disconnect();
 
   // The 0-RTT handshake should succeed.
   client_->Connect();
-  client_->WaitForInitialResponse();
+  EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
   ASSERT_TRUE(client_->client()->connected());
   EXPECT_EQ(kFooResponseBody,
             client_->SendCustomSynchronousRequest(headers, body));
 
   EXPECT_EQ(1, client_->client()->client_session()->GetNumSentClientHellos());
-  EXPECT_EQ(1, client_->client()->GetNumSentClientHellos());
+  if (ServerSendsVersionNegotiation()) {
+    EXPECT_EQ(2, client_->client()->GetNumSentClientHellos());
+  } else {
+    EXPECT_EQ(1, client_->client()->GetNumSentClientHellos());
+  }
 
   client_->Disconnect();
 
@@ -1112,6 +1184,7 @@
   StartServer();
 
   client_->Connect();
+  EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
   ASSERT_TRUE(client_->client()->connected());
   EXPECT_EQ(kFooResponseBody,
             client_->SendCustomSynchronousRequest(headers, body));
@@ -1122,7 +1195,11 @@
   // latest session is 1.
   EXPECT_EQ(expected_num_hellos_latest_session,
             client_->client()->client_session()->GetNumSentClientHellos());
-  EXPECT_EQ(2, client_->client()->GetNumSentClientHellos());
+  if (ServerSendsVersionNegotiation()) {
+    EXPECT_EQ(3, client_->client()->GetNumSentClientHellos());
+  } else {
+    EXPECT_EQ(2, client_->client()->GetNumSentClientHellos());
+  }
 
   VerifyCleanConnection(false);
 }
@@ -1583,6 +1660,7 @@
   EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo"));
   EXPECT_EQ("200", client_->response_headers()->find(":status")->second);
   client_->ResetConnection();
+  EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
   EXPECT_EQ(kBarResponseBody, client_->SendSynchronousRequest("/bar"));
   EXPECT_EQ("200", client_->response_headers()->find(":status")->second);
 }
@@ -3212,6 +3290,9 @@
 TEST_P(EndToEndTest, ResetStreamOnTtlExpires) {
   ASSERT_TRUE(Initialize());
   EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
+  if (!client_->client()->client_session()->session_decides_what_to_write()) {
+    return;
+  }
   SetPacketLossPercentage(30);
 
   QuicSpdyClientStream* stream = client_->GetOrCreateStream();
@@ -3357,6 +3438,7 @@
   // Only send out a CHLO.
   client_->client()->Initialize();
   client_->client()->StartConnect();
+  EXPECT_TRUE(client_->client()->WaitForCryptoHandshakeConfirmed());
   ASSERT_TRUE(client_->client()->connected());
 
   // Send a request before handshake finishes.
@@ -3372,7 +3454,11 @@
   QuicConnectionStats client_stats =
       client_->client()->client_session()->connection()->GetStats();
   EXPECT_EQ(0u, client_stats.packets_lost);
-  EXPECT_EQ(1, client_->client()->GetNumSentClientHellos());
+  if (ServerSendsVersionNegotiation()) {
+    EXPECT_EQ(2, client_->client()->GetNumSentClientHellos());
+  } else {
+    EXPECT_EQ(1, client_->client()->GetNumSentClientHellos());
+  }
 }
 
 }  // namespace
diff --git a/net/third_party/quic/core/http/quic_client_promised_info_test.cc b/net/third_party/quic/core/http/quic_client_promised_info_test.cc
index 05b4236..690f1fc 100644
--- a/net/third_party/quic/core/http/quic_client_promised_info_test.cc
+++ b/net/third_party/quic/core/http/quic_client_promised_info_test.cc
@@ -32,9 +32,11 @@
 class MockQuicSpdyClientSession : public QuicSpdyClientSession {
  public:
   explicit MockQuicSpdyClientSession(
+      const ParsedQuicVersionVector& supported_versions,
       QuicConnection* connection,
       QuicClientPushPromiseIndex* push_promise_index)
       : QuicSpdyClientSession(DefaultQuicConfig(),
+                              supported_versions,
                               connection,
                               QuicServerId("example.com", 443, false),
                               &crypto_config_,
@@ -69,7 +71,9 @@
       : connection_(new StrictMock<MockQuicConnection>(&helper_,
                                                        &alarm_factory_,
                                                        Perspective::IS_CLIENT)),
-        session_(connection_, &push_promise_index_),
+        session_(connection_->supported_versions(),
+                 connection_,
+                 &push_promise_index_),
         body_("hello world"),
         promise_id_(
             QuicUtils::GetInvalidStreamId(connection_->transport_version())) {
diff --git a/net/third_party/quic/core/http/quic_client_push_promise_index_test.cc b/net/third_party/quic/core/http/quic_client_push_promise_index_test.cc
index 27c3e33..3983085 100644
--- a/net/third_party/quic/core/http/quic_client_push_promise_index_test.cc
+++ b/net/third_party/quic/core/http/quic_client_push_promise_index_test.cc
@@ -25,9 +25,11 @@
 class MockQuicSpdyClientSession : public QuicSpdyClientSession {
  public:
   explicit MockQuicSpdyClientSession(
+      const ParsedQuicVersionVector& supported_versions,
       QuicConnection* connection,
       QuicClientPushPromiseIndex* push_promise_index)
       : QuicSpdyClientSession(DefaultQuicConfig(),
+                              supported_versions,
                               connection,
                               QuicServerId("example.com", 443, false),
                               &crypto_config_,
@@ -51,7 +53,7 @@
       : connection_(new StrictMock<MockQuicConnection>(&helper_,
                                                        &alarm_factory_,
                                                        Perspective::IS_CLIENT)),
-        session_(connection_, &index_),
+        session_(connection_->supported_versions(), connection_, &index_),
         promised_(
             &session_,
             QuicSpdySessionPeer::GetNthServerInitiatedStreamId(session_, 0),
diff --git a/net/third_party/quic/core/http/quic_spdy_client_session.cc b/net/third_party/quic/core/http/quic_spdy_client_session.cc
index f2266bdb..6708fd05 100644
--- a/net/third_party/quic/core/http/quic_spdy_client_session.cc
+++ b/net/third_party/quic/core/http/quic_spdy_client_session.cc
@@ -20,11 +20,15 @@
 
 QuicSpdyClientSession::QuicSpdyClientSession(
     const QuicConfig& config,
+    const ParsedQuicVersionVector& supported_versions,
     QuicConnection* connection,
     const QuicServerId& server_id,
     QuicCryptoClientConfig* crypto_config,
     QuicClientPushPromiseIndex* push_promise_index)
-    : QuicSpdyClientSessionBase(connection, push_promise_index, config),
+    : QuicSpdyClientSessionBase(connection,
+                                push_promise_index,
+                                config,
+                                supported_versions),
       server_id_(server_id),
       crypto_config_(crypto_config),
       respect_goaway_(true) {}
diff --git a/net/third_party/quic/core/http/quic_spdy_client_session.h b/net/third_party/quic/core/http/quic_spdy_client_session.h
index a3ca1669..b8a5249 100644
--- a/net/third_party/quic/core/http/quic_spdy_client_session.h
+++ b/net/third_party/quic/core/http/quic_spdy_client_session.h
@@ -26,6 +26,7 @@
   // Takes ownership of |connection|. Caller retains ownership of
   // |promised_by_url|.
   QuicSpdyClientSession(const QuicConfig& config,
+                        const ParsedQuicVersionVector& supported_versions,
                         QuicConnection* connection,
                         const QuicServerId& server_id,
                         QuicCryptoClientConfig* crypto_config,
diff --git a/net/third_party/quic/core/http/quic_spdy_client_session_base.cc b/net/third_party/quic/core/http/quic_spdy_client_session_base.cc
index 466ec9e..703e212 100644
--- a/net/third_party/quic/core/http/quic_spdy_client_session_base.cc
+++ b/net/third_party/quic/core/http/quic_spdy_client_session_base.cc
@@ -18,11 +18,9 @@
 QuicSpdyClientSessionBase::QuicSpdyClientSessionBase(
     QuicConnection* connection,
     QuicClientPushPromiseIndex* push_promise_index,
-    const QuicConfig& config)
-    : QuicSpdySession(connection,
-                      nullptr,
-                      config,
-                      connection->supported_versions()),
+    const QuicConfig& config,
+    const ParsedQuicVersionVector& supported_versions)
+    : QuicSpdySession(connection, nullptr, config, supported_versions),
       push_promise_index_(push_promise_index),
       largest_promised_stream_id_(
           QuicUtils::GetInvalidStreamId(connection->transport_version())) {}
diff --git a/net/third_party/quic/core/http/quic_spdy_client_session_base.h b/net/third_party/quic/core/http/quic_spdy_client_session_base.h
index b40aab9d..ef30a92ae 100644
--- a/net/third_party/quic/core/http/quic_spdy_client_session_base.h
+++ b/net/third_party/quic/core/http/quic_spdy_client_session_base.h
@@ -40,7 +40,8 @@
   // |promised_by_url|.
   QuicSpdyClientSessionBase(QuicConnection* connection,
                             QuicClientPushPromiseIndex* push_promise_index,
-                            const QuicConfig& config);
+                            const QuicConfig& config,
+                            const ParsedQuicVersionVector& supported_versions);
   QuicSpdyClientSessionBase(const QuicSpdyClientSessionBase&) = delete;
   QuicSpdyClientSessionBase& operator=(const QuicSpdyClientSessionBase&) =
       delete;
diff --git a/net/third_party/quic/core/http/quic_spdy_client_session_test.cc b/net/third_party/quic/core/http/quic_spdy_client_session_test.cc
index 53659e6e..361d9b8 100644
--- a/net/third_party/quic/core/http/quic_spdy_client_session_test.cc
+++ b/net/third_party/quic/core/http/quic_spdy_client_session_test.cc
@@ -44,11 +44,13 @@
  public:
   explicit TestQuicSpdyClientSession(
       const QuicConfig& config,
+      const ParsedQuicVersionVector& supported_versions,
       QuicConnection* connection,
       const QuicServerId& server_id,
       QuicCryptoClientConfig* crypto_config,
       QuicClientPushPromiseIndex* push_promise_index)
       : QuicSpdyClientSession(config,
+                              supported_versions,
                               connection,
                               server_id,
                               crypto_config,
@@ -92,7 +94,7 @@
                                              Perspective::IS_CLIENT,
                                              SupportedVersions(GetParam()));
     session_ = QuicMakeUnique<TestQuicSpdyClientSession>(
-        DefaultQuicConfig(), connection_,
+        DefaultQuicConfig(), SupportedVersions(GetParam()), connection_,
         QuicServerId(kServerHostname, kPort, false), &crypto_config_,
         &push_promise_index_);
     session_->Initialize();
diff --git a/net/third_party/quic/core/http/quic_spdy_client_stream_test.cc b/net/third_party/quic/core/http/quic_spdy_client_stream_test.cc
index a6945007..47b6150 100644
--- a/net/third_party/quic/core/http/quic_spdy_client_stream_test.cc
+++ b/net/third_party/quic/core/http/quic_spdy_client_stream_test.cc
@@ -33,9 +33,11 @@
 class MockQuicSpdyClientSession : public QuicSpdyClientSession {
  public:
   explicit MockQuicSpdyClientSession(
+      const ParsedQuicVersionVector& supported_versions,
       QuicConnection* connection,
       QuicClientPushPromiseIndex* push_promise_index)
       : QuicSpdyClientSession(DefaultQuicConfig(),
+                              supported_versions,
                               connection,
                               QuicServerId("example.com", 443, false),
                               &crypto_config_,
@@ -61,7 +63,9 @@
       : connection_(new StrictMock<MockQuicConnection>(&helper_,
                                                        &alarm_factory_,
                                                        Perspective::IS_CLIENT)),
-        session_(connection_, &push_promise_index_),
+        session_(connection_->supported_versions(),
+                 connection_,
+                 &push_promise_index_),
         body_("hello world") {
     session_.Initialize();
 
diff --git a/net/third_party/quic/core/quic_buffered_packet_store.cc b/net/third_party/quic/core/quic_buffered_packet_store.cc
index 9d933a6..78fffcbf 100644
--- a/net/third_party/quic/core/quic_buffered_packet_store.cc
+++ b/net/third_party/quic/core/quic_buffered_packet_store.cc
@@ -55,7 +55,9 @@
 BufferedPacket::~BufferedPacket() {}
 
 BufferedPacketList::BufferedPacketList()
-    : creation_time(QuicTime::Zero()), ietf_quic(false) {}
+    : creation_time(QuicTime::Zero()),
+      ietf_quic(false),
+      version(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED) {}
 
 BufferedPacketList::BufferedPacketList(BufferedPacketList&& other) = default;
 
@@ -84,13 +86,16 @@
     QuicSocketAddress server_address,
     QuicSocketAddress client_address,
     bool is_chlo,
-    const QuicString& alpn) {
+    const QuicString& alpn,
+    const ParsedQuicVersion& version) {
   QUIC_BUG_IF(!FLAGS_quic_allow_chlo_buffering)
       << "Shouldn't buffer packets if disabled via flag.";
   QUIC_BUG_IF(is_chlo && QuicContainsKey(connections_with_chlo_, connection_id))
       << "Shouldn't buffer duplicated CHLO on connection " << connection_id;
   QUIC_BUG_IF(!is_chlo && !alpn.empty())
       << "Shouldn't have an ALPN defined for a non-CHLO packet.";
+  QUIC_BUG_IF(is_chlo && version.transport_version == QUIC_VERSION_UNSUPPORTED)
+      << "Should have version for CHLO packet.";
 
   if (!QuicContainsKey(undecryptable_packets_, connection_id) &&
       ShouldBufferPacket(is_chlo)) {
@@ -134,6 +139,8 @@
     queue.buffered_packets.push_front(std::move(new_entry));
     queue.alpn = alpn;
     connections_with_chlo_[connection_id] = false;  // Dummy value.
+    // Set the version of buffered packets of this connection on CHLO.
+    queue.version = version;
   } else {
     // Buffer non-CHLO packets in arrival order.
     queue.buffered_packets.push_back(std::move(new_entry));
diff --git a/net/third_party/quic/core/quic_buffered_packet_store.h b/net/third_party/quic/core/quic_buffered_packet_store.h
index bf65b37..7b7a65b 100644
--- a/net/third_party/quic/core/quic_buffered_packet_store.h
+++ b/net/third_party/quic/core/quic_buffered_packet_store.h
@@ -71,6 +71,8 @@
     QuicString alpn;
     // Indicating whether this is an IETF QUIC connection.
     bool ietf_quic;
+    // QUIC version if buffered_packets contains the CHLO.
+    ParsedQuicVersion version;
   };
 
   typedef QuicLinkedHashMap<QuicConnectionId, BufferedPacketList>
@@ -96,13 +98,16 @@
   QuicBufferedPacketStore& operator=(const QuicBufferedPacketStore&) = delete;
 
   // Adds a copy of packet into packet queue for given connection.
+  // TODO(danzh): Consider to split this method to EnqueueChlo() and
+  // EnqueueDataPacket().
   EnqueuePacketResult EnqueuePacket(QuicConnectionId connection_id,
                                     bool ietf_quic,
                                     const QuicReceivedPacket& packet,
                                     QuicSocketAddress server_address,
                                     QuicSocketAddress client_address,
                                     bool is_chlo,
-                                    const QuicString& alpn);
+                                    const QuicString& alpn,
+                                    const ParsedQuicVersion& version);
 
   // Returns true if there are any packets buffered for |connection_id|.
   bool HasBufferedPackets(QuicConnectionId connection_id) const;
diff --git a/net/third_party/quic/core/quic_buffered_packet_store_test.cc b/net/third_party/quic/core/quic_buffered_packet_store_test.cc
index d911ada..2029dc4 100644
--- a/net/third_party/quic/core/quic_buffered_packet_store_test.cc
+++ b/net/third_party/quic/core/quic_buffered_packet_store_test.cc
@@ -52,7 +52,9 @@
         client_address_(QuicIpAddress::Any6(), 65535),
         packet_content_("some encrypted content"),
         packet_time_(QuicTime::Zero() + QuicTime::Delta::FromMicroseconds(42)),
-        packet_(packet_content_.data(), packet_content_.size(), packet_time_) {}
+        packet_(packet_content_.data(), packet_content_.size(), packet_time_),
+        invalid_version_(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED),
+        valid_version_(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_44) {}
 
  protected:
   QuicBufferedPacketStoreVisitor visitor_;
@@ -64,18 +66,22 @@
   QuicString packet_content_;
   QuicTime packet_time_;
   QuicReceivedPacket packet_;
+  const ParsedQuicVersion invalid_version_;
+  const ParsedQuicVersion valid_version_;
 };
 
 TEST_F(QuicBufferedPacketStoreTest, SimpleEnqueueAndDeliverPacket) {
   QuicConnectionId connection_id = 1;
   store_.EnqueuePacket(connection_id, false, packet_, server_address_,
-                       client_address_, false, "");
+                       client_address_, false, "", invalid_version_);
   EXPECT_TRUE(store_.HasBufferedPackets(connection_id));
   auto packets = store_.DeliverPackets(connection_id);
   const std::list<BufferedPacket>& queue = packets.buffered_packets;
   ASSERT_EQ(1u, queue.size());
   // The alpn should be ignored for non-chlo packets.
   ASSERT_EQ("", packets.alpn);
+  // There is no valid version because CHLO has not arrived.
+  EXPECT_EQ(invalid_version_, packets.version);
   // Check content of the only packet in the queue.
   EXPECT_EQ(packet_content_, queue.front().packet->AsStringPiece());
   EXPECT_EQ(packet_time_, queue.front().packet->receipt_time());
@@ -90,9 +96,9 @@
   QuicSocketAddress addr_with_new_port(QuicIpAddress::Any4(), 256);
   QuicConnectionId connection_id = 1;
   store_.EnqueuePacket(connection_id, false, packet_, server_address_,
-                       client_address_, false, "");
+                       client_address_, false, "", invalid_version_);
   store_.EnqueuePacket(connection_id, false, packet_, server_address_,
-                       addr_with_new_port, false, "");
+                       addr_with_new_port, false, "", invalid_version_);
   std::list<BufferedPacket> queue =
       store_.DeliverPackets(connection_id).buffered_packets;
   ASSERT_EQ(2u, queue.size());
@@ -107,9 +113,9 @@
   for (QuicConnectionId connection_id = 1; connection_id <= num_connections;
        ++connection_id) {
     store_.EnqueuePacket(connection_id, false, packet_, server_address_,
-                         client_address_, false, "");
+                         client_address_, false, "", invalid_version_);
     store_.EnqueuePacket(connection_id, false, packet_, server_address_,
-                         client_address_, false, "");
+                         client_address_, false, "", invalid_version_);
   }
 
   // Deliver packets in reversed order.
@@ -131,12 +137,12 @@
   // keep.
   EXPECT_EQ(QuicBufferedPacketStore::SUCCESS,
             store_.EnqueuePacket(connection_id, false, packet_, server_address_,
-                                 client_address_, true, ""));
+                                 client_address_, true, "", valid_version_));
   for (size_t i = 1; i <= num_packets; ++i) {
     // Only first |kDefaultMaxUndecryptablePackets packets| will be buffered.
     EnqueuePacketResult result =
         store_.EnqueuePacket(connection_id, false, packet_, server_address_,
-                             client_address_, false, "");
+                             client_address_, false, "", invalid_version_);
     if (i <= kDefaultMaxUndecryptablePackets) {
       EXPECT_EQ(EnqueuePacketResult::SUCCESS, result);
     } else {
@@ -158,7 +164,7 @@
        ++connection_id) {
     EnqueuePacketResult result =
         store_.EnqueuePacket(connection_id, false, packet_, server_address_,
-                             client_address_, false, "");
+                             client_address_, false, "", invalid_version_);
     if (connection_id <= kMaxConnectionsWithoutCHLO) {
       EXPECT_EQ(EnqueuePacketResult::SUCCESS, result);
     } else {
@@ -185,17 +191,19 @@
   size_t num_chlos =
       kDefaultMaxConnectionsInStore - kMaxConnectionsWithoutCHLO + 1;
   for (size_t connection_id = 1; connection_id <= num_chlos; ++connection_id) {
-    EXPECT_EQ(EnqueuePacketResult::SUCCESS,
-              store_.EnqueuePacket(connection_id, false, packet_,
-                                   server_address_, client_address_, true, ""));
+    EXPECT_EQ(
+        EnqueuePacketResult::SUCCESS,
+        store_.EnqueuePacket(connection_id, false, packet_, server_address_,
+                             client_address_, true, "", valid_version_));
   }
 
   // Send data packets on another |kMaxConnectionsWithoutCHLO| connections.
   // Store should only be able to buffer till it's full.
   for (size_t conn_id = num_chlos + 1;
        conn_id <= (kDefaultMaxConnectionsInStore + 1); ++conn_id) {
-    EnqueuePacketResult result = store_.EnqueuePacket(
-        conn_id, false, packet_, server_address_, client_address_, true, "");
+    EnqueuePacketResult result =
+        store_.EnqueuePacket(conn_id, false, packet_, server_address_,
+                             client_address_, true, "", valid_version_);
     if (conn_id <= kDefaultMaxConnectionsInStore) {
       EXPECT_EQ(EnqueuePacketResult::SUCCESS, result);
     } else {
@@ -208,9 +216,10 @@
   // Buffer data packets on different connections upto limit.
   for (QuicConnectionId conn_id = 1; conn_id <= kMaxConnectionsWithoutCHLO;
        ++conn_id) {
-    EXPECT_EQ(EnqueuePacketResult::SUCCESS,
-              store_.EnqueuePacket(conn_id, false, packet_, server_address_,
-                                   client_address_, false, ""));
+    EXPECT_EQ(
+        EnqueuePacketResult::SUCCESS,
+        store_.EnqueuePacket(conn_id, false, packet_, server_address_,
+                             client_address_, false, "", invalid_version_));
   }
 
   // Buffer CHLOs on other connections till store is full.
@@ -218,7 +227,7 @@
        i <= kDefaultMaxConnectionsInStore + 1; ++i) {
     EnqueuePacketResult rs = store_.EnqueuePacket(
         /*connection_id=*/i, false, packet_, server_address_, client_address_,
-        true, "");
+        true, "", valid_version_);
     if (i <= kDefaultMaxConnectionsInStore) {
       EXPECT_EQ(EnqueuePacketResult::SUCCESS, rs);
       EXPECT_TRUE(store_.HasChloForConnection(/*connection_id=*/i));
@@ -232,9 +241,10 @@
   // But buffering a CHLO belonging to a connection already has data packet
   // buffered in the store should success. This is the connection should be
   // delivered at last.
-  EXPECT_EQ(EnqueuePacketResult::SUCCESS,
-            store_.EnqueuePacket(/*connection_id=*/1, false, packet_,
-                                 server_address_, client_address_, true, ""));
+  EXPECT_EQ(
+      EnqueuePacketResult::SUCCESS,
+      store_.EnqueuePacket(/*connection_id=*/1, false, packet_, server_address_,
+                           client_address_, true, "", valid_version_));
   EXPECT_TRUE(store_.HasChloForConnection(/*connection_id=*/1));
 
   QuicConnectionId delivered_conn_id;
@@ -260,14 +270,15 @@
 TEST_F(QuicBufferedPacketStoreTest, PacketQueueExpiredBeforeDelivery) {
   QuicConnectionId connection_id = 1;
   store_.EnqueuePacket(connection_id, false, packet_, server_address_,
-                       client_address_, false, "");
+                       client_address_, false, "", invalid_version_);
   EXPECT_EQ(EnqueuePacketResult::SUCCESS,
             store_.EnqueuePacket(connection_id, false, packet_, server_address_,
-                                 client_address_, true, ""));
+                                 client_address_, true, "", valid_version_));
   QuicConnectionId connection_id2 = 2;
-  EXPECT_EQ(EnqueuePacketResult::SUCCESS,
-            store_.EnqueuePacket(connection_id2, false, packet_,
-                                 server_address_, client_address_, false, ""));
+  EXPECT_EQ(
+      EnqueuePacketResult::SUCCESS,
+      store_.EnqueuePacket(connection_id2, false, packet_, server_address_,
+                           client_address_, false, "", invalid_version_));
 
   // CHLO on connection 3 arrives 1ms later.
   clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
@@ -276,7 +287,7 @@
   // connections.
   QuicSocketAddress another_client_address(QuicIpAddress::Any4(), 255);
   store_.EnqueuePacket(connection_id3, false, packet_, server_address_,
-                       another_client_address, true, "");
+                       another_client_address, true, "", valid_version_);
 
   // Advance clock to the time when connection 1 and 2 expires.
   clock_.AdvanceTime(
@@ -308,9 +319,9 @@
   // for them to expire.
   QuicConnectionId connection_id4 = 4;
   store_.EnqueuePacket(connection_id4, false, packet_, server_address_,
-                       client_address_, false, "");
+                       client_address_, false, "", invalid_version_);
   store_.EnqueuePacket(connection_id4, false, packet_, server_address_,
-                       client_address_, false, "");
+                       client_address_, false, "", invalid_version_);
   clock_.AdvanceTime(
       QuicBufferedPacketStorePeer::expiration_alarm(&store_)->deadline() -
       clock_.ApproximateNow());
@@ -325,9 +336,9 @@
 
   // Enqueue some packets
   store_.EnqueuePacket(connection_id, false, packet_, server_address_,
-                       client_address_, false, "");
+                       client_address_, false, "", invalid_version_);
   store_.EnqueuePacket(connection_id, false, packet_, server_address_,
-                       client_address_, false, "");
+                       client_address_, false, "", invalid_version_);
   EXPECT_TRUE(store_.HasBufferedPackets(connection_id));
   EXPECT_FALSE(store_.HasChlosBuffered());
 
@@ -351,11 +362,11 @@
 
   // Enqueue some packets, which include a CHLO
   store_.EnqueuePacket(connection_id, false, packet_, server_address_,
-                       client_address_, false, "");
+                       client_address_, false, "", invalid_version_);
   store_.EnqueuePacket(connection_id, false, packet_, server_address_,
-                       client_address_, true, "");
+                       client_address_, true, "", valid_version_);
   store_.EnqueuePacket(connection_id, false, packet_, server_address_,
-                       client_address_, false, "");
+                       client_address_, false, "", invalid_version_);
   EXPECT_TRUE(store_.HasBufferedPackets(connection_id));
   EXPECT_TRUE(store_.HasChlosBuffered());
 
@@ -380,11 +391,11 @@
 
   // Enqueue some packets for two connection IDs
   store_.EnqueuePacket(connection_id_1, false, packet_, server_address_,
-                       client_address_, false, "");
+                       client_address_, false, "", invalid_version_);
   store_.EnqueuePacket(connection_id_1, false, packet_, server_address_,
-                       client_address_, false, "");
+                       client_address_, false, "", invalid_version_);
   store_.EnqueuePacket(connection_id_2, false, packet_, server_address_,
-                       client_address_, true, "h3");
+                       client_address_, true, "h3", valid_version_);
   EXPECT_TRUE(store_.HasBufferedPackets(connection_id_1));
   EXPECT_TRUE(store_.HasBufferedPackets(connection_id_2));
   EXPECT_TRUE(store_.HasChlosBuffered());
@@ -402,6 +413,8 @@
   auto packets = store_.DeliverPackets(connection_id_2);
   EXPECT_EQ(1u, packets.buffered_packets.size());
   EXPECT_EQ("h3", packets.alpn);
+  // Since connection_id_2's chlo arrives, verify version is set.
+  EXPECT_EQ(valid_version_, packets.version);
   EXPECT_TRUE(store_.HasChlosBuffered());
 
   // Discard the packets for connection 2
diff --git a/net/third_party/quic/core/quic_connection.cc b/net/third_party/quic/core/quic_connection.cc
index b1ef7c0..77b3276 100644
--- a/net/third_party/quic/core/quic_connection.cc
+++ b/net/third_party/quic/core/quic_connection.cc
@@ -258,6 +258,7 @@
       max_undecryptable_packets_(0),
       max_tracked_packets_(kMaxTrackedPackets),
       pending_version_negotiation_packet_(false),
+      send_ietf_version_negotiation_packet_(false),
       save_crypto_packets_as_termination_packets_(false),
       idle_timeout_connection_close_behavior_(
           ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET),
@@ -378,7 +379,7 @@
                          : kDefaultMaxPacketSize);
   received_packet_manager_.set_max_ack_ranges(255);
   MaybeEnableSessionDecidesWhatToWrite();
-  DCHECK(!GetQuicRestartFlag(quic_no_server_conn_ver_negotiation) ||
+  DCHECK(!GetQuicRestartFlag(quic_no_server_conn_ver_negotiation2) ||
          perspective_ == Perspective::IS_CLIENT ||
          supported_versions.size() == 1);
 }
@@ -561,7 +562,8 @@
 }
 
 bool QuicConnection::OnProtocolVersionMismatch(
-    ParsedQuicVersion received_version) {
+    ParsedQuicVersion received_version,
+    PacketHeaderFormat form) {
   QUIC_DLOG(INFO) << ENDPOINT << "Received packet with mismatched version "
                   << ParsedQuicVersionToString(received_version);
   if (perspective_ == Perspective::IS_CLIENT) {
@@ -585,7 +587,7 @@
   switch (version_negotiation_state_) {
     case START_NEGOTIATION:
       if (!framer_.IsSupportedVersion(received_version)) {
-        SendVersionNegotiationPacket();
+        SendVersionNegotiationPacket(form != GOOGLE_QUIC_PACKET);
         version_negotiation_state_ = NEGOTIATION_IN_PROGRESS;
         return false;
       }
@@ -593,7 +595,7 @@
 
     case NEGOTIATION_IN_PROGRESS:
       if (!framer_.IsSupportedVersion(received_version)) {
-        SendVersionNegotiationPacket();
+        SendVersionNegotiationPacket(form != GOOGLE_QUIC_PACKET);
         return false;
       }
       break;
@@ -665,6 +667,19 @@
 
   server_supported_versions_ = packet.versions;
 
+  if (GetQuicReloadableFlag(quic_no_client_conn_ver_negotiation)) {
+    CloseConnection(
+        QUIC_INVALID_VERSION,
+        QuicStrCat(
+            "Client may support one of the versions in the server's list, but "
+            "it's going to close the connection anyway. Supported versions: {",
+            ParsedQuicVersionVectorToString(framer_.supported_versions()),
+            "}, peer supported versions: {",
+            ParsedQuicVersionVectorToString(packet.versions), "}"),
+        ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET);
+    return;
+  }
+
   if (!SelectMutualVersion(packet.versions)) {
     CloseConnection(
         QUIC_INVALID_VERSION,
@@ -1557,8 +1572,9 @@
   }
 }
 
-void QuicConnection::SendVersionNegotiationPacket() {
+void QuicConnection::SendVersionNegotiationPacket(bool ietf_quic) {
   pending_version_negotiation_packet_ = true;
+  send_ietf_version_negotiation_packet_ = ietf_quic;
 
   if (HandleWriteBlocked()) {
     return;
@@ -1567,10 +1583,10 @@
   QUIC_DLOG(INFO) << ENDPOINT << "Sending version negotiation packet: {"
                   << ParsedQuicVersionVectorToString(
                          framer_.supported_versions())
-                  << "}, ietf_quic: " << framer_.last_packet_is_ietf_quic();
+                  << "}, ietf_quic: " << ietf_quic;
   std::unique_ptr<QuicEncryptedPacket> version_packet(
       packet_generator_.SerializeVersionNegotiationPacket(
-          framer_.last_packet_is_ietf_quic(), framer_.supported_versions()));
+          ietf_quic, framer_.supported_versions()));
   WriteResult result = writer_->WritePacket(
       version_packet->data(), version_packet->length(), self_address().host(),
       peer_address(), per_packet_options_);
@@ -1692,6 +1708,8 @@
   if (!connected_) {
     return;
   }
+  QUIC_BUG_IF(current_packet_data_ != nullptr)
+      << "ProcessUdpPacket must not be called while processing a packet.";
   if (debug_visitor_ != nullptr) {
     debug_visitor_->OnPacketReceived(self_address, peer_address, packet);
   }
@@ -1916,7 +1934,7 @@
 
   if (version_negotiation_state_ != NEGOTIATED_VERSION) {
     if (perspective_ == Perspective::IS_CLIENT) {
-      DCHECK(!header.version_flag || framer_.last_packet_is_ietf_quic());
+      DCHECK(!header.version_flag || header.form != GOOGLE_QUIC_PACKET);
       if (framer_.transport_version() <= QUIC_VERSION_43) {
         // If the client gets a packet without the version flag from the server
         // it should stop sending version since the version negotiation is done.
@@ -1948,7 +1966,7 @@
   DCHECK(!writer_->IsWriteBlocked());
 
   if (pending_version_negotiation_packet_) {
-    SendVersionNegotiationPacket();
+    SendVersionNegotiationPacket(send_ietf_version_negotiation_packet_);
   }
 
   UMA_HISTOGRAM_COUNTS_1000("Net.QuicSession.NumQueuedPacketsBeforeWrite",
diff --git a/net/third_party/quic/core/quic_connection.h b/net/third_party/quic/core/quic_connection.h
index fe4c9c9..142fd19 100644
--- a/net/third_party/quic/core/quic_connection.h
+++ b/net/third_party/quic/core/quic_connection.h
@@ -457,7 +457,8 @@
 
   // From QuicFramerVisitorInterface
   void OnError(QuicFramer* framer) override;
-  bool OnProtocolVersionMismatch(ParsedQuicVersion received_version) override;
+  bool OnProtocolVersionMismatch(ParsedQuicVersion received_version,
+                                 PacketHeaderFormat form) override;
   void OnPacket() override;
   void OnPublicResetPacket(const QuicPublicResetPacket& packet) override;
   void OnVersionNegotiationPacket(
@@ -934,7 +935,7 @@
       const QuicStopWaitingFrame& stop_waiting);
 
   // Sends a version negotiation packet to the peer.
-  void SendVersionNegotiationPacket();
+  void SendVersionNegotiationPacket(bool ietf_quic);
 
   // Clears any accumulated frames from the last received packet.
   void ClearLastFrames();
@@ -1124,6 +1125,8 @@
   // When the version negotiation packet could not be sent because the socket
   // was not writable, this is set to true.
   bool pending_version_negotiation_packet_;
+  // Used when pending_version_negotiation_packet_ is true.
+  bool send_ietf_version_negotiation_packet_;
 
   // When packets could not be sent because the socket was not writable,
   // they are added to this list.  All corresponding frames are in
diff --git a/net/third_party/quic/core/quic_connection_test.cc b/net/third_party/quic/core/quic_connection_test.cc
index 87eb696b..aa44dfc9 100644
--- a/net/third_party/quic/core/quic_connection_test.cc
+++ b/net/third_party/quic/core/quic_connection_test.cc
@@ -6213,11 +6213,20 @@
 
   // Send a version negotiation packet.
   std::unique_ptr<QuicEncryptedPacket> encrypted(
-      peer_framer_.BuildVersionNegotiationPacket(connection_id_, false,
-                                                 AllSupportedVersions()));
+      peer_framer_.BuildVersionNegotiationPacket(
+          connection_id_, connection_.transport_version() > QUIC_VERSION_43,
+          AllSupportedVersions()));
   std::unique_ptr<QuicReceivedPacket> received(
       ConstructReceivedPacket(*encrypted, QuicTime::Zero()));
+  if (GetQuicReloadableFlag(quic_no_client_conn_ver_negotiation)) {
+    EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_INVALID_VERSION, _,
+                                             ConnectionCloseSource::FROM_SELF));
+  }
   connection_.ProcessUdpPacket(kSelfAddress, kPeerAddress, *received);
+  if (GetQuicReloadableFlag(quic_no_client_conn_ver_negotiation)) {
+    EXPECT_FALSE(connection_.connected());
+    return;
+  }
 
   // Now force another packet.  The connection should transition into
   // NEGOTIATED_VERSION state and tell the packet creator to StopSendingVersion.
@@ -6419,8 +6428,7 @@
   QuicPacketHeader header;
   header.packet_number = 1;
   if (GetParam().version.transport_version > QUIC_VERSION_43) {
-    QuicFramerPeer::SetLastPacketIsIetfQuic(
-        QuicConnectionPeer::GetFramer(&connection_), true);
+    header.form = IETF_QUIC_LONG_HEADER_PACKET;
   }
 
   MockQuicConnectionDebugVisitor debug_visitor;
diff --git a/net/third_party/quic/core/quic_crypto_client_handshaker.cc b/net/third_party/quic/core/quic_crypto_client_handshaker.cc
index f1b69c2f..0f87480 100644
--- a/net/third_party/quic/core/quic_crypto_client_handshaker.cc
+++ b/net/third_party/quic/core/quic_crypto_client_handshaker.cc
@@ -318,8 +318,8 @@
 
   if (!cached->IsComplete(session()->connection()->clock()->WallNow())) {
     crypto_config_->FillInchoateClientHello(
-        server_id_, session()->connection()->supported_versions().front(),
-        cached, session()->connection()->random_generator(),
+        server_id_, session()->supported_versions().front(), cached,
+        session()->connection()->random_generator(),
         /* demand_x509_proof= */ true, crypto_negotiated_params_, &out);
     // Pad the inchoate client hello to fill up a packet.
     const QuicByteCount kFramingOverhead = 50;  // A rough estimate.
@@ -360,7 +360,7 @@
   QuicString error_details;
   QuicErrorCode error = crypto_config_->FillClientHello(
       server_id_, session()->connection()->connection_id(),
-      session()->connection()->supported_versions().front(), cached,
+      session()->supported_versions().front(), cached,
       session()->connection()->clock()->WallNow(),
       session()->connection()->random_generator(), channel_id_key_.get(),
       crypto_negotiated_params_, &out, &error_details);
diff --git a/net/third_party/quic/core/quic_crypto_client_stream_test.cc b/net/third_party/quic/core/quic_crypto_client_stream_test.cc
index 5083e74..1690275 100644
--- a/net/third_party/quic/core/quic_crypto_client_stream_test.cc
+++ b/net/third_party/quic/core/quic_crypto_client_stream_test.cc
@@ -52,7 +52,8 @@
     connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1));
 
     session_ = QuicMakeUnique<TestQuicSpdyClientSession>(
-        connection_, DefaultQuicConfig(), server_id_, &crypto_config_);
+        connection_, DefaultQuicConfig(), supported_versions_, server_id_,
+        &crypto_config_);
   }
 
   void CompleteCryptoHandshake() {
@@ -376,6 +377,37 @@
   EXPECT_EQ(0u, stream()->crypto_negotiated_params().token_binding_key_param);
 }
 
+TEST_F(QuicCryptoClientStreamTest, PreferredVersion) {
+  // This mimics the case where client receives version negotiation packet, such
+  // that, the preferred version is different from the packets' version.
+  connection_ = new PacketSavingConnection(
+      &client_helper_, &alarm_factory_, Perspective::IS_CLIENT,
+      ParsedVersionOfIndex(supported_versions_, 1));
+  connection_->AdvanceTime(QuicTime::Delta::FromSeconds(1));
+
+  session_ = QuicMakeUnique<TestQuicSpdyClientSession>(
+      connection_, DefaultQuicConfig(), supported_versions_, server_id_,
+      &crypto_config_);
+  CompleteCryptoHandshake();
+  // 2 CHLOs are sent.
+  ASSERT_EQ(2u, session_->sent_crypto_handshake_messages().size());
+  // Verify preferred version is the highest version that session supports, and
+  // is different from connection's version.
+  QuicVersionLabel client_version_label;
+  EXPECT_EQ(QUIC_NO_ERROR,
+            session_->sent_crypto_handshake_messages()[0].GetVersionLabel(
+                kVER, &client_version_label));
+  EXPECT_EQ(CreateQuicVersionLabel(supported_versions_[0]),
+            client_version_label);
+  EXPECT_EQ(QUIC_NO_ERROR,
+            session_->sent_crypto_handshake_messages()[1].GetVersionLabel(
+                kVER, &client_version_label));
+  EXPECT_EQ(CreateQuicVersionLabel(supported_versions_[0]),
+            client_version_label);
+  EXPECT_NE(CreateQuicVersionLabel(connection_->version()),
+            client_version_label);
+}
+
 class QuicCryptoClientStreamStatelessTest : public QuicTest {
  public:
   QuicCryptoClientStreamStatelessTest()
diff --git a/net/third_party/quic/core/quic_dispatcher.cc b/net/third_party/quic/core/quic_dispatcher.cc
index 170e170..ef32d29 100644
--- a/net/third_party/quic/core/quic_dispatcher.cc
+++ b/net/third_party/quic/core/quic_dispatcher.cc
@@ -128,7 +128,8 @@
   // Generates a packet containing a CONNECTION_CLOSE frame specifying
   // |error_code| and |error_details| and add the connection to time wait.
   void CloseConnection(QuicErrorCode error_code,
-                       const QuicString& error_details) {
+                       const QuicString& error_details,
+                       bool ietf_quic) {
     QuicConnectionCloseFrame* frame = new QuicConnectionCloseFrame;
     frame->error_code = error_code;
     frame->error_details = error_details;
@@ -143,7 +144,7 @@
     creator_.Flush();
     DCHECK_EQ(1u, collector_.packets()->size());
     time_wait_list_manager_->AddConnectionIdToTimeWait(
-        connection_id_, framer_->last_packet_is_ietf_quic(),
+        connection_id_, ietf_quic,
         QuicTimeWaitListManager::SEND_TERMINATION_PACKETS,
         collector_.packets());
   }
@@ -151,7 +152,7 @@
   // Generates a series of termination packets containing the crypto handshake
   // message |reject|.  Adds the connection to time wait list with the
   // generated packets.
-  void RejectConnection(QuicStringPiece reject) {
+  void RejectConnection(QuicStringPiece reject, bool ietf_quic) {
     QuicStreamOffset offset = 0;
     collector_.SaveStatelessRejectFrameData(reject);
     while (offset < reject.length()) {
@@ -174,7 +175,7 @@
       creator_.Flush();
     }
     time_wait_list_manager_->AddConnectionIdToTimeWait(
-        connection_id_, framer_->last_packet_is_ietf_quic(),
+        connection_id_, ietf_quic,
         QuicTimeWaitListManager::SEND_TERMINATION_PACKETS,
         collector_.packets());
     DCHECK(time_wait_list_manager_->IsConnectionIdInTimeWait(connection_id_));
@@ -345,7 +346,7 @@
   }
 
   if (buffered_packets_.HasChloForConnection(connection_id)) {
-    BufferEarlyPacket(connection_id, framer_.last_packet_is_ietf_quic());
+    BufferEarlyPacket(connection_id, header.form != GOOGLE_QUIC_PACKET);
     return false;
   }
 
@@ -354,7 +355,7 @@
       temporarily_buffered_connections_.end()) {
     // This packet was received while the a CHLO for the same connection ID was
     // being processed.  Buffer it.
-    BufferEarlyPacket(connection_id, framer_.last_packet_is_ietf_quic());
+    BufferEarlyPacket(connection_id, header.form != GOOGLE_QUIC_PACKET);
     return false;
   }
 
@@ -394,7 +395,7 @@
       // Since the version is not supported, send a version negotiation
       // packet and stop processing the current packet.
       time_wait_list_manager()->SendVersionNegotiationPacket(
-          connection_id, framer_.last_packet_is_ietf_quic(),
+          connection_id, header.form != GOOGLE_QUIC_PACKET,
           GetSupportedVersions(), current_self_address_, current_peer_address_);
       return false;
     }
@@ -412,11 +413,11 @@
   if (fate == kFateProcess) {
     // Execute stateless rejection logic to determine the packet fate, then
     // invoke ProcessUnauthenticatedHeaderFate.
-    MaybeRejectStatelessly(connection_id, header.version);
+    MaybeRejectStatelessly(connection_id, header.version, header.form);
   } else {
     // If the fate is already known, process it without executing stateless
     // rejection logic.
-    ProcessUnauthenticatedHeaderFate(fate, connection_id);
+    ProcessUnauthenticatedHeaderFate(fate, connection_id, header.form);
   }
 
   return false;
@@ -424,10 +425,11 @@
 
 void QuicDispatcher::ProcessUnauthenticatedHeaderFate(
     QuicPacketFate fate,
-    QuicConnectionId connection_id) {
+    QuicConnectionId connection_id,
+    PacketHeaderFormat form) {
   switch (fate) {
     case kFateProcess: {
-      ProcessChlo();
+      ProcessChlo(form);
       break;
     }
     case kFateTimeWait:
@@ -440,8 +442,7 @@
         QUIC_DLOG(INFO) << "Adding connection ID " << connection_id
                         << "to time-wait list.";
         StatelesslyTerminateConnection(
-            connection_id, framer()->GetLastPacketFormat(),
-            QUIC_HANDSHAKE_FAILED, "Reject connection",
+            connection_id, form, QUIC_HANDSHAKE_FAILED, "Reject connection",
             quic::QuicTimeWaitListManager::SEND_STATELESS_RESET);
       }
       DCHECK(time_wait_list_manager_->IsConnectionIdInTimeWait(connection_id));
@@ -458,7 +459,7 @@
       // This packet is a non-CHLO packet which has arrived before the
       // corresponding CHLO, *or* this packet was received while the
       // corresponding CHLO was being processed.  Buffer it.
-      BufferEarlyPacket(connection_id, framer_.last_packet_is_ietf_quic());
+      BufferEarlyPacket(connection_id, form != GOOGLE_QUIC_PACKET);
       break;
     case kFateDrop:
       // Do nothing with the packet.
@@ -649,7 +650,7 @@
     // connection to time wait list.
     StatelessConnectionTerminator terminator(
         connection_id, &framer_, helper_.get(), time_wait_list_manager_.get());
-    terminator.CloseConnection(error_code, error_details);
+    terminator.CloseConnection(error_code, error_details, true);
     return;
   }
 
@@ -672,7 +673,8 @@
 }
 
 bool QuicDispatcher::OnProtocolVersionMismatch(
-    ParsedQuicVersion /*received_version*/) {
+    ParsedQuicVersion /*received_version*/,
+    PacketHeaderFormat /*form*/) {
   QUIC_BUG_IF(
       !time_wait_list_manager_->IsConnectionIdInTimeWait(
           current_connection_id_) &&
@@ -870,8 +872,9 @@
     if (packets.empty()) {
       return;
     }
-    QuicSession* session = CreateQuicSession(
-        connection_id, packets.front().client_address, packet_list.alpn);
+    QuicSession* session =
+        CreateQuicSession(connection_id, packets.front().client_address,
+                          packet_list.alpn, packet_list.version);
     QUIC_DLOG(INFO) << "Created new session for " << connection_id;
     session_map_.insert(std::make_pair(connection_id, QuicWrapUnique(session)));
     DeliverPacketsToSession(packets, session);
@@ -883,7 +886,8 @@
 }
 
 bool QuicDispatcher::ShouldCreateOrBufferPacketForConnection(
-    QuicConnectionId connection_id) {
+    QuicConnectionId connection_id,
+    bool ietf_quic) {
   VLOG(1) << "Received packet from new connection " << connection_id;
   return true;
 }
@@ -916,23 +920,25 @@
                                        bool ietf_quic) {
   bool is_new_connection = !buffered_packets_.HasBufferedPackets(connection_id);
   if (is_new_connection &&
-      !ShouldCreateOrBufferPacketForConnection(connection_id)) {
+      !ShouldCreateOrBufferPacketForConnection(connection_id, ietf_quic)) {
     return;
   }
+  ParsedQuicVersion version(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED);
   EnqueuePacketResult rs = buffered_packets_.EnqueuePacket(
       connection_id, ietf_quic, *current_packet_, current_self_address_,
-      current_peer_address_, /*is_chlo=*/false, /*alpn=*/"");
+      current_peer_address_, /*is_chlo=*/false,
+      /*alpn=*/"", version);
   if (rs != EnqueuePacketResult::SUCCESS) {
     OnBufferPacketFailure(rs, connection_id);
   }
 }
 
-void QuicDispatcher::ProcessChlo() {
+void QuicDispatcher::ProcessChlo(quic::PacketHeaderFormat form) {
   if (!accept_new_connections_) {
     // Don't any create new connection.
     StatelesslyTerminateConnection(
-        current_connection_id(), framer()->GetLastPacketFormat(),
-        QUIC_HANDSHAKE_FAILED, "Stop accepting new connections",
+        current_connection_id(), form, QUIC_HANDSHAKE_FAILED,
+        "Stop accepting new connections",
         quic::QuicTimeWaitListManager::SEND_STATELESS_RESET);
     // Time wait list will reject the packet correspondingly.
     time_wait_list_manager()->ProcessPacket(current_self_address(),
@@ -941,7 +947,8 @@
     return;
   }
   if (!buffered_packets_.HasBufferedPackets(current_connection_id_) &&
-      !ShouldCreateOrBufferPacketForConnection(current_connection_id_)) {
+      !ShouldCreateOrBufferPacketForConnection(current_connection_id_,
+                                               form != GOOGLE_QUIC_PACKET)) {
     return;
   }
   if (FLAGS_quic_allow_chlo_buffering &&
@@ -949,17 +956,18 @@
     // Can't create new session any more. Wait till next event loop.
     QUIC_BUG_IF(buffered_packets_.HasChloForConnection(current_connection_id_));
     EnqueuePacketResult rs = buffered_packets_.EnqueuePacket(
-        current_connection_id_, framer_.last_packet_is_ietf_quic(),
-        *current_packet_, current_self_address_, current_peer_address_,
-        /*is_chlo=*/true, current_alpn_);
+        current_connection_id_, form != GOOGLE_QUIC_PACKET, *current_packet_,
+        current_self_address_, current_peer_address_,
+        /*is_chlo=*/true, current_alpn_, framer_.version());
     if (rs != EnqueuePacketResult::SUCCESS) {
       OnBufferPacketFailure(rs, current_connection_id_);
     }
     return;
   }
   // Creates a new session and process all buffered packets for this connection.
-  QuicSession* session = CreateQuicSession(
-      current_connection_id_, current_peer_address_, current_alpn_);
+  QuicSession* session =
+      CreateQuicSession(current_connection_id_, current_peer_address_,
+                        current_alpn_, framer_.version());
   QUIC_DLOG(INFO) << "Created new session for " << current_connection_id_;
   session_map_.insert(
       std::make_pair(current_connection_id_, QuicWrapUnique(session)));
@@ -996,7 +1004,8 @@
     : public StatelessRejector::ProcessDoneCallback {
  public:
   StatelessRejectorProcessDoneCallback(QuicDispatcher* dispatcher,
-                                       ParsedQuicVersion first_version)
+                                       ParsedQuicVersion first_version,
+                                       PacketHeaderFormat form)
       : dispatcher_(dispatcher),
         current_client_address_(dispatcher->current_client_address_),
         current_peer_address_(dispatcher->current_peer_address_),
@@ -1005,8 +1014,7 @@
         current_packet_(
             dispatcher->current_packet_->Clone()),  // Note: copies the packet
         first_version_(first_version),
-        current_packet_is_ietf_quic_(
-            dispatcher->framer()->last_packet_is_ietf_quic()) {}
+        current_packet_format_(form) {}
 
   void Run(std::unique_ptr<StatelessRejector> rejector) override {
     if (additional_context_ != nullptr) {
@@ -1015,7 +1023,7 @@
     dispatcher_->OnStatelessRejectorProcessDone(
         std::move(rejector), current_client_address_, current_peer_address_,
         current_self_address_, std::move(current_packet_), first_version_,
-        current_packet_is_ietf_quic_);
+        current_packet_format_);
   }
 
  private:
@@ -1028,13 +1036,14 @@
   std::unique_ptr<QuicDispatcher::PerPacketContext> additional_context_;
   std::unique_ptr<QuicReceivedPacket> current_packet_;
   ParsedQuicVersion first_version_;
-  const bool current_packet_is_ietf_quic_;
+  const PacketHeaderFormat current_packet_format_;
 };
 
 void QuicDispatcher::MaybeRejectStatelessly(QuicConnectionId connection_id,
-                                            ParsedQuicVersion version) {
+                                            ParsedQuicVersion version,
+                                            PacketHeaderFormat form) {
   if (version.handshake_protocol == PROTOCOL_TLS1_3) {
-    ProcessUnauthenticatedHeaderFate(kFateProcess, connection_id);
+    ProcessUnauthenticatedHeaderFate(kFateProcess, connection_id, form);
     return;
     // TODO(nharper): Support buffering non-ClientHello packets when using TLS.
   }
@@ -1050,11 +1059,11 @@
                                 config_.create_session_tag_indicators(),
                                 &alpn_extractor)) {
       // Buffer non-CHLO packets.
-      ProcessUnauthenticatedHeaderFate(kFateBuffer, connection_id);
+      ProcessUnauthenticatedHeaderFate(kFateBuffer, connection_id, form);
       return;
     }
     current_alpn_ = alpn_extractor.ConsumeAlpn();
-    ProcessUnauthenticatedHeaderFate(kFateProcess, connection_id);
+    ProcessUnauthenticatedHeaderFate(kFateProcess, connection_id, form);
     return;
   }
 
@@ -1069,7 +1078,7 @@
   if (!ChloExtractor::Extract(*current_packet_, GetSupportedVersions(),
                               config_.create_session_tag_indicators(),
                               &validator)) {
-    ProcessUnauthenticatedHeaderFate(kFateBuffer, connection_id);
+    ProcessUnauthenticatedHeaderFate(kFateBuffer, connection_id, form);
     return;
   }
   current_alpn_ = validator.ConsumeAlpn();
@@ -1078,10 +1087,10 @@
     // This CHLO is prohibited by policy.
     StatelessConnectionTerminator terminator(connection_id, &framer_, helper(),
                                              time_wait_list_manager_.get());
-    terminator.CloseConnection(QUIC_HANDSHAKE_FAILED,
-                               validator.error_details());
+    terminator.CloseConnection(QUIC_HANDSHAKE_FAILED, validator.error_details(),
+                               form != GOOGLE_QUIC_PACKET);
     OnConnectionClosedStatelessly(QUIC_HANDSHAKE_FAILED);
-    ProcessUnauthenticatedHeaderFate(kFateTimeWait, connection_id);
+    ProcessUnauthenticatedHeaderFate(kFateTimeWait, connection_id, form);
     return;
   }
 
@@ -1089,7 +1098,7 @@
   // information available in OnChlo, just invoke the done callback immediately.
   if (rejector->state() != StatelessRejector::UNKNOWN) {
     ProcessStatelessRejectorState(std::move(rejector),
-                                  version.transport_version);
+                                  version.transport_version, form);
     return;
   }
 
@@ -1102,7 +1111,7 @@
 
   // Continue stateless rejector processing
   std::unique_ptr<StatelessRejectorProcessDoneCallback> cb(
-      new StatelessRejectorProcessDoneCallback(this, version));
+      new StatelessRejectorProcessDoneCallback(this, version, form));
   StatelessRejector::Process(std::move(rejector), std::move(cb));
 }
 
@@ -1113,7 +1122,7 @@
     const QuicSocketAddress& current_self_address,
     std::unique_ptr<QuicReceivedPacket> current_packet,
     ParsedQuicVersion first_version,
-    bool current_packet_is_ietf_quic) {
+    PacketHeaderFormat current_packet_format) {
   // Reset current_* to correspond to the packet which initiated the stateless
   // reject logic.
   current_client_address_ = current_client_address;
@@ -1123,10 +1132,10 @@
   current_connection_id_ = rejector->connection_id();
   framer_.set_version(first_version);
   if (GetQuicReloadableFlag(quic_fix_last_packet_is_ietf_quic)) {
-    if (framer_.last_packet_is_ietf_quic() != current_packet_is_ietf_quic) {
+    if (GetLastPacketFormat() != current_packet_format) {
       QUIC_FLAG_COUNT(quic_reloadable_flag_quic_fix_last_packet_is_ietf_quic);
     }
-    framer_.set_last_packet_is_ietf_quic(current_packet_is_ietf_quic);
+    framer_.set_last_packet_form(current_packet_format);
   }
 
   // Stop buffering packets on this connection
@@ -1146,12 +1155,14 @@
   }
 
   ProcessStatelessRejectorState(std::move(rejector),
-                                first_version.transport_version);
+                                first_version.transport_version,
+                                current_packet_format);
 }
 
 void QuicDispatcher::ProcessStatelessRejectorState(
     std::unique_ptr<StatelessRejector> rejector,
-    QuicTransportVersion first_version) {
+    QuicTransportVersion first_version,
+    PacketHeaderFormat form) {
   QuicPacketFate fate;
   switch (rejector->state()) {
     case StatelessRejector::FAILED: {
@@ -1159,7 +1170,8 @@
       StatelessConnectionTerminator terminator(rejector->connection_id(),
                                                &framer_, helper(),
                                                time_wait_list_manager_.get());
-      terminator.CloseConnection(rejector->error(), rejector->error_details());
+      terminator.CloseConnection(rejector->error(), rejector->error_details(),
+                                 form != GOOGLE_QUIC_PACKET);
       fate = kFateTimeWait;
       break;
     }
@@ -1183,7 +1195,8 @@
                                                &framer_, helper(),
                                                time_wait_list_manager_.get());
       terminator.RejectConnection(
-          rejector->reply().GetSerialized().AsStringPiece());
+          rejector->reply().GetSerialized().AsStringPiece(),
+          form != GOOGLE_QUIC_PACKET);
       OnConnectionRejectedStatelessly();
       fate = kFateTimeWait;
       break;
@@ -1194,7 +1207,7 @@
       fate = kFateDrop;
       break;
   }
-  ProcessUnauthenticatedHeaderFate(fate, rejector->connection_id());
+  ProcessUnauthenticatedHeaderFate(fate, rejector->connection_id(), form);
 }
 
 const QuicTransportVersionVector&
@@ -1215,4 +1228,12 @@
   }
 }
 
+void QuicDispatcher::DisableFlagValidation() {
+  framer_.set_validate_flags(false);
+}
+
+PacketHeaderFormat QuicDispatcher::GetLastPacketFormat() const {
+  return framer_.GetLastPacketFormat();
+}
+
 }  // namespace quic
diff --git a/net/third_party/quic/core/quic_dispatcher.h b/net/third_party/quic/core/quic_dispatcher.h
index 28b9d7c..b93c966 100644
--- a/net/third_party/quic/core/quic_dispatcher.h
+++ b/net/third_party/quic/core/quic_dispatcher.h
@@ -123,7 +123,8 @@
   // destined for the time wait manager.
   bool OnUnauthenticatedHeader(const QuicPacketHeader& header) override;
   void OnError(QuicFramer* framer) override;
-  bool OnProtocolVersionMismatch(ParsedQuicVersion received_version) override;
+  bool OnProtocolVersionMismatch(ParsedQuicVersion received_version,
+                                 PacketHeaderFormat form) override;
 
   // The following methods should never get called because
   // OnUnauthenticatedPublicHeader() or OnUnauthenticatedHeader() (whichever
@@ -186,7 +187,8 @@
  protected:
   virtual QuicSession* CreateQuicSession(QuicConnectionId connection_id,
                                          const QuicSocketAddress& peer_address,
-                                         QuicStringPiece alpn) = 0;
+                                         QuicStringPiece alpn,
+                                         const ParsedQuicVersion& version) = 0;
 
   // Called when a connection is rejected statelessly.
   virtual void OnConnectionRejectedStatelessly();
@@ -228,7 +230,7 @@
 
   // Called when |current_packet_| is a CHLO packet. Creates a new connection
   // and delivers any buffered packets for that connection id.
-  void ProcessChlo();
+  void ProcessChlo(PacketHeaderFormat form);
 
   // Returns the actual client address of the current packet.
   // This function should only be called once per packet at the very beginning
@@ -273,8 +275,6 @@
     return &compressed_certs_cache_;
   }
 
-  QuicFramer* framer() { return &framer_; }
-
   QuicConnectionHelperInterface* helper() { return helper_.get(); }
 
   QuicCryptoServerStream::Helper* session_helper() {
@@ -303,7 +303,8 @@
   // for CHLO. Returns true if a new connection should be created or its packets
   // should be buffered, false otherwise.
   virtual bool ShouldCreateOrBufferPacketForConnection(
-      QuicConnectionId connection_id);
+      QuicConnectionId connection_id,
+      bool ietf_quic);
 
   bool HasBufferedPackets(QuicConnectionId connection_id);
 
@@ -340,6 +341,14 @@
   virtual void RestorePerPacketContext(
       std::unique_ptr<PerPacketContext> /*context*/) {}
 
+  // Skip validating that the public flags are set to legal values.
+  void DisableFlagValidation();
+
+  // Please do not use this method.
+  // TODO(fayang): Remove this method when deprecating
+  // quic_reloadable_flag_quic_proxy_use_real_packet_format_when_reject.
+  PacketHeaderFormat GetLastPacketFormat() const;
+
  private:
   friend class test::QuicDispatcherPeer;
   friend class StatelessRejectorProcessDoneCallback;
@@ -351,7 +360,8 @@
   // fate which describes what subsequent processing should be performed on the
   // packets, like ValidityChecks, and invokes ProcessUnauthenticatedHeaderFate.
   void MaybeRejectStatelessly(QuicConnectionId connection_id,
-                              ParsedQuicVersion version);
+                              ParsedQuicVersion version,
+                              PacketHeaderFormat form);
 
   // Deliver |packets| to |session| for further processing.
   void DeliverPacketsToSession(
@@ -361,7 +371,8 @@
   // Perform the appropriate actions on the current packet based on |fate| -
   // either process, buffer, or drop it.
   void ProcessUnauthenticatedHeaderFate(QuicPacketFate fate,
-                                        QuicConnectionId connection_id);
+                                        QuicConnectionId connection_id,
+                                        PacketHeaderFormat form);
 
   // Invoked when StatelessRejector::Process completes. |first_version| is the
   // version of the packet which initiated the stateless reject.
@@ -376,13 +387,14 @@
       const QuicSocketAddress& current_self_address,
       std::unique_ptr<QuicReceivedPacket> current_packet,
       ParsedQuicVersion first_version,
-      bool current_packet_is_ietf_quic);
+      PacketHeaderFormat current_packet_format);
 
   // Examine the state of the rejector and decide what to do with the current
   // packet.
   void ProcessStatelessRejectorState(
       std::unique_ptr<StatelessRejector> rejector,
-      QuicTransportVersion first_version);
+      QuicTransportVersion first_version,
+      PacketHeaderFormat form);
 
   void set_new_sessions_allowed_per_event_loop(
       int16_t new_sessions_allowed_per_event_loop) {
diff --git a/net/third_party/quic/core/quic_dispatcher_test.cc b/net/third_party/quic/core/quic_dispatcher_test.cc
index 08786125..eb5b596 100644
--- a/net/third_party/quic/core/quic_dispatcher_test.cc
+++ b/net/third_party/quic/core/quic_dispatcher_test.cc
@@ -123,13 +123,14 @@
                                QuicRandom::GetInstance())),
                        QuicMakeUnique<MockAlarmFactory>()) {}
 
-  MOCK_METHOD3(CreateQuicSession,
+  MOCK_METHOD4(CreateQuicSession,
                QuicServerSessionBase*(QuicConnectionId connection_id,
                                       const QuicSocketAddress& peer_address,
-                                      QuicStringPiece alpn));
+                                      QuicStringPiece alpn,
+                                      const quic::ParsedQuicVersion& version));
 
-  MOCK_METHOD1(ShouldCreateOrBufferPacketForConnection,
-               bool(QuicConnectionId connection_id));
+  MOCK_METHOD2(ShouldCreateOrBufferPacketForConnection,
+               bool(QuicConnectionId connection_id, bool ietf_quic));
 
   struct TestQuicPerPacketContext : public PerPacketContext {
     QuicString custom_packet_context;
@@ -153,7 +154,7 @@
   using QuicDispatcher::current_client_address;
   using QuicDispatcher::current_peer_address;
   using QuicDispatcher::current_self_address;
-  using QuicDispatcher::framer;
+  using QuicDispatcher::GetLastPacketFormat;
 };
 
 // A Connection class which unregisters the session from the dispatcher when
@@ -214,7 +215,7 @@
     // Set the counter to some value to start with.
     QuicDispatcherPeer::set_new_sessions_allowed_per_event_loop(
         dispatcher_.get(), kMaxNumSessionsToCreate);
-    ON_CALL(*dispatcher_, ShouldCreateOrBufferPacketForConnection(_))
+    ON_CALL(*dispatcher_, ShouldCreateOrBufferPacketForConnection(_, _))
         .WillByDefault(Return(true));
   }
 
@@ -359,7 +360,7 @@
   server_address_ = QuicSocketAddress(QuicIpAddress::Any4(), 5);
 
   EXPECT_CALL(*dispatcher_,
-              CreateQuicSession(1, client_address, QuicStringPiece("")))
+              CreateQuicSession(1, client_address, QuicStringPiece(""), _))
       .WillOnce(testing::Return(CreateSession(
           dispatcher_.get(), config_, 1, client_address, &mock_helper_,
           &mock_alarm_factory_, &crypto_config_,
@@ -369,7 +370,7 @@
       .WillOnce(WithArg<2>(Invoke([this](const QuicEncryptedPacket& packet) {
         ValidatePacket(1, packet);
       })));
-  EXPECT_CALL(*dispatcher_, ShouldCreateOrBufferPacketForConnection(1));
+  EXPECT_CALL(*dispatcher_, ShouldCreateOrBufferPacketForConnection(1, _));
   ProcessPacket(
       client_address, 1, true,
       ParsedQuicVersion(PROTOCOL_TLS1_3,
@@ -385,7 +386,7 @@
   server_address_ = QuicSocketAddress(QuicIpAddress::Any4(), 5);
 
   EXPECT_CALL(*dispatcher_,
-              CreateQuicSession(1, client_address, QuicStringPiece("hq")))
+              CreateQuicSession(1, client_address, QuicStringPiece("hq"), _))
       .WillOnce(testing::Return(CreateSession(
           dispatcher_.get(), config_, 1, client_address, &mock_helper_,
           &mock_alarm_factory_, &crypto_config_,
@@ -395,13 +396,13 @@
       .WillOnce(WithArg<2>(Invoke([this](const QuicEncryptedPacket& packet) {
         ValidatePacket(1, packet);
       })));
-  EXPECT_CALL(*dispatcher_, ShouldCreateOrBufferPacketForConnection(1));
+  EXPECT_CALL(*dispatcher_, ShouldCreateOrBufferPacketForConnection(1, _));
   ProcessPacket(client_address, 1, true, SerializeCHLO());
   EXPECT_EQ(client_address, dispatcher_->current_peer_address());
   EXPECT_EQ(server_address_, dispatcher_->current_self_address());
 
   EXPECT_CALL(*dispatcher_,
-              CreateQuicSession(2, client_address, QuicStringPiece("hq")))
+              CreateQuicSession(2, client_address, QuicStringPiece("hq"), _))
       .WillOnce(testing::Return(CreateSession(
           dispatcher_.get(), config_, 2, client_address, &mock_helper_,
           &mock_alarm_factory_, &crypto_config_,
@@ -411,7 +412,7 @@
       .WillOnce(WithArg<2>(Invoke([this](const QuicEncryptedPacket& packet) {
         ValidatePacket(2, packet);
       })));
-  EXPECT_CALL(*dispatcher_, ShouldCreateOrBufferPacketForConnection(2));
+  EXPECT_CALL(*dispatcher_, ShouldCreateOrBufferPacketForConnection(2, _));
   ProcessPacket(client_address, 2, true, SerializeCHLO());
 
   EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
@@ -429,7 +430,7 @@
   server_address_ = QuicSocketAddress(QuicIpAddress::Any4(), 5);
 
   EXPECT_CALL(*dispatcher_,
-              CreateQuicSession(1, client_address, QuicStringPiece("hq")))
+              CreateQuicSession(1, client_address, QuicStringPiece("hq"), _))
       .WillOnce(testing::Return(CreateSession(
           dispatcher_.get(), config_, 1, client_address, &mock_helper_,
           &mock_alarm_factory_, &crypto_config_,
@@ -442,7 +443,7 @@
           WithArg<2>(Invoke([this](const QuicEncryptedPacket& packet) {
             ValidatePacket(1, packet);
           })));
-  EXPECT_CALL(*dispatcher_, ShouldCreateOrBufferPacketForConnection(1));
+  EXPECT_CALL(*dispatcher_, ShouldCreateOrBufferPacketForConnection(1, _));
   ProcessPacket(
       client_address, 1, true,
       ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO,
@@ -465,7 +466,7 @@
   server_address_ = QuicSocketAddress(QuicIpAddress::Any4(), 5);
 
   EXPECT_CALL(*dispatcher_,
-              CreateQuicSession(1, client_address, QuicStringPiece("hq")))
+              CreateQuicSession(1, client_address, QuicStringPiece("hq"), _))
       .Times(0);
   QuicTransportVersion version =
       static_cast<QuicTransportVersion>(QuicTransportVersionMin() - 1);
@@ -478,7 +479,7 @@
   QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
 
   EXPECT_CALL(*dispatcher_,
-              CreateQuicSession(_, client_address, QuicStringPiece("hq")))
+              CreateQuicSession(_, client_address, QuicStringPiece("hq"), _))
       .WillOnce(testing::Return(CreateSession(
           dispatcher_.get(), config_, 1, client_address, &mock_helper_,
           &mock_alarm_factory_, &crypto_config_,
@@ -489,7 +490,7 @@
         ValidatePacket(1, packet);
       })));
 
-  EXPECT_CALL(*dispatcher_, ShouldCreateOrBufferPacketForConnection(1));
+  EXPECT_CALL(*dispatcher_, ShouldCreateOrBufferPacketForConnection(1, _));
   ProcessPacket(client_address, 1, true, SerializeCHLO());
 
   EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
@@ -505,7 +506,7 @@
   QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
   QuicConnectionId connection_id = 1;
   EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address,
-                                              QuicStringPiece("hq")))
+                                              QuicStringPiece("hq"), _))
       .WillOnce(testing::Return(CreateSession(
           dispatcher_.get(), config_, connection_id, client_address,
           &mock_helper_, &mock_alarm_factory_, &crypto_config_,
@@ -516,7 +517,7 @@
         ValidatePacket(1, packet);
       })));
 
-  EXPECT_CALL(*dispatcher_, ShouldCreateOrBufferPacketForConnection(1));
+  EXPECT_CALL(*dispatcher_, ShouldCreateOrBufferPacketForConnection(1, _));
   ProcessPacket(client_address, connection_id, true, SerializeCHLO());
 
   // Close the connection by sending public reset packet.
@@ -557,7 +558,7 @@
   QuicConnectionId connection_id = 1;
   // Dispatcher forwards all packets for this connection_id to the time wait
   // list manager.
-  EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _, QuicStringPiece("hq")))
+  EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _, QuicStringPiece("hq"), _))
       .Times(0);
   EXPECT_CALL(*time_wait_list_manager_, ProcessPacket(_, _, connection_id))
       .Times(1);
@@ -574,7 +575,7 @@
 
   // dispatcher_ should drop this packet.
   EXPECT_CALL(*dispatcher_,
-              CreateQuicSession(1, client_address, QuicStringPiece("hq")))
+              CreateQuicSession(1, client_address, QuicStringPiece("hq"), _))
       .Times(0);
   EXPECT_CALL(*time_wait_list_manager_, ProcessPacket(_, _, _)).Times(0);
   EXPECT_CALL(*time_wait_list_manager_, AddConnectionIdToTimeWait(_, _, _, _))
@@ -588,7 +589,7 @@
   server_address_ = QuicSocketAddress(QuicIpAddress::Any4(), 5);
 
   EXPECT_CALL(*dispatcher_,
-              CreateQuicSession(1, client_address, QuicStringPiece("hq")))
+              CreateQuicSession(1, client_address, QuicStringPiece("hq"), _))
       .WillOnce(testing::Return(CreateSession(
           dispatcher_.get(), config_, 1, client_address, &mock_helper_,
           &mock_alarm_factory_, &crypto_config_,
@@ -602,7 +603,7 @@
   // A packet whose packet number is the largest that is allowed to start a
   // connection.
   EXPECT_CALL(*dispatcher_,
-              ShouldCreateOrBufferPacketForConnection(connection_id));
+              ShouldCreateOrBufferPacketForConnection(connection_id, _));
   ProcessPacket(client_address, connection_id, true, SerializeCHLO(),
                 PACKET_8BYTE_CONNECTION_ID, PACKET_4BYTE_PACKET_NUMBER,
                 QuicDispatcher::kMaxReasonableInitialPacketNumber);
@@ -618,7 +619,7 @@
 
   // Dispatcher forwards this packet for this connection_id to the time wait
   // list manager.
-  EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _, QuicStringPiece("hq")))
+  EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _, QuicStringPiece("hq"), _))
       .Times(0);
   EXPECT_CALL(*time_wait_list_manager_, ProcessPacket(_, _, 1)).Times(1);
   EXPECT_CALL(*time_wait_list_manager_, ProcessPacket(_, _, 2)).Times(1);
@@ -651,7 +652,7 @@
   QuicConnectionId connection_id = 1;
 
   EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address,
-                                              QuicStringPiece("hq")))
+                                              QuicStringPiece("hq"), _))
       .Times(0);
   ParsedQuicVersion version(
       PROTOCOL_QUIC_CRYPTO,
@@ -660,7 +661,7 @@
                 PACKET_8BYTE_CONNECTION_ID, PACKET_4BYTE_PACKET_NUMBER, 1);
   ++connection_id;
   EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address,
-                                              QuicStringPiece("hq")))
+                                              QuicStringPiece("hq"), _))
       .WillOnce(testing::Return(CreateSession(
           dispatcher_.get(), config_, connection_id, client_address,
           &mock_helper_, &mock_alarm_factory_, &crypto_config_,
@@ -672,7 +673,7 @@
             ValidatePacket(connection_id, packet);
           })));
   EXPECT_CALL(*dispatcher_,
-              ShouldCreateOrBufferPacketForConnection(connection_id));
+              ShouldCreateOrBufferPacketForConnection(connection_id, _));
   ProcessPacket(client_address, connection_id, true,
                 ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO,
                                   QuicVersionMin().transport_version),
@@ -680,7 +681,7 @@
                 PACKET_4BYTE_PACKET_NUMBER, 1);
   ++connection_id;
   EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address,
-                                              QuicStringPiece("hq")))
+                                              QuicStringPiece("hq"), _))
       .WillOnce(testing::Return(CreateSession(
           dispatcher_.get(), config_, connection_id, client_address,
           &mock_helper_, &mock_alarm_factory_, &crypto_config_,
@@ -692,7 +693,7 @@
             ValidatePacket(connection_id, packet);
           })));
   EXPECT_CALL(*dispatcher_,
-              ShouldCreateOrBufferPacketForConnection(connection_id));
+              ShouldCreateOrBufferPacketForConnection(connection_id, _));
   ProcessPacket(client_address, connection_id, true, QuicVersionMax(),
                 SerializeCHLO(), PACKET_8BYTE_CONNECTION_ID,
                 PACKET_4BYTE_PACKET_NUMBER, 1);
@@ -701,7 +702,7 @@
   SetQuicReloadableFlag(quic_enable_version_46, false);
   ++connection_id;
   EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address,
-                                              QuicStringPiece("hq")))
+                                              QuicStringPiece("hq"), _))
       .Times(0);
   ProcessPacket(client_address, connection_id, true,
                 ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_46),
@@ -712,7 +713,7 @@
   SetQuicReloadableFlag(quic_enable_version_46, true);
   ++connection_id;
   EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address,
-                                              QuicStringPiece("hq")))
+                                              QuicStringPiece("hq"), _))
       .WillOnce(testing::Return(CreateSession(
           dispatcher_.get(), config_, connection_id, client_address,
           &mock_helper_, &mock_alarm_factory_, &crypto_config_,
@@ -724,7 +725,7 @@
             ValidatePacket(connection_id, packet);
           })));
   EXPECT_CALL(*dispatcher_,
-              ShouldCreateOrBufferPacketForConnection(connection_id));
+              ShouldCreateOrBufferPacketForConnection(connection_id, _));
   ProcessPacket(client_address, connection_id, true,
                 ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_46),
                 SerializeCHLO(), PACKET_8BYTE_CONNECTION_ID,
@@ -734,7 +735,7 @@
   SetQuicReloadableFlag(quic_enable_version_45, false);
   ++connection_id;
   EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address,
-                                              QuicStringPiece("hq")))
+                                              QuicStringPiece("hq"), _))
       .Times(0);
   ProcessPacket(client_address, connection_id, true,
                 ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_45),
@@ -745,7 +746,7 @@
   SetQuicReloadableFlag(quic_enable_version_45, true);
   ++connection_id;
   EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address,
-                                              QuicStringPiece("hq")))
+                                              QuicStringPiece("hq"), _))
       .WillOnce(testing::Return(CreateSession(
           dispatcher_.get(), config_, connection_id, client_address,
           &mock_helper_, &mock_alarm_factory_, &crypto_config_,
@@ -757,7 +758,7 @@
             ValidatePacket(connection_id, packet);
           })));
   EXPECT_CALL(*dispatcher_,
-              ShouldCreateOrBufferPacketForConnection(connection_id));
+              ShouldCreateOrBufferPacketForConnection(connection_id, _));
   ProcessPacket(client_address, connection_id, true,
                 ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_45),
                 SerializeCHLO(), PACKET_8BYTE_CONNECTION_ID,
@@ -767,7 +768,7 @@
   SetQuicReloadableFlag(quic_enable_version_44, false);
   ++connection_id;
   EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address,
-                                              QuicStringPiece("hq")))
+                                              QuicStringPiece("hq"), _))
       .Times(0);
   ProcessPacket(client_address, connection_id, true,
                 ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_44),
@@ -778,7 +779,7 @@
   SetQuicReloadableFlag(quic_enable_version_44, true);
   ++connection_id;
   EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address,
-                                              QuicStringPiece("hq")))
+                                              QuicStringPiece("hq"), _))
       .WillOnce(testing::Return(CreateSession(
           dispatcher_.get(), config_, connection_id, client_address,
           &mock_helper_, &mock_alarm_factory_, &crypto_config_,
@@ -790,7 +791,7 @@
             ValidatePacket(connection_id, packet);
           })));
   EXPECT_CALL(*dispatcher_,
-              ShouldCreateOrBufferPacketForConnection(connection_id));
+              ShouldCreateOrBufferPacketForConnection(connection_id, _));
   ProcessPacket(client_address, connection_id, true,
                 ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_44),
                 SerializeCHLO(), PACKET_8BYTE_CONNECTION_ID,
@@ -800,7 +801,7 @@
   SetQuicReloadableFlag(quic_enable_version_43, false);
   ++connection_id;
   EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address,
-                                              QuicStringPiece("hq")))
+                                              QuicStringPiece("hq"), _))
       .Times(0);
   ProcessPacket(client_address, connection_id, true,
                 ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43),
@@ -811,7 +812,7 @@
   SetQuicReloadableFlag(quic_enable_version_43, true);
   ++connection_id;
   EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address,
-                                              QuicStringPiece("hq")))
+                                              QuicStringPiece("hq"), _))
       .WillOnce(testing::Return(CreateSession(
           dispatcher_.get(), config_, connection_id, client_address,
           &mock_helper_, &mock_alarm_factory_, &crypto_config_,
@@ -823,7 +824,7 @@
             ValidatePacket(connection_id, packet);
           })));
   EXPECT_CALL(*dispatcher_,
-              ShouldCreateOrBufferPacketForConnection(connection_id));
+              ShouldCreateOrBufferPacketForConnection(connection_id, _));
   ProcessPacket(client_address, connection_id, true,
                 ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43),
                 SerializeCHLO(), PACKET_8BYTE_CONNECTION_ID,
@@ -833,7 +834,7 @@
   SetQuicReloadableFlag(quic_disable_version_35, true);
   ++connection_id;
   EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address,
-                                              QuicStringPiece("hq")))
+                                              QuicStringPiece("hq"), _))
       .Times(0);
   ProcessPacket(client_address, connection_id, true,
                 ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_35),
@@ -844,7 +845,7 @@
   SetQuicReloadableFlag(quic_disable_version_35, false);
   ++connection_id;
   EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address,
-                                              QuicStringPiece("hq")))
+                                              QuicStringPiece("hq"), _))
       .WillOnce(testing::Return(CreateSession(
           dispatcher_.get(), config_, connection_id, client_address,
           &mock_helper_, &mock_alarm_factory_, &crypto_config_,
@@ -856,7 +857,7 @@
             ValidatePacket(connection_id, packet);
           })));
   EXPECT_CALL(*dispatcher_,
-              ShouldCreateOrBufferPacketForConnection(connection_id));
+              ShouldCreateOrBufferPacketForConnection(connection_id, _));
   ProcessPacket(client_address, connection_id, true,
                 ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_35),
                 SerializeCHLO(), PACKET_8BYTE_CONNECTION_ID,
@@ -999,7 +1000,7 @@
   QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
   QuicConnectionId connection_id = 1;
   EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address,
-                                              QuicStringPiece("hq")))
+                                              QuicStringPiece("hq"), _))
       .WillOnce(testing::Return(
           CreateSessionBasedOnTestParams(connection_id, client_address)));
   EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
@@ -1009,7 +1010,7 @@
             ValidatePacket(connection_id, packet);
           })));
   EXPECT_CALL(*dispatcher_,
-              ShouldCreateOrBufferPacketForConnection(connection_id))
+              ShouldCreateOrBufferPacketForConnection(connection_id, _))
       .Times(1);
 
   // Process the first packet for the connection.
@@ -1053,11 +1054,11 @@
   QuicConnectionId connection_id = 1;
   if (GetParam().enable_stateless_rejects_via_flag) {
     EXPECT_CALL(*dispatcher_,
-                CreateQuicSession(connection_id, client_address, _))
+                CreateQuicSession(connection_id, client_address, _, _))
         .Times(0);
   } else {
     EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address,
-                                                QuicStringPiece("h2")))
+                                                QuicStringPiece("h2"), _))
         .WillOnce(testing::Return(
             CreateSessionBasedOnTestParams(connection_id, client_address)));
     EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
@@ -1084,7 +1085,7 @@
         .Times(1);
   } else {
     EXPECT_CALL(*dispatcher_,
-                ShouldCreateOrBufferPacketForConnection(connection_id))
+                ShouldCreateOrBufferPacketForConnection(connection_id, _))
         .Times(1);
   }
   ProcessPacket(client_address, connection_id, true,
@@ -1104,7 +1105,7 @@
   const QuicConnectionId connection_id = 1;
 
   EXPECT_CALL(*dispatcher_,
-              ShouldCreateOrBufferPacketForConnection(connection_id))
+              ShouldCreateOrBufferPacketForConnection(connection_id, _))
       .Times(1);
   ProcessPacket(client_address, connection_id, true, "NOT DATA FOR A CHLO");
 
@@ -1120,7 +1121,7 @@
   // If stateless rejects are enabled then a connection will be created now
   // and the buffered packet will be processed
   EXPECT_CALL(*dispatcher_, CreateQuicSession(connection_id, client_address,
-                                              QuicStringPiece("h3")))
+                                              QuicStringPiece("h3"), _))
       .WillOnce(testing::Return(
           CreateSessionBasedOnTestParams(connection_id, client_address)));
   EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
@@ -1153,7 +1154,7 @@
 
   QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
   QuicConnectionId connection_id = 1;
-  EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _, QuicStringPiece("hq")))
+  EXPECT_CALL(*dispatcher_, CreateQuicSession(_, _, QuicStringPiece("hq"), _))
       .Times(0);
   if (CurrentSupportedVersions()[0].transport_version > QUIC_VERSION_43) {
     // This IETF packet has invalid connection ID length.
@@ -1203,7 +1204,7 @@
     QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
 
     EXPECT_CALL(*dispatcher_,
-                CreateQuicSession(_, client_address, QuicStringPiece("hq")))
+                CreateQuicSession(_, client_address, QuicStringPiece("hq"), _))
         .WillOnce(testing::Return(CreateSession(
             dispatcher_.get(), config_, 1, client_address, &helper_,
             &alarm_factory_, &crypto_config_,
@@ -1213,11 +1214,11 @@
         .WillOnce(WithArg<2>(Invoke([this](const QuicEncryptedPacket& packet) {
           ValidatePacket(1, packet);
         })));
-    EXPECT_CALL(*dispatcher_, ShouldCreateOrBufferPacketForConnection(1));
+    EXPECT_CALL(*dispatcher_, ShouldCreateOrBufferPacketForConnection(1, _));
     ProcessPacket(client_address, 1, true, SerializeCHLO());
 
     EXPECT_CALL(*dispatcher_,
-                CreateQuicSession(_, client_address, QuicStringPiece("hq")))
+                CreateQuicSession(_, client_address, QuicStringPiece("hq"), _))
         .WillOnce(testing::Return(CreateSession(
             dispatcher_.get(), config_, 2, client_address, &helper_,
             &alarm_factory_, &crypto_config_,
@@ -1227,7 +1228,7 @@
         .WillOnce(WithArg<2>(Invoke([this](const QuicEncryptedPacket& packet) {
           ValidatePacket(2, packet);
         })));
-    EXPECT_CALL(*dispatcher_, ShouldCreateOrBufferPacketForConnection(2));
+    EXPECT_CALL(*dispatcher_, ShouldCreateOrBufferPacketForConnection(2, _));
     ProcessPacket(client_address, 2, true, SerializeCHLO());
 
     blocked_list_ = QuicDispatcherPeer::GetWriteBlockedList(dispatcher_.get());
@@ -1474,7 +1475,7 @@
   QuicConnectionId conn_id = 1;
   // A bunch of non-CHLO should be buffered upon arrival, and the first one
   // should trigger ShouldCreateOrBufferPacketForConnection().
-  EXPECT_CALL(*dispatcher_, ShouldCreateOrBufferPacketForConnection(conn_id))
+  EXPECT_CALL(*dispatcher_, ShouldCreateOrBufferPacketForConnection(conn_id, _))
       .Times(1);
   for (size_t i = 1; i <= kDefaultMaxUndecryptablePackets + 1; ++i) {
     ProcessPacket(client_address, conn_id, true,
@@ -1489,7 +1490,7 @@
   // When CHLO arrives, a new session should be created, and all packets
   // buffered should be delivered to the session.
   EXPECT_CALL(*dispatcher_,
-              CreateQuicSession(conn_id, client_address, QuicStringPiece()))
+              CreateQuicSession(conn_id, client_address, QuicStringPiece(), _))
       .WillOnce(testing::Return(CreateSession(
           dispatcher_.get(), config_, conn_id, client_address, &mock_helper_,
           &mock_alarm_factory_, &crypto_config_,
@@ -1516,7 +1517,8 @@
   for (size_t i = 1; i <= kNumConnections; ++i) {
     QuicSocketAddress client_address(QuicIpAddress::Loopback4(), i);
     QuicConnectionId conn_id = i;
-    EXPECT_CALL(*dispatcher_, ShouldCreateOrBufferPacketForConnection(conn_id));
+    EXPECT_CALL(*dispatcher_,
+                ShouldCreateOrBufferPacketForConnection(conn_id, _));
     ProcessPacket(client_address, conn_id, true,
                   QuicStrCat("data packet on connection ", i),
                   PACKET_8BYTE_CONNECTION_ID, PACKET_4BYTE_PACKET_NUMBER,
@@ -1537,10 +1539,10 @@
     QuicConnectionId conn_id = i;
     if (conn_id == kNumConnections) {
       EXPECT_CALL(*dispatcher_,
-                  ShouldCreateOrBufferPacketForConnection(conn_id));
+                  ShouldCreateOrBufferPacketForConnection(conn_id, _));
     }
-    EXPECT_CALL(*dispatcher_,
-                CreateQuicSession(conn_id, client_address, QuicStringPiece()))
+    EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id, client_address,
+                                                QuicStringPiece(), _))
         .WillOnce(testing::Return(CreateSession(
             dispatcher_.get(), config_, conn_id, client_address, &mock_helper_,
             &mock_alarm_factory_, &crypto_config_,
@@ -1564,9 +1566,10 @@
 TEST_P(BufferedPacketStoreTest, DeliverEmptyPackets) {
   QuicConnectionId conn_id = 1;
   QuicSocketAddress client_address(QuicIpAddress::Loopback4(), 1);
-  EXPECT_CALL(*dispatcher_, ShouldCreateOrBufferPacketForConnection(conn_id));
   EXPECT_CALL(*dispatcher_,
-              CreateQuicSession(conn_id, client_address, QuicStringPiece()))
+              ShouldCreateOrBufferPacketForConnection(conn_id, _));
+  EXPECT_CALL(*dispatcher_,
+              CreateQuicSession(conn_id, client_address, QuicStringPiece(), _))
       .WillOnce(testing::Return(CreateSession(
           dispatcher_.get(), config_, conn_id, client_address, &mock_helper_,
           &mock_alarm_factory_, &crypto_config_,
@@ -1590,7 +1593,7 @@
   // When CHLO arrives, a new session should be created, and all packets
   // buffered should be delivered to the session.
   EXPECT_CALL(*dispatcher_,
-              CreateQuicSession(conn_id, client_address, QuicStringPiece()))
+              CreateQuicSession(conn_id, client_address, QuicStringPiece(), _))
       .Times(1)  // Only triggered by 1st CHLO.
       .WillOnce(testing::Return(CreateSession(
           dispatcher_.get(), config_, conn_id, client_address, &mock_helper_,
@@ -1647,10 +1650,11 @@
   const size_t kNumCHLOs =
       kMaxNumSessionsToCreate + kDefaultMaxConnectionsInStore + 1;
   for (size_t conn_id = 1; conn_id <= kNumCHLOs; ++conn_id) {
-    EXPECT_CALL(*dispatcher_, ShouldCreateOrBufferPacketForConnection(conn_id));
+    EXPECT_CALL(*dispatcher_,
+                ShouldCreateOrBufferPacketForConnection(conn_id, _));
     if (conn_id <= kMaxNumSessionsToCreate) {
-      EXPECT_CALL(*dispatcher_,
-                  CreateQuicSession(conn_id, client_addr_, QuicStringPiece()))
+      EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id, client_addr_,
+                                                  QuicStringPiece(), _))
           .WillOnce(testing::Return(CreateSession(
               dispatcher_.get(), config_, conn_id, client_addr_, &mock_helper_,
               &mock_alarm_factory_, &crypto_config_,
@@ -1681,7 +1685,7 @@
        conn_id <= kMaxNumSessionsToCreate + kDefaultMaxConnectionsInStore;
        ++conn_id) {
     EXPECT_CALL(*dispatcher_,
-                CreateQuicSession(conn_id, client_addr_, QuicStringPiece()))
+                CreateQuicSession(conn_id, client_addr_, QuicStringPiece(), _))
         .WillOnce(testing::Return(CreateSession(
             dispatcher_.get(), config_, conn_id, client_addr_, &mock_helper_,
             &mock_alarm_factory_, &crypto_config_,
@@ -1694,7 +1698,7 @@
             })));
   }
   EXPECT_CALL(*dispatcher_,
-              CreateQuicSession(kNumCHLOs, client_addr_, QuicStringPiece()))
+              CreateQuicSession(kNumCHLOs, client_addr_, QuicStringPiece(), _))
       .Times(0);
 
   while (store->HasChlosBuffered()) {
@@ -1712,8 +1716,8 @@
        ++conn_id) {
     // Last CHLO will be buffered. Others will create connection right away.
     if (conn_id <= kMaxNumSessionsToCreate) {
-      EXPECT_CALL(*dispatcher_,
-                  CreateQuicSession(conn_id, client_addr_, QuicStringPiece()))
+      EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id, client_addr_,
+                                                  QuicStringPiece(), _))
           .WillOnce(testing::Return(CreateSession(
               dispatcher_.get(), config_, conn_id, client_addr_, &mock_helper_,
               &mock_alarm_factory_, &crypto_config_,
@@ -1736,7 +1740,7 @@
 
   // Reset counter and process buffered CHLO.
   EXPECT_CALL(*dispatcher_, CreateQuicSession(last_connection, client_addr_,
-                                              QuicStringPiece()))
+                                              QuicStringPiece(), _))
       .WillOnce(testing::Return(CreateSession(
           dispatcher_.get(), config_, last_connection, client_addr_,
           &mock_helper_, &mock_alarm_factory_, &crypto_config_,
@@ -1757,8 +1761,8 @@
   for (QuicConnectionId conn_id = 1; conn_id <= last_connection_id; ++conn_id) {
     // Last CHLO will be buffered. Others will create connection right away.
     if (conn_id <= kMaxNumSessionsToCreate) {
-      EXPECT_CALL(*dispatcher_,
-                  CreateQuicSession(conn_id, client_addr_, QuicStringPiece()))
+      EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id, client_addr_,
+                                                  QuicStringPiece(), _))
           .WillOnce(testing::Return(CreateSession(
               dispatcher_.get(), config_, conn_id, client_addr_, &mock_helper_,
               &mock_alarm_factory_, &crypto_config_,
@@ -1783,7 +1787,7 @@
 
   // Reset counter and process buffered CHLO.
   EXPECT_CALL(*dispatcher_, CreateQuicSession(last_connection_id, client_addr_,
-                                              QuicStringPiece()))
+                                              QuicStringPiece(), _))
       .WillOnce(testing::Return(CreateSession(
           dispatcher_.get(), config_, last_connection_id, client_addr_,
           &mock_helper_, &mock_alarm_factory_, &crypto_config_,
@@ -1817,8 +1821,8 @@
        conn_id <= kDefaultMaxConnectionsInStore + kMaxNumSessionsToCreate;
        ++conn_id) {
     if (conn_id <= kMaxNumSessionsToCreate + 1) {
-      EXPECT_CALL(*dispatcher_,
-                  CreateQuicSession(conn_id, client_addr_, QuicStringPiece()))
+      EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id, client_addr_,
+                                                  QuicStringPiece(), _))
           .WillOnce(testing::Return(CreateSession(
               dispatcher_.get(), config_, conn_id, client_addr_, &mock_helper_,
               &mock_alarm_factory_, &crypto_config_,
@@ -1840,6 +1844,54 @@
   EXPECT_TRUE(store->HasChloForConnection(/*connection_id=*/1));
 }
 
+// Regression test for b/117874922.
+TEST_P(BufferedPacketStoreTest, ProcessBufferedChloWithDifferentVersion) {
+  QuicConnectionId last_connection_id = kMaxNumSessionsToCreate + 5;
+  ParsedQuicVersionVector supported_versions = CurrentSupportedVersions();
+  for (QuicConnectionId conn_id = 1; conn_id <= last_connection_id; ++conn_id) {
+    // Last 5 CHLOs will be buffered. Others will create connection right away.
+    ParsedQuicVersion version =
+        supported_versions[(conn_id - 1) % supported_versions.size()];
+    if (conn_id <= kMaxNumSessionsToCreate) {
+      EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id, client_addr_,
+                                                  QuicStringPiece(), version))
+          .WillOnce(testing::Return(CreateSession(
+              dispatcher_.get(), config_, conn_id, client_addr_, &mock_helper_,
+              &mock_alarm_factory_, &crypto_config_,
+              QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_)));
+      EXPECT_CALL(
+          *reinterpret_cast<MockQuicConnection*>(session1_->connection()),
+          ProcessUdpPacket(_, _, _))
+          .WillRepeatedly(WithArg<2>(
+              Invoke([this, conn_id](const QuicEncryptedPacket& packet) {
+                ValidatePacket(conn_id, packet);
+              })));
+    }
+    ProcessPacket(client_addr_, conn_id, true, version, SerializeFullCHLO(),
+                  PACKET_8BYTE_CONNECTION_ID, PACKET_4BYTE_PACKET_NUMBER, 1);
+  }
+
+  // Process buffered CHLOs. Verify the version is correct.
+  for (QuicConnectionId conn_id = kMaxNumSessionsToCreate + 1;
+       conn_id <= last_connection_id; ++conn_id) {
+    ParsedQuicVersion version =
+        supported_versions[(conn_id - 1) % supported_versions.size()];
+    EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id, client_addr_,
+                                                QuicStringPiece(), version))
+        .WillOnce(testing::Return(CreateSession(
+            dispatcher_.get(), config_, conn_id, client_addr_, &mock_helper_,
+            &mock_alarm_factory_, &crypto_config_,
+            QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_)));
+    EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
+                ProcessUdpPacket(_, _, _))
+        .WillRepeatedly(WithArg<2>(
+            Invoke([this, conn_id](const QuicEncryptedPacket& packet) {
+              ValidatePacket(conn_id, packet);
+            })));
+  }
+  dispatcher_->ProcessBufferedChlos(kMaxNumSessionsToCreate);
+}
+
 // Test which exercises the async GetProof codepaths, especially in the context
 // of stateless rejection.
 class AsyncGetProofTest : public QuicDispatcherTest {
@@ -1952,9 +2004,10 @@
     InSequence s;
 
     EXPECT_CALL(check, Call(1));
-    EXPECT_CALL(*dispatcher_, ShouldCreateOrBufferPacketForConnection(conn_id));
+    EXPECT_CALL(*dispatcher_,
+                ShouldCreateOrBufferPacketForConnection(conn_id, _));
     EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id, client_addr_,
-                                                QuicStringPiece("HTTP/1")))
+                                                QuicStringPiece("HTTP/1"), _))
         .WillOnce(testing::Return(GetSession(conn_id, client_addr_)));
     EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(
                     GetSession(conn_id, client_addr_)->connection()),
@@ -1998,10 +2051,10 @@
     InSequence s;
     EXPECT_CALL(check, Call(1));
     EXPECT_CALL(*dispatcher_,
-                ShouldCreateOrBufferPacketForConnection(conn_id_1));
+                ShouldCreateOrBufferPacketForConnection(conn_id_1, _));
 
     EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id_1, client_addr_,
-                                                QuicStringPiece("HTTP/1")))
+                                                QuicStringPiece("HTTP/1"), _))
         .WillOnce(testing::Return(GetSession(conn_id_1, client_addr_)));
     EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(
                     GetSession(conn_id_1, client_addr_)->connection()),
@@ -2014,9 +2067,9 @@
     EXPECT_CALL(check, Call(2));
 
     EXPECT_CALL(*dispatcher_,
-                ShouldCreateOrBufferPacketForConnection(conn_id_2));
+                ShouldCreateOrBufferPacketForConnection(conn_id_2, _));
     EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id_2, client_addr_2_,
-                                                QuicStringPiece("HTTP/1")))
+                                                QuicStringPiece("HTTP/1"), _))
         .WillOnce(testing::Return(GetSession(conn_id_2, client_addr_2_)));
     EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(
                     GetSession(conn_id_2, client_addr_2_)->connection()),
@@ -2089,8 +2142,8 @@
                 ProcessPacket(_, client_addr_, conn_id));
 
     EXPECT_CALL(check, Call(2));
-    EXPECT_CALL(*dispatcher_,
-                CreateQuicSession(conn_id, client_addr_, QuicStringPiece("hq")))
+    EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id, client_addr_,
+                                                QuicStringPiece("hq"), _))
         .Times(0);
     EXPECT_CALL(*time_wait_list_manager_,
                 ProcessPacket(_, client_addr_, conn_id));
@@ -2124,9 +2177,9 @@
     InSequence s;
     EXPECT_CALL(check, Call(1));
     EXPECT_CALL(*dispatcher_,
-                ShouldCreateOrBufferPacketForConnection(conn_id_2));
+                ShouldCreateOrBufferPacketForConnection(conn_id_2, _));
     EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id_2, client_addr_,
-                                                QuicStringPiece("HTTP/1")))
+                                                QuicStringPiece("HTTP/1"), _))
         .WillOnce(testing::Return(GetSession(conn_id_2, client_addr_)));
     EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(
                     GetSession(conn_id_2, client_addr_)->connection()),
@@ -2147,11 +2200,11 @@
 
     EXPECT_CALL(check, Call(3));
     EXPECT_CALL(*dispatcher_,
-                ShouldCreateOrBufferPacketForConnection(conn_id_1));
+                ShouldCreateOrBufferPacketForConnection(conn_id_1, _));
 
     EXPECT_CALL(check, Call(4));
     EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id_1, client_addr_,
-                                                QuicStringPiece("HTTP/1")))
+                                                QuicStringPiece("HTTP/1"), _))
         .WillOnce(testing::Return(GetSession(conn_id_1, client_addr_)));
     EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(
                     GetSession(conn_id_1, client_addr_)->connection()),
@@ -2209,7 +2262,7 @@
     InSequence s;
 
     EXPECT_CALL(check, Call(1));
-    EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id_2, client_addr_, _))
+    EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id_2, client_addr_, _, _))
         .Times(0);
     EXPECT_CALL(*time_wait_list_manager_,
                 AddConnectionIdToTimeWait(conn_id_2, _, _, _));
@@ -2222,7 +2275,7 @@
 
     EXPECT_CALL(check, Call(3));
     EXPECT_CALL(*dispatcher_,
-                ShouldCreateOrBufferPacketForConnection(conn_id_1));
+                ShouldCreateOrBufferPacketForConnection(conn_id_1, _));
 
     EXPECT_CALL(check, Call(4));
     EXPECT_CALL(*time_wait_list_manager_,
@@ -2279,11 +2332,11 @@
     InSequence s;
     EXPECT_CALL(check, Call(1));
     EXPECT_CALL(*dispatcher_,
-                ShouldCreateOrBufferPacketForConnection(conn_id_1));
+                ShouldCreateOrBufferPacketForConnection(conn_id_1, _));
 
     EXPECT_CALL(check, Call(2));
-    EXPECT_CALL(*dispatcher_,
-                CreateQuicSession(conn_id_1, client_addr_, QuicStringPiece()))
+    EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id_1, client_addr_,
+                                                QuicStringPiece(), _))
         .Times(0);
     EXPECT_CALL(*time_wait_list_manager_,
                 AddConnectionIdToTimeWait(conn_id_1, _, _, _));
@@ -2324,13 +2377,14 @@
   {
     InSequence s;
     EXPECT_CALL(check, Call(1));
-    EXPECT_CALL(*dispatcher_, ShouldCreateOrBufferPacketForConnection(conn_id));
+    EXPECT_CALL(*dispatcher_,
+                ShouldCreateOrBufferPacketForConnection(conn_id, _));
 
     EXPECT_CALL(check, Call(2));
     EXPECT_CALL(*time_wait_list_manager_,
                 ProcessPacket(_, client_addr_, conn_id));
     EXPECT_CALL(*dispatcher_,
-                CreateQuicSession(conn_id, client_addr_, QuicStringPiece()))
+                CreateQuicSession(conn_id, client_addr_, QuicStringPiece(), _))
         .Times(0);
   }
 
@@ -2378,12 +2432,14 @@
   {
     InSequence s;
     EXPECT_CALL(check, Call(1));
-    EXPECT_CALL(*dispatcher_, ShouldCreateOrBufferPacketForConnection(conn_id));
+    EXPECT_CALL(*dispatcher_,
+                ShouldCreateOrBufferPacketForConnection(conn_id, _));
 
     EXPECT_CALL(check, Call(2));
-    EXPECT_CALL(*dispatcher_, ShouldCreateOrBufferPacketForConnection(conn_id));
+    EXPECT_CALL(*dispatcher_,
+                ShouldCreateOrBufferPacketForConnection(conn_id, _));
     EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id, client_addr_,
-                                                QuicStringPiece("HTTP/1")))
+                                                QuicStringPiece("HTTP/1"), _))
         .WillOnce(testing::Return(GetSession(conn_id, client_addr_)));
     EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(
                     GetSession(conn_id, client_addr_)->connection()),
@@ -2473,25 +2529,25 @@
                 ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_44),
                 SerializeCHLO(), PACKET_8BYTE_CONNECTION_ID,
                 PACKET_4BYTE_PACKET_NUMBER, 1);
-  EXPECT_TRUE(dispatcher_->framer()->last_packet_is_ietf_quic());
+  EXPECT_NE(GOOGLE_QUIC_PACKET, dispatcher_->GetLastPacketFormat());
 
   // Process another packet of v43.
   ProcessPacket(client_addr_, 2, true,
                 ParsedQuicVersion(PROTOCOL_QUIC_CRYPTO, QUIC_VERSION_43),
                 SerializeCHLO(), PACKET_8BYTE_CONNECTION_ID,
                 PACKET_4BYTE_PACKET_NUMBER, 1);
-  EXPECT_FALSE(dispatcher_->framer()->last_packet_is_ietf_quic());
+  EXPECT_EQ(GOOGLE_QUIC_PACKET, dispatcher_->GetLastPacketFormat());
   ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 2);
 
   // Complete the ProofSource::GetProof call for v44.
   GetFakeProofSource()->InvokePendingCallback(0);
   // Verify the last_packet_is_ietf_quic gets reset properly.
-  EXPECT_TRUE(dispatcher_->framer()->last_packet_is_ietf_quic());
+  EXPECT_NE(GOOGLE_QUIC_PACKET, dispatcher_->GetLastPacketFormat());
   ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 1);
 
   // Complete the ProofSource::GetProof call for v43.
   GetFakeProofSource()->InvokePendingCallback(0);
-  EXPECT_FALSE(dispatcher_->framer()->last_packet_is_ietf_quic());
+  EXPECT_EQ(GOOGLE_QUIC_PACKET, dispatcher_->GetLastPacketFormat());
   ASSERT_EQ(GetFakeProofSource()->NumPendingCallbacks(), 0);
 }
 
diff --git a/net/third_party/quic/core/quic_framer.cc b/net/third_party/quic/core/quic_framer.cc
index 0b0b94b..7e56b43 100644
--- a/net/third_party/quic/core/quic_framer.cc
+++ b/net/third_party/quic/core/quic_framer.cc
@@ -241,8 +241,7 @@
       largest_packet_number_(0),
       last_serialized_connection_id_(0),
       last_version_label_(0),
-      last_packet_is_ietf_quic_(false),
-      last_header_form_(LONG_HEADER),
+      last_header_form_(GOOGLE_QUIC_PACKET),
       version_(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED),
       supported_versions_(supported_versions),
       decrypter_level_(ENCRYPTION_NONE),
@@ -1270,14 +1269,14 @@
 bool QuicFramer::ProcessPacket(const QuicEncryptedPacket& packet) {
   QuicDataReader reader(packet.data(), packet.length(), endianness());
 
-  last_packet_is_ietf_quic_ = false;
+  bool last_packet_is_ietf_quic = false;
   if (perspective_ == Perspective::IS_CLIENT) {
-    last_packet_is_ietf_quic_ = version_.transport_version > QUIC_VERSION_43;
+    last_packet_is_ietf_quic = version_.transport_version > QUIC_VERSION_43;
   } else if (!reader.IsDoneReading()) {
     uint8_t type = reader.PeekByte();
-    last_packet_is_ietf_quic_ = QuicUtils::IsIetfPacketHeader(type);
+    last_packet_is_ietf_quic = QuicUtils::IsIetfPacketHeader(type);
   }
-  if (last_packet_is_ietf_quic_) {
+  if (last_packet_is_ietf_quic) {
     QUIC_DVLOG(1) << ENDPOINT << "Processing IETF QUIC packet.";
     reader.set_endianness(NETWORK_BYTE_ORDER);
   }
@@ -1285,13 +1284,14 @@
   visitor_->OnPacket();
 
   QuicPacketHeader header;
-  if (!ProcessPublicHeader(&reader, &header)) {
+  if (!ProcessPublicHeader(&reader, last_packet_is_ietf_quic, &header)) {
     DCHECK_NE("", detailed_error_);
     QUIC_DVLOG(1) << ENDPOINT << "Unable to process public header. Error: "
                   << detailed_error_;
     DCHECK_NE("", detailed_error_);
     return RaiseError(QUIC_INVALID_PACKET_HEADER);
   }
+  last_header_form_ = header.form;
 
   if (!visitor_->OnUnauthenticatedPublicHeader(header)) {
     // The visitor suppresses further processing of the packet.
@@ -1300,7 +1300,7 @@
 
   if (perspective_ == Perspective::IS_SERVER && header.version_flag &&
       header.version != version_) {
-    if (!visitor_->OnProtocolVersionMismatch(header.version)) {
+    if (!visitor_->OnProtocolVersionMismatch(header.version, header.form)) {
       return true;
     }
   }
@@ -1309,7 +1309,7 @@
   reader.set_endianness(endianness());
 
   bool rv;
-  if (IsVersionNegotiation(header)) {
+  if (IsVersionNegotiation(header, last_packet_is_ietf_quic)) {
     QUIC_DVLOG(1) << ENDPOINT << "Received version negotiation packet";
     rv = ProcessVersionNegotiationPacket(&reader, header);
   } else if (header.reset_flag) {
@@ -1318,7 +1318,7 @@
     // The optimized decryption algorithm implementations run faster when
     // operating on aligned memory.
     QUIC_CACHELINE_ALIGNED char buffer[kMaxPacketSize];
-    if (last_packet_is_ietf_quic_) {
+    if (last_packet_is_ietf_quic) {
       rv = ProcessIetfDataPacket(&reader, &header, packet, buffer,
                                  kMaxPacketSize);
     } else {
@@ -1326,7 +1326,7 @@
     }
   } else {
     std::unique_ptr<char[]> large_buffer(new char[packet.length()]);
-    if (last_packet_is_ietf_quic_) {
+    if (last_packet_is_ietf_quic) {
       rv = ProcessIetfDataPacket(&reader, &header, packet, large_buffer.get(),
                                  packet.length());
     } else {
@@ -1366,8 +1366,9 @@
                                        const QuicEncryptedPacket& packet,
                                        char* decrypted_buffer,
                                        size_t buffer_length) {
+  DCHECK_NE(GOOGLE_QUIC_PACKET, header->form);
   DCHECK(!header->has_possible_stateless_reset_token);
-  if (header->form == SHORT_HEADER) {
+  if (header->form == IETF_QUIC_SHORT_HEADER_PACKET) {
     if (!process_stateless_reset_at_client_only_) {
       // Peak possible stateless reset token. Will only be used on decryption
       // failure.
@@ -1400,7 +1401,7 @@
     }
   }
 
-  if (header->form == SHORT_HEADER ||
+  if (header->form == IETF_QUIC_SHORT_HEADER_PACKET ||
       header->long_packet_type != VERSION_NEGOTIATION) {
     // Process packet number.
     QuicPacketNumber base_packet_number = largest_packet_number_;
@@ -1427,7 +1428,7 @@
 
   // A nonce should only present in SHLO from the server to the client when
   // using QUIC crypto.
-  if (header->form == LONG_HEADER &&
+  if (header->form == IETF_QUIC_LONG_HEADER_PACKET &&
       header->long_packet_type == ZERO_RTT_PROTECTED &&
       perspective_ == Perspective::IS_CLIENT) {
     if (!encrypted_reader->ReadBytes(
@@ -1591,7 +1592,7 @@
 bool QuicFramer::IsIetfStatelessResetPacket(
     const QuicPacketHeader& header) const {
   return perspective_ == Perspective::IS_CLIENT &&
-         header.form == SHORT_HEADER &&
+         header.form == IETF_QUIC_SHORT_HEADER_PACKET &&
          (!process_stateless_reset_at_client_only_ ||
           header.has_possible_stateless_reset_token) &&
          visitor_->IsValidStatelessResetToken(
@@ -1772,8 +1773,9 @@
 }
 
 bool QuicFramer::ProcessPublicHeader(QuicDataReader* reader,
+                                     bool last_packet_is_ietf_quic,
                                      QuicPacketHeader* header) {
-  if (last_packet_is_ietf_quic_) {
+  if (last_packet_is_ietf_quic) {
     return ProcessIetfPacketHeader(reader, header);
   }
   uint8_t public_flags;
@@ -1954,9 +1956,9 @@
     return false;
   }
   // Determine whether this is a long or short header.
-  header->form = type & FLAGS_LONG_HEADER ? LONG_HEADER : SHORT_HEADER;
-  last_header_form_ = header->form;
-  if (header->form == LONG_HEADER) {
+  header->form = type & FLAGS_LONG_HEADER ? IETF_QUIC_LONG_HEADER_PACKET
+                                          : IETF_QUIC_SHORT_HEADER_PACKET;
+  if (header->form == IETF_QUIC_LONG_HEADER_PACKET) {
     // Get long packet type.
     header->long_packet_type =
         static_cast<QuicLongHeaderType>(type & kQuicLongHeaderTypeMask);
@@ -2008,7 +2010,7 @@
   }
 
   QuicVersionLabel version_label;
-  if (header->form == LONG_HEADER) {
+  if (header->form == IETF_QUIC_LONG_HEADER_PACKET) {
     // Read version tag.
     if (!reader->ReadTag(&version_label)) {
       set_detailed_error("Unable to read protocol version.");
@@ -4493,14 +4495,15 @@
   return false;
 }
 
-bool QuicFramer::IsVersionNegotiation(const QuicPacketHeader& header) const {
+bool QuicFramer::IsVersionNegotiation(const QuicPacketHeader& header,
+                                      bool last_packet_is_ietf_quic) const {
   if (perspective_ == Perspective::IS_SERVER) {
     return false;
   }
-  if (!last_packet_is_ietf_quic_) {
+  if (!last_packet_is_ietf_quic) {
     return header.version_flag;
   }
-  if (header.form == SHORT_HEADER) {
+  if (header.form == IETF_QUIC_SHORT_HEADER_PACKET) {
     return false;
   }
   return header.long_packet_type == VERSION_NEGOTIATION;
@@ -4531,11 +4534,7 @@
 }
 
 PacketHeaderFormat QuicFramer::GetLastPacketFormat() const {
-  if (!last_packet_is_ietf_quic_) {
-    return GOOGLE_QUIC_PACKET;
-  }
-  return last_header_form_ == LONG_HEADER ? IETF_QUIC_LONG_HEADER_PACKET
-                                          : IETF_QUIC_SHORT_HEADER_PACKET;
+  return last_header_form_;
 }
 
 bool QuicFramer::AppendIetfConnectionCloseFrame(
diff --git a/net/third_party/quic/core/quic_framer.h b/net/third_party/quic/core/quic_framer.h
index 62b367de..203f64f 100644
--- a/net/third_party/quic/core/quic_framer.h
+++ b/net/third_party/quic/core/quic_framer.h
@@ -77,8 +77,8 @@
   // |quic_version_|. The visitor should return true after it updates the
   // version of the |framer_| to |received_version| or false to stop processing
   // this packet.
-  virtual bool OnProtocolVersionMismatch(
-      ParsedQuicVersion received_version) = 0;
+  virtual bool OnProtocolVersionMismatch(ParsedQuicVersion received_version,
+                                         PacketHeaderFormat form) = 0;
 
   // Called when a new packet has been received, before it
   // has been validated or processed.
@@ -499,6 +499,9 @@
   bool IsIetfStatelessResetPacket(const QuicPacketHeader& header) const;
 
   // Returns header wire format of last received packet.
+  // Please do not use this method.
+  // TODO(fayang): Remove last_header_form_ when deprecating
+  // quic_reloadable_flag_quic_proxy_use_real_packet_format_when_reject.
   PacketHeaderFormat GetLastPacketFormat() const;
 
   void set_validate_flags(bool value) { validate_flags_ = value; }
@@ -507,10 +510,8 @@
 
   QuicVersionLabel last_version_label() const { return last_version_label_; }
 
-  bool last_packet_is_ietf_quic() const { return last_packet_is_ietf_quic_; }
-
-  void set_last_packet_is_ietf_quic(bool last_packet_is_ietf_quic) {
-    last_packet_is_ietf_quic_ = last_packet_is_ietf_quic;
+  void set_last_packet_form(PacketHeaderFormat form) {
+    last_header_form_ = form;
   }
 
   void set_data_producer(QuicStreamFrameDataProducer* data_producer) {
@@ -570,7 +571,9 @@
   bool ProcessVersionNegotiationPacket(QuicDataReader* reader,
                                        const QuicPacketHeader& header);
 
-  bool ProcessPublicHeader(QuicDataReader* reader, QuicPacketHeader* header);
+  bool ProcessPublicHeader(QuicDataReader* reader,
+                           bool last_packet_is_ietf_quic,
+                           QuicPacketHeader* header);
 
   // Processes the unauthenticated portion of the header into |header| from
   // the current QuicDataReader.  Returns true on success, false on failure.
@@ -798,7 +801,8 @@
   bool RaiseError(QuicErrorCode error);
 
   // Returns true if |header| indicates a version negotiation packet.
-  bool IsVersionNegotiation(const QuicPacketHeader& header) const;
+  bool IsVersionNegotiation(const QuicPacketHeader& header,
+                            bool last_packet_is_ietf_quic) const;
 
   // Calculates and returns type byte of stream frame.
   uint8_t GetStreamFrameTypeByte(const QuicStreamFrame& frame,
@@ -819,11 +823,9 @@
   QuicConnectionId last_serialized_connection_id_;
   // The last QUIC version label received.
   QuicVersionLabel last_version_label_;
-  // Whether last received packet is IETF QUIC packet.
-  bool last_packet_is_ietf_quic_;
-  // Whether last received IETF QUIC packet has long or short header. Only used
-  // when last_packet_is_ietf_quic_ is true.
-  QuicIetfPacketHeaderForm last_header_form_;
+  // Format of last received packet header, whether it is Google QUIC, IETF long
+  // header packet or IETF short header packet.
+  PacketHeaderFormat last_header_form_;
   // Version of the protocol being used.
   ParsedQuicVersion version_;
   // This vector contains QUIC versions which we currently support.
diff --git a/net/third_party/quic/core/quic_framer_test.cc b/net/third_party/quic/core/quic_framer_test.cc
index d0a79171..b262bca 100644
--- a/net/third_party/quic/core/quic_framer_test.cc
+++ b/net/third_party/quic/core/quic_framer_test.cc
@@ -178,7 +178,8 @@
         QuicMakeUnique<QuicVersionNegotiationPacket>((packet));
   }
 
-  bool OnProtocolVersionMismatch(ParsedQuicVersion received_version) override {
+  bool OnProtocolVersionMismatch(ParsedQuicVersion received_version,
+                                 PacketHeaderFormat /*form*/) override {
     QUIC_DLOG(INFO) << "QuicFramer Version Mismatch, version: "
                     << received_version;
     ++version_mismatch_;
diff --git a/net/third_party/quic/core/quic_ietf_framer_test.cc b/net/third_party/quic/core/quic_ietf_framer_test.cc
index 8e5810f..515f4ea 100644
--- a/net/third_party/quic/core/quic_ietf_framer_test.cc
+++ b/net/third_party/quic/core/quic_ietf_framer_test.cc
@@ -93,7 +93,8 @@
   void OnVersionNegotiationPacket(
       const QuicVersionNegotiationPacket& packet) override {}
 
-  bool OnProtocolVersionMismatch(ParsedQuicVersion received_version) override {
+  bool OnProtocolVersionMismatch(ParsedQuicVersion received_version,
+                                 PacketHeaderFormat form) override {
     return true;
   }
 
diff --git a/net/third_party/quic/core/quic_packets.cc b/net/third_party/quic/core/quic_packets.cc
index 4b956a9..900cc58 100644
--- a/net/third_party/quic/core/quic_packets.cc
+++ b/net/third_party/quic/core/quic_packets.cc
@@ -76,7 +76,7 @@
           ParsedQuicVersion(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED)),
       nonce(nullptr),
       packet_number(0),
-      form(LONG_HEADER),
+      form(GOOGLE_QUIC_PACKET),
       long_packet_type(INITIAL),
       possible_stateless_reset_token(0) {}
 
diff --git a/net/third_party/quic/core/quic_packets.h b/net/third_party/quic/core/quic_packets.h
index d4877ad8..057c8d0 100644
--- a/net/third_party/quic/core/quic_packets.h
+++ b/net/third_party/quic/core/quic_packets.h
@@ -86,8 +86,8 @@
   // packet, |nonce| will be empty.
   DiversificationNonce* nonce;
   QuicPacketNumber packet_number;
-  // Only used if this is an IETF QUIC packet.
-  QuicIetfPacketHeaderForm form;
+  // Format of this header.
+  PacketHeaderFormat form;
   // Short packet type is reflected in packet_number_length.
   QuicLongHeaderType long_packet_type;
   // Only valid if |has_possible_stateless_reset_token| is true.
diff --git a/net/third_party/quic/core/quic_stream.cc b/net/third_party/quic/core/quic_stream.cc
index 70bf01e..317cf3b5 100644
--- a/net/third_party/quic/core/quic_stream.cc
+++ b/net/third_party/quic/core/quic_stream.cc
@@ -126,9 +126,8 @@
   bool is_stream_too_long =
       (frame.offset > kMaxStreamLength) ||
       (kMaxStreamLength - frame.offset < frame.data_length);
-  if (GetQuicReloadableFlag(quic_stream_too_long) && is_stream_too_long) {
+  if (is_stream_too_long) {
     // Close connection if stream becomes too long.
-    QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_stream_too_long, 4, 5);
     QUIC_PEER_BUG
         << "Receive stream frame reaches max stream length. frame offset "
         << frame.offset << " length " << frame.data_length;
@@ -184,9 +183,7 @@
 
 void QuicStream::OnStreamReset(const QuicRstStreamFrame& frame) {
   rst_received_ = true;
-  if (GetQuicReloadableFlag(quic_stream_too_long) &&
-      frame.byte_offset > kMaxStreamLength) {
-    QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_stream_too_long, 5, 5);
+  if (frame.byte_offset > kMaxStreamLength) {
     // Peer are not suppose to write bytes more than maxium allowed.
     CloseConnectionWithDetails(QUIC_STREAM_LENGTH_OVERFLOW,
                                "Reset frame stream offset overflow.");
@@ -286,9 +283,7 @@
   if (data.length() > 0) {
     struct iovec iov(MakeIovec(data));
     QuicStreamOffset offset = send_buffer_.stream_offset();
-    if (GetQuicReloadableFlag(quic_stream_too_long) &&
-        kMaxStreamLength - offset < data.length()) {
-      QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_stream_too_long, 1, 5);
+    if (kMaxStreamLength - offset < data.length()) {
       QUIC_BUG << "Write too many data via stream " << id_;
       CloseConnectionWithDetails(
           QUIC_STREAM_LENGTH_OVERFLOW,
@@ -376,9 +371,7 @@
     return consumed_data;
   }
 
-  if (GetQuicReloadableFlag(quic_stream_too_long) &&
-      kMaxStreamLength - send_buffer_.stream_offset() < write_length) {
-    QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_stream_too_long, 2, 5);
+  if (kMaxStreamLength - send_buffer_.stream_offset() < write_length) {
     QUIC_BUG << "Write too many data via stream " << id_;
     CloseConnectionWithDetails(
         QUIC_STREAM_LENGTH_OVERFLOW,
@@ -439,10 +432,8 @@
       QuicStreamOffset offset = send_buffer_.stream_offset();
       consumed_data.bytes_consumed =
           span.SaveMemSlicesInSendBuffer(&send_buffer_);
-      if (GetQuicReloadableFlag(quic_stream_too_long) &&
-          (offset > send_buffer_.stream_offset() ||
-           kMaxStreamLength < send_buffer_.stream_offset())) {
-        QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_stream_too_long, 3, 5);
+      if (offset > send_buffer_.stream_offset() ||
+          kMaxStreamLength < send_buffer_.stream_offset()) {
         QUIC_BUG << "Write too many data via stream " << id_;
         CloseConnectionWithDetails(
             QUIC_STREAM_LENGTH_OVERFLOW,
diff --git a/net/third_party/quic/core/quic_stream_test.cc b/net/third_party/quic/core/quic_stream_test.cc
index 8c2e3b50..a6c52a8 100644
--- a/net/third_party/quic/core/quic_stream_test.cc
+++ b/net/third_party/quic/core/quic_stream_test.cc
@@ -258,7 +258,6 @@
 }
 
 TEST_F(QuicStreamTest, WriteOrBufferDataReachStreamLimit) {
-  SetQuicReloadableFlag(quic_stream_too_long, true);
   Initialize();
   QuicString data("aaaaa");
   QuicStreamPeer::SetStreamBytesWritten(kMaxStreamLength - data.length(),
@@ -536,7 +535,6 @@
 }
 
 TEST_F(QuicStreamTest, OnStreamResetOffsetOverflow) {
-  SetQuicReloadableFlag(quic_stream_too_long, true);
   Initialize();
   QuicRstStreamFrame rst_frame(kInvalidControlFrameId, stream_->id(),
                                QUIC_STREAM_CANCELLED, kMaxStreamLength + 1);
@@ -545,7 +543,6 @@
 }
 
 TEST_F(QuicStreamTest, OnStreamFrameUpperLimit) {
-  SetQuicReloadableFlag(quic_stream_too_long, true);
   Initialize();
 
   // Modify receive window offset and sequencer buffer total_bytes_read_ to
@@ -568,7 +565,6 @@
 }
 
 TEST_F(QuicStreamTest, StreamTooLong) {
-  SetQuicReloadableFlag(quic_stream_too_long, true);
   Initialize();
   EXPECT_CALL(*connection_, CloseConnection(QUIC_STREAM_LENGTH_OVERFLOW, _, _))
       .Times(1);
@@ -926,7 +922,6 @@
 }
 
 TEST_F(QuicStreamTest, WritevDataReachStreamLimit) {
-  SetQuicReloadableFlag(quic_stream_too_long, true);
   Initialize();
   QuicString data("aaaaa");
   QuicStreamPeer::SetStreamBytesWritten(kMaxStreamLength - data.length(),
@@ -1009,7 +1004,6 @@
 }
 
 TEST_F(QuicStreamTest, WriteMemSlicesReachStreamLimit) {
-  SetQuicReloadableFlag(quic_stream_too_long, true);
   Initialize();
   QuicStreamPeer::SetStreamBytesWritten(kMaxStreamLength - 5u, stream_);
   char data[5];
diff --git a/net/third_party/quic/core/quic_time.h b/net/third_party/quic/core/quic_time.h
index ebd4c0d..25bbec31 100644
--- a/net/third_party/quic/core/quic_time.h
+++ b/net/third_party/quic/core/quic_time.h
@@ -112,6 +112,13 @@
     return QuicTime(Delta::kQuicInfiniteTimeUs);
   }
 
+  QuicTime(const QuicTime& other) = default;
+
+  QuicTime& operator=(const QuicTime& other) {
+    time_ = other.time_;
+    return *this;
+  }
+
   // Produce the internal value to be used when logging.  This value
   // represents the number of microseconds since some epoch.  It may
   // be the UNIX epoch on some platforms.  On others, it may
diff --git a/net/third_party/quic/core/quic_time_test.cc b/net/third_party/quic/core/quic_time_test.cc
index 74f2bbd..d407f37 100644
--- a/net/third_party/quic/core/quic_time_test.cc
+++ b/net/third_party/quic/core/quic_time_test.cc
@@ -107,6 +107,20 @@
                   .IsInitialized());
 }
 
+TEST_F(QuicTimeTest, CopyConstruct) {
+  QuicTime time_1 = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(1234);
+  EXPECT_NE(time_1, QuicTime(QuicTime::Zero()));
+  EXPECT_EQ(time_1, QuicTime(time_1));
+}
+
+TEST_F(QuicTimeTest, CopyAssignment) {
+  QuicTime time_1 = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(1234);
+  QuicTime time_2 = QuicTime::Zero();
+  EXPECT_NE(time_1, time_2);
+  time_2 = time_1;
+  EXPECT_EQ(time_1, time_2);
+}
+
 TEST_F(QuicTimeTest, Add) {
   QuicTime time_1 = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(1);
   QuicTime time_2 = QuicTime::Zero() + QuicTime::Delta::FromMilliseconds(2);
diff --git a/net/third_party/quic/core/quic_types.h b/net/third_party/quic/core/quic_types.h
index 5365f10d..be4736b 100644
--- a/net/third_party/quic/core/quic_types.h
+++ b/net/third_party/quic/core/quic_types.h
@@ -462,14 +462,6 @@
   FRAME_ERROR_base = 0x100,  // add frame type to this base
 };
 
-enum QuicIetfPacketHeaderForm : uint8_t {
-  // Long header is used for packets that are sent prior to the completion of
-  // version negotiation and establishment of 1-RTT keys.
-  LONG_HEADER,
-  // Short header is used after the version and 1-RTT keys are negotiated.
-  SHORT_HEADER,
-};
-
 // Used in long header to explicitly indicate the packet type.
 enum QuicLongHeaderType : uint8_t {
   VERSION_NEGOTIATION = 0,  // Value does not matter.
diff --git a/net/third_party/quic/core/tls_client_handshaker.cc b/net/third_party/quic/core/tls_client_handshaker.cc
index 0ac19c5e..f57e886 100644
--- a/net/third_party/quic/core/tls_client_handshaker.cc
+++ b/net/third_party/quic/core/tls_client_handshaker.cc
@@ -99,8 +99,8 @@
 bool TlsClientHandshaker::SetTransportParameters() {
   TransportParameters params;
   params.perspective = Perspective::IS_CLIENT;
-  params.version = CreateQuicVersionLabel(
-      session()->connection()->supported_versions().front());
+  params.version =
+      CreateQuicVersionLabel(session()->supported_versions().front());
 
   if (!session()->config()->FillTransportParameters(&params)) {
     return false;
diff --git a/net/third_party/quic/platform/api/quic_clock.h b/net/third_party/quic/platform/api/quic_clock.h
index 55066df..a6eab8f 100644
--- a/net/third_party/quic/platform/api/quic_clock.h
+++ b/net/third_party/quic/platform/api/quic_clock.h
@@ -26,7 +26,7 @@
   // calibrate the clock, or all instances of this clock type.
   QuicTime::Delta ComputeCalibrationOffset() const;
 
-  // Calibrate this clock. A calibrated clock gurantees that the
+  // Calibrate this clock. A calibrated clock guarantees that the
   // ConvertWallTimeToQuicTime() function always return the same result for the
   // same walltime.
   // Should not be called more than once for each QuicClock.
diff --git a/net/third_party/quic/platform/impl/quic_epoll_clock.cc b/net/third_party/quic/platform/impl/quic_epoll_clock.cc
index f228b23..51792f4 100644
--- a/net/third_party/quic/platform/impl/quic_epoll_clock.cc
+++ b/net/third_party/quic/platform/impl/quic_epoll_clock.cc
@@ -4,23 +4,35 @@
 
 #include "net/third_party/quic/platform/impl/quic_epoll_clock.h"
 
+#include "net/third_party/quic/platform/api/quic_flag_utils.h"
+#include "net/third_party/quic/platform/api/quic_flags.h"
 #include "net/tools/epoll_server/epoll_server.h"
 
 namespace quic {
 
 QuicEpollClock::QuicEpollClock(net::EpollServer* epoll_server)
-    : epoll_server_(epoll_server) {}
+    : epoll_server_(epoll_server), largest_time_(QuicTime::Zero()) {}
 
-QuicEpollClock::~QuicEpollClock() = default;
+QuicEpollClock::~QuicEpollClock() {}
 
 QuicTime QuicEpollClock::ApproximateNow() const {
-  return QuicTime::Zero() + QuicTime::Delta::FromMicroseconds(
-                                epoll_server_->ApproximateNowInUsec());
+  return CreateTimeFromMicroseconds(epoll_server_->ApproximateNowInUsec());
 }
 
 QuicTime QuicEpollClock::Now() const {
-  return QuicTime::Zero() +
-         QuicTime::Delta::FromMicroseconds(epoll_server_->NowInUsec());
+  QuicTime now = CreateTimeFromMicroseconds(epoll_server_->NowInUsec());
+  if (!GetQuicReloadableFlag(quic_monotonic_epoll_clock)) {
+    return now;
+  }
+
+  if (now <= largest_time_) {
+    QUIC_FLAG_COUNT(quic_reloadable_flag_quic_monotonic_epoll_clock);
+    // Time not increasing, return |largest_time_|.
+    return largest_time_;
+  }
+
+  largest_time_ = now;
+  return largest_time_;
 }
 
 QuicWallTime QuicEpollClock::WallNow() const {
diff --git a/net/third_party/quic/platform/impl/quic_epoll_clock.h b/net/third_party/quic/platform/impl/quic_epoll_clock.h
index 2cc21bf..6f34aa2 100644
--- a/net/third_party/quic/platform/impl/quic_epoll_clock.h
+++ b/net/third_party/quic/platform/impl/quic_epoll_clock.h
@@ -41,6 +41,8 @@
 
  protected:
   net::EpollServer* epoll_server_;
+  // Largest time returned from Now() so far.
+  mutable QuicTime largest_time_;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(QuicEpollClock);
diff --git a/net/third_party/quic/platform/impl/quic_epoll_clock_test.cc b/net/third_party/quic/platform/impl/quic_epoll_clock_test.cc
index 2b34654..83ab721 100644
--- a/net/third_party/quic/platform/impl/quic_epoll_clock_test.cc
+++ b/net/third_party/quic/platform/impl/quic_epoll_clock_test.cc
@@ -4,6 +4,7 @@
 
 #include "net/third_party/quic/platform/impl/quic_epoll_clock.h"
 
+#include "net/third_party/quic/platform/api/quic_flags.h"
 #include "net/third_party/quic/platform/api/quic_test.h"
 #include "net/third_party/quic/test_tools/fake_epoll_server.h"
 
@@ -44,5 +45,37 @@
   EXPECT_EQ(1000005, (clock.Now() - QuicTime::Zero()).ToMicroseconds());
 }
 
+TEST_F(QuicEpollClockTest, MonotonicityWithRealEpollClock) {
+  SetQuicReloadableFlag(quic_monotonic_epoll_clock, true);
+  net::EpollServer epoll_server;
+  QuicEpollClock clock(&epoll_server);
+
+  quic::QuicTime last_now = clock.Now();
+  for (int i = 0; i < 1e5; ++i) {
+    quic::QuicTime now = clock.Now();
+
+    ASSERT_LE(last_now, now);
+
+    last_now = now;
+  }
+}
+
+TEST_F(QuicEpollClockTest, MonotonicityWithFakeEpollClock) {
+  FakeEpollServer epoll_server;
+  QuicEpollClock clock(&epoll_server);
+
+  epoll_server.set_now_in_usec(100);
+  quic::QuicTime last_now = clock.Now();
+
+  epoll_server.set_now_in_usec(90);
+  quic::QuicTime now = clock.Now();
+
+  if (GetQuicReloadableFlag(quic_monotonic_epoll_clock)) {
+    ASSERT_EQ(last_now, now);
+  } else {
+    ASSERT_GT(last_now, now);
+  }
+}
+
 }  // namespace test
 }  // namespace quic
diff --git a/net/third_party/quic/platform/impl/quic_flag_utils_impl.h b/net/third_party/quic/platform/impl/quic_flag_utils_impl.h
index 3cd866c..08dd4ab 100644
--- a/net/third_party/quic/platform/impl/quic_flag_utils_impl.h
+++ b/net/third_party/quic/platform/impl/quic_flag_utils_impl.h
@@ -5,6 +5,8 @@
 #ifndef NET_THIRD_PARTY_QUIC_PLATFORM_IMPL_QUIC_FLAG_UTILS_IMPL_H_
 #define NET_THIRD_PARTY_QUIC_PLATFORM_IMPL_QUIC_FLAG_UTILS_IMPL_H_
 
+#include "base/logging.h"
+
 #define QUIC_FLAG_COUNT_IMPL(flag) \
   DVLOG(1) << "FLAG_" #flag ": " << FLAGS_##flag
 #define QUIC_FLAG_COUNT_N_IMPL(flag, instance, total) QUIC_FLAG_COUNT_IMPL(flag)
diff --git a/net/third_party/quic/quartc/quartc_session_test.cc b/net/third_party/quic/quartc/quartc_session_test.cc
index 74352ae..c1ea06aa 100644
--- a/net/third_party/quic/quartc/quartc_session_test.cc
+++ b/net/third_party/quic/quartc/quartc_session_test.cc
@@ -50,7 +50,6 @@
   void OnIncomingStream(QuartcStream* quartc_stream) override {
     last_incoming_stream_ = quartc_stream;
     last_incoming_stream_->SetDelegate(stream_delegate_);
-    quartc_stream->set_deliver_on_complete(false);
   }
 
   void OnCongestionControlChange(QuicBandwidth bandwidth_estimate,
@@ -69,10 +68,17 @@
 
 class FakeQuartcStreamDelegate : public QuartcStream::Delegate {
  public:
-  void OnReceived(QuartcStream* stream,
-                  const char* data,
-                  size_t size) override {
-    received_data_[stream->id()] += QuicString(data, size);
+  size_t OnReceived(QuartcStream* stream,
+                    iovec* iov,
+                    size_t iov_length,
+                    bool fin) override {
+    size_t bytes_consumed = 0;
+    for (size_t i = 0; i < iov_length; ++i) {
+      received_data_[stream->id()] +=
+          QuicString(static_cast<const char*>(iov[i].iov_base), iov[i].iov_len);
+      bytes_consumed += iov[i].iov_len;
+    }
+    return bytes_consumed;
   }
 
   void OnClose(QuartcStream* stream) override {
@@ -187,7 +193,6 @@
     EXPECT_TRUE(server_peer_->HasOpenDynamicStreams());
 
     outgoing_stream->SetDelegate(server_stream_delegate_.get());
-    outgoing_stream->set_deliver_on_complete(false);
 
     // Send a test message from peer 1 to peer 2.
     char kTestMessage[] = "Hello";
diff --git a/net/third_party/quic/quartc/quartc_stream.cc b/net/third_party/quic/quartc/quartc_stream.cc
index 3a8257a..37ea7fc 100644
--- a/net/third_party/quic/quartc/quartc_stream.cc
+++ b/net/third_party/quic/quartc/quartc_stream.cc
@@ -16,26 +16,23 @@
 QuartcStream::~QuartcStream() {}
 
 void QuartcStream::OnDataAvailable() {
-  // Do not deliver data until the entire stream's data is available.
-  if (deliver_on_complete_ &&
-      sequencer()->ReadableBytes() + sequencer()->NumBytesConsumed() <
-          sequencer()->close_offset()) {
-    return;
-  }
+  bool fin = sequencer()->ReadableBytes() + sequencer()->NumBytesConsumed() ==
+             sequencer()->close_offset();
 
-  struct iovec iov;
-  while (sequencer()->GetReadableRegion(&iov)) {
-    DCHECK(delegate_);
-    delegate_->OnReceived(this, reinterpret_cast<const char*>(iov.iov_base),
-                          iov.iov_len);
-    sequencer()->MarkConsumed(iov.iov_len);
-  }
-  // All the data has been received if the sequencer is closed.
-  // Notify the delegate by calling the callback function one more time with
-  // iov_len = 0.
+  // Upper bound on number of readable regions.  Each complete block's worth of
+  // data crosses at most one region boundary.  The remainder may cross one more
+  // boundary.  Number of regions is one more than the number of region
+  // boundaries crossed.
+  size_t iov_length = sequencer()->ReadableBytes() /
+                          QuicStreamSequencerBuffer::kBlockSizeBytes +
+                      2;
+  std::unique_ptr<iovec[]> iovecs = QuicMakeUnique<iovec[]>(iov_length);
+  iov_length = sequencer()->GetReadableRegions(iovecs.get(), iov_length);
+
+  sequencer()->MarkConsumed(
+      delegate_->OnReceived(this, iovecs.get(), iov_length, fin));
   if (sequencer()->IsClosed()) {
     OnFinRead();
-    delegate_->OnReceived(this, reinterpret_cast<const char*>(iov.iov_base), 0);
   }
 }
 
@@ -95,14 +92,6 @@
   cancel_on_loss_ = cancel_on_loss;
 }
 
-bool QuartcStream::deliver_on_complete() {
-  return deliver_on_complete_;
-}
-
-void QuartcStream::set_deliver_on_complete(bool deliver_on_complete) {
-  deliver_on_complete_ = deliver_on_complete;
-}
-
 QuicByteCount QuartcStream::BytesPendingRetransmission() {
   if (cancel_on_loss_) {
     return 0;  // Lost bytes will never be retransmitted.
diff --git a/net/third_party/quic/quartc/quartc_stream.h b/net/third_party/quic/quartc/quartc_stream.h
index 6c3282f..2f9598da 100644
--- a/net/third_party/quic/quartc/quartc_stream.h
+++ b/net/third_party/quic/quartc/quartc_stream.h
@@ -53,11 +53,6 @@
   bool cancel_on_loss();
   void set_cancel_on_loss(bool cancel_on_loss);
 
-  // If true, stream data will only be delivered after the FIN bit arrives and
-  // all data has been received.
-  bool deliver_on_complete();
-  void set_deliver_on_complete(bool deliver_on_complete);
-
   QuicByteCount BytesPendingRetransmission();
 
   // Marks this stream as finished writing.  Asynchronously sends a FIN and
@@ -71,13 +66,16 @@
    public:
     virtual ~Delegate() {}
 
-    // Called when the stream receives data.  Called with |size| == 0 after all
-    // stream data has been delivered (once the stream receives a FIN bit).
-    // Note that the same packet may include both data and a FIN bit, causing
-    // this method to be called twice.
-    virtual void OnReceived(QuartcStream* stream,
-                            const char* data,
-                            size_t size) = 0;
+    // Called when the stream receives data. |iov| is a pointer to the first of
+    // |iov_length| readable regions. |iov| points to readable data within
+    // |stream|'s sequencer buffer. QUIC may modify or delete this data after
+    // the application consumes it. |fin| indicates the end of stream data.
+    // Returns the number of bytes consumed. May return 0 if the delegate is
+    // unable to consume any bytes at this time.
+    virtual size_t OnReceived(QuartcStream* stream,
+                              iovec* iov,
+                              size_t iov_length,
+                              bool fin) = 0;
 
     // Called when the stream is closed, either locally or by the remote
     // endpoint.  Streams close when (a) fin bits are both sent and received,
@@ -98,9 +96,6 @@
 
   // Whether the stream should cancel itself instead of retransmitting frames.
   bool cancel_on_loss_ = false;
-
-  // Whether stream data should only be delivered after all data is received.
-  bool deliver_on_complete_ = true;
 };
 
 }  // namespace quic
diff --git a/net/third_party/quic/quartc/quartc_stream_test.cc b/net/third_party/quic/quartc/quartc_stream_test.cc
index 6c16ee66..2c8d434 100644
--- a/net/third_party/quic/quartc/quartc_stream_test.cc
+++ b/net/third_party/quic/quartc/quartc_stream_test.cc
@@ -144,11 +144,18 @@
     last_bytes_pending_retransmission_ = stream->BytesPendingRetransmission();
   }
 
-  void OnReceived(QuartcStream* stream,
-                  const char* data,
-                  size_t size) override {
+  size_t OnReceived(QuartcStream* stream,
+                    iovec* iov,
+                    size_t iov_length,
+                    bool fin) override {
     EXPECT_EQ(id_, stream->id());
-    read_buffer_->append(data, size);
+    size_t bytes_consumed = 0;
+    for (size_t i = 0; i < iov_length; ++i) {
+      read_buffer_->append(static_cast<const char*>(iov[i].iov_base),
+                           iov[i].iov_len);
+      bytes_consumed += iov[i].iov_len;
+    }
+    return bytes_consumed;
   }
 
   void OnClose(QuartcStream* stream) override { closed_ = true; }
@@ -174,6 +181,13 @@
 
 class QuartcStreamTest : public QuicTest, public QuicConnectionHelperInterface {
  public:
+  QuartcStreamTest() {
+    // Required to correctly handle StopReading().
+    SetQuicReloadableFlag(quic_stop_reading_when_level_triggered, true);
+  }
+
+  ~QuartcStreamTest() override = default;
+
   void CreateReliableQuicStream() {
     // Arbitrary values for QuicConnection.
     Perspective perspective = Perspective::IS_SERVER;
@@ -197,8 +211,6 @@
     session_->ActivateReliableStream(std::unique_ptr<QuartcStream>(stream_));
   }
 
-  ~QuartcStreamTest() override {}
-
   const QuicClock* GetClock() const override { return &clock_; }
 
   QuicRandom* GetRandomGenerator() override {
@@ -306,7 +318,6 @@
 // Read an entire string.
 TEST_F(QuartcStreamTest, ReadDataWhole) {
   CreateReliableQuicStream();
-  stream_->set_deliver_on_complete(false);
   QuicStreamFrame frame(kStreamId, false, 0, "Hello, World!");
   stream_->OnStreamFrame(frame);
 
@@ -316,7 +327,6 @@
 // Read part of a string.
 TEST_F(QuartcStreamTest, ReadDataPartial) {
   CreateReliableQuicStream();
-  stream_->set_deliver_on_complete(false);
   QuicStreamFrame frame(kStreamId, false, 0, "Hello, World!");
   frame.data_length = 5;
   stream_->OnStreamFrame(frame);
@@ -342,28 +352,6 @@
   EXPECT_TRUE(stream_->fin_received());
 }
 
-// Streams set to deliver_on_complete do not deliver data to the delegate
-// until all data is available.
-TEST_F(QuartcStreamTest, DeliverOnComplete) {
-  CreateReliableQuicStream();
-  stream_->set_deliver_on_complete(true);
-
-  QuicStreamFrame first_frame(kStreamId, /*fin=*/false, 0, "Hello");
-  stream_->OnStreamFrame(first_frame);
-
-  EXPECT_EQ(0ul, read_buffer_.size());
-
-  QuicStreamFrame last_frame(kStreamId, /*fin=*/true, 7, "World!");
-  stream_->OnStreamFrame(last_frame);
-
-  EXPECT_EQ(0ul, read_buffer_.size());
-
-  QuicStreamFrame middle_frame(kStreamId, /*fin=*/false, 5, ", ");
-  stream_->OnStreamFrame(middle_frame);
-
-  EXPECT_EQ("Hello, World!", read_buffer_);
-}
-
 // Test that closing the stream results in a callback.
 TEST_F(QuartcStreamTest, CloseStream) {
   CreateReliableQuicStream();
diff --git a/net/third_party/quic/test_tools/crypto_test_utils.cc b/net/third_party/quic/test_tools/crypto_test_utils.cc
index 7899de9..3080ed39 100644
--- a/net/third_party/quic/test_tools/crypto_test_utils.cc
+++ b/net/third_party/quic/test_tools/crypto_test_utils.cc
@@ -458,7 +458,8 @@
     crypto_config.tb_key_params = options.token_binding_params;
   }
   TestQuicSpdyClientSession client_session(client_conn, DefaultQuicConfig(),
-                                           server_id, &crypto_config);
+                                           supported_versions, server_id,
+                                           &crypto_config);
 
   EXPECT_CALL(client_session, OnProofValid(testing::_))
       .Times(testing::AnyNumber());
diff --git a/net/third_party/quic/test_tools/quic_dispatcher_peer.cc b/net/third_party/quic/test_tools/quic_dispatcher_peer.cc
index 619f765..3929ee4 100644
--- a/net/third_party/quic/test_tools/quic_dispatcher_peer.cc
+++ b/net/third_party/quic/test_tools/quic_dispatcher_peer.cc
@@ -86,10 +86,10 @@
     QuicDispatcher* dispatcher,
     const QuicSocketAddress& server_address,
     const QuicSocketAddress& client_address,
-    QuicConnectionId connection_id) {
+    QuicConnectionId connection_id,
+    bool ietf_quic) {
   dispatcher->time_wait_list_manager()->SendPublicReset(
-      server_address, client_address, connection_id,
-      dispatcher->framer_.last_packet_is_ietf_quic());
+      server_address, client_address, connection_id, ietf_quic);
 }
 
 // static
diff --git a/net/third_party/quic/test_tools/quic_dispatcher_peer.h b/net/third_party/quic/test_tools/quic_dispatcher_peer.h
index 7494d32..b07b7bb 100644
--- a/net/third_party/quic/test_tools/quic_dispatcher_peer.h
+++ b/net/third_party/quic/test_tools/quic_dispatcher_peer.h
@@ -54,7 +54,8 @@
   static void SendPublicReset(QuicDispatcher* dispatcher,
                               const QuicSocketAddress& server_address,
                               const QuicSocketAddress& client_address,
-                              QuicConnectionId connection_id);
+                              QuicConnectionId connection_id,
+                              bool ietf_quic);
 
   static std::unique_ptr<QuicDispatcher::PerPacketContext> GetPerPacketContext(
       QuicDispatcher* dispatcher);
diff --git a/net/third_party/quic/test_tools/quic_framer_peer.cc b/net/third_party/quic/test_tools/quic_framer_peer.cc
index a02a8cc2..62a4f18 100644
--- a/net/third_party/quic/test_tools/quic_framer_peer.cc
+++ b/net/third_party/quic/test_tools/quic_framer_peer.cc
@@ -328,12 +328,6 @@
 }
 
 // static
-void QuicFramerPeer::SetLastPacketIsIetfQuic(QuicFramer* framer,
-                                             bool last_packet_is_ietf_quic) {
-  framer->last_packet_is_ietf_quic_ = last_packet_is_ietf_quic;
-}
-
-// static
 size_t QuicFramerPeer::ComputeFrameLength(
     QuicFramer* framer,
     const QuicFrame& frame,
diff --git a/net/third_party/quic/test_tools/quic_framer_peer.h b/net/third_party/quic/test_tools/quic_framer_peer.h
index 3b306ad..13decf55 100644
--- a/net/third_party/quic/test_tools/quic_framer_peer.h
+++ b/net/third_party/quic/test_tools/quic_framer_peer.h
@@ -35,9 +35,6 @@
 
   static QuicEncrypter* GetEncrypter(QuicFramer* framer, EncryptionLevel level);
 
-  static void SetLastPacketIsIetfQuic(QuicFramer* framer,
-                                      bool last_packet_is_ietf_quic);
-
   // IETF defined frame append/process methods.
   static bool ProcessIetfStreamFrame(QuicFramer* framer,
                                      QuicDataReader* reader,
diff --git a/net/third_party/quic/test_tools/quic_test_server.cc b/net/third_party/quic/test_tools/quic_test_server.cc
index 2489b37..7b2e72ec6 100644
--- a/net/third_party/quic/test_tools/quic_test_server.cc
+++ b/net/third_party/quic/test_tools/quic_test_server.cc
@@ -88,18 +88,20 @@
         stream_factory_(nullptr),
         crypto_stream_factory_(nullptr) {}
 
-  QuicServerSessionBase* CreateQuicSession(QuicConnectionId id,
-                                           const QuicSocketAddress& client,
-                                           QuicStringPiece alpn) override {
+  QuicServerSessionBase* CreateQuicSession(
+      QuicConnectionId id,
+      const QuicSocketAddress& client,
+      QuicStringPiece alpn,
+      const ParsedQuicVersion& version) override {
     QuicReaderMutexLock lock(&factory_lock_);
     if (session_factory_ == nullptr && stream_factory_ == nullptr &&
         crypto_stream_factory_ == nullptr) {
-      return QuicSimpleDispatcher::CreateQuicSession(id, client, alpn);
+      return QuicSimpleDispatcher::CreateQuicSession(id, client, alpn, version);
     }
     QuicConnection* connection =
         new QuicConnection(id, client, helper(), alarm_factory(), writer(),
                            /* owns_writer= */ false, Perspective::IS_SERVER,
-                           ParsedQuicVersionVector{framer()->version()});
+                           ParsedQuicVersionVector{version});
 
     QuicServerSessionBase* session = nullptr;
     if (stream_factory_ != nullptr || crypto_stream_factory_ != nullptr) {
diff --git a/net/third_party/quic/test_tools/quic_test_utils.cc b/net/third_party/quic/test_tools/quic_test_utils.cc
index 9bc1ffc..4f2b0e9 100644
--- a/net/third_party/quic/test_tools/quic_test_utils.cc
+++ b/net/third_party/quic/test_tools/quic_test_utils.cc
@@ -125,7 +125,7 @@
 
 MockFramerVisitor::MockFramerVisitor() {
   // By default, we want to accept packets.
-  ON_CALL(*this, OnProtocolVersionMismatch(_))
+  ON_CALL(*this, OnProtocolVersionMismatch(_, _))
       .WillByDefault(testing::Return(false));
 
   // By default, we want to accept packets.
@@ -169,7 +169,8 @@
 
 MockFramerVisitor::~MockFramerVisitor() {}
 
-bool NoOpFramerVisitor::OnProtocolVersionMismatch(ParsedQuicVersion version) {
+bool NoOpFramerVisitor::OnProtocolVersionMismatch(ParsedQuicVersion version,
+                                                  PacketHeaderFormat form) {
   return false;
 }
 
@@ -407,7 +408,8 @@
   static_cast<MockQuicConnectionHelper*>(helper())->AdvanceTime(delta);
 }
 
-bool MockQuicConnection::OnProtocolVersionMismatch(ParsedQuicVersion version) {
+bool MockQuicConnection::OnProtocolVersionMismatch(ParsedQuicVersion version,
+                                                   PacketHeaderFormat form) {
   return false;
 }
 
@@ -610,9 +612,13 @@
 TestQuicSpdyClientSession::TestQuicSpdyClientSession(
     QuicConnection* connection,
     const QuicConfig& config,
+    const ParsedQuicVersionVector& supported_versions,
     const QuicServerId& server_id,
     QuicCryptoClientConfig* crypto_config)
-    : QuicSpdyClientSessionBase(connection, &push_promise_index_, config) {
+    : QuicSpdyClientSessionBase(connection,
+                                &push_promise_index_,
+                                config,
+                                supported_versions) {
   crypto_stream_ = QuicMakeUnique<QuicCryptoClientStream>(
       server_id, this, crypto_test_utils::ProofVerifyContextForTesting(),
       crypto_config, this);
@@ -1036,8 +1042,9 @@
                           : DefaultQuicConfig();
   *client_connection = new PacketSavingConnection(
       helper, alarm_factory, Perspective::IS_CLIENT, supported_versions);
-  *client_session = new TestQuicSpdyClientSession(
-      *client_connection, config, server_id, crypto_client_config);
+  *client_session = new TestQuicSpdyClientSession(*client_connection, config,
+                                                  supported_versions, server_id,
+                                                  crypto_client_config);
   (*client_connection)->AdvanceTime(connection_start_time);
 }
 
diff --git a/net/third_party/quic/test_tools/quic_test_utils.h b/net/third_party/quic/test_tools/quic_test_utils.h
index c36eb7b..ab02563 100644
--- a/net/third_party/quic/test_tools/quic_test_utils.h
+++ b/net/third_party/quic/test_tools/quic_test_utils.h
@@ -242,7 +242,8 @@
 
   MOCK_METHOD1(OnError, void(QuicFramer* framer));
   // The constructor sets this up to return false by default.
-  MOCK_METHOD1(OnProtocolVersionMismatch, bool(ParsedQuicVersion version));
+  MOCK_METHOD2(OnProtocolVersionMismatch,
+               bool(ParsedQuicVersion version, PacketHeaderFormat form));
   MOCK_METHOD0(OnPacket, void());
   MOCK_METHOD1(OnPublicResetPacket, void(const QuicPublicResetPacket& header));
   MOCK_METHOD1(OnVersionNegotiationPacket,
@@ -300,7 +301,8 @@
   void OnPublicResetPacket(const QuicPublicResetPacket& packet) override {}
   void OnVersionNegotiationPacket(
       const QuicVersionNegotiationPacket& packet) override {}
-  bool OnProtocolVersionMismatch(ParsedQuicVersion version) override;
+  bool OnProtocolVersionMismatch(ParsedQuicVersion version,
+                                 PacketHeaderFormat form) override;
   bool OnUnauthenticatedHeader(const QuicPacketHeader& header) override;
   bool OnUnauthenticatedPublicHeader(const QuicPacketHeader& header) override;
   void OnDecryptedPacket(EncryptionLevel level) override {}
@@ -510,7 +512,8 @@
     QuicConnection::ProcessUdpPacket(self_address, peer_address, packet);
   }
 
-  bool OnProtocolVersionMismatch(ParsedQuicVersion version) override;
+  bool OnProtocolVersionMismatch(ParsedQuicVersion version,
+                                 PacketHeaderFormat form) override;
 
   bool ReallySendControlFrame(const QuicFrame& frame) {
     return QuicConnection::SendControlFrame(frame);
@@ -776,6 +779,7 @@
  public:
   TestQuicSpdyClientSession(QuicConnection* connection,
                             const QuicConfig& config,
+                            const ParsedQuicVersionVector& supported_versions,
                             const QuicServerId& server_id,
                             QuicCryptoClientConfig* crypto_config);
   TestQuicSpdyClientSession(const TestQuicSpdyClientSession&) = delete;
@@ -803,9 +807,21 @@
   QuicCryptoClientStream* GetMutableCryptoStream() override;
   const QuicCryptoClientStream* GetCryptoStream() const override;
 
+  // Override to save sent crypto handshake messages.
+  void OnCryptoHandshakeMessageSent(
+      const CryptoHandshakeMessage& message) override {
+    sent_crypto_handshake_messages_.push_back(message);
+  }
+
+  const std::vector<CryptoHandshakeMessage>& sent_crypto_handshake_messages()
+      const {
+    return sent_crypto_handshake_messages_;
+  }
+
  private:
   std::unique_ptr<QuicCryptoClientStream> crypto_stream_;
   QuicClientPushPromiseIndex push_promise_index_;
+  std::vector<CryptoHandshakeMessage> sent_crypto_handshake_messages_;
 };
 
 class MockPacketWriter : public QuicPacketWriter {
diff --git a/net/third_party/quic/test_tools/simple_quic_framer.cc b/net/third_party/quic/test_tools/simple_quic_framer.cc
index 0f728ac2..8ee0442 100644
--- a/net/third_party/quic/test_tools/simple_quic_framer.cc
+++ b/net/third_party/quic/test_tools/simple_quic_framer.cc
@@ -25,7 +25,8 @@
 
   void OnError(QuicFramer* framer) override { error_ = framer->error(); }
 
-  bool OnProtocolVersionMismatch(ParsedQuicVersion version) override {
+  bool OnProtocolVersionMismatch(ParsedQuicVersion version,
+                                 PacketHeaderFormat form) override {
     return false;
   }
 
diff --git a/net/third_party/quic/tools/quic_client.cc b/net/third_party/quic/tools/quic_client.cc
index 2b00375..0b3366bec 100644
--- a/net/third_party/quic/tools/quic_client.cc
+++ b/net/third_party/quic/tools/quic_client.cc
@@ -87,10 +87,11 @@
 QuicClient::~QuicClient() = default;
 
 std::unique_ptr<QuicSession> QuicClient::CreateQuicClientSession(
+    const ParsedQuicVersionVector& supported_versions,
     QuicConnection* connection) {
   return QuicMakeUnique<QuicSimpleClientSession>(
-      *config(), connection, server_id(), crypto_config(), push_promise_index(),
-      drop_response_body_);
+      *config(), supported_versions, connection, server_id(), crypto_config(),
+      push_promise_index(), drop_response_body_);
 }
 
 QuicClientEpollNetworkHelper* QuicClient::epoll_network_helper() {
diff --git a/net/third_party/quic/tools/quic_client.h b/net/third_party/quic/tools/quic_client.h
index 6778176..af77a73a 100644
--- a/net/third_party/quic/tools/quic_client.h
+++ b/net/third_party/quic/tools/quic_client.h
@@ -62,6 +62,7 @@
   ~QuicClient() override;
 
   std::unique_ptr<QuicSession> CreateQuicClientSession(
+      const ParsedQuicVersionVector& supported_versions,
       QuicConnection* connection) override;
 
   // Exposed for the quic client test.
diff --git a/net/third_party/quic/tools/quic_client_base.cc b/net/third_party/quic/tools/quic_client_base.cc
index 8b7958d..6a55a32 100644
--- a/net/third_party/quic/tools/quic_client_base.cc
+++ b/net/third_party/quic/tools/quic_client_base.cc
@@ -88,10 +88,13 @@
       // Resend any previously queued data.
       ResendSavedData();
     }
+    ParsedQuicVersion version(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED);
     if (session() != nullptr &&
-        session()->error() != QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT) {
+        session()->error() != QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT &&
+        !CanReconnectWithDifferentVersion(&version)) {
       // We've successfully created a session but we're not connected, and there
-      // is no stateless reject to recover from.  Give up trying.
+      // is no stateless reject to recover from and cannot try to reconnect with
+      // different version.  Give up trying.
       break;
     }
   }
@@ -109,10 +112,17 @@
   DCHECK(initialized_);
   DCHECK(!connected());
   QuicPacketWriter* writer = network_helper_->CreateQuicPacketWriter();
+  ParsedQuicVersion mutual_version(PROTOCOL_UNSUPPORTED,
+                                   QUIC_VERSION_UNSUPPORTED);
+  const bool can_reconnect_with_different_version =
+      CanReconnectWithDifferentVersion(&mutual_version);
   if (connected_or_attempting_connect()) {
     // If the last error was not a stateless reject, then the queued up data
     // does not need to be resent.
-    if (session()->error() != QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT) {
+    // Keep queued up data if client can try to connect with a different
+    // version.
+    if (session()->error() != QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT &&
+        !can_reconnect_with_different_version) {
       ClearDataToResend();
     }
     // Before we destroy the last session and create a new one, gather its stats
@@ -120,10 +130,14 @@
     UpdateStats();
   }
 
-  session_ = CreateQuicClientSession(new QuicConnection(
-      GetNextConnectionId(), server_address(), helper(), alarm_factory(),
-      writer,
-      /* owns_writer= */ false, Perspective::IS_CLIENT, supported_versions()));
+  session_ = CreateQuicClientSession(
+      supported_versions(),
+      new QuicConnection(GetNextConnectionId(), server_address(), helper(),
+                         alarm_factory(), writer,
+                         /* owns_writer= */ false, Perspective::IS_CLIENT,
+                         can_reconnect_with_different_version
+                             ? ParsedQuicVersionVector{mutual_version}
+                             : supported_versions()));
   if (initial_max_packet_length_ != 0) {
     session()->connection()->SetMaxPacketLength(initial_max_packet_length_);
   }
@@ -168,11 +182,18 @@
   network_helper_->RunEventLoop();
 
   DCHECK(session() != nullptr);
+  ParsedQuicVersion version(PROTOCOL_UNSUPPORTED, QUIC_VERSION_UNSUPPORTED);
   if (!connected() &&
-      session()->error() == QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT) {
-    DCHECK(GetQuicReloadableFlag(enable_quic_stateless_reject_support));
-    QUIC_DLOG(INFO) << "Detected stateless reject while waiting for events.  "
-                    << "Attempting to reconnect.";
+      (session()->error() == QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT ||
+       CanReconnectWithDifferentVersion(&version))) {
+    if (session()->error() == QUIC_CRYPTO_HANDSHAKE_STATELESS_REJECT) {
+      DCHECK(GetQuicReloadableFlag(enable_quic_stateless_reject_support));
+      QUIC_DLOG(INFO) << "Detected stateless reject while waiting for events.  "
+                      << "Attempting to reconnect.";
+    } else {
+      QUIC_DLOG(INFO) << "Can reconnect with version: " << version
+                      << ", attempting to reconnect.";
+    }
     Connect();
   }
 
@@ -310,4 +331,21 @@
   return QuicRandom::GetInstance()->RandUint64();
 }
 
+bool QuicClientBase::CanReconnectWithDifferentVersion(
+    ParsedQuicVersion* version) const {
+  if (session_ == nullptr || session_->connection() == nullptr ||
+      session_->error() != QUIC_INVALID_VERSION ||
+      session_->connection()->server_supported_versions().empty()) {
+    return false;
+  }
+  for (const auto& client_version : supported_versions_) {
+    if (QuicContainsValue(session_->connection()->server_supported_versions(),
+                          client_version)) {
+      *version = client_version;
+      return true;
+    }
+  }
+  return false;
+}
+
 }  // namespace quic
diff --git a/net/third_party/quic/tools/quic_client_base.h b/net/third_party/quic/tools/quic_client_base.h
index 60dd7fad3..f21c3f199 100644
--- a/net/third_party/quic/tools/quic_client_base.h
+++ b/net/third_party/quic/tools/quic_client_base.h
@@ -267,6 +267,7 @@
   // TODO(rch): Change the connection parameter to take in a
   // std::unique_ptr<QuicConnection> instead.
   virtual std::unique_ptr<QuicSession> CreateQuicClientSession(
+      const ParsedQuicVersionVector& supported_versions,
       QuicConnection* connection) = 0;
 
   // Generates the next ConnectionId for |server_id_|.  By default, if the
@@ -290,6 +291,10 @@
   void ResetSession() { session_.reset(); }
 
  private:
+  // Returns true and set |version| if client can reconnect with a different
+  // version.
+  bool CanReconnectWithDifferentVersion(ParsedQuicVersion* version) const;
+
   // |server_id_| is a tuple (hostname, port, is_https) of the server.
   QuicServerId server_id_;
 
diff --git a/net/third_party/quic/tools/quic_packet_printer_bin.cc b/net/third_party/quic/tools/quic_packet_printer_bin.cc
index 3cce36b..495f4bd 100644
--- a/net/third_party/quic/tools/quic_packet_printer_bin.cc
+++ b/net/third_party/quic/tools/quic_packet_printer_bin.cc
@@ -65,7 +65,8 @@
     std::cerr << "OnError: " << QuicErrorCodeToString(framer->error())
               << " detail: " << framer->detailed_error() << "\n";
   }
-  bool OnProtocolVersionMismatch(ParsedQuicVersion received_version) override {
+  bool OnProtocolVersionMismatch(ParsedQuicVersion received_version,
+                                 PacketHeaderFormat form) override {
     framer_->set_version(received_version);
     std::cerr << "OnProtocolVersionMismatch: "
               << ParsedQuicVersionToString(received_version) << "\n";
diff --git a/net/third_party/quic/tools/quic_simple_client_session.h b/net/third_party/quic/tools/quic_simple_client_session.h
index 05d9121..26d77604 100644
--- a/net/third_party/quic/tools/quic_simple_client_session.h
+++ b/net/third_party/quic/tools/quic_simple_client_session.h
@@ -13,12 +13,14 @@
 class QuicSimpleClientSession : public QuicSpdyClientSession {
  public:
   QuicSimpleClientSession(const QuicConfig& config,
+                          const ParsedQuicVersionVector& supported_versions,
                           QuicConnection* connection,
                           const QuicServerId& server_id,
                           QuicCryptoClientConfig* crypto_config,
                           QuicClientPushPromiseIndex* push_promise_index,
                           bool drop_response_body)
       : QuicSpdyClientSession(config,
+                              supported_versions,
                               connection,
                               server_id,
                               crypto_config,
diff --git a/net/third_party/quic/tools/quic_simple_dispatcher.cc b/net/third_party/quic/tools/quic_simple_dispatcher.cc
index 3be52ff..eca3a7bb 100644
--- a/net/third_party/quic/tools/quic_simple_dispatcher.cc
+++ b/net/third_party/quic/tools/quic_simple_dispatcher.cc
@@ -49,12 +49,13 @@
 QuicServerSessionBase* QuicSimpleDispatcher::CreateQuicSession(
     QuicConnectionId connection_id,
     const QuicSocketAddress& client_address,
-    QuicStringPiece /*alpn*/) {
+    QuicStringPiece /*alpn*/,
+    const ParsedQuicVersion& version) {
   // The QuicServerSessionBase takes ownership of |connection| below.
   QuicConnection* connection = new QuicConnection(
       connection_id, client_address, helper(), alarm_factory(), writer(),
       /* owns_writer= */ false, Perspective::IS_SERVER,
-      ParsedQuicVersionVector{framer()->version()});
+      ParsedQuicVersionVector{version});
 
   QuicServerSessionBase* session = new QuicSimpleServerSession(
       config(), GetSupportedVersions(), connection, this, session_helper(),
diff --git a/net/third_party/quic/tools/quic_simple_dispatcher.h b/net/third_party/quic/tools/quic_simple_dispatcher.h
index 25414a1..d968b1b 100644
--- a/net/third_party/quic/tools/quic_simple_dispatcher.h
+++ b/net/third_party/quic/tools/quic_simple_dispatcher.h
@@ -32,7 +32,8 @@
   QuicServerSessionBase* CreateQuicSession(
       QuicConnectionId connection_id,
       const QuicSocketAddress& client_address,
-      QuicStringPiece alpn) override;
+      QuicStringPiece alpn,
+      const ParsedQuicVersion& version) override;
 
   QuicSimpleServerBackend* server_backend() {
     return quic_simple_server_backend_;
diff --git a/net/third_party/quic/tools/quic_spdy_client_base.cc b/net/third_party/quic/tools/quic_spdy_client_base.cc
index f13ee93..f2c205b 100644
--- a/net/third_party/quic/tools/quic_spdy_client_base.cc
+++ b/net/third_party/quic/tools/quic_spdy_client_base.cc
@@ -92,10 +92,11 @@
 }
 
 std::unique_ptr<QuicSession> QuicSpdyClientBase::CreateQuicClientSession(
+    const quic::ParsedQuicVersionVector& supported_versions,
     QuicConnection* connection) {
-  return QuicMakeUnique<QuicSpdyClientSession>(*config(), connection,
-                                               server_id(), crypto_config(),
-                                               &push_promise_index_);
+  return QuicMakeUnique<QuicSpdyClientSession>(
+      *config(), supported_versions, connection, server_id(), crypto_config(),
+      &push_promise_index_);
 }
 
 void QuicSpdyClientBase::SendRequest(const spdy::SpdyHeaderBlock& headers,
diff --git a/net/third_party/quic/tools/quic_spdy_client_base.h b/net/third_party/quic/tools/quic_spdy_client_base.h
index fb5f149..a0905bc 100644
--- a/net/third_party/quic/tools/quic_spdy_client_base.h
+++ b/net/third_party/quic/tools/quic_spdy_client_base.h
@@ -142,6 +142,7 @@
 
   // Takes ownership of |connection|.
   std::unique_ptr<QuicSession> CreateQuicClientSession(
+      const quic::ParsedQuicVersionVector& supported_versions,
       QuicConnection* connection) override;
 
   // If the crypto handshake has not yet been confirmed, adds the data to the
diff --git a/net/third_party/spdy/core/hpack/hpack_decoder_adapter_test.cc b/net/third_party/spdy/core/hpack/hpack_decoder_adapter_test.cc
index 63adb094..67a47324 100644
--- a/net/third_party/spdy/core/hpack/hpack_decoder_adapter_test.cc
+++ b/net/third_party/spdy/core/hpack/hpack_decoder_adapter_test.cc
@@ -17,7 +17,7 @@
 #include "net/third_party/http2/hpack/decoder/hpack_decoder_state.h"
 #include "net/third_party/http2/hpack/decoder/hpack_decoder_tables.h"
 #include "net/third_party/http2/hpack/tools/hpack_block_builder.h"
-#include "net/third_party/http2/tools/http2_random.h"
+#include "net/third_party/http2/test_tools/http2_random.h"
 #include "net/third_party/spdy/core/hpack/hpack_constants.h"
 #include "net/third_party/spdy/core/hpack/hpack_encoder.h"
 #include "net/third_party/spdy/core/hpack/hpack_output_stream.h"
diff --git a/ppapi/host/resource_message_filter_unittest.cc b/ppapi/host/resource_message_filter_unittest.cc
index 76b82fd..976b1fb 100644
--- a/ppapi/host/resource_message_filter_unittest.cc
+++ b/ppapi/host/resource_message_filter_unittest.cc
@@ -7,12 +7,11 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/location.h"
-#include "base/message_loop/message_loop.h"
-#include "base/message_loop/message_loop_current.h"
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/threading/thread.h"
+#include "base/threading/thread_task_runner_handle.h"
 #include "ipc/ipc_message.h"
 #include "ppapi/c/pp_errors.h"
 #include "ppapi/host/host_message_context.h"
@@ -52,12 +51,12 @@
       : ResourceHost(host, instance, resource),
         msg_type_(msg_type),
         reply_msg_type_(reply_msg_type),
-        last_reply_message_loop_(NULL) {}
+        last_reply_task_runner_(NULL) {}
 
   const IPC::Message& last_handled_msg() const { return last_handled_msg_; }
   const IPC::Message& last_reply_msg() const { return last_reply_msg_; }
-  base::MessageLoop* last_reply_message_loop() const {
-    return last_reply_message_loop_;
+  scoped_refptr<base::SingleThreadTaskRunner> last_reply_task_runner() const {
+    return last_reply_task_runner_;
   }
 
   void AddMessageFilter(scoped_refptr<ResourceMessageFilter> filter) {
@@ -78,7 +77,7 @@
   void SendReply(const ReplyMessageContext& context,
                  const IPC::Message& msg) override {
     last_reply_msg_ = msg;
-    last_reply_message_loop_ = base::MessageLoopCurrent::Get();
+    last_reply_task_runner_ = base::ThreadTaskRunnerHandle::Get();
     g_handler_completion.Signal();
   }
 
@@ -88,7 +87,7 @@
 
   IPC::Message last_handled_msg_;
   IPC::Message last_reply_msg_;
-  base::MessageLoop* last_reply_message_loop_;
+  scoped_refptr<base::SingleThreadTaskRunner> last_reply_task_runner_;
 };
 
 // Dummy message filter which simply stores a copy of messages it handles.
@@ -107,11 +106,12 @@
       : ResourceMessageFilter(io_thread.task_runner()),
         task_runner_(bg_thread.task_runner()),
         msg_type_(msg_type),
-        reply_msg_type_(reply_msg_type),
-        last_message_loop_(NULL) {}
+        reply_msg_type_(reply_msg_type) {}
 
   const IPC::Message& last_handled_msg() const { return last_handled_msg_; }
-  base::MessageLoop* last_message_loop() const { return last_message_loop_; }
+  scoped_refptr<base::SingleThreadTaskRunner> last_task_runner() const {
+    return last_task_runner_;
+  }
 
   scoped_refptr<base::TaskRunner> OverrideTaskRunnerForMessage(
       const IPC::Message& msg) override {
@@ -124,7 +124,7 @@
       const IPC::Message& msg,
       HostMessageContext* context) override {
     last_handled_msg_ = msg;
-    last_message_loop_ = base::MessageLoopCurrent::Get();
+    last_task_runner_ = base::ThreadTaskRunnerHandle::Get();
     if (msg.type() == msg_type_) {
       context->reply_msg = IPC::Message(0, reply_msg_type_,
                                         IPC::Message::PRIORITY_NORMAL);
@@ -139,7 +139,7 @@
   uint32_t reply_msg_type_;
 
   IPC::Message last_handled_msg_;
-  base::MessageLoop* last_message_loop_;
+  scoped_refptr<base::SingleThreadTaskRunner> last_task_runner_;
 };
 
 }  // namespace
@@ -177,20 +177,20 @@
     host.HandleMessage(message1, &context);
     g_handler_completion.Wait();
     EXPECT_EQ(filter1->last_handled_msg().type(), message1.type());
-    EXPECT_EQ(filter1->last_message_loop(), bg_thread1.message_loop());
+    EXPECT_EQ(filter1->last_task_runner(), bg_thread1.task_runner());
     EXPECT_EQ(host.last_reply_msg().type(),
               static_cast<uint32_t>(REPLY_MSG1_TYPE));
-    EXPECT_EQ(host.last_reply_message_loop(), io_thread.message_loop());
+    EXPECT_EQ(host.last_reply_task_runner(), io_thread.task_runner());
     g_handler_completion.Reset();
 
     // Message 2 handled by the second filter.
     host.HandleMessage(message2, &context);
     g_handler_completion.Wait();
     EXPECT_EQ(filter2->last_handled_msg().type(), message2.type());
-    EXPECT_EQ(filter2->last_message_loop(), bg_thread2.message_loop());
+    EXPECT_EQ(filter2->last_task_runner(), bg_thread2.task_runner());
     EXPECT_EQ(host.last_reply_msg().type(),
               static_cast<uint32_t>(REPLY_MSG2_TYPE));
-    EXPECT_EQ(host.last_reply_message_loop(), io_thread.message_loop());
+    EXPECT_EQ(host.last_reply_task_runner(), io_thread.task_runner());
     g_handler_completion.Reset();
 
     // Message 3 handled by the resource host.
diff --git a/services/audio/BUILD.gn b/services/audio/BUILD.gn
index 58ade00..a5c7979 100644
--- a/services/audio/BUILD.gn
+++ b/services/audio/BUILD.gn
@@ -89,10 +89,12 @@
     "user_input_monitor.h",
   ]
 
+  deps = [
+    "//components/crash/core/common:crash_key",  # Temporary: crbug.com/888478
+  ]
+
   if (audio_processing_in_audio_service_supported) {
-    deps = [
-      "//media/webrtc",
-    ]
+    deps += [ "//media/webrtc" ]
   }
 
   public_deps = [
diff --git a/services/audio/DEPS b/services/audio/DEPS
index 5c8ac887..3b2ed1e 100644
--- a/services/audio/DEPS
+++ b/services/audio/DEPS
@@ -1,4 +1,5 @@
 include_rules = [
+   "+components/crash/core/common/crash_key.h",  # Temporary: crbug.com/888478
    "+media/audio",
    "+media/base",
    "+media/mojo",
diff --git a/services/audio/loopback_stream.cc b/services/audio/loopback_stream.cc
index 26c7b7ef..9755a46 100644
--- a/services/audio/loopback_stream.cc
+++ b/services/audio/loopback_stream.cc
@@ -5,14 +5,17 @@
 #include "services/audio/loopback_stream.h"
 
 #include <algorithm>
+#include <cinttypes>
 #include <string>
 
 #include "base/bind.h"
 #include "base/stl_util.h"
+#include "base/strings/stringprintf.h"
 #include "base/sync_socket.h"
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "base/time/default_tick_clock.h"
 #include "base/trace_event/trace_event.h"
+#include "components/crash/core/common/crash_key.h"
 #include "media/base/audio_bus.h"
 #include "media/base/vector_math.h"
 #include "mojo/public/cpp/system/buffer.h"
@@ -228,6 +231,9 @@
   // take care of the rest.
 }
 
+// static
+std::atomic<int> LoopbackStream::FlowNetwork::instance_count_;
+
 LoopbackStream::FlowNetwork::FlowNetwork(
     scoped_refptr<base::SequencedTaskRunner> flow_task_runner,
     const media::AudioParameters& output_params,
@@ -236,26 +242,39 @@
       flow_task_runner_(flow_task_runner),
       output_params_(output_params),
       writer_(std::move(writer)),
-      mix_bus_(media::AudioBus::Create(output_params_)) {}
+      mix_bus_(media::AudioBus::Create(output_params_)) {
+  ++instance_count_;
+  magic_bytes_ = 0x600DC0DEu;
+  HelpDiagnoseCauseOfLoopbackCrash("constructed");
+}
 
 void LoopbackStream::FlowNetwork::AddInput(SnooperNode* node) {
+  CHECK_EQ(magic_bytes_, 0x600DC0DEu);
   DCHECK_CALLED_ON_VALID_SEQUENCE(control_sequence_);
 
   base::AutoLock scoped_lock(lock_);
+  if (inputs_.empty()) {
+    HelpDiagnoseCauseOfLoopbackCrash("adding first input");
+  }
   DCHECK(!base::ContainsValue(inputs_, node));
   inputs_.push_back(node);
 }
 
 void LoopbackStream::FlowNetwork::RemoveInput(SnooperNode* node) {
+  CHECK_EQ(magic_bytes_, 0x600DC0DEu);
   DCHECK_CALLED_ON_VALID_SEQUENCE(control_sequence_);
 
   base::AutoLock scoped_lock(lock_);
   const auto it = std::find(inputs_.begin(), inputs_.end(), node);
   DCHECK(it != inputs_.end());
   inputs_.erase(it);
+  if (inputs_.empty()) {
+    HelpDiagnoseCauseOfLoopbackCrash("removed last input");
+  }
 }
 
 void LoopbackStream::FlowNetwork::SetVolume(double volume) {
+  CHECK_EQ(magic_bytes_, 0x600DC0DEu);
   DCHECK_CALLED_ON_VALID_SEQUENCE(control_sequence_);
 
   base::AutoLock scoped_lock(lock_);
@@ -263,6 +282,7 @@
 }
 
 void LoopbackStream::FlowNetwork::Start() {
+  CHECK_EQ(magic_bytes_, 0x600DC0DEu);
   DCHECK_CALLED_ON_VALID_SEQUENCE(control_sequence_);
   DCHECK(!is_started());
 
@@ -270,6 +290,8 @@
   timer_->SetTaskRunner(flow_task_runner_);
   // Note: GenerateMoreAudio() will schedule the timer.
 
+  HelpDiagnoseCauseOfLoopbackCrash("starting");
+
   first_generate_time_ = clock_->NowTicks();
   frames_elapsed_ = 0;
   next_generate_time_ = first_generate_time_;
@@ -282,11 +304,17 @@
 }
 
 LoopbackStream::FlowNetwork::~FlowNetwork() {
+  CHECK_EQ(magic_bytes_, 0x600DC0DEu);
   DCHECK(flow_task_runner_->RunsTasksInCurrentSequence());
   DCHECK(inputs_.empty());
+
+  HelpDiagnoseCauseOfLoopbackCrash("destructing");
+  magic_bytes_ = 0xDEADBEEFu;
+  --instance_count_;
 }
 
 void LoopbackStream::FlowNetwork::GenerateMoreAudio() {
+  CHECK_EQ(magic_bytes_, 0x600DC0DEu);
   DCHECK(flow_task_runner_->RunsTasksInCurrentSequence());
 
   TRACE_EVENT_WITH_FLOW0("audio", "GenerateMoreAudio", this,
@@ -305,6 +333,8 @@
     base::AutoLock scoped_lock(lock_);
     output_volume = volume_;
 
+    HelpDiagnoseCauseOfLoopbackCrash("generating");
+
     // Render the audio from each input, apply this stream's volume setting by
     // scaling the data, then mix it all together to form a single audio
     // signal. If there are no snoopers, just render silence.
@@ -373,4 +403,45 @@
                 &FlowNetwork::GenerateMoreAudio);
 }
 
+void LoopbackStream::FlowNetwork::HelpDiagnoseCauseOfLoopbackCrash(
+    const char* event) {
+  static crash_reporter::CrashKeyString<512> crash_string(
+      "audio-service-loopback");
+  const auto ToAbbreviatedParamsString =
+      [](const media::AudioParameters& params) {
+        return base::StringPrintf(
+            "F%d|L%d|R%d|FPB%d", static_cast<int>(params.format()),
+            static_cast<int>(params.channel_layout()), params.sample_rate(),
+            params.frames_per_buffer());
+      };
+  std::vector<std::string> input_formats;
+  input_formats.reserve(inputs_.size());
+  for (const SnooperNode* input : inputs_) {
+    input_formats.push_back(ToAbbreviatedParamsString(input->input_params()));
+  }
+  crash_string.Set(base::StringPrintf(
+      "num_instances=%d, event=%s, elapsed=%" PRId64 ", first_gen_ts=%" PRId64
+      ", next_gen_ts=%" PRId64
+      ", has_transfer_bus=%c, format=%s, volume=%f, has_timer=%c, inputs={%s}",
+      instance_count_.load(), event, frames_elapsed_,
+      (first_generate_time_ - base::TimeTicks()).InMicroseconds(),
+      (next_generate_time_ - base::TimeTicks()).InMicroseconds(),
+      transfer_bus_ ? 'Y' : 'N',
+      ToAbbreviatedParamsString(output_params_).c_str(), volume_,
+      timer_ ? 'Y' : 'N', base::JoinString(input_formats, ", ").c_str()));
+
+  // If there are any crashes from this code, please record to crbug.com/888478.
+  CHECK_EQ(magic_bytes_, 0x600DC0DEu);
+  CHECK(mix_bus_);
+  CHECK_GT(mix_bus_->channels(), 0);
+  CHECK_EQ(mix_bus_->channels(), output_params_.channels());
+  CHECK_GT(mix_bus_->frames(), 0);
+  CHECK_EQ(mix_bus_->frames(), output_params_.frames_per_buffer());
+  for (int i = 0; i < mix_bus_->channels(); ++i) {
+    float* const data = mix_bus_->channel(i);
+    CHECK(data);
+    memset(data, 0, mix_bus_->frames() * sizeof(data[0]));
+  }
+}
+
 }  // namespace audio
diff --git a/services/audio/loopback_stream.h b/services/audio/loopback_stream.h
index 3907bd1..074d34b8 100644
--- a/services/audio/loopback_stream.h
+++ b/services/audio/loopback_stream.h
@@ -5,6 +5,7 @@
 #ifndef SERVICES_AUDIO_LOOPBACK_STREAM_H_
 #define SERVICES_AUDIO_LOOPBACK_STREAM_H_
 
+#include <atomic>
 #include <map>
 #include <memory>
 #include <utility>
@@ -159,6 +160,12 @@
     // becomes stopped.
     void GenerateMoreAudio();
 
+    // TODO(crbug.com/888478): Remove this and all call points after diagnosis.
+    // This generates crash key strings exposing the current state of the flow
+    // network, and also ensures |mix_bus_| is valid, hasn't been corrupted, and
+    // that writing to its data arrays will not cause a page fault.
+    void HelpDiagnoseCauseOfLoopbackCrash(const char* event);
+
     const base::TickClock* clock_;
 
     // Task runner that calls GenerateMoreAudio() to drive all the audio data
@@ -201,6 +208,10 @@
     std::unique_ptr<media::AudioBus> transfer_bus_;
     const std::unique_ptr<media::AudioBus> mix_bus_;
 
+    // TODO(crbug.com/888478): Remove these after diagnosis.
+    volatile uint32_t magic_bytes_;
+    static std::atomic<int> instance_count_;
+
     SEQUENCE_CHECKER(control_sequence_);
 
     DISALLOW_COPY_AND_ASSIGN(FlowNetwork);
diff --git a/services/audio/service.cc b/services/audio/service.cc
index a9850d8..7cb4be0 100644
--- a/services/audio/service.cc
+++ b/services/audio/service.cc
@@ -12,6 +12,7 @@
 #include "base/system/system_monitor.h"
 #include "base/time/default_tick_clock.h"
 #include "base/trace_event/trace_event.h"
+#include "components/crash/core/common/crash_key.h"
 #include "media/audio/audio_manager.h"
 #include "services/audio/debug_recording.h"
 #include "services/audio/device_notifier.h"
@@ -27,6 +28,12 @@
 
 namespace audio {
 
+namespace {
+// TODO(crbug.com/888478): Remove this after diagnosis.
+crash_reporter::CrashKeyString<64> g_service_state_for_crashing(
+    "audio-service-state");
+}  // namespace
+
 Service::Service(std::unique_ptr<AudioManagerAccessor> audio_manager_accessor,
                  base::TimeDelta quit_timeout,
                  bool enable_remote_client_support,
@@ -35,6 +42,8 @@
       audio_manager_accessor_(std::move(audio_manager_accessor)),
       enable_remote_client_support_(enable_remote_client_support),
       registry_(std::move(registry)) {
+  magic_bytes_ = 0x600DC0DEu;
+  g_service_state_for_crashing.Set("constructing");
   DCHECK(audio_manager_accessor_);
   if (enable_remote_client_support_) {
     log_factory_manager_ = std::make_unique<LogFactoryManager>();
@@ -45,30 +54,41 @@
     // created. This is required for in-process device notifications.
     InitializeDeviceMonitor();
   }
+  g_service_state_for_crashing.Set("constructed");
 }
 
 Service::~Service() {
+  CHECK_EQ(magic_bytes_, 0x600DC0DEu);
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  g_service_state_for_crashing.Set("destructing");
   TRACE_EVENT0("audio", "audio::Service::~Service");
 
   metrics_.reset();
+  g_service_state_for_crashing.Set("destructing - killed metrics");
 
   // |ref_factory_| may reentrantly call its |quit_closure| when we reset the
   // members below. Destroy it ahead of time to prevent this.
   ref_factory_.reset();
+  g_service_state_for_crashing.Set("destructing - killed ref_factory");
 
   // Stop all streams cleanly before shutting down the audio manager.
   stream_factory_.reset();
+  g_service_state_for_crashing.Set("destructing - killed stream_factory");
 
   // Reset |debug_recording_| to disable debug recording before AudioManager
   // shutdown.
   debug_recording_.reset();
+  g_service_state_for_crashing.Set("destructing - killed debug_recording");
 
   audio_manager_accessor_->Shutdown();
+  g_service_state_for_crashing.Set("destructing - did shut down manager");
+  magic_bytes_ = 0xDEADBEEFu;
 }
 
 void Service::OnStart() {
+  CHECK_EQ(magic_bytes_, 0x600DC0DEu);
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  g_service_state_for_crashing.Set("starting");
   TRACE_EVENT0("audio", "audio::Service::OnStart")
 
   // This will pre-create AudioManager if AudioManagerAccessor owns it.
@@ -91,14 +111,17 @@
     registry_->AddInterface<mojom::LogFactoryManager>(base::BindRepeating(
         &Service::BindLogFactoryManagerRequest, base::Unretained(this)));
   }
+  g_service_state_for_crashing.Set("started");
 }
 
 void Service::OnBindInterface(
     const service_manager::BindSourceInfo& source_info,
     const std::string& interface_name,
     mojo::ScopedMessagePipeHandle interface_pipe) {
+  CHECK_EQ(magic_bytes_, 0x600DC0DEu);
   DCHECK(ref_factory_);
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  g_service_state_for_crashing.Set("binding " + interface_name);
   TRACE_EVENT1("audio", "audio::Service::OnBindInterface", "interface",
                interface_name);
 
@@ -108,19 +131,24 @@
   registry_->BindInterface(interface_name, std::move(interface_pipe));
   DCHECK(!ref_factory_->HasNoRefs());
   quit_timer_.AbandonAndStop();
+  g_service_state_for_crashing.Set("bound " + interface_name);
 }
 
 bool Service::OnServiceManagerConnectionLost() {
+  CHECK_EQ(magic_bytes_, 0x600DC0DEu);
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  g_service_state_for_crashing.Set("connection lost");
   return true;
 }
 
 void Service::SetQuitClosureForTesting(base::RepeatingClosure quit_closure) {
+  CHECK_EQ(magic_bytes_, 0x600DC0DEu);
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   quit_closure_ = std::move(quit_closure);
 }
 
 void Service::BindSystemInfoRequest(mojom::SystemInfoRequest request) {
+  CHECK_EQ(magic_bytes_, 0x600DC0DEu);
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   DCHECK(ref_factory_);
 
@@ -134,6 +162,7 @@
 }
 
 void Service::BindDebugRecordingRequest(mojom::DebugRecordingRequest request) {
+  CHECK_EQ(magic_bytes_, 0x600DC0DEu);
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   DCHECK(ref_factory_);
   TracedServiceRef service_ref(ref_factory_->CreateRef(),
@@ -149,6 +178,7 @@
 }
 
 void Service::BindStreamFactoryRequest(mojom::StreamFactoryRequest request) {
+  CHECK_EQ(magic_bytes_, 0x600DC0DEu);
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   DCHECK(ref_factory_);
 
@@ -160,6 +190,7 @@
 }
 
 void Service::BindDeviceNotifierRequest(mojom::DeviceNotifierRequest request) {
+  CHECK_EQ(magic_bytes_, 0x600DC0DEu);
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   DCHECK(ref_factory_);
   DCHECK(enable_remote_client_support_);
@@ -178,6 +209,7 @@
 
 void Service::BindLogFactoryManagerRequest(
     mojom::LogFactoryManagerRequest request) {
+  CHECK_EQ(magic_bytes_, 0x600DC0DEu);
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   DCHECK(ref_factory_);
   DCHECK(log_factory_manager_);
@@ -188,6 +220,7 @@
 }
 
 void Service::MaybeRequestQuitDelayed() {
+  CHECK_EQ(magic_bytes_, 0x600DC0DEu);
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   metrics_->HasNoConnections();
   if (quit_timeout_ <= base::TimeDelta())
@@ -196,6 +229,7 @@
 }
 
 void Service::MaybeRequestQuit() {
+  CHECK_EQ(magic_bytes_, 0x600DC0DEu);
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   DCHECK(ref_factory_ && ref_factory_->HasNoRefs() &&
          quit_timeout_ > base::TimeDelta());
@@ -207,6 +241,7 @@
 }
 
 void Service::InitializeDeviceMonitor() {
+  CHECK_EQ(magic_bytes_, 0x600DC0DEu);
 #if defined(OS_MACOSX)
   if (audio_device_listener_mac_)
     return;
diff --git a/services/audio/service.h b/services/audio/service.h
index 7451c600..98aa6f12 100644
--- a/services/audio/service.h
+++ b/services/audio/service.h
@@ -129,6 +129,9 @@
 
   std::unique_ptr<service_manager::ServiceContextRefFactory> ref_factory_;
 
+  // TODO(crbug.com/888478): Remove this after diagnosis.
+  volatile uint32_t magic_bytes_;
+
   DISALLOW_COPY_AND_ASSIGN(Service);
 };
 
diff --git a/services/audio/snooper_node.h b/services/audio/snooper_node.h
index 4f6ebc3f..7ead2e79 100644
--- a/services/audio/snooper_node.h
+++ b/services/audio/snooper_node.h
@@ -66,6 +66,8 @@
 
   ~SnooperNode() final;
 
+  const media::AudioParameters& input_params() const { return input_params_; }
+
   // GroupMember::Snooper implementation. Inserts more data into the delay
   // buffer.
   void OnData(const media::AudioBus& input_bus,
diff --git a/services/audio/stream_factory.cc b/services/audio/stream_factory.cc
index 88b9e6f..fece0c4 100644
--- a/services/audio/stream_factory.cc
+++ b/services/audio/stream_factory.cc
@@ -6,8 +6,10 @@
 
 #include <utility>
 
+#include "base/strings/stringprintf.h"
 #include "base/trace_event/trace_event.h"
 #include "base/unguessable_token.h"
+#include "components/crash/core/common/crash_key.h"
 #include "services/audio/input_stream.h"
 #include "services/audio/local_muter.h"
 #include "services/audio/loopback_stream.h"
@@ -17,14 +19,21 @@
 namespace audio {
 
 StreamFactory::StreamFactory(media::AudioManager* audio_manager)
-    : audio_manager_(audio_manager) {}
+    : audio_manager_(audio_manager) {
+  magic_bytes_ = 0x600DC0DEu;
+  SetStateForCrashing("constructed");
+}
 
 StreamFactory::~StreamFactory() {
+  CHECK_EQ(magic_bytes_, 0x600DC0DEu);
   DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
+  SetStateForCrashing("destructing");
+  magic_bytes_ = 0xDEADBEEFu;
 }
 
 void StreamFactory::Bind(mojom::StreamFactoryRequest request,
                          TracedServiceRef context_ref) {
+  CHECK_EQ(magic_bytes_, 0x600DC0DEu);
   DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
   bindings_.AddBinding(this, std::move(request), std::move(context_ref));
 }
@@ -41,7 +50,9 @@
     mojo::ScopedSharedBufferHandle key_press_count_buffer,
     mojom::AudioProcessingConfigPtr processing_config,
     CreateInputStreamCallback created_callback) {
+  CHECK_EQ(magic_bytes_, 0x600DC0DEu);
   DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
+  SetStateForCrashing("creating input stream");
   TRACE_EVENT_NESTABLE_ASYNC_INSTANT1(
       "audio", "CreateInputStream", bindings_.dispatch_context().id_for_trace(),
       "device id", device_id);
@@ -54,6 +65,7 @@
     log->OnError();
     // The callback must still be invoked or mojo complains.
     std::move(created_callback).Run(nullptr, false, base::nullopt);
+    SetStateForCrashing("input stream create failed");
     return;
   }
 
@@ -68,18 +80,23 @@
       UserInputMonitor::Create(std::move(key_press_count_buffer)), device_id,
       params, shared_memory_count, enable_agc, &stream_monitor_coordinator_,
       std::move(processing_config)));
+  SetStateForCrashing("created input stream");
 }
 
 void StreamFactory::AssociateInputAndOutputForAec(
     const base::UnguessableToken& input_stream_id,
     const std::string& output_device_id) {
+  CHECK_EQ(magic_bytes_, 0x600DC0DEu);
   DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
+  SetStateForCrashing("associating for AEC");
   for (const auto& stream : input_streams_) {
     if (stream->id() == input_stream_id) {
       stream->SetOutputDeviceForAec(output_device_id);
+      SetStateForCrashing("associated for AEC");
       return;
     }
   }
+  SetStateForCrashing("did not associate for AEC");
 }
 
 void StreamFactory::CreateOutputStream(
@@ -91,7 +108,9 @@
     const base::UnguessableToken& group_id,
     const base::Optional<base::UnguessableToken>& processing_id,
     CreateOutputStreamCallback created_callback) {
+  CHECK_EQ(magic_bytes_, 0x600DC0DEu);
   DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
+  SetStateForCrashing("creating output stream");
   TRACE_EVENT_NESTABLE_ASYNC_INSTANT1(
       "audio", "CreateOutputStream",
       bindings_.dispatch_context().id_for_trace(), "device id",
@@ -110,11 +129,14 @@
       audio_manager_, output_device_id, params, &coordinator_, group_id,
       &stream_monitor_coordinator_,
       processing_id.value_or(base::UnguessableToken())));
+  SetStateForCrashing("created output stream");
 }
 
 void StreamFactory::BindMuter(mojom::LocalMuterAssociatedRequest request,
                               const base::UnguessableToken& group_id) {
+  CHECK_EQ(magic_bytes_, 0x600DC0DEu);
   DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
+  SetStateForCrashing("binding muter");
   TRACE_EVENT_NESTABLE_ASYNC_INSTANT1(
       "audio", "BindMuter", bindings_.dispatch_context().id_for_trace(),
       "group id", group_id.GetLowForSerialization());
@@ -137,6 +159,7 @@
 
   // Add the binding.
   muter->AddBinding(std::move(request));
+  SetStateForCrashing("bound muter");
 }
 
 void StreamFactory::CreateLoopbackStream(
@@ -147,8 +170,9 @@
     uint32_t shared_memory_count,
     const base::UnguessableToken& group_id,
     CreateLoopbackStreamCallback created_callback) {
+  CHECK_EQ(magic_bytes_, 0x600DC0DEu);
   DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
-
+  SetStateForCrashing("creating loopback stream");
   TRACE_EVENT_NESTABLE_ASYNC_INSTANT1(
       "audio", "CreateLoopbackStream",
       bindings_.dispatch_context().id_for_trace(), "group id",
@@ -162,39 +186,67 @@
       std::move(client), std::move(observer), params, shared_memory_count,
       &coordinator_, group_id);
   loopback_streams_.emplace_back(std::move(stream));
+  SetStateForCrashing("created loopback stream");
 }
 
 void StreamFactory::DestroyInputStream(InputStream* stream) {
+  CHECK_EQ(magic_bytes_, 0x600DC0DEu);
   DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
+  SetStateForCrashing("destroying input stream");
   size_t erased = input_streams_.erase(stream);
   DCHECK_EQ(1u, erased);
+  SetStateForCrashing("destroyed input stream");
 }
 
 void StreamFactory::DestroyOutputStream(OutputStream* stream) {
+  CHECK_EQ(magic_bytes_, 0x600DC0DEu);
   DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
+  SetStateForCrashing("destroying output stream");
   size_t erased = output_streams_.erase(stream);
   DCHECK_EQ(1u, erased);
+  SetStateForCrashing("destroyed output stream");
 }
 
 void StreamFactory::DestroyMuter(LocalMuter* muter) {
+  CHECK_EQ(magic_bytes_, 0x600DC0DEu);
   DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
   DCHECK(muter);
+  SetStateForCrashing("destroying muter");
 
   const auto it = std::find_if(muters_.begin(), muters_.end(),
                                base::MatchesUniquePtr(muter));
   DCHECK(it != muters_.end());
   muters_.erase(it);
+  SetStateForCrashing("destroyed muter");
 }
 
 void StreamFactory::DestroyLoopbackStream(LoopbackStream* stream) {
+  CHECK_EQ(magic_bytes_, 0x600DC0DEu);
   DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
   DCHECK(stream);
 
+  SetStateForCrashing("destroying loopback stream");
+
   const auto it =
       std::find_if(loopback_streams_.begin(), loopback_streams_.end(),
                    base::MatchesUniquePtr(stream));
   DCHECK(it != loopback_streams_.end());
   loopback_streams_.erase(it);
+
+  SetStateForCrashing("destroyed loopback stream");
+}
+
+void StreamFactory::SetStateForCrashing(const char* state) {
+  static crash_reporter::CrashKeyString<256> crash_string(
+      "audio-service-factory-state");
+  crash_string.Set(base::StringPrintf(
+      "%s: binding_count=%d, muters_count=%d, loopback_count=%d, "
+      "input_stream_count=%d, output_stream_count=%d",
+      state, static_cast<int>(bindings_.size()),
+      static_cast<int>(muters_.size()),
+      static_cast<int>(loopback_streams_.size()),
+      static_cast<int>(input_streams_.size()),
+      static_cast<int>(output_streams_.size())));
 }
 
 }  // namespace audio
diff --git a/services/audio/stream_factory.h b/services/audio/stream_factory.h
index 37fddfa7..ae18dbf 100644
--- a/services/audio/stream_factory.h
+++ b/services/audio/stream_factory.h
@@ -97,6 +97,9 @@
   void DestroyMuter(LocalMuter* muter);
   void DestroyLoopbackStream(LoopbackStream* stream);
 
+  // TODO(crbug.com/888478): Remove this after diagnosis.
+  void SetStateForCrashing(const char* state);
+
   SEQUENCE_CHECKER(owning_sequence_);
 
   media::AudioManager* const audio_manager_;
@@ -111,6 +114,9 @@
   InputStreamSet input_streams_;
   OutputStreamSet output_streams_;
 
+  // TODO(crbug.com/888478): Remove this after diagnosis.
+  volatile uint32_t magic_bytes_;
+
   DISALLOW_COPY_AND_ASSIGN(StreamFactory);
 };
 
diff --git a/services/data_decoder/data_decoder_service.cc b/services/data_decoder/data_decoder_service.cc
index a9d954c..8dd5d49 100644
--- a/services/data_decoder/data_decoder_service.cc
+++ b/services/data_decoder/data_decoder_service.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 
+#include "base/bind.h"
 #include "base/macros.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
@@ -14,23 +15,17 @@
 #include "services/data_decoder/json_parser_impl.h"
 #include "services/data_decoder/public/mojom/image_decoder.mojom.h"
 #include "services/data_decoder/xml_parser.h"
-#include "services/service_manager/public/cpp/service_context.h"
 
 namespace data_decoder {
 
-DataDecoderService::DataDecoderService() = default;
+namespace {
 
-DataDecoderService::~DataDecoderService() = default;
+constexpr auto kMaxServiceIdleTime = base::TimeDelta::FromSeconds(5);
 
-// static
-std::unique_ptr<service_manager::Service> DataDecoderService::Create() {
-  return std::make_unique<DataDecoderService>();
-}
+}  // namespace
 
-void DataDecoderService::OnStart() {
-  constexpr int kMaxServiceIdleTimeInSeconds = 5;
-  keepalive_ = std::make_unique<service_manager::ServiceKeepalive>(
-      context(), base::TimeDelta::FromSeconds(kMaxServiceIdleTimeInSeconds));
+DataDecoderService::DataDecoderService()
+    : keepalive_(&binding_, kMaxServiceIdleTime) {
   registry_.AddInterface(base::BindRepeating(
       &DataDecoderService::BindImageDecoder, base::Unretained(this)));
   registry_.AddInterface(base::BindRepeating(
@@ -39,6 +34,19 @@
                                              base::Unretained(this)));
 }
 
+DataDecoderService::DataDecoderService(
+    service_manager::mojom::ServiceRequest request)
+    : DataDecoderService() {
+  BindRequest(std::move(request));
+}
+
+DataDecoderService::~DataDecoderService() = default;
+
+void DataDecoderService::BindRequest(
+    service_manager::mojom::ServiceRequest request) {
+  binding_.Bind(std::move(request));
+}
+
 void DataDecoderService::OnBindInterface(
     const service_manager::BindSourceInfo& source_info,
     const std::string& interface_name,
@@ -48,18 +56,18 @@
 
 void DataDecoderService::BindImageDecoder(mojom::ImageDecoderRequest request) {
   mojo::MakeStrongBinding(
-      std::make_unique<ImageDecoderImpl>(keepalive_->CreateRef()),
+      std::make_unique<ImageDecoderImpl>(keepalive_.CreateRef()),
       std::move(request));
 }
 
 void DataDecoderService::BindJsonParser(mojom::JsonParserRequest request) {
   mojo::MakeStrongBinding(
-      std::make_unique<JsonParserImpl>(keepalive_->CreateRef()),
+      std::make_unique<JsonParserImpl>(keepalive_.CreateRef()),
       std::move(request));
 }
 
 void DataDecoderService::BindXmlParser(mojom::XmlParserRequest request) {
-  mojo::MakeStrongBinding(std::make_unique<XmlParser>(keepalive_->CreateRef()),
+  mojo::MakeStrongBinding(std::make_unique<XmlParser>(keepalive_.CreateRef()),
                           std::move(request));
 }
 
diff --git a/services/data_decoder/data_decoder_service.h b/services/data_decoder/data_decoder_service.h
index bee6e7a..657f1f83 100644
--- a/services/data_decoder/data_decoder_service.h
+++ b/services/data_decoder/data_decoder_service.h
@@ -13,20 +13,23 @@
 #include "services/data_decoder/public/mojom/xml_parser.mojom.h"
 #include "services/service_manager/public/cpp/binder_registry.h"
 #include "services/service_manager/public/cpp/service.h"
+#include "services/service_manager/public/cpp/service_binding.h"
 #include "services/service_manager/public/cpp/service_keepalive.h"
+#include "services/service_manager/public/mojom/service.mojom.h"
 
 namespace data_decoder {
 
 class DataDecoderService : public service_manager::Service {
  public:
   DataDecoderService();
+  explicit DataDecoderService(service_manager::mojom::ServiceRequest request);
   ~DataDecoderService() override;
 
-  // Factory function for use as an embedded service.
-  static std::unique_ptr<service_manager::Service> Create();
+  // May be used to establish a latent Service binding for this instance. May
+  // only be called once, and only if this instance was default-constructed.
+  void BindRequest(service_manager::mojom::ServiceRequest request);
 
   // service_manager::Service:
-  void OnStart() override;
   void OnBindInterface(const service_manager::BindSourceInfo& source_info,
                        const std::string& interface_name,
                        mojo::ScopedMessagePipeHandle interface_pipe) override;
@@ -36,8 +39,9 @@
   void BindJsonParser(mojom::JsonParserRequest request);
   void BindXmlParser(mojom::XmlParserRequest request);
 
+  service_manager::ServiceBinding binding_{this};
+  service_manager::ServiceKeepalive keepalive_;
   service_manager::BinderRegistry registry_;
-  std::unique_ptr<service_manager::ServiceKeepalive> keepalive_;
 
   DISALLOW_COPY_AND_ASSIGN(DataDecoderService);
 };
diff --git a/services/data_decoder/public/cpp/test_data_decoder_service.cc b/services/data_decoder/public/cpp/test_data_decoder_service.cc
index c62ced3..02cc6d7 100644
--- a/services/data_decoder/public/cpp/test_data_decoder_service.cc
+++ b/services/data_decoder/public/cpp/test_data_decoder_service.cc
@@ -5,28 +5,29 @@
 #include "services/data_decoder/public/cpp/test_data_decoder_service.h"
 
 #include "services/data_decoder/data_decoder_service.h"
+#include "services/data_decoder/public/mojom/constants.mojom.h"
 
 namespace data_decoder {
 
 TestDataDecoderService::TestDataDecoderService()
-    : connector_factory_(
-          service_manager::TestConnectorFactory::CreateForUniqueService(
-              std::make_unique<DataDecoderService>())),
-      connector_(connector_factory_->CreateConnector()) {}
+    : connector_(connector_factory_.CreateConnector()),
+      service_(connector_factory_.RegisterInstance(
+          data_decoder::mojom::kServiceName)) {}
 
 TestDataDecoderService::~TestDataDecoderService() = default;
 
-CrashyDataDecoderService::CrashyDataDecoderService(bool crash_json,
-                                                   bool crash_image)
-    : CrashyDataDecoderService(DataDecoderService::Create(),
-                               crash_json,
-                               crash_image) {}
+CrashyDataDecoderService::CrashyDataDecoderService(
+    service_manager::mojom::ServiceRequest request,
+    bool crash_json,
+    bool crash_image)
+    : binding_(this, std::move(request)),
+      crash_json_(crash_json),
+      crash_image_(crash_image) {}
 
 CrashyDataDecoderService::~CrashyDataDecoderService() = default;
 
-// service_manager::Service:
 void CrashyDataDecoderService::OnStart() {
-  real_service_->OnStart();
+  real_service_.OnStart();
 }
 
 void CrashyDataDecoderService::OnBindInterface(
@@ -48,8 +49,8 @@
             this, mojom::ImageDecoderRequest(std::move(interface_pipe)));
     return;
   }
-  real_service_->OnBindInterface(source_info, interface_name,
-                                 std::move(interface_pipe));
+  real_service_.OnBindInterface(source_info, interface_name,
+                                std::move(interface_pipe));
 }
 
 // Overridden from mojom::ImageDecoder:
@@ -76,13 +77,4 @@
   json_parser_binding_.reset();
 }
 
-CrashyDataDecoderService::CrashyDataDecoderService(
-    std::unique_ptr<service_manager::Service> real_service,
-    bool crash_json,
-    bool crash_image)
-    : ForwardingService(real_service.get()),
-      real_service_(std::move(real_service)),
-      crash_json_(crash_json),
-      crash_image_(crash_image) {}
-
 }  // namespace data_decoder
diff --git a/services/data_decoder/public/cpp/test_data_decoder_service.h b/services/data_decoder/public/cpp/test_data_decoder_service.h
index 3b8e153..36b92f2 100644
--- a/services/data_decoder/public/cpp/test_data_decoder_service.h
+++ b/services/data_decoder/public/cpp/test_data_decoder_service.h
@@ -13,6 +13,7 @@
 #include "services/data_decoder/public/mojom/image_decoder.mojom.h"
 #include "services/data_decoder/public/mojom/json_parser.mojom.h"
 #include "services/service_manager/public/cpp/service.h"
+#include "services/service_manager/public/cpp/service_binding.h"
 #include "services/service_manager/public/cpp/test/test_connector_factory.h"
 
 namespace service_manager {
@@ -33,8 +34,9 @@
   service_manager::Connector* connector() const { return connector_.get(); }
 
  private:
-  std::unique_ptr<service_manager::TestConnectorFactory> connector_factory_;
+  service_manager::TestConnectorFactory connector_factory_;
   std::unique_ptr<service_manager::Connector> connector_;
+  DataDecoderService service_;
 
   DISALLOW_COPY_AND_ASSIGN(TestDataDecoderService);
 };
@@ -43,14 +45,16 @@
 // a call is made on an interface.
 // Can be used with a TestConnectorFactory to simulate crashes in the service
 // while processing a call.
-class CrashyDataDecoderService : public service_manager::ForwardingService,
+class CrashyDataDecoderService : public service_manager::Service,
                                  public mojom::ImageDecoder,
                                  public mojom::JsonParser {
  public:
-  CrashyDataDecoderService(bool crash_json, bool crash_image);
+  CrashyDataDecoderService(service_manager::mojom::ServiceRequest request,
+                           bool crash_json,
+                           bool crash_image);
   ~CrashyDataDecoderService() override;
 
-  // service_manager::ForwardingService:
+  // service_manager::Service:
   void OnStart() override;
   void OnBindInterface(const service_manager::BindSourceInfo& source_info,
                        const std::string& interface_name,
@@ -72,17 +76,14 @@
   void Parse(const std::string& json, ParseCallback callback) override;
 
  private:
-  CrashyDataDecoderService(
-      std::unique_ptr<service_manager::Service> real_service,
-      bool crash_json,
-      bool crash_image);
+  service_manager::ServiceBinding binding_;
 
   std::unique_ptr<mojo::Binding<mojom::ImageDecoder>> image_decoder_binding_;
   std::unique_ptr<mojo::Binding<mojom::JsonParser>> json_parser_binding_;
 
   // An instance of the actual DataDecoderService we forward requests to for
   // interfaces that should not crash.
-  std::unique_ptr<service_manager::Service> real_service_;
+  DataDecoderService real_service_;
 
   bool crash_json_ = false;
   bool crash_image_ = false;
diff --git a/services/device/battery/battery_status_manager_linux.cc b/services/device/battery/battery_status_manager_linux.cc
index 157a2c60..162f0df 100644
--- a/services/device/battery/battery_status_manager_linux.cc
+++ b/services/device/battery/battery_status_manager_linux.cc
@@ -321,7 +321,7 @@
   ~BatteryStatusNotificationThread() override {
     // Make sure to shutdown the dbus connection if it is still open in the very
     // end. It needs to happen on the BatteryStatusNotificationThread.
-    message_loop()->task_runner()->PostTask(
+    task_runner()->PostTask(
         FROM_HERE,
         base::Bind(&BatteryStatusNotificationThread::ShutdownDBusConnection,
                    base::Unretained(this)));
@@ -475,7 +475,7 @@
 
     // Shutdown DBus connection later because there may be pending tasks on
     // this thread.
-    message_loop()->task_runner()->PostTask(
+    task_runner()->PostTask(
         FROM_HERE, base::Bind(&dbus::Bus::ShutdownAndBlock, system_bus_));
     system_bus_ = nullptr;
   }
diff --git a/services/device/bluetooth/bluetooth_system_unittest.cc b/services/device/bluetooth/bluetooth_system_unittest.cc
index cc5b767..08a6ef8 100644
--- a/services/device/bluetooth/bluetooth_system_unittest.cc
+++ b/services/device/bluetooth/bluetooth_system_unittest.cc
@@ -230,8 +230,7 @@
   }
 
   void StartDiscovery(const dbus::ObjectPath& object_path,
-                      const base::Closure& callback,
-                      ErrorCallback error_callback) override {
+                      ResponseCallback callback) override {
     NOTIMPLEMENTED();
   }
 
diff --git a/services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom b/services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom
index 42a2130..9826b15 100644
--- a/services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom
+++ b/services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom
@@ -27,7 +27,8 @@
   RENDERER,
   GPU,
   UTILITY,
-  PLUGIN
+  PLUGIN,
+  ARC
 };
 
 enum MemoryMapOption {
diff --git a/services/service_manager/public/cpp/service.cc b/services/service_manager/public/cpp/service.cc
index 11e6996..f0a65d7 100644
--- a/services/service_manager/public/cpp/service.cc
+++ b/services/service_manager/public/cpp/service.cc
@@ -19,12 +19,19 @@
                               const std::string& interface_name,
                               mojo::ScopedMessagePipeHandle interface_pipe) {}
 
-void Service::OnDisconnected() {}
+void Service::OnDisconnected() {
+  Terminate();
+}
 
 bool Service::OnServiceManagerConnectionLost() {
   return true;
 }
 
+void Service::Terminate() {
+  if (termination_closure_)
+    std::move(termination_closure_).Run();
+}
+
 ServiceContext* Service::context() const {
   DCHECK(service_context_)
       << "Service::context() may only be called after the Service constructor.";
diff --git a/services/service_manager/public/cpp/service.h b/services/service_manager/public/cpp/service.h
index cf17566..78d1075 100644
--- a/services/service_manager/public/cpp/service.h
+++ b/services/service_manager/public/cpp/service.h
@@ -7,6 +7,7 @@
 
 #include <string>
 
+#include "base/callback.h"
 #include "base/component_export.h"
 #include "base/macros.h"
 #include "mojo/public/cpp/system/message_pipe.h"
@@ -23,6 +24,13 @@
   Service();
   virtual ~Service();
 
+  // Sets a closure to run when the service wants to self-terminate. This may be
+  // used by whomever created the Service instance in order to clean up
+  // associated resources.
+  void set_termination_closure(base::OnceClosure callback) {
+    termination_closure_ = std::move(callback);
+  }
+
   // Called exactly once when a bidirectional connection with the Service
   // Manager has been established. No calls to OnBindInterface() will be made
   // before this.
@@ -42,7 +50,7 @@
   // Service, and no further communication with the Service Manager is possible.
   //
   // The Service may continue to operate and service existing client connections
-  // as it deems appropriate.
+  // as it deems appropriate. The default implementation invokes |Terminate()|.
   virtual void OnDisconnected();
 
   // Called when the Service Manager has stopped tracking this instance. The
@@ -63,6 +71,21 @@
   virtual bool OnServiceManagerConnectionLost();
 
  protected:
+  // Subclasses should always invoke |Terminate()| when they want to
+  // self-terminate. This should generally only be done once the service is
+  // disconnected from the Service Manager and has no outstanding interface
+  // connections servicing clients. Calling |Terminate()| should be considered
+  // roughly equivalent to calling |exit(0)| in a normal POSIX process
+  // environment, except that services allow for the host environment to define
+  // exactly what termination means (see |set_termination_closure| above).
+  //
+  // Note that if no termination closure is set on this Service instance,
+  // calls to |Terminate()| do nothing.
+  //
+  // As a general rule, subclasses should *ALWAYS* assume that |Terminate()| may
+  // delete |*this| before returning.
+  void Terminate();
+
   // Accesses the ServiceContext associated with this Service. Note that this is
   // only valid AFTER the Service's constructor has run.
   ServiceContext* context() const;
@@ -72,6 +95,8 @@
   friend class ServiceContext;
   friend class TestServiceDecorator;
 
+  base::OnceClosure termination_closure_;
+
   // NOTE: This MUST be called before any public Service methods. ServiceContext
   // satisfies this guarantee for any Service instance it owns.
   virtual void SetContext(ServiceContext* context);
diff --git a/services/service_manager/public/cpp/service_keepalive.cc b/services/service_manager/public/cpp/service_keepalive.cc
index d8f30aa..baefbae 100644
--- a/services/service_manager/public/cpp/service_keepalive.cc
+++ b/services/service_manager/public/cpp/service_keepalive.cc
@@ -6,10 +6,21 @@
 
 #include "base/bind.h"
 #include "base/task/post_task.h"
+#include "services/service_manager/public/cpp/service_binding.h"
 #include "services/service_manager/public/cpp/service_context.h"
 
 namespace service_manager {
 
+ServiceKeepalive::ServiceKeepalive(ServiceBinding* binding,
+                                   base::Optional<base::TimeDelta> idle_timeout)
+    : binding_(binding),
+      idle_timeout_(idle_timeout),
+      ref_factory_(base::BindRepeating(&ServiceKeepalive::OnRefCountZero,
+                                       base::Unretained(this))) {
+  ref_factory_.SetRefAddedCallback(base::BindRepeating(
+      &ServiceKeepalive::OnRefAdded, base::Unretained(this)));
+}
+
 ServiceKeepalive::ServiceKeepalive(ServiceContext* context,
                                    base::Optional<base::TimeDelta> idle_timeout,
                                    TimeoutObserver* timeout_observer)
@@ -17,8 +28,7 @@
       idle_timeout_(idle_timeout),
       timeout_observer_(timeout_observer),
       ref_factory_(base::BindRepeating(&ServiceKeepalive::OnRefCountZero,
-                                       base::Unretained(this))),
-      weak_ptr_factory_(this) {
+                                       base::Unretained(this))) {
   ref_factory_.SetRefAddedCallback(base::BindRepeating(
       &ServiceKeepalive::OnRefAdded, base::Unretained(this)));
 }
@@ -34,23 +44,27 @@
 }
 
 void ServiceKeepalive::OnRefAdded() {
-  if (idle_timer_.IsRunning() && timeout_observer_)
+  if (idle_timer_ && timeout_observer_)
     timeout_observer_->OnTimeoutCancelled();
-  idle_timer_.Stop();
+  idle_timer_.reset();
 }
 
 void ServiceKeepalive::OnRefCountZero() {
   if (!idle_timeout_.has_value())
     return;
-  idle_timer_.Start(FROM_HERE, idle_timeout_.value(),
-                    base::BindRepeating(&ServiceKeepalive::OnTimerExpired,
-                                        weak_ptr_factory_.GetWeakPtr()));
+  idle_timer_.emplace();
+  idle_timer_->Start(FROM_HERE, *idle_timeout_,
+                     base::BindRepeating(&ServiceKeepalive::OnTimerExpired,
+                                         base::Unretained(this)));
 }
 
 void ServiceKeepalive::OnTimerExpired() {
   if (timeout_observer_)
     timeout_observer_->OnTimeoutExpired();
-  context_->CreateQuitClosure().Run();
+  if (context_)
+    context_->CreateQuitClosure().Run();
+  else
+    binding_->RequestClose();
 }
 
 }  // namespace service_manager
diff --git a/services/service_manager/public/cpp/service_keepalive.h b/services/service_manager/public/cpp/service_keepalive.h
index 9fb0b9df..60bee754 100644
--- a/services/service_manager/public/cpp/service_keepalive.h
+++ b/services/service_manager/public/cpp/service_keepalive.h
@@ -15,6 +15,7 @@
 
 namespace service_manager {
 
+class ServiceBinding;
 class ServiceContext;
 
 // Helper class which vends ServiceContextRefs from its own
@@ -39,11 +40,17 @@
     virtual void OnTimeoutCancelled() = 0;
   };
 
+  ServiceKeepalive(ServiceBinding* binding,
+                   base::Optional<base::TimeDelta> idle_timeout);
+
   // Creates a keepalive which allows the service to be idle for |idle_timeout|
   // before requesting termination. If |idle_timeout| is not given, the
   // ServiceKeepalive will never request termination, i.e. the service will
   // stay alive indefinitely. Both |context| and |timeout_observer| are not
   // owned and must outlive the ServiceKeepalive instance.
+  //
+  // DEPRECATED: Please consider switching from ServiceContext to ServiceBinding
+  // and using the constructor above.
   ServiceKeepalive(ServiceContext* context,
                    base::Optional<base::TimeDelta> idle_timeout,
                    TimeoutObserver* timeout_observer = nullptr);
@@ -57,12 +64,12 @@
   void OnRefCountZero();
   void OnTimerExpired();
 
-  ServiceContext* const context_;
+  ServiceBinding* const binding_ = nullptr;
+  ServiceContext* const context_ = nullptr;
   const base::Optional<base::TimeDelta> idle_timeout_;
-  TimeoutObserver* const timeout_observer_;
-  base::OneShotTimer idle_timer_;
+  base::Optional<base::OneShotTimer> idle_timer_;
+  TimeoutObserver* const timeout_observer_ = nullptr;
   ServiceContextRefFactory ref_factory_;
-  base::WeakPtrFactory<ServiceKeepalive> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(ServiceKeepalive);
 };
diff --git a/services/service_manager/public/cpp/test/test_connector_factory.cc b/services/service_manager/public/cpp/test/test_connector_factory.cc
index d9f7c53..72f19434 100644
--- a/services/service_manager/public/cpp/test/test_connector_factory.cc
+++ b/services/service_manager/public/cpp/test/test_connector_factory.cc
@@ -187,8 +187,82 @@
   DISALLOW_COPY_AND_ASSIGN(MultipleServiceConnector);
 };
 
+class ProxiedServiceConnector : public mojom::Connector {
+ public:
+  ProxiedServiceConnector(TestConnectorFactory::NameToServiceProxyMap* proxies,
+                          const std::string& test_user_id)
+      : proxies_(proxies), test_user_id_(test_user_id) {}
+
+  ~ProxiedServiceConnector() override = default;
+
+ private:
+  // mojom::Connector:
+  void BindInterface(const Identity& target,
+                     const std::string& interface_name,
+                     mojo::ScopedMessagePipeHandle interface_pipe,
+                     BindInterfaceCallback callback) override {
+    auto it = proxies_->find(target.name());
+    CHECK(it != proxies_->end())
+        << "TestConnectorFactory received a BindInterface request for an "
+        << "unregistered service '" << target.name() << "'";
+    mojom::ServicePtr& proxy = it->second;
+    proxy->OnBindInterface(
+        BindSourceInfo(Identity("TestConnectorFactory", test_user_id_),
+                       CapabilitySet()),
+        interface_name, std::move(interface_pipe), base::DoNothing());
+    std::move(callback).Run(mojom::ConnectResult::SUCCEEDED, Identity());
+  }
+
+  void StartService(const Identity& target,
+                    StartServiceCallback callback) override {
+    NOTREACHED();
+  }
+
+  void QueryService(const Identity& target,
+                    QueryServiceCallback callback) override {
+    NOTREACHED();
+  }
+
+  void StartServiceWithProcess(
+      const Identity& identity,
+      mojo::ScopedMessagePipeHandle service,
+      mojom::PIDReceiverRequest pid_receiver_request,
+      StartServiceWithProcessCallback callback) override {
+    NOTREACHED();
+  }
+
+  void Clone(mojom::ConnectorRequest request) override {
+    bindings_.AddBinding(this, std::move(request));
+  }
+
+  void FilterInterfaces(const std::string& spec,
+                        const Identity& source,
+                        mojom::InterfaceProviderRequest source_request,
+                        mojom::InterfaceProviderPtr target) override {
+    NOTREACHED();
+  }
+
+  TestConnectorFactory::NameToServiceProxyMap* const proxies_;
+  const std::string test_user_id_;
+  mojo::BindingSet<mojom::Connector> bindings_;
+
+  DISALLOW_COPY_AND_ASSIGN(ProxiedServiceConnector);
+};
+
+void OnStartResponse(mojom::Connector* connector,
+                     mojom::ConnectorRequest connector_request,
+                     mojom::ServiceControlAssociatedRequest control_request) {
+  connector->Clone(std::move(connector_request));
+}
+
 }  // namespace
 
+TestConnectorFactory::TestConnectorFactory() {
+  std::string guid = base::GenerateGUID();
+  impl_ = std::make_unique<ProxiedServiceConnector>(&service_proxies_, guid);
+  test_user_id_ = guid;
+}
+
 TestConnectorFactory::TestConnectorFactory(
     std::unique_ptr<mojom::Connector> impl,
     std::string test_user_id)
@@ -227,4 +301,14 @@
   return std::make_unique<Connector>(std::move(proxy));
 }
 
+mojom::ServiceRequest TestConnectorFactory::RegisterInstance(
+    const std::string& service_name) {
+  mojom::ServicePtr proxy;
+  mojom::ServiceRequest request = mojo::MakeRequest(&proxy);
+  proxy->OnStart(Identity(service_name, test_user_id_),
+                 base::BindOnce(&OnStartResponse, impl_.get()));
+  service_proxies_[service_name] = std::move(proxy);
+  return request;
+}
+
 }  // namespace service_manager
diff --git a/services/service_manager/public/cpp/test/test_connector_factory.h b/services/service_manager/public/cpp/test/test_connector_factory.h
index 8af22ba..4eb69106 100644
--- a/services/service_manager/public/cpp/test/test_connector_factory.h
+++ b/services/service_manager/public/cpp/test/test_connector_factory.h
@@ -52,8 +52,16 @@
 //   ...
 class TestConnectorFactory {
  public:
+  // Creates a simple TestConnectorFactory which can be used register unowned
+  // Service instances and vend Connectors which can connect to them.
+  TestConnectorFactory();
   ~TestConnectorFactory();
 
+  // A mapping from service names to Service proxies for unowned Service
+  // instances.
+  using NameToServiceProxyMap = std::map<std::string, mojom::ServicePtr>;
+
+  // Used to hold a mapping from service names to owned Service instances.
   using NameToServiceMap = std::map<std::string, std::unique_ptr<Service>>;
 
   // Constructs a new TestConnectorFactory which creates Connectors whose
@@ -77,6 +85,11 @@
   // the Service instance associated with this factory.
   std::unique_ptr<Connector> CreateConnector();
 
+  // Registers a Service instance not owned by this TestConnectorFactory.
+  // Returns a ServiceRequest which the instance must bind in order to receive
+  // simulated events from this object.
+  mojom::ServiceRequest RegisterInstance(const std::string& service_name);
+
   const std::string& test_user_id() const { return test_user_id_; }
 
  private:
@@ -88,6 +101,11 @@
   std::unique_ptr<mojom::Connector> impl_;
   std::string test_user_id_;
 
+  // Mapping used only in the default-constructed case where Service instances
+  // are unowned by the TestConnectorFactory. Maps service names to their
+  // proxies.
+  NameToServiceProxyMap service_proxies_;
+
   DISALLOW_COPY_AND_ASSIGN(TestConnectorFactory);
 };
 
diff --git a/services/tracing/BUILD.gn b/services/tracing/BUILD.gn
index bf6aebd..e7ec2d0 100644
--- a/services/tracing/BUILD.gn
+++ b/services/tracing/BUILD.gn
@@ -108,6 +108,8 @@
     sources += [
       "perfetto/json_trace_exporter_unittest.cc",
       "perfetto/perfetto_integration_unittest.cc",
+      "perfetto/test_utils.cc",
+      "perfetto/test_utils.h",
     ]
 
     deps += [
diff --git a/services/tracing/perfetto/perfetto_integration_unittest.cc b/services/tracing/perfetto/perfetto_integration_unittest.cc
index 94c6ce2..611b418 100644
--- a/services/tracing/perfetto/perfetto_integration_unittest.cc
+++ b/services/tracing/perfetto/perfetto_integration_unittest.cc
@@ -11,29 +11,14 @@
 #include "mojo/public/cpp/bindings/binding.h"
 #include "services/tracing/perfetto/perfetto_service.h"
 #include "services/tracing/perfetto/producer_host.h"
+#include "services/tracing/perfetto/test_utils.h"
 #include "services/tracing/public/cpp/perfetto/producer_client.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/perfetto/include/perfetto/tracing/core/commit_data_request.h"
-#include "third_party/perfetto/include/perfetto/tracing/core/consumer.h"
-#include "third_party/perfetto/include/perfetto/tracing/core/data_source_descriptor.h"
-#include "third_party/perfetto/include/perfetto/tracing/core/trace_config.h"
-#include "third_party/perfetto/include/perfetto/tracing/core/trace_packet.h"
-#include "third_party/perfetto/include/perfetto/tracing/core/trace_writer.h"
-#include "third_party/perfetto/include/perfetto/tracing/core/tracing_service.h"
-#include "third_party/perfetto/protos/perfetto/common/commit_data_request.pb.h"
-#include "third_party/perfetto/protos/perfetto/trace/test_event.pbzero.h"
-#include "third_party/perfetto/protos/perfetto/trace/trace_packet.pb.h"
-#include "third_party/perfetto/protos/perfetto/trace/trace_packet.pbzero.h"
 
 namespace tracing {
 
 namespace {
 
-const char kPerfettoTestDataSourceName[] =
-    "org.chromium.chrome_integration_unittest";
-const char kPerfettoProducerName[] = "chrome_producer_test";
-const char kPerfettoTestString[] = "d00df00d";
-
 class PerfettoIntegrationTest : public testing::Test {
  public:
   void SetUp() override {
@@ -56,240 +41,14 @@
   base::test::ScopedTaskEnvironment scoped_task_environment_;
 };
 
-class TestDataSource {
- public:
-  TestDataSource(ProducerClient* producer_client,
-                 size_t send_packet_count,
-                 const std::string& trace_config,
-                 uint32_t target_buffer)
-      : producer_client_(producer_client),
-        send_packet_count_(send_packet_count),
-        target_buffer_(target_buffer) {
-    if (send_packet_count_ > 0) {
-      std::unique_ptr<perfetto::TraceWriter> writer =
-          producer_client_->CreateTraceWriter(target_buffer);
-      CHECK(writer);
-
-      for (size_t i = 0; i < send_packet_count_; i++) {
-        writer->NewTracePacket()->set_for_testing()->set_str(
-            kPerfettoTestString);
-      }
-    }
-  }
-
-  void WritePacketBigly() {
-    const size_t kMessageSize = 10 * 1024;
-    std::unique_ptr<char[]> payload(new char[kMessageSize]);
-    memset(payload.get(), '.', kMessageSize);
-    payload.get()[kMessageSize - 1] = 0;
-
-    std::unique_ptr<perfetto::TraceWriter> writer =
-        producer_client_->CreateTraceWriter(target_buffer_);
-    CHECK(writer);
-
-    writer->NewTracePacket()->set_for_testing()->set_str(payload.get(),
-                                                         kMessageSize);
-  }
-
- private:
-  ProducerClient* producer_client_;
-  const size_t send_packet_count_;
-  uint32_t target_buffer_;
-};
-
-class MockProducerClient : public ProducerClient {
- public:
-  MockProducerClient(
-      size_t send_packet_count,
-      base::OnceClosure client_enabled_callback = base::OnceClosure(),
-      base::OnceClosure client_disabled_callback = base::OnceClosure())
-      : client_enabled_callback_(std::move(client_enabled_callback)),
-        client_disabled_callback_(std::move(client_disabled_callback)),
-        send_packet_count_(send_packet_count) {}
-
-  size_t send_packet_count() const { return send_packet_count_; }
-
-  void StartDataSource(uint64_t id,
-                       mojom::DataSourceConfigPtr data_source_config) override {
-    enabled_data_source_ = std::make_unique<TestDataSource>(
-        this, send_packet_count_, data_source_config->trace_config,
-        data_source_config->target_buffer);
-
-    if (client_enabled_callback_) {
-      std::move(client_enabled_callback_).Run();
-    }
-  }
-
-  void StopDataSource(uint64_t id, StopDataSourceCallback callback) override {
-    enabled_data_source_.reset();
-
-    if (client_disabled_callback_) {
-      std::move(client_disabled_callback_).Run();
-    }
-
-    std::move(callback).Run();
-  }
-
-  void CommitData(const perfetto::CommitDataRequest& commit,
-                  CommitDataCallback callback = {}) override {
-    // Only write out commits that have actual data in it; Perfetto
-    // might send two commits from different threads (one always empty),
-    // which causes TSan to complain.
-    if (commit.chunks_to_patch_size() || commit.chunks_to_move_size()) {
-      perfetto::protos::CommitDataRequest proto;
-      commit.ToProto(&proto);
-      std::string proto_string;
-      CHECK(proto.SerializeToString(&proto_string));
-      all_client_commit_data_requests_ += proto_string;
-    }
-    ProducerClient::CommitData(commit, callback);
-  }
-
-  void SetAgentEnabledCallback(base::OnceClosure client_enabled_callback) {
-    client_enabled_callback_ = std::move(client_enabled_callback);
-  }
-
-  void SetAgentDisabledCallback(base::OnceClosure client_disabled_callback) {
-    client_disabled_callback_ = std::move(client_disabled_callback);
-  }
-
-  const std::string& all_client_commit_data_requests() const {
-    return all_client_commit_data_requests_;
-  }
-
-  TestDataSource* data_source() { return enabled_data_source_.get(); }
-
- private:
-  base::OnceClosure client_enabled_callback_;
-  base::OnceClosure client_disabled_callback_;
-  const size_t send_packet_count_;
-
-  std::string all_client_commit_data_requests_;
-  std::unique_ptr<TestDataSource> enabled_data_source_;
-};
-
-class MockConsumer : public perfetto::Consumer {
- public:
-  using PacketReceivedCallback = std::function<void(bool)>;
-  MockConsumer(perfetto::TracingService* service,
-               std::string data_source_name,
-               PacketReceivedCallback packet_received_callback)
-      : packet_received_callback_(packet_received_callback),
-        data_source_name_(data_source_name) {
-    consumer_endpoint_ = service->ConnectConsumer(this);
-  }
-
-  void ReadBuffers() { consumer_endpoint_->ReadBuffers(); }
-
-  void StopTracing() {
-    ReadBuffers();
-    consumer_endpoint_->DisableTracing();
-  }
-
-  void StartTracing() {
-    perfetto::TraceConfig trace_config;
-    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);
-
-    consumer_endpoint_->EnableTracing(trace_config);
-  }
-
-  void FreeBuffers() { consumer_endpoint_->FreeBuffers(); }
-
-  size_t received_packets() const { return received_packets_; }
-
-  // perfetto::Consumer implementation
-  void OnConnect() override { StartTracing(); }
-  void OnDisconnect() override {}
-  void OnTracingDisabled() override {}
-
-  void OnTraceData(std::vector<perfetto::TracePacket> packets,
-                   bool has_more) override {
-    for (auto& encoded_packet : packets) {
-      perfetto::protos::TracePacket packet;
-      EXPECT_TRUE(encoded_packet.Decode(&packet));
-      if (packet.for_testing().str() == kPerfettoTestString) {
-        received_packets_++;
-      }
-    }
-
-    packet_received_callback_(has_more);
-  }
-
- private:
-  std::unique_ptr<perfetto::TracingService::ConsumerEndpoint>
-      consumer_endpoint_;
-  size_t received_packets_ = 0;
-  PacketReceivedCallback packet_received_callback_;
-  std::string data_source_name_;
-};
-
-class MockProducer : public ProducerHost {
- public:
-  MockProducer(
-      std::string data_source_name,
-      base::OnceClosure datasource_registered_callback = base::OnceClosure())
-      : datasource_registered_callback_(
-            std::move(datasource_registered_callback)),
-        data_source_name_(data_source_name) {}
-
-  void OnConnect() override {
-    on_commit_callback_for_testing_ =
-        base::BindRepeating(&MockProducer::OnCommit, base::Unretained(this));
-
-    perfetto::DataSourceDescriptor descriptor;
-    descriptor.set_name(data_source_name_);
-    producer_endpoint_->RegisterDataSource(descriptor);
-
-    if (datasource_registered_callback_) {
-      std::move(datasource_registered_callback_).Run();
-    }
-  }
-
-  void OnCommit(const perfetto::CommitDataRequest& commit_data_request) {
-    if (!commit_data_request.chunks_to_patch_size() &&
-        !commit_data_request.chunks_to_move_size()) {
-      return;
-    }
-
-    perfetto::protos::CommitDataRequest proto;
-    commit_data_request.ToProto(&proto);
-    std::string proto_string;
-    CHECK(proto.SerializeToString(&proto_string));
-    all_host_commit_data_requests_ += proto_string;
-  }
-
-  void OnMessagepipesReadyCallback(
-      perfetto::TracingService* perfetto_service,
-      mojom::ProducerClientPtr producer_client_pipe,
-      mojom::ProducerHostRequest producer_host_pipe) {
-    Initialize(std::move(producer_client_pipe), std::move(producer_host_pipe),
-               perfetto_service, kPerfettoProducerName);
-  }
-
-  const std::string& all_host_commit_data_requests() const {
-    return all_host_commit_data_requests_;
-  }
-
- protected:
-  base::OnceClosure datasource_registered_callback_;
-  const std::string data_source_name_;
-  std::string all_host_commit_data_requests_;
-};
-
 TEST_F(PerfettoIntegrationTest, ProducerDatasourceInitialized) {
   auto dummy_client =
       std::make_unique<MockProducerClient>(0 /* send_packet_count */);
 
   base::RunLoop producer_initialized_runloop;
-  auto new_producer = std::make_unique<MockProducer>(
-      kPerfettoTestDataSourceName, producer_initialized_runloop.QuitClosure());
-  dummy_client->CreateMojoMessagepipes(
-      base::BindOnce(&MockProducer::OnMessagepipesReadyCallback,
-                     base::Unretained(new_producer.get()),
-                     base::Unretained(perfetto_service()->GetService())));
+  auto new_producer = std::make_unique<MockProducerHost>(
+      kPerfettoTestDataSourceName, perfetto_service()->GetService(),
+      dummy_client.get(), producer_initialized_runloop.QuitClosure());
 
   producer_initialized_runloop.Run();
 
@@ -298,8 +57,8 @@
 
 TEST_F(PerfettoIntegrationTest, ClientEnabledAndDisabled) {
   base::RunLoop on_trace_packets;
-  MockConsumer consumer(perfetto_service()->GetService(),
-                        kPerfettoTestDataSourceName,
+  MockConsumer consumer(kPerfettoTestDataSourceName,
+                        perfetto_service()->GetService(),
                         [&on_trace_packets](bool has_more) {
                           EXPECT_FALSE(has_more);
                           on_trace_packets.Quit();
@@ -311,12 +70,9 @@
       0 /* send_packet_count */, client_enabled_callback.QuitClosure(),
       client_disabled_callback.QuitClosure());
 
-  auto producer = std::make_unique<MockProducer>(kPerfettoTestDataSourceName);
-  client->CreateMojoMessagepipes(
-      base::BindOnce(&MockProducer::OnMessagepipesReadyCallback,
-                     base::Unretained(producer.get()),
-                     base::Unretained(perfetto_service()->GetService())));
-
+  auto producer = std::make_unique<MockProducerHost>(
+      kPerfettoTestDataSourceName, perfetto_service()->GetService(),
+      client.get());
   client_enabled_callback.Run();
 
   RunUntilIdle();
@@ -340,15 +96,13 @@
       kNumPackets, client_enabled_callback.QuitClosure(),
       client_disabled_callback.QuitClosure());
 
-  auto producer = std::make_unique<MockProducer>(kPerfettoTestDataSourceName);
-  client->CreateMojoMessagepipes(
-      base::BindOnce(&MockProducer::OnMessagepipesReadyCallback,
-                     base::Unretained(producer.get()),
-                     base::Unretained(perfetto_service()->GetService())));
+  auto producer = std::make_unique<MockProducerHost>(
+      kPerfettoTestDataSourceName, perfetto_service()->GetService(),
+      client.get());
 
   base::RunLoop no_more_packets_runloop;
-  MockConsumer consumer(perfetto_service()->GetService(),
-                        kPerfettoTestDataSourceName,
+  MockConsumer consumer(kPerfettoTestDataSourceName,
+                        perfetto_service()->GetService(),
                         [&no_more_packets_runloop](bool has_more) {
                           if (!has_more) {
                             no_more_packets_runloop.Quit();
@@ -373,8 +127,8 @@
   const size_t kNumPackets = 10;
 
   base::RunLoop no_more_packets_runloop;
-  MockConsumer consumer(perfetto_service()->GetService(),
-                        kPerfettoTestDataSourceName,
+  MockConsumer consumer(kPerfettoTestDataSourceName,
+                        perfetto_service()->GetService(),
                         [&no_more_packets_runloop](bool has_more) {
                           if (!has_more) {
                             no_more_packets_runloop.Quit();
@@ -385,12 +139,9 @@
   auto client = std::make_unique<MockProducerClient>(
       kNumPackets, client_enabled_callback.QuitClosure());
 
-  auto new_producer =
-      std::make_unique<MockProducer>(kPerfettoTestDataSourceName);
-  client->CreateMojoMessagepipes(
-      base::BindOnce(&MockProducer::OnMessagepipesReadyCallback,
-                     base::Unretained(new_producer.get()),
-                     base::Unretained(perfetto_service()->GetService())));
+  auto new_producer = std::make_unique<MockProducerHost>(
+      kPerfettoTestDataSourceName, perfetto_service()->GetService(),
+      client.get());
 
   client_enabled_callback.Run();
 
@@ -404,18 +155,12 @@
   ProducerClient::DeleteSoonForTesting(std::move(client));
 }
 
-#if defined(THREAD_SANITIZER)
-#define MAYBE_CommitDataRequestIsMaybeComplete \
-  DISABLED_CommitDataRequestIsMaybeComplete
-#else
-#define MAYBE_CommitDataRequestIsMaybeComplete CommitDataRequestIsMaybeComplete
-#endif
-TEST_F(PerfettoIntegrationTest, MAYBE_CommitDataRequestIsMaybeComplete) {
+TEST_F(PerfettoIntegrationTest, CommitDataRequestIsMaybeComplete) {
   const size_t kNumPackets = 100;
 
   base::RunLoop no_more_packets_runloop;
-  MockConsumer consumer(perfetto_service()->GetService(),
-                        kPerfettoTestDataSourceName,
+  MockConsumer consumer(kPerfettoTestDataSourceName,
+                        perfetto_service()->GetService(),
                         [&no_more_packets_runloop](bool has_more) {
                           if (!has_more) {
                             no_more_packets_runloop.Quit();
@@ -425,16 +170,19 @@
   base::RunLoop client_enabled_callback;
   auto client = std::make_unique<MockProducerClient>(
       kNumPackets, client_enabled_callback.QuitClosure());
-  auto new_producer =
-      std::make_unique<MockProducer>(kPerfettoTestDataSourceName);
-  client->CreateMojoMessagepipes(
-      base::BindOnce(&MockProducer::OnMessagepipesReadyCallback,
-                     base::Unretained(new_producer.get()),
-                     base::Unretained(perfetto_service()->GetService())));
+  auto new_producer = std::make_unique<MockProducerHost>(
+      kPerfettoTestDataSourceName, perfetto_service()->GetService(),
+      client.get());
 
   client_enabled_callback.Run();
 
-  client->data_source()->WritePacketBigly();
+  base::RunLoop wait_for_packet_write;
+  client->GetTaskRunner()->PostTaskAndReply(
+      FROM_HERE,
+      base::BindOnce(&TestDataSource::WritePacketBigly,
+                     base::Unretained(client->data_source())),
+      wait_for_packet_write.QuitClosure());
+  wait_for_packet_write.Run();
 
   RunUntilIdle();
 
@@ -452,8 +200,8 @@
   const size_t kNumPackets = 10;
 
   base::RunLoop no_more_packets_runloop;
-  MockConsumer consumer(perfetto_service()->GetService(),
-                        kPerfettoTestDataSourceName,
+  MockConsumer consumer(kPerfettoTestDataSourceName,
+                        perfetto_service()->GetService(),
                         [&no_more_packets_runloop](bool has_more) {
                           if (!has_more) {
                             no_more_packets_runloop.Quit();
@@ -464,12 +212,9 @@
   auto client = std::make_unique<MockProducerClient>(
       kNumPackets, client_enabled_callback.QuitClosure());
 
-  auto new_producer =
-      std::make_unique<MockProducer>(kPerfettoTestDataSourceName);
-  client->CreateMojoMessagepipes(
-      base::BindOnce(&MockProducer::OnMessagepipesReadyCallback,
-                     base::Unretained(new_producer.get()),
-                     base::Unretained(perfetto_service()->GetService())));
+  auto new_producer = std::make_unique<MockProducerHost>(
+      kPerfettoTestDataSourceName, perfetto_service()->GetService(),
+      client.get());
 
   client_enabled_callback.Run();
 
@@ -515,17 +260,12 @@
       client_disabled_callback.QuitClosure());
 
   base::RunLoop producer_initialized_runloop;
-  auto new_producer = std::make_unique<MockProducer>(
-      "fake", producer_initialized_runloop.QuitClosure());
-  client->CreateMojoMessagepipes(
-      base::BindOnce(&MockProducer::OnMessagepipesReadyCallback,
-                     base::Unretained(new_producer.get()),
-                     base::Unretained(perfetto_service()->GetService())));
-  producer_initialized_runloop.Run();
+  auto new_producer = std::make_unique<MockProducerHost>(
+      "fake_data_source", perfetto_service()->GetService(), client.get());
 
   base::RunLoop no_more_packets_runloop;
-  MockConsumer consumer(perfetto_service()->GetService(),
-                        kPerfettoTestDataSourceName,
+  MockConsumer consumer(kPerfettoTestDataSourceName,
+                        perfetto_service()->GetService(),
                         [&no_more_packets_runloop](bool has_more) {
                           if (!has_more) {
                             no_more_packets_runloop.Quit();
@@ -551,20 +291,16 @@
   auto client2 = std::make_unique<MockProducerClient>(
       0 /* send_packet_count */, client2_enabled_callback.QuitClosure());
 
-  auto producer1 = std::make_unique<MockProducer>(kPerfettoTestDataSourceName);
-  client1->CreateMojoMessagepipes(
-      base::BindOnce(&MockProducer::OnMessagepipesReadyCallback,
-                     base::Unretained(producer1.get()),
-                     base::Unretained(perfetto_service()->GetService())));
+  auto producer1 = std::make_unique<MockProducerHost>(
+      kPerfettoTestDataSourceName, perfetto_service()->GetService(),
+      client1.get());
 
-  auto producer2 = std::make_unique<MockProducer>(kPerfettoTestDataSourceName);
-  client2->CreateMojoMessagepipes(
-      base::BindOnce(&MockProducer::OnMessagepipesReadyCallback,
-                     base::Unretained(producer2.get()),
-                     base::Unretained(perfetto_service()->GetService())));
+  auto producer2 = std::make_unique<MockProducerHost>(
+      kPerfettoTestDataSourceName, perfetto_service()->GetService(),
+      client2.get());
 
-  MockConsumer consumer(perfetto_service()->GetService(),
-                        kPerfettoTestDataSourceName, nullptr);
+  MockConsumer consumer(kPerfettoTestDataSourceName,
+                        perfetto_service()->GetService(), nullptr);
 
   client1_enabled_callback.Run();
   client2_enabled_callback.Run();
diff --git a/services/tracing/perfetto/test_utils.cc b/services/tracing/perfetto/test_utils.cc
new file mode 100644
index 0000000..2d5a97c9
--- /dev/null
+++ b/services/tracing/perfetto/test_utils.cc
@@ -0,0 +1,265 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+#include <utility>
+
+#include "base/run_loop.h"
+#include "services/tracing/perfetto/test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/perfetto/include/perfetto/tracing/core/commit_data_request.h"
+#include "third_party/perfetto/include/perfetto/tracing/core/trace_config.h"
+#include "third_party/perfetto/include/perfetto/tracing/core/trace_packet.h"
+#include "third_party/perfetto/include/perfetto/tracing/core/trace_writer.h"
+#include "third_party/perfetto/protos/perfetto/common/commit_data_request.pb.h"
+#include "third_party/perfetto/protos/perfetto/trace/test_event.pbzero.h"
+#include "third_party/perfetto/protos/perfetto/trace/trace_packet.pb.h"
+#include "third_party/perfetto/protos/perfetto/trace/trace_packet.pbzero.h"
+
+namespace tracing {
+
+TestDataSource::TestDataSource(const std::string& data_source_name,
+                               size_t send_packet_count)
+    : DataSourceBase(data_source_name), send_packet_count_(send_packet_count) {}
+
+TestDataSource::~TestDataSource() = default;
+
+void TestDataSource::WritePacketBigly() {
+  std::unique_ptr<char[]> payload(new char[kLargeMessageSize]);
+  memset(payload.get(), '.', kLargeMessageSize);
+  payload.get()[kLargeMessageSize - 1] = 0;
+
+  std::unique_ptr<perfetto::TraceWriter> writer =
+      producer_client_->CreateTraceWriter(target_buffer_);
+  CHECK(writer);
+
+  writer->NewTracePacket()->set_for_testing()->set_str(payload.get(),
+                                                       kLargeMessageSize);
+}
+
+void TestDataSource::StartTracing(
+    ProducerClient* producer_client,
+    const mojom::DataSourceConfig& data_source_config) {
+  producer_client_ = producer_client;
+  target_buffer_ = data_source_config.target_buffer;
+
+  if (send_packet_count_ > 0) {
+    std::unique_ptr<perfetto::TraceWriter> writer =
+        producer_client_->CreateTraceWriter(target_buffer_);
+    CHECK(writer);
+
+    for (size_t i = 0; i < send_packet_count_; i++) {
+      writer->NewTracePacket()->set_for_testing()->set_str(kPerfettoTestString);
+    }
+  }
+}
+
+void TestDataSource::StopTracing(base::OnceClosure stop_complete_callback) {
+  std::move(stop_complete_callback).Run();
+}
+
+void TestDataSource::Flush(base::RepeatingClosure flush_complete_callback) {
+  if (flush_complete_callback) {
+    flush_complete_callback.Run();
+  }
+}
+
+MockProducerClient::MockProducerClient(
+    size_t send_packet_count,
+    base::OnceClosure client_enabled_callback,
+    base::OnceClosure client_disabled_callback)
+    : client_enabled_callback_(std::move(client_enabled_callback)),
+      client_disabled_callback_(std::move(client_disabled_callback)),
+      send_packet_count_(send_packet_count) {}
+
+MockProducerClient::~MockProducerClient() = default;
+
+void MockProducerClient::SetupDataSource(const std::string& data_source_name) {
+  enabled_data_source_ =
+      std::make_unique<TestDataSource>(data_source_name, send_packet_count_);
+  AddDataSource(enabled_data_source_.get());
+}
+
+void MockProducerClient::StartDataSource(
+    uint64_t id,
+    mojom::DataSourceConfigPtr data_source_config) {
+  ProducerClient::StartDataSource(id, std::move(data_source_config));
+
+  if (client_enabled_callback_) {
+    std::move(client_enabled_callback_).Run();
+  }
+}
+
+void MockProducerClient::StopDataSource(uint64_t id,
+                                        StopDataSourceCallback callback) {
+  ProducerClient::StopDataSource(id, std::move(callback));
+
+  if (client_disabled_callback_) {
+    std::move(client_disabled_callback_).Run();
+  }
+}
+
+void MockProducerClient::CommitData(const perfetto::CommitDataRequest& commit,
+                                    CommitDataCallback callback) {
+  // Only write out commits that have actual data in it; Perfetto
+  // might send two commits from different threads (one always empty),
+  // which causes TSan to complain.
+  if (commit.chunks_to_patch_size() || commit.chunks_to_move_size()) {
+    perfetto::protos::CommitDataRequest proto;
+    commit.ToProto(&proto);
+    std::string proto_string;
+    CHECK(proto.SerializeToString(&proto_string));
+    all_client_commit_data_requests_ += proto_string;
+  }
+  ProducerClient::CommitData(commit, callback);
+}
+
+void MockProducerClient::SetAgentEnabledCallback(
+    base::OnceClosure client_enabled_callback) {
+  client_enabled_callback_ = std::move(client_enabled_callback);
+}
+
+void MockProducerClient::SetAgentDisabledCallback(
+    base::OnceClosure client_disabled_callback) {
+  client_disabled_callback_ = std::move(client_disabled_callback);
+}
+
+MockConsumer::MockConsumer(std::string data_source_name,
+                           perfetto::TracingService* service,
+                           PacketReceivedCallback packet_received_callback)
+    : packet_received_callback_(packet_received_callback),
+      data_source_name_(data_source_name) {
+  consumer_endpoint_ = service->ConnectConsumer(this);
+}
+
+MockConsumer::~MockConsumer() = default;
+
+void MockConsumer::ReadBuffers() {
+  consumer_endpoint_->ReadBuffers();
+}
+
+void MockConsumer::StopTracing() {
+  ReadBuffers();
+  consumer_endpoint_->DisableTracing();
+}
+
+void MockConsumer::StartTracing() {
+  perfetto::TraceConfig trace_config;
+  trace_config.add_buffers()->set_size_kb(1024 * 32);
+  auto* ds_config = trace_config.add_data_sources()->mutable_config();
+  ds_config->set_name(data_source_name_);
+  ds_config->set_target_buffer(0);
+
+  consumer_endpoint_->EnableTracing(trace_config);
+}
+
+void MockConsumer::FreeBuffers() {
+  consumer_endpoint_->FreeBuffers();
+}
+
+void MockConsumer::OnConnect() {
+  StartTracing();
+}
+void MockConsumer::OnDisconnect() {}
+void MockConsumer::OnTracingDisabled() {}
+
+void MockConsumer::OnTraceData(std::vector<perfetto::TracePacket> packets,
+                               bool has_more) {
+  for (auto& encoded_packet : packets) {
+    perfetto::protos::TracePacket packet;
+    EXPECT_TRUE(encoded_packet.Decode(&packet));
+    if (packet.for_testing().str() == kPerfettoTestString) {
+      received_packets_++;
+    }
+  }
+
+  packet_received_callback_(has_more);
+}
+
+MockProducerHost::MockProducerHost(
+    const std::string& data_source_name,
+    perfetto::TracingService* service,
+    MockProducerClient* producer_client,
+    base::OnceClosure datasource_registered_callback)
+    : datasource_registered_callback_(
+          std::move(datasource_registered_callback)) {
+  auto on_mojo_connected_callback =
+      [](MockProducerClient* producer_client,
+         const std::string& data_source_name, MockProducerHost* producer_host,
+         perfetto::TracingService* service,
+         mojom::ProducerClientPtr producer_client_pipe,
+         mojom::ProducerHostRequest producer_host_pipe) {
+        producer_host->OnMessagepipesReadyCallback(
+            service, std::move(producer_client_pipe),
+            std::move(producer_host_pipe));
+        producer_client->SetupDataSource(data_source_name);
+      };
+
+  producer_client->CreateMojoMessagepipes(base::BindOnce(
+      on_mojo_connected_callback, base::Unretained(producer_client),
+      data_source_name, base::Unretained(this), base::Unretained(service)));
+}
+
+MockProducerHost::~MockProducerHost() = default;
+
+void MockProducerHost::RegisterDataSource(
+    mojom::DataSourceRegistrationPtr registration_info) {
+  ProducerHost::RegisterDataSource(std::move(registration_info));
+
+  on_commit_callback_for_testing_ =
+      base::BindRepeating(&MockProducerHost::OnCommit, base::Unretained(this));
+
+  if (datasource_registered_callback_) {
+    std::move(datasource_registered_callback_).Run();
+  }
+}
+
+void MockProducerHost::OnConnect() {}
+
+void MockProducerHost::OnCommit(
+    const perfetto::CommitDataRequest& commit_data_request) {
+  if (!commit_data_request.chunks_to_patch_size() &&
+      !commit_data_request.chunks_to_move_size()) {
+    return;
+  }
+
+  perfetto::protos::CommitDataRequest proto;
+  commit_data_request.ToProto(&proto);
+  std::string proto_string;
+  CHECK(proto.SerializeToString(&proto_string));
+  all_host_commit_data_requests_ += proto_string;
+}
+
+void MockProducerHost::OnMessagepipesReadyCallback(
+    perfetto::TracingService* perfetto_service,
+    mojom::ProducerClientPtr producer_client_pipe,
+    mojom::ProducerHostRequest producer_host_pipe) {
+  Initialize(std::move(producer_client_pipe), std::move(producer_host_pipe),
+             perfetto_service, kPerfettoProducerName);
+}
+
+MockProducer::MockProducer(const std::string& data_source_name,
+                           perfetto::TracingService* service,
+                           base::OnceClosure on_datasource_registered,
+                           base::OnceClosure on_tracing_started,
+                           size_t num_packets) {
+  producer_client_ = std::make_unique<MockProducerClient>(
+      num_packets, std::move(on_tracing_started));
+
+  producer_host_ = std::make_unique<MockProducerHost>(
+      data_source_name, service, producer_client_.get(),
+      std::move(on_datasource_registered));
+}
+
+MockProducer::~MockProducer() {
+  ProducerClient::DeleteSoonForTesting(std::move(producer_client_));
+}
+
+void MockProducer::WritePacketBigly(base::OnceClosure on_write_complete) {
+  producer_client_->GetTaskRunner()->PostTaskAndReply(
+      FROM_HERE,
+      base::BindOnce(&TestDataSource::WritePacketBigly,
+                     base::Unretained(producer_client_->data_source())),
+      std::move(on_write_complete));
+}
+
+}  // namespace tracing
diff --git a/services/tracing/perfetto/test_utils.h b/services/tracing/perfetto/test_utils.h
new file mode 100644
index 0000000..0dcf1dc
--- /dev/null
+++ b/services/tracing/perfetto/test_utils.h
@@ -0,0 +1,163 @@
+// 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 SERVICES_TRACING_PERFETTO_TEST_UTILS_H_
+#define SERVICES_TRACING_PERFETTO_TEST_UTILS_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "services/tracing/perfetto/producer_host.h"
+#include "services/tracing/public/cpp/perfetto/producer_client.h"
+#include "third_party/perfetto/include/perfetto/tracing/core/consumer.h"
+
+namespace tracing {
+
+const char kPerfettoTestDataSourceName[] =
+    "org.chromium.chrome_integration_unittest";
+const char kPerfettoProducerName[] = "chrome_producer_test";
+const char kPerfettoTestString[] = "d00df00d";
+const size_t kLargeMessageSize = 1 * 1024 * 1024;
+
+class TestDataSource : public ProducerClient::DataSourceBase {
+ public:
+  TestDataSource(const std::string& data_source_name, size_t send_packet_count);
+  ~TestDataSource() override;
+
+  void WritePacketBigly();
+
+  // DataSourceBase implementation
+  void StartTracing(ProducerClient* producer_client,
+                    const mojom::DataSourceConfig& data_source_config) override;
+  void StopTracing(
+      base::OnceClosure stop_complete_callback = base::OnceClosure()) override;
+  void Flush(base::RepeatingClosure flush_complete_callback) override;
+
+ private:
+  ProducerClient* producer_client_ = nullptr;
+  const size_t send_packet_count_;
+  uint32_t target_buffer_ = 0;
+};
+
+class MockProducerClient : public ProducerClient {
+ public:
+  MockProducerClient(
+      size_t send_packet_count,
+      base::OnceClosure client_enabled_callback = base::OnceClosure(),
+      base::OnceClosure client_disabled_callback = base::OnceClosure());
+  ~MockProducerClient() override;
+
+  void SetupDataSource(const std::string& data_source_name);
+
+  void StartDataSource(uint64_t id,
+                       mojom::DataSourceConfigPtr data_source_config) override;
+
+  void StopDataSource(uint64_t id, StopDataSourceCallback callback) override;
+
+  void CommitData(const perfetto::CommitDataRequest& commit,
+                  CommitDataCallback callback = {}) override;
+
+  void SetAgentEnabledCallback(base::OnceClosure client_enabled_callback);
+
+  void SetAgentDisabledCallback(base::OnceClosure client_disabled_callback);
+
+  const std::string& all_client_commit_data_requests() const {
+    return all_client_commit_data_requests_;
+  }
+
+  TestDataSource* data_source() { return enabled_data_source_.get(); }
+
+ private:
+  base::OnceClosure client_enabled_callback_;
+  base::OnceClosure client_disabled_callback_;
+  size_t send_packet_count_;
+  std::string all_client_commit_data_requests_;
+  std::unique_ptr<TestDataSource> enabled_data_source_;
+};
+
+class MockConsumer : public perfetto::Consumer {
+ public:
+  using PacketReceivedCallback = std::function<void(bool)>;
+  MockConsumer(std::string data_source_name,
+               perfetto::TracingService* service,
+               PacketReceivedCallback packet_received_callback);
+  ~MockConsumer() override;
+
+  void ReadBuffers();
+
+  void StopTracing();
+
+  void StartTracing();
+
+  void FreeBuffers();
+
+  size_t received_packets() const { return received_packets_; }
+
+  // perfetto::Consumer implementation
+  void OnConnect() override;
+  void OnDisconnect() override;
+  void OnTracingDisabled() override;
+
+  void OnTraceData(std::vector<perfetto::TracePacket> packets,
+                   bool has_more) override;
+
+ private:
+  std::unique_ptr<perfetto::TracingService::ConsumerEndpoint>
+      consumer_endpoint_;
+  size_t received_packets_ = 0;
+  PacketReceivedCallback packet_received_callback_;
+  std::string data_source_name_;
+};
+
+class MockProducerHost : public ProducerHost {
+ public:
+  MockProducerHost(
+      const std::string& data_source_name,
+      perfetto::TracingService* service,
+      MockProducerClient* producer_client,
+      base::OnceClosure datasource_registered_callback = base::OnceClosure());
+  ~MockProducerHost() override;
+
+  void RegisterDataSource(
+      mojom::DataSourceRegistrationPtr registration_info) override;
+
+  void OnConnect() override;
+
+  void OnCommit(const perfetto::CommitDataRequest& commit_data_request);
+
+  void OnMessagepipesReadyCallback(
+      perfetto::TracingService* perfetto_service,
+      mojom::ProducerClientPtr producer_client_pipe,
+      mojom::ProducerHostRequest producer_host_pipe);
+
+  const std::string& all_host_commit_data_requests() const {
+    return all_host_commit_data_requests_;
+  }
+
+ protected:
+  base::OnceClosure datasource_registered_callback_;
+  const std::string data_source_name_;
+  std::string all_host_commit_data_requests_;
+};
+
+class MockProducer {
+ public:
+  MockProducer(const std::string& data_source_name,
+               perfetto::TracingService* service,
+               base::OnceClosure on_datasource_registered,
+               base::OnceClosure on_tracing_started,
+               size_t num_packets = 10);
+  virtual ~MockProducer();
+
+  void WritePacketBigly(base::OnceClosure on_write_complete);
+
+ private:
+  std::unique_ptr<MockProducerClient> producer_client_;
+  std::unique_ptr<MockProducerHost> producer_host_;
+};
+
+}  // namespace tracing
+
+#endif  // SERVICES_TRACING_PERFETTO_TEST_UTILS_H_
diff --git a/services/ws/public/mojom/window_manager.mojom b/services/ws/public/mojom/window_manager.mojom
index e0b2c8d..15423f0 100644
--- a/services/ws/public/mojom/window_manager.mojom
+++ b/services/ws/public/mojom/window_manager.mojom
@@ -97,11 +97,6 @@
   const string kFrameActiveColor_Property = "prop:frame-active-color";
   const string kFrameInactiveColor_Property = "prop:frame-inactive-color";
 
-  // If true, when a window is in in fullscreen mode, the user cannot reveal
-  // the top portion of the window through a touch / mouse gesture.
-  // Type: bool.
-  const string kImmersiveFullscreen_Property = "prop:immersive-fullscreen";
-
   // The window's minimum size as defined by its content. Maps to
   // aura::client::kMinimumSize_Property. Type: gfx::Size.
   const string kMinimumSize_Property = "prop:minimum-size";
diff --git a/skia/config/SkUserConfig.h b/skia/config/SkUserConfig.h
index 2795820..13be3e4b8d 100644
--- a/skia/config/SkUserConfig.h
+++ b/skia/config/SkUserConfig.h
@@ -155,6 +155,10 @@
 #define SK_DISABLE_EXPLICIT_GPU_RESOURCE_ALLOCATION
 #endif
 
+#ifndef SK_SUPPORT_LEGACY_PAINTALIGNENUM
+#define SK_SUPPORT_LEGACY_PAINTALIGNENUM
+#endif
+
 // Max. verb count for paths rendered by the edge-AA tessellating path renderer.
 #define GR_AA_TESSELLATOR_MAX_VERB_COUNT 100
 
diff --git a/testing/buildbot/trybot_analyze_config.json b/testing/buildbot/trybot_analyze_config.json
index 2322d12..65decbe7 100644
--- a/testing/buildbot/trybot_analyze_config.json
+++ b/testing/buildbot/trybot_analyze_config.json
@@ -53,6 +53,7 @@
       "net/data/.*",
       "sql/test/data/.*",
       "third_party/accessibility-audit/axs_testing.js",
+      "third_party/angle/DEPS",
       "third_party/chaijs/.*(css|html|js)",
       "third_party/closure_compiler/.*(css|html|js)",
       "third_party/hunspell_dictionaries/.*",
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 3632821..94462c3 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -47,7 +47,7 @@
 crbug.com/891427 fast/overflow/scrollRevealButton.html [ Crash ]
 crbug.com/891427 fast/overflow/transformed-frame-scrollIntoView.html [ Crash ]
 ## Next 1 here: https://ci.chromium.org/p/chromium/builders/luci.chromium.try/win7_chromium_rel_ng/114099
-crbug.com/891427 [ Win ] external/wpt/feature-policy/feature-policy-frame-policy-allowed-for-all.https.sub.html [ Timeout ]
+crbug.com/891427 [ Win Mac10.12 ] external/wpt/feature-policy/feature-policy-frame-policy-allowed-for-all.https.sub.html [ Timeout ]
 
 ### Flaky on trybots:
 ### Note: this list includes anything that flaked even once during my (many)
@@ -3496,7 +3496,7 @@
 crbug.com/626703 virtual/outofblink-cors-ns/external/wpt/service-workers/service-worker/fetch-event-is-history-forward-navigation-manual.https.html [ Skip ]
 crbug.com/626703 external/wpt/service-workers/service-worker/fetch-event-is-history-forward-navigation-manual.https.html [ Skip ]
 crbug.com/626703 external/wpt/service-workers/service-worker/fetch-event-is-history-backward-navigation-manual.https.html [ Skip ]
-crbug.com/626703 [ Mac10.12 ] virtual/video-surface-layer/external/wpt/feature-policy/feature-policy-frame-policy-allowed-for-all.https.sub.html [ Timeout ]
+crbug.com/626703 [ Mac10.12 Win7 ] virtual/video-surface-layer/external/wpt/feature-policy/feature-policy-frame-policy-allowed-for-all.https.sub.html [ Timeout ]
 crbug.com/626703 external/wpt/fetch/security/redirect-to-url-with-credentials.https.html [ Timeout ]
 crbug.com/626703 virtual/outofblink-cors/external/wpt/fetch/security/redirect-to-url-with-credentials.https.html [ Timeout ]
 crbug.com/626703 virtual/outofblink-cors-ns/external/wpt/fetch/security/redirect-to-url-with-credentials.https.html [ Timeout ]
diff --git a/third_party/WebKit/LayoutTests/fast/forms/number/number-input-event-composed.html b/third_party/WebKit/LayoutTests/fast/forms/number/number-input-event-composed.html
new file mode 100644
index 0000000..62317b0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/forms/number/number-input-event-composed.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<html>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../resources/common.js"></script>
+<body>
+<input id="test" type="number" value="5" min="1" max="10"/>
+
+<script type="text/javascript">
+var test = document.getElementById("test");
+var spinButton = getElementByPseudoId(internals.shadowRoot(test), "-webkit-inner-spin-button");
+var rect = spinButton.getBoundingClientRect();
+var spinButtonUpX = rect.left + rect.width / 2;
+var spinButtonUpY = rect.top + rect.height / 4;
+var expectedValue = 6;
+
+var t = async_test('Test for a bug in setting composed flag for input events in a type=number input.');
+test.addEventListener('input', t.step_func(e => {
+  assert_true(e.composed);
+  assert_equals(test.value, expectedValue.toString());
+  if (expectedValue === 7)
+    t.done();
+  expectedValue++;
+}));
+test.focus();
+t.step(() => {
+  chrome.gpuBenchmarking.pointerActionSequence(
+    [{ source: 'mouse',
+      actions: [
+        { name: 'pointerMove', x: spinButtonUpX, y: spinButtonUpY },
+        { name: 'pointerDown', x: spinButtonUpX, y: spinButtonUpY },
+        { name: 'pointerUp' }]}]
+  );
+});
+eventSender.keyDown('ArrowUp');
+</script>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/gradients/unprefixed-generated-gradients.html b/third_party/WebKit/LayoutTests/fast/gradients/unprefixed-generated-gradients.html
index 53ebc44..a0cb8a4b8 100644
--- a/third_party/WebKit/LayoutTests/fast/gradients/unprefixed-generated-gradients.html
+++ b/third_party/WebKit/LayoutTests/fast/gradients/unprefixed-generated-gradients.html
@@ -1,5 +1,6 @@
-<!doctype html>
+<!DOCTYPE html>
 <style>
+body { overflow:hidden; } /* Prevent an additional layout pass, which could hide bugs. */
 .radial::before { width:150px; height:150px; border:2px solid black;
 	content: radial-gradient(circle at 45px 45px, #A7D30C, #019F62 40px, rgba(1,159,98,0) 50px);
 	display: block;
@@ -16,4 +17,4 @@
 if (window.testRunner) {
   testRunner.dumpAsTextWithPixelResults();
 }
-</script>
\ No newline at end of file
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/credentialmanager/credentialscontainer-get-with-virtual-authenticator.html b/third_party/WebKit/LayoutTests/http/tests/credentialmanager/credentialscontainer-get-with-virtual-authenticator.html
index b2f831d..b9778bd 100644
--- a/third_party/WebKit/LayoutTests/http/tests/credentialmanager/credentialscontainer-get-with-virtual-authenticator.html
+++ b/third_party/WebKit/LayoutTests/http/tests/credentialmanager/credentialscontainer-get-with-virtual-authenticator.html
@@ -47,6 +47,13 @@
     navigator.credentials.get({ publicKey : customGetAssertionOptions}));
 }, "navigator.credentials.get() with empty allowCredentials returns NotSupportedError");
 
+
+promise_test(t => {
+  var customGetCredentialOptions = deepCopy(GET_CREDENTIAL_OPTIONS);
+  customGetCredentialOptions.allowCredentials.transports = [];
+  return navigator.credentials.get({publicKey: customGetCredentialOptions}).then();
+}, "navigator.credentials.get() with missing transports in allowCredentials.");
+
 promise_test(t => {
   return navigator.credentials.test.clearAuthenticators();
 }, "Clean up testing environment.");
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/system-info/process-info-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/system-info/process-info-expected.txt
new file mode 100644
index 0000000..b125222
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/system-info/process-info-expected.txt
@@ -0,0 +1,12 @@
+Tests ProcessInfo retrieval
+Process:{
+    cpuTime : <number>
+    id : <number>
+    type : browser
+}
+Process:{
+    cpuTime : <number>
+    id : <number>
+    type : renderer
+}
+
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/system-info/process-info.js b/third_party/WebKit/LayoutTests/inspector-protocol/system-info/process-info.js
new file mode 100644
index 0000000..915eb23
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/system-info/process-info.js
@@ -0,0 +1,21 @@
+(async function(testRunner) {
+  var {page, session, dp} = await testRunner
+      .startBlank('Tests ProcessInfo retrieval');
+
+  response = await testRunner.browserP().SystemInfo.getProcessInfo();
+
+  // The number of renderer processes varies, so log only the very first one.
+  seenRenderer = false;
+  for (process of response.result.processInfo) {
+    if (process.type === "renderer") {
+      if (!seenRenderer) {
+        seenRenderer = true;
+      } else {
+        continue;
+      }
+    }
+    testRunner.log(process, 'Process:', ['id', 'cpuTime']);
+  }
+
+  testRunner.completeTest();
+})
diff --git a/third_party/abseil-cpp/absl/debugging/BUILD.gn b/third_party/abseil-cpp/absl/debugging/BUILD.gn
index b50b0a6d..d3582d6 100644
--- a/third_party/abseil-cpp/absl/debugging/BUILD.gn
+++ b/third_party/abseil-cpp/absl/debugging/BUILD.gn
@@ -92,10 +92,10 @@
   ]
   public_configs = [ "//third_party/abseil-cpp:absl_include_config" ]
   sources = [
-    "failure_signal_handler.cc"
+    "failure_signal_handler.cc",
   ]
   public = [
-    "failure_signal_handler.h"
+    "failure_signal_handler.h",
   ]
   deps = [
     ":examine_stack",
@@ -126,6 +126,7 @@
   ]
   deps = [
     "../base",
+    "../base:core_headers",
     "../base:dynamic_annotations",
   ]
 }
diff --git a/third_party/abseil-cpp/absl/time/BUILD.gn b/third_party/abseil-cpp/absl/time/BUILD.gn
index 9927af8..5758e9dc 100644
--- a/third_party/abseil-cpp/absl/time/BUILD.gn
+++ b/third_party/abseil-cpp/absl/time/BUILD.gn
@@ -62,8 +62,9 @@
     ":time",
     "../base",
     "../time/internal/cctz:time_zone",
-    "//testing/gtest",
     "//testing/gmock",
+    "//testing/gtest",
+    "//third_party/googletest/:gmock",
   ]
   visibility = []
   visibility += [ "../time:*" ]
diff --git a/third_party/abseil-cpp/absl/types/BUILD.gn b/third_party/abseil-cpp/absl/types/BUILD.gn
index fd7e89d..bfdafb31 100644
--- a/third_party/abseil-cpp/absl/types/BUILD.gn
+++ b/third_party/abseil-cpp/absl/types/BUILD.gn
@@ -104,6 +104,7 @@
   deps = [
     ":bad_optional_access",
     "../base:config",
+    "../base:core_headers",
     "../memory",
     "../meta:type_traits",
     "../utility",
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc
index 0d0c1ea..c2c9f60 100644
--- a/third_party/blink/common/features.cc
+++ b/third_party/blink/common/features.cc
@@ -18,6 +18,12 @@
     "EagerCacheStorageSetupForServiceWorkers",
     base::FEATURE_ENABLED_BY_DEFAULT};
 
+// Controls the user-specified viewport restriction for GPU Rasterization on
+// mobile. See https://crbug.com/899399
+const base::Feature kEnableGpuRasterizationViewportRestriction{
+    "EnableGpuRasterizationViewportRestriction",
+    base::FEATURE_ENABLED_BY_DEFAULT};
+
 // Enable LayoutNG.
 const base::Feature kLayoutNG{"LayoutNG", base::FEATURE_DISABLED_BY_DEFAULT};
 
diff --git a/third_party/blink/public/common/features.h b/third_party/blink/public/common/features.h
index 5b99a2d..290e4ef 100644
--- a/third_party/blink/public/common/features.h
+++ b/third_party/blink/public/common/features.h
@@ -14,6 +14,8 @@
 BLINK_COMMON_EXPORT extern const base::Feature kAutofillPreviewStyleExperiment;
 BLINK_COMMON_EXPORT extern const base::Feature
     kEagerCacheStorageSetupForServiceWorkers;
+BLINK_COMMON_EXPORT extern const base::Feature
+    kEnableGpuRasterizationViewportRestriction;
 BLINK_COMMON_EXPORT extern const base::Feature kLayoutNG;
 BLINK_COMMON_EXPORT extern const base::Feature kMojoBlobURLs;
 BLINK_COMMON_EXPORT extern const base::Feature kNestedWorkers;
diff --git a/third_party/blink/renderer/build/scripts/make_instrumenting_probes.py b/third_party/blink/renderer/build/scripts/make_instrumenting_probes.py
index 514a0dc..6288ae1 100644
--- a/third_party/blink/renderer/build/scripts/make_instrumenting_probes.py
+++ b/third_party/blink/renderer/build/scripts/make_instrumenting_probes.py
@@ -60,8 +60,7 @@
 def agent_name_to_include(config, agent_name):
     include_path = agent_config(config, agent_name, "include_path") or config["settings"]["include_path"]
     agent_class = agent_name_to_class(config, agent_name)
-    include_file = os.path.join(include_path, NameStyleConverter(agent_class).to_snake_case() + ".h")
-    return include_file.replace("dev_tools", "devtools")
+    return os.path.join(include_path, NameStyleConverter(agent_class).to_snake_case() + ".h")
 
 
 def initialize_jinja_env(config, cache_dir):
diff --git a/third_party/blink/renderer/core/animation/compositor_animations_test.cc b/third_party/blink/renderer/core/animation/compositor_animations_test.cc
index d9be8e9..307f604 100644
--- a/third_party/blink/renderer/core/animation/compositor_animations_test.cc
+++ b/third_party/blink/renderer/core/animation/compositor_animations_test.cc
@@ -1930,21 +1930,26 @@
   const ComputedStyle* style1 = target1->GetLayoutObject()->Style();
   EXPECT_FALSE(style1->HasTransformAnimationWithForwardsOrBothFillMode());
   EXPECT_FALSE(style1->HasTransformRelatedProperty());
+  // HasOpacity is true;
+  EXPECT_TRUE(style1->IsStackingContext());
 
   Element* target2 = document->getElementById("target2");
   const ComputedStyle* style2 = target2->GetLayoutObject()->Style();
   EXPECT_TRUE(style2->HasTransformAnimationWithForwardsOrBothFillMode());
   EXPECT_TRUE(style2->HasTransformRelatedProperty());
+  EXPECT_TRUE(style2->IsStackingContext());
 
   Element* target3 = document->getElementById("target3");
   const ComputedStyle* style3 = target3->GetLayoutObject()->Style();
   EXPECT_TRUE(style3->HasTransformAnimationWithForwardsOrBothFillMode());
   EXPECT_TRUE(style3->HasTransformRelatedProperty());
+  EXPECT_TRUE(style3->IsStackingContext());
 
   Element* target4 = document->getElementById("target4");
   const ComputedStyle* style4 = target4->GetLayoutObject()->Style();
   EXPECT_FALSE(style4->HasTransformAnimationWithForwardsOrBothFillMode());
   EXPECT_FALSE(style4->HasTransformRelatedProperty());
+  EXPECT_TRUE(style4->IsStackingContext());
 }
 
 TEST_F(AnimationCompositorAnimationsTest, HasWebAnimationsWithFillMode) {
@@ -1954,21 +1959,26 @@
   const ComputedStyle* style1 = target1->GetLayoutObject()->Style();
   EXPECT_FALSE(style1->HasTransformAnimationWithForwardsOrBothFillMode());
   EXPECT_FALSE(style1->HasTransformRelatedProperty());
+  // HasOpacity is true;
+  EXPECT_TRUE(style1->IsStackingContext());
 
   Element* target2 = document->getElementById("target2");
   const ComputedStyle* style2 = target2->GetLayoutObject()->Style();
   EXPECT_TRUE(style2->HasTransformAnimationWithForwardsOrBothFillMode());
   EXPECT_TRUE(style2->HasTransformRelatedProperty());
+  EXPECT_TRUE(style2->IsStackingContext());
 
   Element* target3 = document->getElementById("target3");
   const ComputedStyle* style3 = target3->GetLayoutObject()->Style();
   EXPECT_TRUE(style3->HasTransformAnimationWithForwardsOrBothFillMode());
   EXPECT_TRUE(style3->HasTransformRelatedProperty());
+  EXPECT_TRUE(style3->IsStackingContext());
 
   Element* target4 = document->getElementById("target4");
   const ComputedStyle* style4 = target4->GetLayoutObject()->Style();
   EXPECT_FALSE(style4->HasTransformAnimationWithForwardsOrBothFillMode());
   EXPECT_FALSE(style4->HasTransformRelatedProperty());
+  EXPECT_TRUE(style4->IsStackingContext());
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/core_initializer.h b/third_party/blink/renderer/core/core_initializer.h
index 467bb2b..0012e0e 100644
--- a/third_party/blink/renderer/core/core_initializer.h
+++ b/third_party/blink/renderer/core/core_initializer.h
@@ -39,11 +39,11 @@
 
 namespace blink {
 
-class DevToolsSession;
 class Document;
 class HTMLMediaElement;
 class InspectedFrames;
 class InspectorDOMAgent;
+class InspectorSession;
 class LocalFrame;
 class MediaControls;
 class Page;
@@ -94,7 +94,7 @@
   // These methods typically create agents and append them to a session.
   // TODO(nverne): remove this and restore to WebDevToolsAgentImpl once that
   // class is a controller/ crbug:731490
-  virtual void InitInspectorAgentSession(DevToolsSession*,
+  virtual void InitInspectorAgentSession(InspectorSession*,
                                          bool,
                                          InspectorDOMAgent*,
                                          InspectedFrames*,
diff --git a/third_party/blink/renderer/core/dom/node.cc b/third_party/blink/renderer/core/dom/node.cc
index 4a289fae..811a272 100644
--- a/third_party/blink/renderer/core/dom/node.cc
+++ b/third_party/blink/renderer/core/dom/node.cc
@@ -2573,7 +2573,9 @@
 
 void Node::DispatchInputEvent() {
   // Legacy 'input' event for forms set value and checked.
-  DispatchScopedEvent(*Event::CreateBubble(EventTypeNames::input));
+  Event* event = Event::CreateBubble(EventTypeNames::input);
+  event->SetComposed(true);
+  DispatchScopedEvent(*event);
 }
 
 void Node::DefaultEventHandler(Event& event) {
diff --git a/third_party/blink/renderer/core/exported/web_dev_tools_agent_impl.cc b/third_party/blink/renderer/core/exported/web_dev_tools_agent_impl.cc
index 36909617..41db169 100644
--- a/third_party/blink/renderer/core/exported/web_dev_tools_agent_impl.cc
+++ b/third_party/blink/renderer/core/exported/web_dev_tools_agent_impl.cc
@@ -55,7 +55,6 @@
 #include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
 #include "third_party/blink/renderer/core/inspector/dev_tools_emulator.h"
 #include "third_party/blink/renderer/core/inspector/devtools_agent.h"
-#include "third_party/blink/renderer/core/inspector/devtools_session.h"
 #include "third_party/blink/renderer/core/inspector/inspected_frames.h"
 #include "third_party/blink/renderer/core/inspector/inspector_animation_agent.h"
 #include "third_party/blink/renderer/core/inspector/inspector_application_cache_agent.h"
@@ -75,6 +74,7 @@
 #include "third_party/blink/renderer/core/inspector/inspector_performance_agent.h"
 #include "third_party/blink/renderer/core/inspector/inspector_resource_container.h"
 #include "third_party/blink/renderer/core/inspector/inspector_resource_content_loader.h"
+#include "third_party/blink/renderer/core/inspector/inspector_session.h"
 #include "third_party/blink/renderer/core/inspector/inspector_task_runner.h"
 #include "third_party/blink/renderer/core/inspector/inspector_testing_agent.h"
 #include "third_party/blink/renderer/core/inspector/main_thread_debugger.h"
@@ -184,9 +184,10 @@
 
 ClientMessageLoopAdapter* ClientMessageLoopAdapter::instance_ = nullptr;
 
-void WebDevToolsAgentImpl::AttachSession(DevToolsSession* session,
-                                         bool restore) {
-  if (!network_agents_.size())
+InspectorSession* WebDevToolsAgentImpl::AttachSession(
+    InspectorSession::Client* session_client,
+    mojom::blink::DevToolsSessionStatePtr reattach_session_state) {
+  if (!sessions_.size())
     Platform::Current()->CurrentThread()->AddTaskObserver(this);
 
   ClientMessageLoopAdapter::EnsureMainThreadDebuggerCreated();
@@ -194,85 +195,98 @@
   v8::Isolate* isolate = V8PerIsolateData::MainThreadIsolate();
   InspectedFrames* inspected_frames = inspected_frames_.Get();
 
-  int context_group_id =
-      main_thread_debugger->ContextGroupId(inspected_frames->Root());
-  session->ConnectToV8(main_thread_debugger->GetV8Inspector(),
-                       context_group_id);
+  bool should_reattach = !reattach_session_state.is_null();
 
-  InspectorDOMAgent* dom_agent =
-      new InspectorDOMAgent(isolate, inspected_frames, session->V8Session());
-  session->Append(dom_agent);
+  InspectorSession* inspector_session = new InspectorSession(
+      session_client, probe_sink_.Get(), inspected_frames, 0,
+      main_thread_debugger->GetV8Inspector(),
+      main_thread_debugger->ContextGroupId(inspected_frames->Root()),
+      std::move(reattach_session_state));
+
+  InspectorDOMAgent* dom_agent = new InspectorDOMAgent(
+      isolate, inspected_frames, inspector_session->V8Session());
+  inspector_session->Append(dom_agent);
 
   InspectorLayerTreeAgent* layer_tree_agent =
       InspectorLayerTreeAgent::Create(inspected_frames, this);
-  session->Append(layer_tree_agent);
+  inspector_session->Append(layer_tree_agent);
 
   InspectorNetworkAgent* network_agent = new InspectorNetworkAgent(
-      inspected_frames, nullptr, session->V8Session());
-  session->Append(network_agent);
+      inspected_frames, nullptr, inspector_session->V8Session());
+  inspector_session->Append(network_agent);
 
   InspectorCSSAgent* css_agent = InspectorCSSAgent::Create(
       dom_agent, inspected_frames, network_agent,
       resource_content_loader_.Get(), resource_container_.Get());
-  session->Append(css_agent);
+  inspector_session->Append(css_agent);
 
-  InspectorDOMDebuggerAgent* dom_debugger_agent =
-      new InspectorDOMDebuggerAgent(isolate, dom_agent, session->V8Session());
-  session->Append(dom_debugger_agent);
+  InspectorDOMDebuggerAgent* dom_debugger_agent = new InspectorDOMDebuggerAgent(
+      isolate, dom_agent, inspector_session->V8Session());
+  inspector_session->Append(dom_debugger_agent);
 
-  session->Append(
+  inspector_session->Append(
       InspectorDOMSnapshotAgent::Create(inspected_frames, dom_debugger_agent));
 
-  session->Append(new InspectorAnimationAgent(inspected_frames, css_agent,
-                                              session->V8Session()));
+  inspector_session->Append(new InspectorAnimationAgent(
+      inspected_frames, css_agent, inspector_session->V8Session()));
 
-  session->Append(InspectorMemoryAgent::Create(inspected_frames));
+  inspector_session->Append(InspectorMemoryAgent::Create(inspected_frames));
 
-  session->Append(InspectorPerformanceAgent::Create(inspected_frames));
+  inspector_session->Append(
+      InspectorPerformanceAgent::Create(inspected_frames));
 
-  session->Append(InspectorApplicationCacheAgent::Create(inspected_frames));
+  inspector_session->Append(
+      InspectorApplicationCacheAgent::Create(inspected_frames));
 
   InspectorPageAgent* page_agent = InspectorPageAgent::Create(
       inspected_frames, this, resource_content_loader_.Get(),
-      session->V8Session());
-  session->Append(page_agent);
+      inspector_session->V8Session());
+  inspector_session->Append(page_agent);
 
-  session->Append(new InspectorLogAgent(
+  inspector_session->Append(new InspectorLogAgent(
       &inspected_frames->Root()->GetPage()->GetConsoleMessageStorage(),
-      inspected_frames->Root()->GetPerformanceMonitor(), session->V8Session()));
+      inspected_frames->Root()->GetPerformanceMonitor(),
+      inspector_session->V8Session()));
 
   InspectorOverlayAgent* overlay_agent =
       new InspectorOverlayAgent(web_local_frame_impl_.Get(), inspected_frames,
-                                session->V8Session(), dom_agent);
-  session->Append(overlay_agent);
+                                inspector_session->V8Session(), dom_agent);
+  inspector_session->Append(overlay_agent);
 
-  session->Append(new InspectorIOAgent(isolate, session->V8Session()));
+  inspector_session->Append(
+      new InspectorIOAgent(isolate, inspector_session->V8Session()));
 
-  session->Append(new InspectorAuditsAgent(network_agent));
+  inspector_session->Append(new InspectorAuditsAgent(network_agent));
 
   // TODO(dgozman): we should actually pass the view instead of frame, but
   // during remote->local transition we cannot access mainFrameImpl() yet, so
   // we have to store the frame which will become the main frame later.
-  session->Append(new InspectorEmulationAgent(web_local_frame_impl_.Get()));
+  inspector_session->Append(
+      new InspectorEmulationAgent(web_local_frame_impl_.Get()));
 
-  session->Append(new InspectorTestingAgent(inspected_frames));
+  inspector_session->Append(new InspectorTestingAgent(inspected_frames));
 
-  // Call session init callbacks registered from higher layers.
+  // Call session init callbacks registered from higher layers
   CoreInitializer::GetInstance().InitInspectorAgentSession(
-      session, include_view_agents_, dom_agent, inspected_frames,
+      inspector_session, include_view_agents_, dom_agent, inspected_frames,
       web_local_frame_impl_->ViewImpl()->GetPage());
 
-  if (restore && worker_client_)
-    worker_client_->ResumeStartup();
+  if (should_reattach) {
+    inspector_session->Restore();
+    if (worker_client_)
+      worker_client_->ResumeStartup();
+  }
 
   if (node_to_inspect_) {
     overlay_agent->Inspect(node_to_inspect_);
     node_to_inspect_ = nullptr;
   }
 
-  network_agents_.insert(session, network_agent);
-  page_agents_.insert(session, page_agent);
-  overlay_agents_.insert(session, overlay_agent);
+  sessions_.insert(inspector_session);
+  network_agents_.insert(inspector_session, network_agent);
+  page_agents_.insert(inspector_session, page_agent);
+  overlay_agents_.insert(inspector_session, overlay_agent);
+  return inspector_session;
 }
 
 // static
@@ -302,8 +316,7 @@
       include_view_agents_(include_view_agents) {
   DCHECK(IsMainThread());
   agent_ = new DevToolsAgent(
-      this, inspected_frames_.Get(), probe_sink_.Get(),
-      web_local_frame_impl_->GetFrame()->GetInspectorTaskRunner(),
+      this, web_local_frame_impl_->GetFrame()->GetInspectorTaskRunner(),
       Platform::Current()->GetIOTaskRunner());
 }
 
@@ -313,6 +326,7 @@
 
 void WebDevToolsAgentImpl::Trace(blink::Visitor* visitor) {
   visitor->Trace(agent_);
+  visitor->Trace(sessions_);
   visitor->Trace(network_agents_);
   visitor->Trace(page_agents_);
   visitor->Trace(overlay_agents_);
@@ -340,11 +354,12 @@
       web_local_frame_impl_->GetTaskRunner(TaskType::kInternalInspector));
 }
 
-void WebDevToolsAgentImpl::DetachSession(DevToolsSession* session) {
+void WebDevToolsAgentImpl::DetachSession(InspectorSession* session) {
   network_agents_.erase(session);
   page_agents_.erase(session);
   overlay_agents_.erase(session);
-  if (!network_agents_.size())
+  sessions_.erase(session);
+  if (!sessions_.size())
     Platform::Current()->CurrentThread()->RemoveTaskObserver(this);
 }
 
@@ -398,6 +413,8 @@
 void WebDevToolsAgentImpl::DidCommitLoadForLocalFrame(LocalFrame* frame) {
   resource_container_->DidCommitLoadForLocalFrame(frame);
   resource_content_loader_->DidCommitLoadForLocalFrame(frame);
+  for (auto& session : sessions_)
+    session->DidCommitLoadForLocalFrame(frame);
 }
 
 bool WebDevToolsAgentImpl::ScreencastEnabled() {
@@ -461,14 +478,14 @@
 
 void WebDevToolsAgentImpl::WillProcessTask(
     const base::PendingTask& pending_task) {
-  if (network_agents_.IsEmpty())
+  if (sessions_.IsEmpty())
     return;
   ThreadDebugger::IdleFinished(V8PerIsolateData::MainThreadIsolate());
 }
 
 void WebDevToolsAgentImpl::DidProcessTask(
     const base::PendingTask& pending_task) {
-  if (network_agents_.IsEmpty())
+  if (sessions_.IsEmpty())
     return;
   ThreadDebugger::IdleStarted(V8PerIsolateData::MainThreadIsolate());
   FlushProtocolNotifications();
diff --git a/third_party/blink/renderer/core/exported/web_dev_tools_agent_impl.h b/third_party/blink/renderer/core/exported/web_dev_tools_agent_impl.h
index 4f9cc566..e2735a9 100644
--- a/third_party/blink/renderer/core/exported/web_dev_tools_agent_impl.h
+++ b/third_party/blink/renderer/core/exported/web_dev_tools_agent_impl.h
@@ -96,8 +96,10 @@
                        WorkerClient*);
 
   // DevToolsAgent::Client implementation.
-  void AttachSession(DevToolsSession*, bool restore) override;
-  void DetachSession(DevToolsSession*) override;
+  InspectorSession* AttachSession(
+      InspectorSession::Client*,
+      mojom::blink::DevToolsSessionStatePtr reattach_session_state) override;
+  void DetachSession(InspectorSession*) override;
   void InspectElement(const WebPoint& point_in_local_root) override;
   void DebuggerTaskStarted() override;
   void DebuggerTaskFinished() override;
@@ -113,10 +115,12 @@
   void DidProcessTask(const base::PendingTask&) override;
 
   Member<DevToolsAgent> agent_;
-  HeapHashMap<Member<DevToolsSession>, Member<InspectorNetworkAgent>>
+  HeapHashSet<Member<InspectorSession>> sessions_;
+  HeapHashMap<Member<InspectorSession>, Member<InspectorNetworkAgent>>
       network_agents_;
-  HeapHashMap<Member<DevToolsSession>, Member<InspectorPageAgent>> page_agents_;
-  HeapHashMap<Member<DevToolsSession>, Member<InspectorOverlayAgent>>
+  HeapHashMap<Member<InspectorSession>, Member<InspectorPageAgent>>
+      page_agents_;
+  HeapHashMap<Member<InspectorSession>, Member<InspectorOverlayAgent>>
       overlay_agents_;
   WorkerClient* worker_client_;
   Member<WebLocalFrameImpl> web_local_frame_impl_;
diff --git a/third_party/blink/renderer/core/inspector/BUILD.gn b/third_party/blink/renderer/core/inspector/BUILD.gn
index 49980be..6365f54f 100644
--- a/third_party/blink/renderer/core/inspector/BUILD.gn
+++ b/third_party/blink/renderer/core/inspector/BUILD.gn
@@ -25,8 +25,6 @@
     "dev_tools_host.h",
     "devtools_agent.cc",
     "devtools_agent.h",
-    "devtools_session.cc",
-    "devtools_session.h",
     "dom_editor.cc",
     "dom_editor.h",
     "dom_patch_support.cc",
@@ -79,6 +77,8 @@
     "inspector_resource_container.h",
     "inspector_resource_content_loader.cc",
     "inspector_resource_content_loader.h",
+    "inspector_session.cc",
+    "inspector_session.h",
     "inspector_session_state.cc",
     "inspector_session_state.h",
     "inspector_style_sheet.cc",
diff --git a/third_party/blink/renderer/core/inspector/browser_protocol.pdl b/third_party/blink/renderer/core/inspector/browser_protocol.pdl
index 95256f9..0fec6df 100644
--- a/third_party/blink/renderer/core/inspector/browser_protocol.pdl
+++ b/third_party/blink/renderer/core/inspector/browser_protocol.pdl
@@ -5901,6 +5901,23 @@
       # An optional array of GPU driver bug workarounds.
       array of string driverBugWorkarounds
 
+  # Specifies process type.
+  type ProcessType extends string
+    enum
+      browser
+      renderer
+
+  # Represents process info.
+  type ProcessInfo extends object
+    properties
+      # Specifies process type.
+      ProcessType type
+      # Specifies process id.
+      integer id
+      # Specifies cumulative CPU usage in seconds across all threads of the
+      # process since the process start.
+      number cpuTime
+
   # Returns information about the system.
   command getInfo
     returns
@@ -5916,6 +5933,12 @@
       # supported.
       string commandLine
 
+  # Returns information about all running processes.
+  command getProcessInfo
+    returns
+      # An array of process info blocks.
+      array of ProcessInfo processInfo
+
 # Supports additional targets discovery and allows to attach to them.
 domain Target
 
diff --git a/third_party/blink/renderer/core/inspector/devtools_agent.cc b/third_party/blink/renderer/core/inspector/devtools_agent.cc
index 46f930a9..3b86c2fc 100644
--- a/third_party/blink/renderer/core/inspector/devtools_agent.cc
+++ b/third_party/blink/renderer/core/inspector/devtools_agent.cc
@@ -7,22 +7,206 @@
 #include <v8-inspector.h>
 #include <memory>
 
+#include "mojo/public/cpp/bindings/binding.h"
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/exported/web_dev_tools_agent_impl.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
-#include "third_party/blink/renderer/core/inspector/devtools_session.h"
-#include "third_party/blink/renderer/core/inspector/inspected_frames.h"
+#include "third_party/blink/renderer/core/inspector/inspector_session.h"
 #include "third_party/blink/renderer/core/inspector/inspector_task_runner.h"
 #include "third_party/blink/renderer/core/inspector/worker_inspector_controller.h"
-#include "third_party/blink/renderer/core/probe/core_probes.h"
 #include "third_party/blink/renderer/core/workers/worker_global_scope.h"
 #include "third_party/blink/renderer/core/workers/worker_thread.h"
+#include "third_party/blink/renderer/platform/cross_thread_functional.h"
 #include "third_party/blink/renderer/platform/heap/persistent.h"
+#include "third_party/blink/renderer/platform/layout_test_support.h"
+#include "third_party/blink/renderer/platform/web_task_runner.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
 namespace blink {
 
+// --------- DevToolsAgent::Session -------------
+
+class DevToolsAgent::Session : public GarbageCollectedFinalized<Session>,
+                               public mojom::blink::DevToolsSession,
+                               public InspectorSession::Client {
+ public:
+  Session(DevToolsAgent*,
+          mojom::blink::DevToolsSessionHostAssociatedPtrInfo host_ptr_info,
+          mojom::blink::DevToolsSessionAssociatedRequest main_request,
+          mojom::blink::DevToolsSessionRequest io_request,
+          mojom::blink::DevToolsSessionStatePtr reattach_session_state);
+  ~Session() override;
+
+  virtual void Trace(blink::Visitor*);
+  void Detach();
+
+  InspectorSession* inspector_session() { return inspector_session_.Get(); }
+
+ private:
+  class IOSession;
+
+  // mojom::blink::DevToolsSession implementation.
+  void DispatchProtocolCommand(int call_id,
+                               const String& method,
+                               const String& message) override;
+
+  // InspectorSession::Client implementation.
+  void SendProtocolResponse(
+      int session_id,
+      int call_id,
+      const String& response,
+      mojom::blink::DevToolsSessionStatePtr updates) override;
+  void SendProtocolNotification(
+      int session_id,
+      const String& message,
+      mojom::blink::DevToolsSessionStatePtr updates) override;
+
+  void DispatchProtocolCommandInternal(int call_id,
+                                       const String& method,
+                                       const String& message);
+
+  Member<DevToolsAgent> agent_;
+  mojo::AssociatedBinding<mojom::blink::DevToolsSession> binding_;
+  mojom::blink::DevToolsSessionHostAssociatedPtr host_ptr_;
+  IOSession* io_session_;
+  Member<InspectorSession> inspector_session_;
+
+  DISALLOW_COPY_AND_ASSIGN(Session);
+};
+
+// Created and stored in unique_ptr on UI.
+// Binds request, receives messages and destroys on IO.
+class DevToolsAgent::Session::IOSession : public mojom::blink::DevToolsSession {
+ public:
+  IOSession(scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
+            scoped_refptr<InspectorTaskRunner> inspector_task_runner,
+            CrossThreadWeakPersistent<DevToolsAgent::Session> session,
+            mojom::blink::DevToolsSessionRequest request)
+      : io_task_runner_(io_task_runner),
+        inspector_task_runner_(inspector_task_runner),
+        session_(std::move(session)),
+        binding_(this) {
+    io_task_runner->PostTask(
+        FROM_HERE, ConvertToBaseCallback(CrossThreadBind(
+                       &IOSession::BindInterface, CrossThreadUnretained(this),
+                       WTF::Passed(std::move(request)))));
+  }
+
+  ~IOSession() override {}
+
+  void BindInterface(mojom::blink::DevToolsSessionRequest request) {
+    binding_.Bind(std::move(request), io_task_runner_);
+  }
+
+  void DeleteSoon() { io_task_runner_->DeleteSoon(FROM_HERE, this); }
+
+  // mojom::blink::DevToolsSession implementation.
+  void DispatchProtocolCommand(int call_id,
+                               const String& method,
+                               const String& message) override {
+    DCHECK(InspectorSession::ShouldInterruptForMethod(method));
+    // Crash renderer.
+    if (method == "Page.crash")
+      CHECK(false);
+    inspector_task_runner_->AppendTask(
+        CrossThreadBind(&DevToolsAgent::Session::DispatchProtocolCommand,
+                        session_, call_id, method, message));
+  }
+
+ private:
+  scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
+  scoped_refptr<InspectorTaskRunner> inspector_task_runner_;
+  CrossThreadWeakPersistent<DevToolsAgent::Session> session_;
+  mojo::Binding<mojom::blink::DevToolsSession> binding_;
+
+  DISALLOW_COPY_AND_ASSIGN(IOSession);
+};
+
+DevToolsAgent::Session::Session(
+    DevToolsAgent* agent,
+    mojom::blink::DevToolsSessionHostAssociatedPtrInfo host_ptr_info,
+    mojom::blink::DevToolsSessionAssociatedRequest request,
+    mojom::blink::DevToolsSessionRequest io_request,
+    mojom::blink::DevToolsSessionStatePtr reattach_session_state)
+    : agent_(agent), binding_(this, std::move(request)) {
+  io_session_ =
+      new IOSession(agent_->io_task_runner_, agent_->inspector_task_runner_,
+                    WrapCrossThreadWeakPersistent(this), std::move(io_request));
+
+  host_ptr_.Bind(std::move(host_ptr_info));
+  host_ptr_.set_connection_error_handler(
+      WTF::Bind(&DevToolsAgent::Session::Detach, WrapWeakPersistent(this)));
+  inspector_session_ =
+      agent_->client_->AttachSession(this, std::move(reattach_session_state));
+}
+
+DevToolsAgent::Session::~Session() {
+  DCHECK(!host_ptr_.is_bound());
+}
+
+void DevToolsAgent::Session::Trace(blink::Visitor* visitor) {
+  visitor->Trace(agent_);
+  visitor->Trace(inspector_session_);
+}
+
+void DevToolsAgent::Session::Detach() {
+  agent_->client_->DebuggerTaskStarted();
+  agent_->client_->DetachSession(inspector_session_.Get());
+  agent_->sessions_.erase(this);
+  binding_.Close();
+  host_ptr_.reset();
+  io_session_->DeleteSoon();
+  io_session_ = nullptr;
+  inspector_session_->Dispose();
+  agent_->client_->DebuggerTaskFinished();
+}
+
+void DevToolsAgent::Session::SendProtocolResponse(
+    int session_id,
+    int call_id,
+    const String& response,
+    mojom::blink::DevToolsSessionStatePtr updates) {
+  if (!host_ptr_.is_bound())
+    return;
+  // Make tests more predictable by flushing all sessions before sending
+  // protocol response in any of them.
+  if (LayoutTestSupport::IsRunningLayoutTest())
+    agent_->FlushProtocolNotifications();
+  host_ptr_->DispatchProtocolResponse(response, call_id, std::move(updates));
+}
+
+void DevToolsAgent::Session::SendProtocolNotification(
+    int session_id,
+    const String& message,
+    mojom::blink::DevToolsSessionStatePtr updates) {
+  if (!host_ptr_.is_bound())
+    return;
+  host_ptr_->DispatchProtocolNotification(message, std::move(updates));
+}
+
+void DevToolsAgent::Session::DispatchProtocolCommand(int call_id,
+                                                     const String& method,
+                                                     const String& message) {
+  // IOSession does not provide ordering guarantees relative to
+  // Session, so a command may come to IOSession after Session is detached,
+  // and get posted to main thread to this method.
+  //
+  // At the same time, Session may not be garbage collected yet
+  // (even though already detached), and CrossThreadWeakPersistent<Session>
+  // will still be valid.
+  //
+  // Both these factors combined may lead to this method being called after
+  // detach, so we have to check it here.
+  if (!host_ptr_.is_bound())
+    return;
+  agent_->client_->DebuggerTaskStarted();
+  inspector_session_->DispatchProtocolMessage(call_id, method, message);
+  agent_->client_->DebuggerTaskFinished();
+}
+
+// --------- DevToolsAgent -------------
+
 // static
 DevToolsAgent* DevToolsAgent::From(ExecutionContext* execution_context) {
   if (!execution_context)
@@ -47,28 +231,22 @@
 
 DevToolsAgent::DevToolsAgent(
     Client* client,
-    InspectedFrames* inspected_frames,
-    CoreProbeSink* probe_sink,
     scoped_refptr<InspectorTaskRunner> inspector_task_runner,
     scoped_refptr<base::SingleThreadTaskRunner> io_task_runner)
     : client_(client),
       binding_(this),
       associated_binding_(this),
-      inspected_frames_(inspected_frames),
-      probe_sink_(probe_sink),
       inspector_task_runner_(std::move(inspector_task_runner)),
       io_task_runner_(std::move(io_task_runner)) {}
 
 DevToolsAgent::~DevToolsAgent() {}
 
 void DevToolsAgent::Trace(blink::Visitor* visitor) {
-  visitor->Trace(inspected_frames_);
-  visitor->Trace(probe_sink_);
   visitor->Trace(sessions_);
 }
 
 void DevToolsAgent::Dispose() {
-  HeapHashSet<Member<DevToolsSession>> copy(sessions_);
+  HeapHashSet<Member<Session>> copy(sessions_);
   for (auto& session : copy)
     session->Detach();
   CleanupConnection();
@@ -104,7 +282,7 @@
     mojom::blink::DevToolsSessionRequest io_session_request,
     mojom::blink::DevToolsSessionStatePtr reattach_session_state) {
   client_->DebuggerTaskStarted();
-  DevToolsSession* session = new DevToolsSession(
+  Session* session = new Session(
       this, std::move(host), std::move(session_request),
       std::move(io_session_request), std::move(reattach_session_state));
   sessions_.insert(session);
@@ -117,7 +295,7 @@
 
 void DevToolsAgent::FlushProtocolNotifications() {
   for (auto& session : sessions_)
-    session->FlushProtocolNotifications();
+    session->inspector_session()->flushProtocolNotifications();
 }
 
 void DevToolsAgent::ReportChildWorkers(bool report, bool wait_for_debugger) {
diff --git a/third_party/blink/renderer/core/inspector/devtools_agent.h b/third_party/blink/renderer/core/inspector/devtools_agent.h
index 7669f68..c02b3d17 100644
--- a/third_party/blink/renderer/core/inspector/devtools_agent.h
+++ b/third_party/blink/renderer/core/inspector/devtools_agent.h
@@ -13,16 +13,14 @@
 #include "mojo/public/cpp/bindings/binding.h"
 #include "third_party/blink/public/web/devtools_agent.mojom-blink.h"
 #include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/inspector/inspector_session.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/wtf/forward.h"
 #include "third_party/blink/renderer/platform/wtf/ref_counted.h"
 
 namespace blink {
 
-class CoreProbeSink;
-class DevToolsSession;
 class ExecutionContext;
-class InspectedFrames;
 class InspectorTaskRunner;
 class WorkerThread;
 
@@ -33,8 +31,10 @@
   class Client {
    public:
     virtual ~Client() {}
-    virtual void AttachSession(DevToolsSession*, bool restore) = 0;
-    virtual void DetachSession(DevToolsSession*) = 0;
+    virtual InspectorSession* AttachSession(
+        InspectorSession::Client*,
+        mojom::blink::DevToolsSessionStatePtr reattach_session_state) = 0;
+    virtual void DetachSession(InspectorSession*) = 0;
     virtual void InspectElement(const WebPoint&) = 0;
     virtual void DebuggerTaskStarted() = 0;
     virtual void DebuggerTaskFinished() = 0;
@@ -42,8 +42,6 @@
 
   static DevToolsAgent* From(ExecutionContext*);
   DevToolsAgent(Client*,
-                InspectedFrames*,
-                CoreProbeSink*,
                 scoped_refptr<InspectorTaskRunner> inspector_task_runner,
                 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner);
   ~DevToolsAgent() override;
@@ -65,7 +63,7 @@
   virtual void Trace(blink::Visitor*);
 
  private:
-  friend class DevToolsSession;
+  class Session;
 
   // mojom::blink::DevToolsAgent implementation.
   void AttachDevToolsSession(
@@ -92,9 +90,7 @@
   mojo::AssociatedBinding<mojom::blink::DevToolsAgent> associated_binding_;
   mojom::blink::DevToolsAgentHostPtr host_ptr_;
   mojom::blink::DevToolsAgentHostAssociatedPtr associated_host_ptr_;
-  Member<InspectedFrames> inspected_frames_;
-  Member<CoreProbeSink> probe_sink_;
-  HeapHashSet<Member<DevToolsSession>> sessions_;
+  HeapHashSet<Member<Session>> sessions_;
   scoped_refptr<InspectorTaskRunner> inspector_task_runner_;
   scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
   HashMap<WorkerThread*, std::unique_ptr<WorkerData>>
diff --git a/third_party/blink/renderer/core/inspector/devtools_session.cc b/third_party/blink/renderer/core/inspector/devtools_session.cc
deleted file mode 100644
index be57971..0000000
--- a/third_party/blink/renderer/core/inspector/devtools_session.cc
+++ /dev/null
@@ -1,316 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "third_party/blink/renderer/core/inspector/devtools_session.h"
-
-#include "third_party/blink/renderer/bindings/core/v8/script_controller.h"
-#include "third_party/blink/renderer/core/frame/local_frame.h"
-#include "third_party/blink/renderer/core/frame/use_counter.h"
-#include "third_party/blink/renderer/core/inspector/devtools_agent.h"
-#include "third_party/blink/renderer/core/inspector/inspected_frames.h"
-#include "third_party/blink/renderer/core/inspector/inspector_base_agent.h"
-#include "third_party/blink/renderer/core/inspector/inspector_session_state.h"
-#include "third_party/blink/renderer/core/inspector/inspector_task_runner.h"
-#include "third_party/blink/renderer/core/inspector/protocol/Protocol.h"
-#include "third_party/blink/renderer/core/inspector/v8_inspector_string.h"
-#include "third_party/blink/renderer/core/probe/core_probes.h"
-#include "third_party/blink/renderer/platform/cross_thread_functional.h"
-#include "third_party/blink/renderer/platform/heap/persistent.h"
-#include "third_party/blink/renderer/platform/layout_test_support.h"
-#include "third_party/blink/renderer/platform/web_task_runner.h"
-
-namespace blink {
-
-namespace {
-const char kV8StateKey[] = "v8";
-bool ShouldInterruptForMethod(const String& method) {
-  // Keep in sync with DevToolsSession::ShouldSendOnIO.
-  // TODO(dgozman): find a way to share this.
-  return method == "Debugger.pause" || method == "Debugger.setBreakpoint" ||
-         method == "Debugger.setBreakpointByUrl" ||
-         method == "Debugger.removeBreakpoint" ||
-         method == "Debugger.setBreakpointsActive" ||
-         method == "Performance.getMetrics" || method == "Page.crash" ||
-         method == "Runtime.terminateExecution" ||
-         method == "Emulation.setScriptExecutionDisabled";
-}
-}  // namespace
-
-// Created and stored in unique_ptr on UI.
-// Binds request, receives messages and destroys on IO.
-class DevToolsSession::IOSession : public mojom::blink::DevToolsSession {
- public:
-  IOSession(scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
-            scoped_refptr<InspectorTaskRunner> inspector_task_runner,
-            CrossThreadWeakPersistent<::blink::DevToolsSession> session,
-            mojom::blink::DevToolsSessionRequest request)
-      : io_task_runner_(io_task_runner),
-        inspector_task_runner_(inspector_task_runner),
-        session_(std::move(session)),
-        binding_(this) {
-    io_task_runner->PostTask(
-        FROM_HERE, ConvertToBaseCallback(CrossThreadBind(
-                       &IOSession::BindInterface, CrossThreadUnretained(this),
-                       WTF::Passed(std::move(request)))));
-  }
-
-  ~IOSession() override {}
-
-  void BindInterface(mojom::blink::DevToolsSessionRequest request) {
-    binding_.Bind(std::move(request), io_task_runner_);
-  }
-
-  void DeleteSoon() { io_task_runner_->DeleteSoon(FROM_HERE, this); }
-
-  // mojom::blink::DevToolsSession implementation.
-  void DispatchProtocolCommand(int call_id,
-                               const String& method,
-                               const String& message) override {
-    DCHECK(ShouldInterruptForMethod(method));
-    // Crash renderer.
-    if (method == "Page.crash")
-      CHECK(false);
-    inspector_task_runner_->AppendTask(
-        CrossThreadBind(&DevToolsSession::DispatchProtocolCommand, session_,
-                        call_id, method, message));
-  }
-
- private:
-  scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
-  scoped_refptr<InspectorTaskRunner> inspector_task_runner_;
-  CrossThreadWeakPersistent<::blink::DevToolsSession> session_;
-  mojo::Binding<mojom::blink::DevToolsSession> binding_;
-
-  DISALLOW_COPY_AND_ASSIGN(IOSession);
-};
-
-DevToolsSession::DevToolsSession(
-    DevToolsAgent* agent,
-    mojom::blink::DevToolsSessionHostAssociatedPtrInfo host_ptr_info,
-    mojom::blink::DevToolsSessionAssociatedRequest main_request,
-    mojom::blink::DevToolsSessionRequest io_request,
-    mojom::blink::DevToolsSessionStatePtr reattach_session_state)
-    : agent_(agent),
-      binding_(this, std::move(main_request)),
-      inspector_backend_dispatcher_(new protocol::UberDispatcher(this)),
-      session_state_(std::move(reattach_session_state)),
-      v8_session_state_(kV8StateKey),
-      v8_session_state_json_(&v8_session_state_, /*default_value=*/String()) {
-  io_session_ =
-      new IOSession(agent_->io_task_runner_, agent_->inspector_task_runner_,
-                    WrapCrossThreadWeakPersistent(this), std::move(io_request));
-
-  host_ptr_.Bind(std::move(host_ptr_info));
-  host_ptr_.set_connection_error_handler(
-      WTF::Bind(&DevToolsSession::Detach, WrapWeakPersistent(this)));
-
-  bool restore = !!session_state_.ReattachState();
-  v8_session_state_.InitFrom(&session_state_);
-  agent_->client_->AttachSession(this, restore);
-  agent_->probe_sink_->addDevToolsSession(this);
-  if (restore) {
-    for (wtf_size_t i = 0; i < agents_.size(); i++)
-      agents_[i]->Restore();
-  }
-}
-
-DevToolsSession::~DevToolsSession() {
-  DCHECK(IsDetached());
-}
-
-void DevToolsSession::ConnectToV8(v8_inspector::V8Inspector* inspector,
-                                  int context_group_id) {
-  v8_session_ =
-      inspector->connect(context_group_id, this,
-                         ToV8InspectorStringView(v8_session_state_json_.Get()));
-}
-
-bool DevToolsSession::IsDetached() {
-  return !host_ptr_.is_bound();
-}
-
-void DevToolsSession::Append(InspectorAgent* agent) {
-  agents_.push_back(agent);
-  agent->Init(agent_->probe_sink_.Get(), inspector_backend_dispatcher_.get(),
-              &session_state_);
-}
-
-void DevToolsSession::Detach() {
-  agent_->client_->DebuggerTaskStarted();
-  agent_->client_->DetachSession(this);
-  agent_->sessions_.erase(this);
-  binding_.Close();
-  host_ptr_.reset();
-  io_session_->DeleteSoon();
-  io_session_ = nullptr;
-  agent_->probe_sink_->removeDevToolsSession(this);
-  inspector_backend_dispatcher_.reset();
-  for (wtf_size_t i = agents_.size(); i > 0; i--)
-    agents_[i - 1]->Dispose();
-  agents_.clear();
-  v8_session_.reset();
-  agent_->client_->DebuggerTaskFinished();
-}
-
-void DevToolsSession::FlushProtocolNotifications() {
-  flushProtocolNotifications();
-}
-
-void DevToolsSession::DispatchProtocolCommand(int call_id,
-                                              const String& method,
-                                              const String& message) {
-  // IOSession does not provide ordering guarantees relative to
-  // Session, so a command may come to IOSession after Session is detached,
-  // and get posted to main thread to this method.
-  //
-  // At the same time, Session may not be garbage collected yet
-  // (even though already detached), and CrossThreadWeakPersistent<Session>
-  // will still be valid.
-  //
-  // Both these factors combined may lead to this method being called after
-  // detach, so we have to check it here.
-  if (IsDetached())
-    return;
-  agent_->client_->DebuggerTaskStarted();
-  if (v8_inspector::V8InspectorSession::canDispatchMethod(
-          ToV8InspectorStringView(method))) {
-    v8_session_->dispatchProtocolMessage(ToV8InspectorStringView(message));
-  } else {
-    inspector_backend_dispatcher_->dispatch(
-        call_id, method, protocol::StringUtil::parseJSON(message), message);
-  }
-  agent_->client_->DebuggerTaskFinished();
-}
-
-void DevToolsSession::DidStartProvisionalLoad(LocalFrame* frame) {
-  if (v8_session_ && agent_->inspected_frames_->Root() == frame) {
-    v8_session_->setSkipAllPauses(true);
-    v8_session_->resume();
-  }
-}
-
-void DevToolsSession::DidFailProvisionalLoad(LocalFrame* frame) {
-  if (v8_session_ && agent_->inspected_frames_->Root() == frame)
-    v8_session_->setSkipAllPauses(false);
-}
-
-void DevToolsSession::DidCommitLoad(LocalFrame* frame, DocumentLoader*) {
-  for (wtf_size_t i = 0; i < agents_.size(); i++)
-    agents_[i]->DidCommitLoadForLocalFrame(frame);
-  if (v8_session_ && agent_->inspected_frames_->Root() == frame)
-    v8_session_->setSkipAllPauses(false);
-}
-
-void DevToolsSession::sendProtocolResponse(
-    int call_id,
-    std::unique_ptr<protocol::Serializable> message) {
-  SendProtocolResponse(call_id, message->serialize());
-}
-
-void DevToolsSession::fallThrough(int call_id,
-                                  const String& method,
-                                  const String& message) {
-  // There's no other layer to handle the command.
-  NOTREACHED();
-}
-
-void DevToolsSession::sendResponse(
-    int call_id,
-    std::unique_ptr<v8_inspector::StringBuffer> message) {
-  // We can potentially avoid copies if WebString would convert to utf8 right
-  // from StringView, but it uses StringImpl itself, so we don't create any
-  // extra copies here.
-  SendProtocolResponse(call_id, ToCoreString(message->string()));
-}
-
-void DevToolsSession::SendProtocolResponse(int call_id, const String& message) {
-  if (IsDetached())
-    return;
-  flushProtocolNotifications();
-  if (v8_session_)
-    v8_session_state_json_.Set(ToCoreString(v8_session_->stateJSON()));
-  // Make tests more predictable by flushing all sessions before sending
-  // protocol response in any of them.
-  if (LayoutTestSupport::IsRunningLayoutTest())
-    agent_->FlushProtocolNotifications();
-  host_ptr_->DispatchProtocolResponse(message, call_id,
-                                      session_state_.TakeUpdates());
-}
-
-class DevToolsSession::Notification {
- public:
-  static std::unique_ptr<Notification> CreateForBlink(
-      std::unique_ptr<protocol::Serializable> notification) {
-    return std::unique_ptr<Notification>(
-        new Notification(std::move(notification)));
-  }
-
-  static std::unique_ptr<Notification> CreateForV8(
-      std::unique_ptr<v8_inspector::StringBuffer> notification) {
-    return std::unique_ptr<Notification>(
-        new Notification(std::move(notification)));
-  }
-
-  String Serialize() {
-    if (blink_notification_) {
-      serialized_ = blink_notification_->serialize();
-      blink_notification_.reset();
-    } else if (v8_notification_) {
-      serialized_ = ToCoreString(v8_notification_->string());
-      v8_notification_.reset();
-    }
-    return serialized_;
-  }
-
- private:
-  explicit Notification(std::unique_ptr<protocol::Serializable> notification)
-      : blink_notification_(std::move(notification)) {}
-
-  explicit Notification(
-      std::unique_ptr<v8_inspector::StringBuffer> notification)
-      : v8_notification_(std::move(notification)) {}
-
-  std::unique_ptr<protocol::Serializable> blink_notification_;
-  std::unique_ptr<v8_inspector::StringBuffer> v8_notification_;
-  String serialized_;
-};
-
-void DevToolsSession::sendProtocolNotification(
-    std::unique_ptr<protocol::Serializable> notification) {
-  if (IsDetached())
-    return;
-  notification_queue_.push_back(
-      Notification::CreateForBlink(std::move(notification)));
-}
-
-void DevToolsSession::sendNotification(
-    std::unique_ptr<v8_inspector::StringBuffer> notification) {
-  if (IsDetached())
-    return;
-  notification_queue_.push_back(
-      Notification::CreateForV8(std::move(notification)));
-}
-
-void DevToolsSession::flushProtocolNotifications() {
-  if (IsDetached())
-    return;
-  for (wtf_size_t i = 0; i < agents_.size(); i++)
-    agents_[i]->FlushPendingProtocolNotifications();
-  if (!notification_queue_.size())
-    return;
-  if (v8_session_)
-    v8_session_state_json_.Set(ToCoreString(v8_session_->stateJSON()));
-  for (wtf_size_t i = 0; i < notification_queue_.size(); ++i) {
-    host_ptr_->DispatchProtocolNotification(notification_queue_[i]->Serialize(),
-                                            session_state_.TakeUpdates());
-  }
-  notification_queue_.clear();
-}
-
-void DevToolsSession::Trace(blink::Visitor* visitor) {
-  visitor->Trace(agent_);
-  visitor->Trace(agents_);
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/core/inspector/inspector_session.cc b/third_party/blink/renderer/core/inspector/inspector_session.cc
new file mode 100644
index 0000000..f9ebccd
--- /dev/null
+++ b/third_party/blink/renderer/core/inspector/inspector_session.cc
@@ -0,0 +1,235 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/inspector/inspector_session.h"
+
+#include "third_party/blink/renderer/bindings/core/v8/script_controller.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/core/frame/use_counter.h"
+#include "third_party/blink/renderer/core/inspector/inspected_frames.h"
+#include "third_party/blink/renderer/core/inspector/inspector_base_agent.h"
+#include "third_party/blink/renderer/core/inspector/inspector_session_state.h"
+#include "third_party/blink/renderer/core/inspector/protocol/Protocol.h"
+#include "third_party/blink/renderer/core/inspector/v8_inspector_string.h"
+#include "third_party/blink/renderer/core/probe/core_probes.h"
+
+namespace blink {
+
+namespace {
+const char kV8StateKey[] = "v8";
+}
+
+// static
+bool InspectorSession::ShouldInterruptForMethod(const String& method) {
+  // Keep in sync with DevToolsSession::ShouldSendOnIO.
+  // TODO(dgozman): find a way to share this.
+  return method == "Debugger.pause" || method == "Debugger.setBreakpoint" ||
+         method == "Debugger.setBreakpointByUrl" ||
+         method == "Debugger.removeBreakpoint" ||
+         method == "Debugger.setBreakpointsActive" ||
+         method == "Performance.getMetrics" || method == "Page.crash" ||
+         method == "Runtime.terminateExecution" ||
+         method == "Emulation.setScriptExecutionDisabled";
+}
+
+InspectorSession::InspectorSession(
+    Client* client,
+    CoreProbeSink* instrumenting_agents,
+    InspectedFrames* inspected_frames,
+    int session_id,
+    v8_inspector::V8Inspector* inspector,
+    int context_group_id,
+    mojom::blink::DevToolsSessionStatePtr reattach_session_state)
+    : client_(client),
+      v8_session_(nullptr),
+      session_id_(session_id),
+      disposed_(false),
+      instrumenting_agents_(instrumenting_agents),
+      inspected_frames_(inspected_frames),
+      inspector_backend_dispatcher_(new protocol::UberDispatcher(this)),
+      session_state_(std::move(reattach_session_state)),
+      v8_session_state_(kV8StateKey),
+      v8_session_state_json_(&v8_session_state_, /*default_value=*/String()) {
+  v8_session_state_.InitFrom(&session_state_);
+
+  // inspector->connect may result in calls to |this| against the
+  // V8Inspector::Channel interface for receiving responses / notifications,
+  // while v8_session_ is still nullptr.
+  v8_session_ =
+      inspector->connect(context_group_id, /*channel*/ this,
+                         ToV8InspectorStringView(v8_session_state_json_.Get()));
+
+  instrumenting_agents_->addInspectorSession(this);
+}
+
+InspectorSession::~InspectorSession() {
+  DCHECK(disposed_);
+}
+
+void InspectorSession::Append(InspectorAgent* agent) {
+  agents_.push_back(agent);
+  agent->Init(instrumenting_agents_.Get(), inspector_backend_dispatcher_.get(),
+              &session_state_);
+}
+
+void InspectorSession::Restore() {
+  DCHECK(!disposed_);
+  for (wtf_size_t i = 0; i < agents_.size(); i++)
+    agents_[i]->Restore();
+}
+
+void InspectorSession::Dispose() {
+  DCHECK(!disposed_);
+  disposed_ = true;
+  instrumenting_agents_->removeInspectorSession(this);
+  inspector_backend_dispatcher_.reset();
+  for (wtf_size_t i = agents_.size(); i > 0; i--)
+    agents_[i - 1]->Dispose();
+  agents_.clear();
+  v8_session_.reset();
+}
+
+void InspectorSession::DispatchProtocolMessage(int call_id,
+                                               const String& method,
+                                               const String& message) {
+  DCHECK(!disposed_);
+  if (v8_inspector::V8InspectorSession::canDispatchMethod(
+          ToV8InspectorStringView(method))) {
+    v8_session_->dispatchProtocolMessage(ToV8InspectorStringView(message));
+  } else {
+    inspector_backend_dispatcher_->dispatch(
+        call_id, method, protocol::StringUtil::parseJSON(message), message);
+  }
+}
+
+void InspectorSession::DidStartProvisionalLoad(LocalFrame* frame) {
+  if (inspected_frames_->Root() == frame) {
+    v8_session_->setSkipAllPauses(true);
+    v8_session_->resume();
+  }
+}
+
+void InspectorSession::DidFailProvisionalLoad(LocalFrame* frame) {
+  if (inspected_frames_->Root() == frame)
+    v8_session_->setSkipAllPauses(false);
+}
+
+void InspectorSession::DidCommitLoadForLocalFrame(LocalFrame* frame) {
+  for (wtf_size_t i = 0; i < agents_.size(); i++)
+    agents_[i]->DidCommitLoadForLocalFrame(frame);
+  if (inspected_frames_->Root() == frame)
+    v8_session_->setSkipAllPauses(false);
+}
+
+void InspectorSession::sendProtocolResponse(
+    int call_id,
+    std::unique_ptr<protocol::Serializable> message) {
+  SendProtocolResponse(call_id, message->serialize());
+}
+
+void InspectorSession::fallThrough(int call_id,
+                                   const String& method,
+                                   const String& message) {
+  // There's no other layer to handle the command.
+  NOTREACHED();
+}
+
+void InspectorSession::sendResponse(
+    int call_id,
+    std::unique_ptr<v8_inspector::StringBuffer> message) {
+  // We can potentially avoid copies if WebString would convert to utf8 right
+  // from StringView, but it uses StringImpl itself, so we don't create any
+  // extra copies here.
+  SendProtocolResponse(call_id, ToCoreString(message->string()));
+}
+
+void InspectorSession::SendProtocolResponse(int call_id,
+                                            const String& message) {
+  if (disposed_)
+    return;
+  flushProtocolNotifications();
+  if (v8_session_)
+    v8_session_state_json_.Set(ToCoreString(v8_session_->stateJSON()));
+  client_->SendProtocolResponse(session_id_, call_id, message,
+                                session_state_.TakeUpdates());
+}
+
+class InspectorSession::Notification {
+ public:
+  static std::unique_ptr<Notification> CreateForBlink(
+      std::unique_ptr<protocol::Serializable> notification) {
+    return std::unique_ptr<Notification>(
+        new Notification(std::move(notification)));
+  }
+
+  static std::unique_ptr<Notification> CreateForV8(
+      std::unique_ptr<v8_inspector::StringBuffer> notification) {
+    return std::unique_ptr<Notification>(
+        new Notification(std::move(notification)));
+  }
+
+  String Serialize() {
+    if (blink_notification_) {
+      serialized_ = blink_notification_->serialize();
+      blink_notification_.reset();
+    } else if (v8_notification_) {
+      serialized_ = ToCoreString(v8_notification_->string());
+      v8_notification_.reset();
+    }
+    return serialized_;
+  }
+
+ private:
+  explicit Notification(std::unique_ptr<protocol::Serializable> notification)
+      : blink_notification_(std::move(notification)) {}
+
+  explicit Notification(
+      std::unique_ptr<v8_inspector::StringBuffer> notification)
+      : v8_notification_(std::move(notification)) {}
+
+  std::unique_ptr<protocol::Serializable> blink_notification_;
+  std::unique_ptr<v8_inspector::StringBuffer> v8_notification_;
+  String serialized_;
+};
+
+void InspectorSession::sendProtocolNotification(
+    std::unique_ptr<protocol::Serializable> notification) {
+  if (disposed_)
+    return;
+  notification_queue_.push_back(
+      Notification::CreateForBlink(std::move(notification)));
+}
+
+void InspectorSession::sendNotification(
+    std::unique_ptr<v8_inspector::StringBuffer> notification) {
+  if (disposed_)
+    return;
+  notification_queue_.push_back(
+      Notification::CreateForV8(std::move(notification)));
+}
+
+void InspectorSession::flushProtocolNotifications() {
+  if (disposed_)
+    return;
+  for (wtf_size_t i = 0; i < agents_.size(); i++)
+    agents_[i]->FlushPendingProtocolNotifications();
+  if (!notification_queue_.size())
+    return;
+  if (v8_session_)
+    v8_session_state_json_.Set(ToCoreString(v8_session_->stateJSON()));
+  for (wtf_size_t i = 0; i < notification_queue_.size(); ++i) {
+    client_->SendProtocolNotification(session_id_,
+                                      notification_queue_[i]->Serialize(),
+                                      session_state_.TakeUpdates());
+  }
+  notification_queue_.clear();
+}
+
+void InspectorSession::Trace(blink::Visitor* visitor) {
+  visitor->Trace(instrumenting_agents_);
+  visitor->Trace(inspected_frames_);
+  visitor->Trace(agents_);
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/inspector/devtools_session.h b/third_party/blink/renderer/core/inspector/inspector_session.h
similarity index 62%
rename from third_party/blink/renderer/core/inspector/devtools_session.h
rename to third_party/blink/renderer/core/inspector/inspector_session.h
index b187664e..332da5d 100644
--- a/third_party/blink/renderer/core/inspector/devtools_session.h
+++ b/third_party/blink/renderer/core/inspector/inspector_session.h
@@ -2,11 +2,10 @@
 // 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_INSPECTOR_DEVTOOLS_SESSION_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_INSPECTOR_DEVTOOLS_SESSION_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_INSPECTOR_INSPECTOR_SESSION_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_INSPECTOR_INSPECTOR_SESSION_H_
 
 #include "base/macros.h"
-#include "mojo/public/cpp/bindings/associated_binding.h"
 #include "third_party/blink/public/web/devtools_agent.mojom-blink.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/inspector/inspector_session_state.h"
@@ -19,56 +18,66 @@
 
 namespace blink {
 
-class DevToolsAgent;
-class DocumentLoader;
 class InspectorAgent;
+class InspectedFrames;
+class CoreProbeSink;
 class LocalFrame;
 
-class CORE_EXPORT DevToolsSession
-    : public GarbageCollectedFinalized<DevToolsSession>,
-      public mojom::blink::DevToolsSession,
+class CORE_EXPORT InspectorSession
+    : public GarbageCollectedFinalized<InspectorSession>,
       public protocol::FrontendChannel,
       public v8_inspector::V8Inspector::Channel {
  public:
-  DevToolsSession(
-      DevToolsAgent*,
-      mojom::blink::DevToolsSessionHostAssociatedPtrInfo host_ptr_info,
-      mojom::blink::DevToolsSessionAssociatedRequest main_request,
-      mojom::blink::DevToolsSessionRequest io_request,
-      mojom::blink::DevToolsSessionStatePtr reattach_session_state);
-  ~DevToolsSession() override;
+  class Client {
+   public:
+    virtual void SendProtocolResponse(
+        int session_id,
+        int call_id,
+        const String& response,
+        mojom::blink::DevToolsSessionStatePtr updates) = 0;
+    virtual void SendProtocolNotification(
+        int session_id,
+        const String& message,
+        mojom::blink::DevToolsSessionStatePtr updates) = 0;
+    virtual ~Client() = default;
+  };
 
-  void ConnectToV8(v8_inspector::V8Inspector*, int context_group_id);
+  InspectorSession(
+      Client*,
+      CoreProbeSink*,
+      InspectedFrames*,
+      int session_id,
+      v8_inspector::V8Inspector*,
+      int context_group_id,
+      mojom::blink::DevToolsSessionStatePtr reattach_session_state);
+  ~InspectorSession() override;
+  // TODO(dgozman): remove session id once WokrerInspectorController
+  // does not use it anymore.
+  int SessionId() { return session_id_; }
   v8_inspector::V8InspectorSession* V8Session() { return v8_session_.get(); }
 
   void Append(InspectorAgent*);
-  void Detach();
-  void FlushProtocolNotifications();
-  void Trace(blink::Visitor*);
-
-  // Core probes.
+  void Restore();
+  void Dispose();
   void DidStartProvisionalLoad(LocalFrame*);
   void DidFailProvisionalLoad(LocalFrame*);
-  void DidCommitLoad(LocalFrame*, DocumentLoader*);
+  void DidCommitLoadForLocalFrame(LocalFrame*);
+  void DispatchProtocolMessage(int call_id,
+                               const String& method,
+                               const String& message);
+  void flushProtocolNotifications() override;
+
+  void Trace(blink::Visitor*);
+
+  static bool ShouldInterruptForMethod(const String& method);
 
  private:
-  class IOSession;
-
-  // mojom::blink::DevToolsSession implementation.
-  void DispatchProtocolCommand(int call_id,
-                               const String& method,
-                               const String& message) override;
-
   // protocol::FrontendChannel implementation.
   void sendProtocolResponse(
       int call_id,
       std::unique_ptr<protocol::Serializable> message) override;
   void sendProtocolNotification(
       std::unique_ptr<protocol::Serializable> message) override;
-  void fallThrough(int call_id,
-                   const String& method,
-                   const String& message) override;
-  void flushProtocolNotifications() override;
 
   // v8_inspector::V8Inspector::Channel implementation.
   void sendResponse(
@@ -77,14 +86,17 @@
   void sendNotification(
       std::unique_ptr<v8_inspector::StringBuffer> message) override;
 
-  bool IsDetached();
   void SendProtocolResponse(int call_id, const String& message);
+  void fallThrough(int call_id,
+                   const String& method,
+                   const String& message) override;
 
-  Member<DevToolsAgent> agent_;
-  mojo::AssociatedBinding<mojom::blink::DevToolsSession> binding_;
-  mojom::blink::DevToolsSessionHostAssociatedPtr host_ptr_;
-  IOSession* io_session_;
+  Client* client_;
   std::unique_ptr<v8_inspector::V8InspectorSession> v8_session_;
+  int session_id_;
+  bool disposed_;
+  Member<CoreProbeSink> instrumenting_agents_;
+  Member<InspectedFrames> inspected_frames_;
   std::unique_ptr<protocol::UberDispatcher> inspector_backend_dispatcher_;
   InspectorSessionState session_state_;
   HeapVector<Member<InspectorAgent>> agents_;
@@ -93,9 +105,9 @@
   InspectorAgentState v8_session_state_;
   InspectorAgentState::String v8_session_state_json_;
 
-  DISALLOW_COPY_AND_ASSIGN(DevToolsSession);
+  DISALLOW_COPY_AND_ASSIGN(InspectorSession);
 };
 
 }  // namespace blink
 
-#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_INSPECTOR_DEVTOOLS_SESSION_H_
+#endif  // !defined(InspectorSession_h)
diff --git a/third_party/blink/renderer/core/inspector/worker_inspector_controller.cc b/third_party/blink/renderer/core/inspector/worker_inspector_controller.cc
index dc50f9a..9a3eecda 100644
--- a/third_party/blink/renderer/core/inspector/worker_inspector_controller.cc
+++ b/third_party/blink/renderer/core/inspector/worker_inspector_controller.cc
@@ -32,10 +32,10 @@
 
 #include "base/single_thread_task_runner.h"
 #include "third_party/blink/renderer/core/core_probe_sink.h"
-#include "third_party/blink/renderer/core/inspector/devtools_session.h"
 #include "third_party/blink/renderer/core/inspector/inspector_emulation_agent.h"
 #include "third_party/blink/renderer/core/inspector/inspector_log_agent.h"
 #include "third_party/blink/renderer/core/inspector/inspector_network_agent.h"
+#include "third_party/blink/renderer/core/inspector/inspector_session.h"
 #include "third_party/blink/renderer/core/inspector/inspector_trace_events.h"
 #include "third_party/blink/renderer/core/inspector/protocol/Protocol.h"
 #include "third_party/blink/renderer/core/inspector/worker_thread_debugger.h"
@@ -70,10 +70,7 @@
     scoped_refptr<InspectorTaskRunner> inspector_task_runner,
     mojom::blink::DevToolsAgentRequest agent_request,
     mojom::blink::DevToolsAgentHostPtrInfo host_ptr_info)
-    : debugger_(debugger),
-      thread_(thread),
-      inspected_frames_(nullptr),
-      probe_sink_(new CoreProbeSink()) {
+    : debugger_(debugger), thread_(thread), probe_sink_(new CoreProbeSink()) {
   probe_sink_->addInspectorTraceEvents(new InspectorTraceEvents());
   if (auto* scope = DynamicTo<WorkerGlobalScope>(thread->GlobalScope())) {
     worker_devtools_token_ = thread->GetDevToolsWorkerToken();
@@ -85,8 +82,7 @@
       Platform::Current()->GetIOTaskRunner();
   if (!parent_devtools_token_.is_empty() && io_task_runner) {
     // There may be no io task runner in unit tests.
-    agent_ = new DevToolsAgent(this, inspected_frames_.Get(), probe_sink_.Get(),
-                               std::move(inspector_task_runner),
+    agent_ = new DevToolsAgent(this, std::move(inspector_task_runner),
                                std::move(io_task_runner));
     agent_->BindRequest(std::move(host_ptr_info), std::move(agent_request),
                         thread->GetTaskRunner(TaskType::kInternalInspector));
@@ -100,26 +96,38 @@
   TraceEvent::RemoveEnabledStateObserver(this);
 }
 
-void WorkerInspectorController::AttachSession(DevToolsSession* session,
-                                              bool restore) {
-  if (!session_count_)
+InspectorSession* WorkerInspectorController::AttachSession(
+    InspectorSession::Client* session_client,
+    mojom::blink::DevToolsSessionStatePtr reattach_session_state) {
+  if (!sessions_.size())
     thread_->GetWorkerBackingThread().BackingThread().AddTaskObserver(this);
-  session->ConnectToV8(debugger_->GetV8Inspector(),
-                       debugger_->ContextGroupId(thread_));
-  session->Append(new InspectorLogAgent(thread_->GetConsoleMessageStorage(),
-                                        nullptr, session->V8Session()));
+
+  bool should_reattach = !reattach_session_state.is_null();
+
+  InspectedFrames* inspected_frames = new InspectedFrames(nullptr);
+  InspectorSession* inspector_session = new InspectorSession(
+      session_client, probe_sink_.Get(), inspected_frames, 0,
+      debugger_->GetV8Inspector(), debugger_->ContextGroupId(thread_),
+      std::move(reattach_session_state));
+  inspector_session->Append(
+      new InspectorLogAgent(thread_->GetConsoleMessageStorage(), nullptr,
+                            inspector_session->V8Session()));
   if (auto* scope = DynamicTo<WorkerGlobalScope>(thread_->GlobalScope())) {
     DCHECK(scope->EnsureFetcher());
-    session->Append(new InspectorNetworkAgent(inspected_frames_.Get(), scope,
-                                              session->V8Session()));
-    session->Append(new InspectorEmulationAgent(nullptr));
+    inspector_session->Append(new InspectorNetworkAgent(
+        inspected_frames, scope, inspector_session->V8Session()));
+    inspector_session->Append(new InspectorEmulationAgent(nullptr));
   }
-  ++session_count_;
+
+  if (should_reattach)
+    inspector_session->Restore();
+  sessions_.insert(inspector_session);
+  return inspector_session;
 }
 
-void WorkerInspectorController::DetachSession(DevToolsSession*) {
-  --session_count_;
-  if (!session_count_)
+void WorkerInspectorController::DetachSession(InspectorSession* session) {
+  sessions_.erase(session);
+  if (!sessions_.size())
     thread_->GetWorkerBackingThread().BackingThread().RemoveTaskObserver(this);
 }
 
@@ -173,8 +181,8 @@
 
 void WorkerInspectorController::Trace(blink::Visitor* visitor) {
   visitor->Trace(agent_);
-  visitor->Trace(inspected_frames_);
   visitor->Trace(probe_sink_);
+  visitor->Trace(sessions_);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/inspector/worker_inspector_controller.h b/third_party/blink/renderer/core/inspector/worker_inspector_controller.h
index 8445b41..694322d1 100644
--- a/third_party/blink/renderer/core/inspector/worker_inspector_controller.h
+++ b/third_party/blink/renderer/core/inspector/worker_inspector_controller.h
@@ -47,7 +47,6 @@
 namespace blink {
 
 class CoreProbeSink;
-class InspectedFrames;
 class WorkerThread;
 class WorkerThreadDebugger;
 
@@ -88,8 +87,10 @@
   void EmitTraceEvent();
 
   // DevToolsAgent::Client implementation.
-  void AttachSession(DevToolsSession*, bool restore) override;
-  void DetachSession(DevToolsSession*) override;
+  InspectorSession* AttachSession(
+      InspectorSession::Client*,
+      mojom::blink::DevToolsSessionStatePtr reattach_session_state) override;
+  void DetachSession(InspectorSession*) override;
   void InspectElement(const WebPoint&) override;
   void DebuggerTaskStarted() override;
   void DebuggerTaskFinished() override;
@@ -97,9 +98,8 @@
   Member<DevToolsAgent> agent_;
   WorkerThreadDebugger* debugger_;
   WorkerThread* thread_;
-  Member<InspectedFrames> inspected_frames_;
   Member<CoreProbeSink> probe_sink_;
-  int session_count_ = 0;
+  HeapHashSet<Member<InspectorSession>> sessions_;
 
   // These fields are set up in the constructor and then read
   // on a random thread from EmitTraceEvent().
diff --git a/third_party/blink/renderer/core/layout/layout_image.cc b/third_party/blink/renderer/core/layout/layout_image.cc
index 35ce87d7..07d46b5 100644
--- a/third_party/blink/renderer/core/layout/layout_image.cc
+++ b/third_party/blink/renderer/core/layout/layout_image.cc
@@ -441,14 +441,23 @@
     if (intrinsic_sizing_info.size.IsEmpty() &&
         image_resource_->ImageHasRelativeSize() &&
         !IsLayoutNGListMarkerImage()) {
-      LayoutObject* containing_block =
-          IsOutOfFlowPositioned() ? Container() : ContainingBlock();
-      if (containing_block->IsBox()) {
-        LayoutBox* box = ToLayoutBox(containing_block);
+      if (HasOverrideContainingBlockContentLogicalWidth() &&
+          HasOverrideContainingBlockContentLogicalHeight()) {
         intrinsic_sizing_info.size.SetWidth(
-            box->AvailableLogicalWidth().ToFloat());
+            OverrideContainingBlockContentLogicalWidth().ToFloat());
         intrinsic_sizing_info.size.SetHeight(
-            box->AvailableLogicalHeight(kIncludeMarginBorderPadding).ToFloat());
+            OverrideContainingBlockContentLogicalHeight().ToFloat());
+      } else {
+        LayoutObject* containing_block =
+            IsOutOfFlowPositioned() ? Container() : ContainingBlock();
+        if (containing_block->IsBox()) {
+          LayoutBox* box = ToLayoutBox(containing_block);
+          intrinsic_sizing_info.size.SetWidth(
+              box->AvailableLogicalWidth().ToFloat());
+          intrinsic_sizing_info.size.SetHeight(
+              box->AvailableLogicalHeight(kIncludeMarginBorderPadding)
+                  .ToFloat());
+        }
       }
     }
   }
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.cc
index c5794730..c254b3a 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.cc
@@ -208,6 +208,16 @@
       box->has_end_edge = true;
     EndBoxState(box, line_box, baseline_type);
   }
+
+  // Up to this point, the offset of inline boxes are stored in placeholder so
+  // that |ApplyBaselineShift()| can compute offset for both children and boxes.
+  // Copy the final offset to |box_data_list_|.
+  for (BoxData& box_data : box_data_list_) {
+    const NGLineBoxFragmentBuilder::Child& placeholder =
+        (*line_box)[box_data.fragment_end];
+    DCHECK(!placeholder.HasFragment());
+    box_data.offset = placeholder.offset;
+  }
 }
 
 void NGInlineLayoutStateStack::EndBoxState(
@@ -341,7 +351,6 @@
     const NGLineBoxFragmentBuilder::Child& placeholder =
         (*line_box)[box_data.fragment_end];
     DCHECK(!placeholder.HasFragment());
-    box_data.offset = placeholder.offset;
     box_data.box_data_index = placeholder.box_data_index;
   }
 }
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc
index 360d880..dd1c9e8f 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc
@@ -308,14 +308,11 @@
 
   box_states_->OnEndPlaceItems(&line_box_, baseline_type_);
 
-  // TODO(kojii): For LTR, we can optimize ComputeInlinePositions() to compute
-  // without PrepareForReorder() and UpdateAfterReorder() even when
-  // HasBoxFragments(). We do this to share the logic between LTR and RTL, and
-  // to get more coverage for RTL, but when we're more stabilized, we could have
-  // optimized code path for LTR.
-  box_states_->PrepareForReorder(&line_box_);
-  BidiReorder();
-  box_states_->UpdateAfterReorder(&line_box_);
+  if (UNLIKELY(Node().IsBidiEnabled())) {
+    box_states_->PrepareForReorder(&line_box_);
+    BidiReorder();
+    box_states_->UpdateAfterReorder(&line_box_);
+  }
   LayoutUnit inline_size = box_states_->ComputeInlinePositions(&line_box_);
 
   // Truncate the line if 'text-overflow: ellipsis' is set.
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 1377d7bb..3454fe7 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
@@ -41,34 +41,6 @@
 
 }  // namespace
 
-NGContainerFragmentBuilder& NGBoxFragmentBuilder::AddChild(
-    scoped_refptr<const NGPhysicalFragment> child,
-    const NGLogicalOffset& child_offset) {
-  switch (child->Type()) {
-    case NGPhysicalBoxFragment::kFragmentBox:
-    case NGPhysicalBoxFragment::kFragmentRenderedLegend:
-      if (child->BreakToken())
-        child_break_tokens_.push_back(child->BreakToken());
-      break;
-    case NGPhysicalBoxFragment::kFragmentLineBox:
-      // NGInlineNode produces multiple line boxes in an anonymous box. We won't
-      // know up front which line box to insert a fragment break before (due to
-      // widows), so keep them all until we know.
-      DCHECK(child->BreakToken());
-      DCHECK(child->BreakToken()->InputNode() == node_);
-      inline_break_tokens_.push_back(child->BreakToken());
-      break;
-    case NGPhysicalBoxFragment::kFragmentText:
-      DCHECK(!child->BreakToken());
-      break;
-    default:
-      NOTREACHED();
-      break;
-  }
-
-  return NGContainerFragmentBuilder::AddChild(std::move(child), child_offset);
-}
-
 void NGBoxFragmentBuilder::RemoveChildren() {
   child_break_tokens_.resize(0);
   inline_break_tokens_.resize(0);
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 40a00010..776c2364 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
@@ -74,12 +74,6 @@
     return *this;
   }
 
-  using NGContainerFragmentBuilder::AddChild;
-
-  // Our version of AddChild captures any child NGBreakTokens.
-  NGContainerFragmentBuilder& AddChild(scoped_refptr<const NGPhysicalFragment>,
-                                       const NGLogicalOffset&) final;
-
   // Remove all children.
   void RemoveChildren();
 
@@ -257,9 +251,6 @@
   // The break-after value of the previous in-flow sibling.
   EBreakBetween previous_break_after_ = EBreakBetween::kAuto;
 
-  NGBreakTokenVector child_break_tokens_;
-  NGBreakTokenVector inline_break_tokens_;
-
   Vector<NGBaseline> baselines_;
 
   NGBorderEdges border_edges_;
diff --git a/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc b/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc
index a6e6275..9c163ee 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc
@@ -62,6 +62,26 @@
 NGContainerFragmentBuilder& NGContainerFragmentBuilder::AddChild(
     scoped_refptr<const NGPhysicalFragment> child,
     const NGLogicalOffset& child_offset) {
+  NGBreakToken* child_break_token = child->BreakToken();
+  if (child_break_token) {
+    switch (child->Type()) {
+      case NGPhysicalFragment::kFragmentBox:
+      case NGPhysicalFragment::kFragmentRenderedLegend:
+        child_break_tokens_.push_back(child_break_token);
+        break;
+      case NGPhysicalFragment::kFragmentLineBox:
+        // NGInlineNode produces multiple line boxes in an anonymous box. We
+        // won't know up front which line box to insert a fragment break before
+        // (due to widows), so keep them all until we know.
+        inline_break_tokens_.push_back(child_break_token);
+        break;
+      case NGPhysicalFragment::kFragmentText:
+      default:
+        NOTREACHED();
+        break;
+    }
+  }
+
   if (!has_last_resort_break_) {
     if (const auto* token = child->BreakToken()) {
       if (token->IsBlockType() &&
diff --git a/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h b/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h
index 06388d55..7807816 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h
@@ -81,9 +81,8 @@
 
   // This version of AddChild will not propagate floats/out_of_flow.
   // Use the AddChild(NGLayoutResult) variant if NGLayoutResult is available.
-  virtual NGContainerFragmentBuilder& AddChild(
-      scoped_refptr<const NGPhysicalFragment>,
-      const NGLogicalOffset&);
+  NGContainerFragmentBuilder& AddChild(scoped_refptr<const NGPhysicalFragment>,
+                                       const NGLogicalOffset&);
 
   const ChildrenVector& Children() const { return children_; }
 
@@ -219,6 +218,11 @@
   // determined.
   OffsetVector offsets_;
 
+  // Only used by the NGBoxFragmentBuilder subclass, but defined here to avoid
+  // a virtual function call.
+  NGBreakTokenVector child_break_tokens_;
+  NGBreakTokenVector inline_break_tokens_;
+
   NGFloatTypes adjoining_floats_ = kFloatTypeNone;
 
   bool has_last_resort_break_ = false;
diff --git a/third_party/blink/renderer/core/page/viewport_description.cc b/third_party/blink/renderer/core/page/viewport_description.cc
index ee87f7d8..5d8a3c15 100644
--- a/third_party/blink/renderer/core/page/viewport_description.cc
+++ b/third_party/blink/renderer/core/page/viewport_description.cc
@@ -30,6 +30,7 @@
 #include "third_party/blink/renderer/core/page/viewport_description.h"
 
 #include "build/build_config.h"
+#include "third_party/blink/public/common/features.h"
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
@@ -301,7 +302,9 @@
 }
 
 bool ViewportDescription::MatchesHeuristicsForGpuRasterization() const {
-  return IsSpecifiedByAuthor();
+  bool enable_viewport_restriction = base::FeatureList::IsEnabled(
+      features::kEnableGpuRasterizationViewportRestriction);
+  return !enable_viewport_restriction || IsSpecifiedByAuthor();
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/probe/core_probes.json5 b/third_party/blink/renderer/core/probe/core_probes.json5
index f95bfba5..37748538 100644
--- a/third_party/blink/renderer/core/probe/core_probes.json5
+++ b/third_party/blink/renderer/core/probe/core_probes.json5
@@ -208,12 +208,10 @@
         "willSendRequest",
       ]
     },
-    DevToolsSession: {
-      class: "DevToolsSession",
+    InspectorSession: {
       probes: [
         "didStartProvisionalLoad",
         "didFailProvisionalLoad",
-        "didCommitLoad",
       ]
     },
   }
diff --git a/third_party/blink/renderer/devtools/front_end/Tests.js b/third_party/blink/renderer/devtools/front_end/Tests.js
index 574c67c..c52d9010 100644
--- a/third_party/blink/renderer/devtools/front_end/Tests.js
+++ b/third_party/blink/renderer/devtools/front_end/Tests.js
@@ -591,6 +591,15 @@
     }
   };
 
+  TestSuite.prototype.testSharedWorkerNetworkPanel = function() {
+    this.takeControl();
+    this.showPanel('network').then(() => {
+      if (!document.querySelector('#network-container'))
+        this.fail('unable to find #network-container');
+      this.releaseControl();
+    });
+  };
+
   TestSuite.prototype.enableTouchEmulation = function() {
     const deviceModeModel = new Emulation.DeviceModeModel(function() {});
     deviceModeModel._target = SDK.targetManager.mainTarget();
diff --git a/third_party/blink/renderer/devtools/front_end/network/NetworkLogView.js b/third_party/blink/renderer/devtools/front_end/network/NetworkLogView.js
index 5c804456..a5bdabfb 100644
--- a/third_party/blink/renderer/devtools/front_end/network/NetworkLogView.js
+++ b/third_party/blink/renderer/devtools/front_end/network/NetworkLogView.js
@@ -592,20 +592,31 @@
     this._hideRecordingHint();
     this._recordingHint = this.element.createChild('div', 'network-status-pane fill');
     const hintText = this._recordingHint.createChild('div', 'recording-hint');
-    const reloadShortcutNode = this._recordingHint.createChild('b');
-    reloadShortcutNode.textContent = UI.shortcutRegistry.shortcutDescriptorsForAction('inspector_main.reload')[0].name;
+
+    let reloadShortcutNode = null;
+    const reloadShortcutDescriptor = UI.shortcutRegistry.shortcutDescriptorsForAction('inspector_main.reload')[0];
+    if (reloadShortcutDescriptor) {
+      reloadShortcutNode = this._recordingHint.createChild('b');
+      reloadShortcutNode.textContent = reloadShortcutDescriptor.name;
+    }
 
     if (this._recording) {
       const recordingText = hintText.createChild('span');
       recordingText.textContent = Common.UIString('Recording network activity\u2026');
-      hintText.createChild('br');
-      hintText.appendChild(
-          UI.formatLocalized('Perform a request or hit %s to record the reload.', [reloadShortcutNode]));
+      if (reloadShortcutNode) {
+        hintText.createChild('br');
+        hintText.appendChild(
+            UI.formatLocalized('Perform a request or hit %s to record the reload.', [reloadShortcutNode]));
+      }
     } else {
       const recordNode = hintText.createChild('b');
       recordNode.textContent = UI.shortcutRegistry.shortcutTitleForAction('network.toggle-recording');
-      hintText.appendChild(UI.formatLocalized(
-          'Record (%s) or reload (%s) to display network activity.', [recordNode, reloadShortcutNode]));
+      if (reloadShortcutNode) {
+        hintText.appendChild(UI.formatLocalized(
+            'Record (%s) or reload (%s) to display network activity.', [recordNode, reloadShortcutNode]));
+      } else {
+        hintText.appendChild(UI.formatLocalized('Record (%s) to display network activity.', [recordNode]));
+      }
     }
   }
 
diff --git a/third_party/blink/renderer/devtools/front_end/network/NetworkPanel.js b/third_party/blink/renderer/devtools/front_end/network/NetworkPanel.js
index d1a4804..03ead61 100644
--- a/third_party/blink/renderer/devtools/front_end/network/NetworkPanel.js
+++ b/third_party/blink/renderer/devtools/front_end/network/NetworkPanel.js
@@ -368,10 +368,13 @@
   }
 
   _resetFilmStripView() {
+    const reloadShortcutDescriptor = UI.shortcutRegistry.shortcutDescriptorsForAction('inspector_main.reload')[0];
+
     this._filmStripView.reset();
-    this._filmStripView.setStatusText(Common.UIString(
-        'Hit %s to reload and capture filmstrip.',
-        UI.shortcutRegistry.shortcutDescriptorsForAction('inspector_main.reload')[0].name));
+    if (reloadShortcutDescriptor) {
+      this._filmStripView.setStatusText(
+          Common.UIString('Hit %s to reload and capture filmstrip.', reloadShortcutDescriptor.name));
+    }
   }
 
   /**
diff --git a/third_party/blink/renderer/devtools/front_end/profiler/HeapProfileView.js b/third_party/blink/renderer/devtools/front_end/profiler/HeapProfileView.js
index 44cd414c..3c220b1 100644
--- a/third_party/blink/renderer/devtools/front_end/profiler/HeapProfileView.js
+++ b/third_party/blink/renderer/devtools/front_end/profiler/HeapProfileView.js
@@ -36,12 +36,14 @@
       this._timelineOverview.addEventListener(
           Profiler.HeapTimelineOverview.IdsRangeChanged, this._onIdsRangeChanged.bind(this));
       this._timelineOverview.show(this.element, this.element.firstChild);
+      this._timelineOverview.start();
 
       this._profileType.addEventListener(
           Profiler.SamplingHeapProfileType.Events.StatsUpdate, this._onStatsUpdate, this);
       this._profileType.once(Profiler.ProfileType.Events.ProfileComplete).then(() => {
         this._profileType.removeEventListener(
             Profiler.SamplingHeapProfileType.Events.StatsUpdate, this._onStatsUpdate, this);
+        this._timelineOverview.stop();
         this._timelineOverview.updateGrid();
       });
     }
@@ -82,8 +84,7 @@
   _onStatsUpdate(event) {
     const profile = event.data;
 
-    if (!this._startTime) {
-      this._startTime = Date.now();
+    if (!this._totalTime) {
       this._timestamps = [];
       this._sizes = [];
       this._max = [];
@@ -94,7 +95,7 @@
 
     this._sizes.fill(0);
     this._sizes.push(0);
-    this._timestamps.push(Date.now() - this._startTime);
+    this._timestamps.push(Date.now());
     this._ordinals.push(this._lastOrdinal + 1);
     this._lastOrdinal = profile.samples.reduce((res, sample) => Math.max(res, sample.ordinal), this._lastOrdinal);
     for (const sample of profile.samples) {
@@ -103,7 +104,7 @@
     }
     this._max.push(this._sizes.peekLast());
 
-    if (this._timestamps.peekLast() > this._totalTime)
+    if (this._timestamps.peekLast() - this._timestamps[0] > this._totalTime)
       this._totalTime *= 2;
 
     const samples = /** @type {!Profiler.HeapTimelineOverview.Samples} */ ({
diff --git a/third_party/blink/renderer/devtools/front_end/profiler/HeapSnapshotView.js b/third_party/blink/renderer/devtools/front_end/profiler/HeapSnapshotView.js
index 482e7955..c33e950 100644
--- a/third_party/blink/renderer/devtools/front_end/profiler/HeapSnapshotView.js
+++ b/third_party/blink/renderer/devtools/front_end/profiler/HeapSnapshotView.js
@@ -180,6 +180,7 @@
           Profiler.TrackingHeapSnapshotProfileType.HeapStatsUpdate, this._onHeapStatsUpdate, this);
       profileType.addEventListener(
           Profiler.TrackingHeapSnapshotProfileType.TrackingStopped, this._onStopTracking, this);
+      this._trackingOverviewGrid.start();
     }
   }
 
@@ -188,6 +189,8 @@
         Profiler.TrackingHeapSnapshotProfileType.HeapStatsUpdate, this._onHeapStatsUpdate, this);
     this._profile.profileType().removeEventListener(
         Profiler.TrackingHeapSnapshotProfileType.TrackingStopped, this._onStopTracking, this);
+    if (this._trackingOverviewGrid)
+      this._trackingOverviewGrid.stop();
   }
 
   /**
diff --git a/third_party/blink/renderer/devtools/front_end/profiler/HeapTimelineOverview.js b/third_party/blink/renderer/devtools/front_end/profiler/HeapTimelineOverview.js
index 2e1d3e21..e60c72bf 100644
--- a/third_party/blink/renderer/devtools/front_end/profiler/HeapTimelineOverview.js
+++ b/third_party/blink/renderer/devtools/front_end/profiler/HeapTimelineOverview.js
@@ -29,12 +29,27 @@
     this._profileSamples = new Profiler.HeapTimelineOverview.Samples();
   }
 
+  start() {
+    this._running = true;
+    const drawFrame = () => {
+      this.update();
+      if (this._running)
+        this.element.window().requestAnimationFrame(drawFrame);
+    };
+    drawFrame();
+  }
+
+  stop() {
+    this._running = false;
+  }
+
   /**
    * @param {!Profiler.HeapTimelineOverview.Samples} samples
    */
   setSamples(samples) {
     this._profileSamples = samples;
-    this.update();
+    if (!this._running)
+      this.update();
   }
 
   /**
@@ -49,7 +64,6 @@
     const topSizes = profileSamples.max;
     const timestamps = profileSamples.timestamps;
     const startTime = timestamps[0];
-    const endTime = timestamps[timestamps.length - 1];
 
     const scaleFactor = this._xScale.nextScale(width / profileSamples.totalTime);
     let maxSize = 0;
@@ -93,14 +107,16 @@
     const context = this._overviewCanvas.getContext('2d');
     context.scale(window.devicePixelRatio, window.devicePixelRatio);
 
-    context.beginPath();
-    context.lineWidth = 2;
-    context.strokeStyle = 'rgba(192, 192, 192, 0.6)';
-    const currentX = (endTime - startTime) * scaleFactor;
-    context.moveTo(currentX, height - 1);
-    context.lineTo(currentX, 0);
-    context.stroke();
-    context.closePath();
+    if (this._running) {
+      context.beginPath();
+      context.lineWidth = 2;
+      context.strokeStyle = 'rgba(192, 192, 192, 0.6)';
+      const currentX = (Date.now() - startTime) * scaleFactor;
+      context.moveTo(currentX, height - 1);
+      context.lineTo(currentX, 0);
+      context.stroke();
+      context.closePath();
+    }
 
     let gridY;
     let gridValue;
diff --git a/third_party/blink/renderer/modules/credentialmanager/credential_manager_type_converters.cc b/third_party/blink/renderer/modules/credentialmanager/credential_manager_type_converters.cc
index 0d589c38e..d67cdf3b 100644
--- a/third_party/blink/renderer/modules/credentialmanager/credential_manager_type_converters.cc
+++ b/third_party/blink/renderer/modules/credentialmanager/credential_manager_type_converters.cc
@@ -328,7 +328,7 @@
 
   mojo_descriptor->type = ConvertTo<PublicKeyCredentialType>(descriptor.type());
   mojo_descriptor->id = ConvertTo<Vector<uint8_t>>(descriptor.id());
-  if (descriptor.hasTransports()) {
+  if (descriptor.hasTransports() && !descriptor.transports().IsEmpty()) {
     for (const auto& transport : descriptor.transports()) {
       mojo_descriptor->transports.push_back(
           ConvertTo<AuthenticatorTransport>(transport));
diff --git a/third_party/blink/renderer/modules/modules_initializer.cc b/third_party/blink/renderer/modules/modules_initializer.cc
index 14f7893..9faf47ed 100644
--- a/third_party/blink/renderer/modules/modules_initializer.cc
+++ b/third_party/blink/renderer/modules/modules_initializer.cc
@@ -22,7 +22,7 @@
 #include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
 #include "third_party/blink/renderer/core/html/canvas/html_canvas_element.h"
 #include "third_party/blink/renderer/core/html/media/html_media_element.h"
-#include "third_party/blink/renderer/core/inspector/devtools_session.h"
+#include "third_party/blink/renderer/core/inspector/inspector_session.h"
 #include "third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.h"
 #include "third_party/blink/renderer/core/origin_trials/origin_trials.h"
 #include "third_party/blink/renderer/core/page/chrome_client.h"
@@ -211,7 +211,7 @@
 }
 
 void ModulesInitializer::InitInspectorAgentSession(
-    DevToolsSession* session,
+    InspectorSession* session,
     bool allow_view_agents,
     InspectorDOMAgent* dom_agent,
     InspectedFrames* inspected_frames,
diff --git a/third_party/blink/renderer/modules/modules_initializer.h b/third_party/blink/renderer/modules/modules_initializer.h
index e67c306..4a7fc6c 100644
--- a/third_party/blink/renderer/modules/modules_initializer.h
+++ b/third_party/blink/renderer/modules/modules_initializer.h
@@ -28,7 +28,7 @@
                                      ShadowRoot&) const override;
   PictureInPictureController* CreatePictureInPictureController(
       Document&) const override;
-  void InitInspectorAgentSession(DevToolsSession*,
+  void InitInspectorAgentSession(InspectorSession*,
                                  bool,
                                  InspectorDOMAgent*,
                                  InspectedFrames*,
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc
index 6d73381f..a23d702 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.cc
@@ -489,8 +489,74 @@
                            new_fingerprint_end - new_fingerprint_pos);
 }
 
+enum class SdpFormat {
+  kSimple,
+  kComplexPlanB,
+  kComplexUnifiedPlan,
+};
+
+base::Optional<SdpFormat> DeduceSdpFormat(const String& type,
+                                          const String& sdp) {
+  std::unique_ptr<webrtc::SessionDescriptionInterface> session_description(
+      webrtc::CreateSessionDescription(type.Utf8().data(), sdp.Utf8().data(),
+                                       nullptr));
+  if (!session_description)
+    return base::nullopt;
+  size_t num_audio_mlines = 0u;
+  size_t num_video_mlines = 0u;
+  size_t num_audio_tracks = 0u;
+  size_t num_video_tracks = 0u;
+  for (const cricket::ContentInfo& content :
+       session_description->description()->contents()) {
+    cricket::MediaType media_type = content.media_description()->type();
+    size_t num_tracks = std::max(static_cast<size_t>(1u),
+                                 content.media_description()->streams().size());
+    if (media_type == cricket::MEDIA_TYPE_AUDIO) {
+      ++num_audio_mlines;
+      num_audio_tracks += num_tracks;
+    } else if (media_type == cricket::MEDIA_TYPE_VIDEO) {
+      ++num_video_mlines;
+      num_video_tracks += num_tracks;
+    }
+  }
+  if (num_audio_mlines <= 1u && num_audio_tracks <= 1u &&
+      num_video_mlines <= 1u && num_video_tracks <= 1u) {
+    return SdpFormat::kSimple;
+  }
+  if ((num_audio_mlines == 1u && num_audio_tracks > 1u) ||
+      (num_video_mlines == 1u && num_video_tracks > 1u)) {
+    return SdpFormat::kComplexPlanB;
+  }
+  DCHECK(num_audio_mlines > 1u || num_audio_tracks > 1u ||
+         num_video_mlines > 1u || num_video_tracks > 1u);
+  return SdpFormat::kComplexUnifiedPlan;
+}
+
 }  // namespace
 
+SdpUsageCategory DeduceSdpUsageCategory(const String& sdp_type,
+                                        const String& sdp,
+                                        bool sdp_semantics_specified,
+                                        webrtc::SdpSemantics sdp_semantics) {
+  auto sdp_format = DeduceSdpFormat(sdp_type, sdp);
+  if (!sdp_format)
+    return SdpUsageCategory::kUnknown;
+  switch (*sdp_format) {
+    case SdpFormat::kSimple:
+      return SdpUsageCategory::kSafe;
+    case SdpFormat::kComplexPlanB:
+      return (sdp_semantics_specified &&
+              sdp_semantics == webrtc::SdpSemantics::kPlanB)
+                 ? SdpUsageCategory::kSafe
+                 : SdpUsageCategory::kUnsafe;
+    case SdpFormat::kComplexUnifiedPlan:
+      return (sdp_semantics_specified &&
+              sdp_semantics == webrtc::SdpSemantics::kUnifiedPlan)
+                 ? SdpUsageCategory::kSafe
+                 : SdpUsageCategory::kUnsafe;
+  }
+}
+
 RTCPeerConnection::EventWrapper::EventWrapper(Event* event,
                                               BoolFunction function)
     : event_(event), setup_function_(std::move(function)) {}
@@ -855,31 +921,43 @@
     return false;
   if (!session_description_init.hasType() || !session_description_init.hasSdp())
     return false;
-  std::unique_ptr<webrtc::SessionDescriptionInterface> session_description(
-      webrtc::CreateSessionDescription(
-          session_description_init.type().Utf8().data(),
-          session_description_init.sdp().Utf8().data(), nullptr));
-  if (!session_description)
+  auto sdp_format = DeduceSdpFormat(session_description_init.type(),
+                                    session_description_init.sdp());
+  if (!sdp_format)
     return false;
-  size_t num_audio_mlines = 0u;
-  size_t num_video_mlines = 0u;
-  size_t num_audio_tracks = 0u;
-  size_t num_video_tracks = 0u;
-  for (const cricket::ContentInfo& content :
-       session_description->description()->contents()) {
-    cricket::MediaType media_type = content.media_description()->type();
-    size_t num_tracks = std::max(static_cast<size_t>(1u),
-                                 content.media_description()->streams().size());
-    if (media_type == cricket::MEDIA_TYPE_AUDIO) {
-      ++num_audio_mlines;
-      num_audio_tracks += num_tracks;
-    } else if (media_type == cricket::MEDIA_TYPE_VIDEO) {
-      ++num_video_mlines;
-      num_video_tracks += num_tracks;
+  return *sdp_format == SdpFormat::kComplexPlanB;
+}
+
+void RTCPeerConnection::ReportSetSdpUsage(
+    SetSdpOperationType operation_type,
+    const RTCSessionDescriptionInit& session_description_init) const {
+  SdpUsageCategory sdp_usage = DeduceSdpUsageCategory(
+      session_description_init.type(), session_description_init.sdp(),
+      sdp_semantics_specified_, sdp_semantics_);
+  if (session_description_init.type() == "offer") {
+    switch (operation_type) {
+      case SetSdpOperationType::kSetLocalDescription:
+        UMA_HISTOGRAM_ENUMERATION(
+            "WebRTC.PeerConnection.SdpComplexUsage.SetLocalOffer", sdp_usage);
+        break;
+      case SetSdpOperationType::kSetRemoteDescription:
+        UMA_HISTOGRAM_ENUMERATION(
+            "WebRTC.PeerConnection.SdpComplexUsage.SetRemoteOffer", sdp_usage);
+        break;
+    }
+  } else if (session_description_init.type() == "answer" ||
+             session_description_init.type() == "pranswer") {
+    switch (operation_type) {
+      case SetSdpOperationType::kSetLocalDescription:
+        UMA_HISTOGRAM_ENUMERATION(
+            "WebRTC.PeerConnection.SdpComplexUsage.SetLocalAnswer", sdp_usage);
+        break;
+      case SetSdpOperationType::kSetRemoteDescription:
+        UMA_HISTOGRAM_ENUMERATION(
+            "WebRTC.PeerConnection.SdpComplexUsage.SetRemoteAnswer", sdp_usage);
+        break;
     }
   }
-  return (num_audio_mlines == 1u && num_audio_tracks > 1u) ||
-         (num_video_mlines == 1u && num_video_tracks > 1u);
 }
 
 ScriptPromise RTCPeerConnection::setLocalDescription(
@@ -890,6 +968,8 @@
         GetExecutionContext(),
         WebFeature::kRTCPeerConnectionComplexPlanBSdpUsingDefaultSdpSemantics);
   }
+  ReportSetSdpUsage(SetSdpOperationType::kSetLocalDescription,
+                    session_description_init);
   String sdp;
   DOMException* exception = checkSdpForStateErrors(
       ExecutionContext::From(script_state), session_description_init, &sdp);
@@ -915,6 +995,8 @@
         GetExecutionContext(),
         WebFeature::kRTCPeerConnectionComplexPlanBSdpUsingDefaultSdpSemantics);
   }
+  ReportSetSdpUsage(SetSdpOperationType::kSetLocalDescription,
+                    session_description_init);
   ExecutionContext* context = ExecutionContext::From(script_state);
   if (success_callback && error_callback) {
     UseCounter::Count(
@@ -985,6 +1067,8 @@
         GetExecutionContext(),
         WebFeature::kRTCPeerConnectionComplexPlanBSdpUsingDefaultSdpSemantics);
   }
+  ReportSetSdpUsage(SetSdpOperationType::kSetRemoteDescription,
+                    session_description_init);
   if (signaling_state_ ==
       webrtc::PeerConnectionInterface::SignalingState::kClosed) {
     return ScriptPromise::RejectWithDOMException(
@@ -1012,6 +1096,8 @@
         GetExecutionContext(),
         WebFeature::kRTCPeerConnectionComplexPlanBSdpUsingDefaultSdpSemantics);
   }
+  ReportSetSdpUsage(SetSdpOperationType::kSetRemoteDescription,
+                    session_description_init);
   ExecutionContext* context = ExecutionContext::From(script_state);
   if (success_callback && error_callback) {
     UseCounter::Count(
@@ -2086,10 +2172,16 @@
 }
 
 void RTCPeerConnection::NoteSdpCreated(const RTCSessionDescription& desc) {
+  SdpUsageCategory sdp_usage = DeduceSdpUsageCategory(
+      desc.type(), desc.sdp(), sdp_semantics_specified_, sdp_semantics_);
   if (desc.type() == "offer") {
     last_offer_ = desc.sdp();
+    UMA_HISTOGRAM_ENUMERATION(
+        "WebRTC.PeerConnection.SdpComplexUsage.CreateOffer", sdp_usage);
   } else if (desc.type() == "answer") {
     last_answer_ = desc.sdp();
+    UMA_HISTOGRAM_ENUMERATION(
+        "WebRTC.PeerConnection.SdpComplexUsage.CreateAnswer", sdp_usage);
   }
 }
 
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.h b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.h
index 3cf36fc..8995afba 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.h
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection.h
@@ -72,6 +72,28 @@
 class V8RTCStatsCallback;
 class V8VoidFunction;
 
+// This enum is used to track usage of SDP during the transition of the default
+// "sdpSemantics" value from "Plan B" to "Unified Plan". Usage refers to
+// operations such as createOffer(), createAnswer(), setLocalDescription() and
+// setRemoteDescription(). "Complex" SDP refers to SDP that is not compatible
+// between SDP formats. Usage of SDP falls into two categories: "safe" and
+// "unsafe". Applications with unsafe usage are predicted to break when the
+// default changes. This includes complex SDP usage and relying on the default
+// sdpSemantics. kUnknown is used if the SDP format could not be deduced, such
+// as if SDP could not be parsed.
+enum class SdpUsageCategory {
+  kSafe = 0,
+  kUnsafe = 1,
+  kUnknown = 2,
+  kMaxValue = kUnknown,
+};
+
+SdpUsageCategory MODULES_EXPORT
+DeduceSdpUsageCategory(const String& sdp_type,
+                       const String& sdp,
+                       bool sdp_semantics_specified,
+                       webrtc::SdpSemantics sdp_semantics);
+
 class MODULES_EXPORT RTCPeerConnection final
     : public EventTargetWithInlineData,
       public WebRTCPeerConnectionHandlerClient,
@@ -220,6 +242,14 @@
 
   // Utility to note result of CreateOffer / CreateAnswer
   void NoteSdpCreated(const RTCSessionDescription&);
+  // Utility to report SDP usage of setLocalDescription / setRemoteDescription.
+  enum class SetSdpOperationType {
+    kSetLocalDescription,
+    kSetRemoteDescription,
+  };
+  void ReportSetSdpUsage(
+      SetSdpOperationType operation_type,
+      const RTCSessionDescriptionInit& session_description_init) const;
 
   // MediaStreamObserver
   void OnStreamAddTrack(MediaStream*, MediaStreamTrack*) override;
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_test.cc b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_test.cc
index a20d8fa8..e70a4feb 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_test.cc
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_peer_connection_test.cc
@@ -646,4 +646,101 @@
   ASSERT_FALSE(pc->ShouldShowComplexPlanBSdpWarning(sdp));
 }
 
+// Test that simple Plan B is considered safe regardless of configurations.
+TEST(DeduceSdpUsageCategory, SimplePlanBIsAlwaysSafe) {
+  // If the default is Plan B.
+  EXPECT_EQ(
+      SdpUsageCategory::kSafe,
+      DeduceSdpUsageCategory("offer", kOfferSdpPlanBSingleAudioSingleVideo,
+                             false, webrtc::SdpSemantics::kPlanB));
+  // If the default is Unified Plan.
+  EXPECT_EQ(
+      SdpUsageCategory::kSafe,
+      DeduceSdpUsageCategory("offer", kOfferSdpPlanBSingleAudioSingleVideo,
+                             false, webrtc::SdpSemantics::kUnifiedPlan));
+  // If sdpSemantics is explicitly set to Plan B.
+  EXPECT_EQ(
+      SdpUsageCategory::kSafe,
+      DeduceSdpUsageCategory("offer", kOfferSdpPlanBSingleAudioSingleVideo,
+                             true, webrtc::SdpSemantics::kPlanB));
+  // If sdpSemantics is explicitly set to Unified Plan.
+  EXPECT_EQ(
+      SdpUsageCategory::kSafe,
+      DeduceSdpUsageCategory("offer", kOfferSdpPlanBSingleAudioSingleVideo,
+                             true, webrtc::SdpSemantics::kUnifiedPlan));
+}
+
+// Test that simple Unified Plan is considered safe regardless of
+// configurations.
+TEST(DeduceSdpUsageCategory, SimpleUnifiedPlanIsAlwaysSafe) {
+  // If the default is Plan B.
+  EXPECT_EQ(SdpUsageCategory::kSafe,
+            DeduceSdpUsageCategory("offer",
+                                   kOfferSdpUnifiedPlanSingleAudioSingleVideo,
+                                   false, webrtc::SdpSemantics::kPlanB));
+  // If the default is Unified Plan.
+  EXPECT_EQ(SdpUsageCategory::kSafe,
+            DeduceSdpUsageCategory("offer",
+                                   kOfferSdpUnifiedPlanSingleAudioSingleVideo,
+                                   false, webrtc::SdpSemantics::kUnifiedPlan));
+  // If sdpSemantics is explicitly set to Plan B.
+  EXPECT_EQ(SdpUsageCategory::kSafe,
+            DeduceSdpUsageCategory("offer",
+                                   kOfferSdpUnifiedPlanSingleAudioSingleVideo,
+                                   true, webrtc::SdpSemantics::kPlanB));
+  // If sdpSemantics is explicitly set to Unified Plan.
+  EXPECT_EQ(SdpUsageCategory::kSafe,
+            DeduceSdpUsageCategory("offer",
+                                   kOfferSdpUnifiedPlanSingleAudioSingleVideo,
+                                   true, webrtc::SdpSemantics::kUnifiedPlan));
+}
+
+// Test that complex SDP is always unsafe when relying on default sdpSemantics.
+TEST(DeduceSdpUsageCategory, ComplexSdpIsAlwaysUnsafeWithDefaultSdpSemantics) {
+  // If the default is Plan B and the SDP is complex Plan B.
+  EXPECT_EQ(SdpUsageCategory::kUnsafe,
+            DeduceSdpUsageCategory("offer", kOfferSdpPlanBMultipleAudioTracks,
+                                   false, webrtc::SdpSemantics::kPlanB));
+  // If the default is Plan B and the SDP is complex Unified Plan.
+  EXPECT_EQ(
+      SdpUsageCategory::kUnsafe,
+      DeduceSdpUsageCategory("offer", kOfferSdpUnifiedPlanMultipleAudioTracks,
+                             false, webrtc::SdpSemantics::kPlanB));
+  // If the default is Unified Plan and the SDP is complex Plan B.
+  EXPECT_EQ(SdpUsageCategory::kUnsafe,
+            DeduceSdpUsageCategory("offer", kOfferSdpPlanBMultipleAudioTracks,
+                                   false, webrtc::SdpSemantics::kUnifiedPlan));
+  // If the default is Unified Plan and the SDP is complex UNified Plan.
+  EXPECT_EQ(
+      SdpUsageCategory::kUnsafe,
+      DeduceSdpUsageCategory("offer", kOfferSdpUnifiedPlanMultipleAudioTracks,
+                             false, webrtc::SdpSemantics::kUnifiedPlan));
+}
+
+// Test that when sdpSemantics is explicitly set, complex SDP is safe if it is
+// of the same format and unsafe if the format is different.
+TEST(DeduceSdpUsageCategory, ComplexSdpIsSafeIfMatchingExplicitSdpSemantics) {
+  // If sdpSemantics is explicitly set to Plan B and the SDP is complex Plan B.
+  EXPECT_EQ(SdpUsageCategory::kSafe,
+            DeduceSdpUsageCategory("offer", kOfferSdpPlanBMultipleAudioTracks,
+                                   true, webrtc::SdpSemantics::kPlanB));
+  // If sdpSemantics is explicitly set to Unified Plan and the SDP is complex
+  // Unified Plan.
+  EXPECT_EQ(
+      SdpUsageCategory::kSafe,
+      DeduceSdpUsageCategory("offer", kOfferSdpUnifiedPlanMultipleAudioTracks,
+                             true, webrtc::SdpSemantics::kUnifiedPlan));
+  // If the sdpSemantics is explicitly set to Plan B but the SDP is complex
+  // Unified Plan.
+  EXPECT_EQ(
+      SdpUsageCategory::kUnsafe,
+      DeduceSdpUsageCategory("offer", kOfferSdpUnifiedPlanMultipleAudioTracks,
+                             true, webrtc::SdpSemantics::kPlanB));
+  // If the sdpSemantics is explicitly set to Unified Plan but the SDP is
+  // complex Plan B.
+  EXPECT_EQ(SdpUsageCategory::kUnsafe,
+            DeduceSdpUsageCategory("offer", kOfferSdpPlanBMultipleAudioTracks,
+                                   true, webrtc::SdpSemantics::kUnifiedPlan));
+}
+
 }  // namespace blink
diff --git a/third_party/polymer/v1_0/bower.json b/third_party/polymer/v1_0/bower.json
index cdeb4408..a6bda30 100644
--- a/third_party/polymer/v1_0/bower.json
+++ b/third_party/polymer/v1_0/bower.json
@@ -6,7 +6,6 @@
     "iron-a11y-announcer": "PolymerElements/iron-a11y-announcer#2.1.0",
     "iron-a11y-keys-behavior": "PolymerElements/iron-a11y-keys-behavior#2.1.1",
     "iron-a11y-keys": "PolymerElements/iron-a11y-keys#2.0.0",
-    "iron-autogrow-textarea": "PolymerElements/iron-autogrow-textarea#2.1.1",
     "iron-behaviors": "PolymerElements/iron-behaviors#2.1.1",
     "iron-checked-element-behavior": "PolymerElements/iron-checked-element-behavior#2.1.0",
     "iron-collapse": "PolymerElements/iron-collapse#2.1.0",
@@ -38,7 +37,6 @@
     "paper-icon-button": "PolymerElements/paper-icon-button#2.1.0",
     "paper-input": "PolymerElements/paper-input#2.2.2",
     "paper-item": "PolymerElements/paper-item#2.0.0",
-    "paper-listbox": "PolymerelEments/paper-listbox#2.0.0",
     "paper-progress": "PolymerElements/paper-progress#2.0.1",
     "paper-ripple": "PolymerElements/paper-ripple#2.0.1",
     "paper-slider": "PolymerElements/paper-slider#2.0.2",
diff --git a/third_party/polymer/v1_0/chromium.patch b/third_party/polymer/v1_0/chromium.patch
index 341bf28b..616aada 100644
--- a/third_party/polymer/v1_0/chromium.patch
+++ b/third_party/polymer/v1_0/chromium.patch
@@ -9,50 +9,6 @@
 -<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:400,300,300italic,400italic,500,500italic,700,700italic">
 -<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto+Mono:400,700">
 +<link rel="stylesheet" href="chrome://resources/css/roboto.css">
-diff --git a/components-chromium/paper-input/paper-input-extracted.js b/components-chromium/paper-input/paper-input-extracted.js
-index 754820fb5d0c..3f8e640ffa71 100644
---- a/components-chromium/paper-input/paper-input-extracted.js
-+++ b/components-chromium/paper-input/paper-input-extracted.js
-@@ -7,13 +7,7 @@ Polymer({
-     ],
- 
-     beforeRegister: function() {
--      // We need to tell which kind of of template to stamp based on
--      // what kind of `iron-input` we got, but because of polyfills and
--      // custom elements differences between v0 and v1, the safest bet is
--      // to check a particular method we know the iron-input#2.x can have.
--      // If it doesn't have it, then it's an iron-input#1.x.
--      var ironInput = document.createElement('iron-input');
--      var version = typeof ironInput._initSlottedInput == 'function' ? 'v1' : 'v0';
-+      var version = 'v1';  // Hard coded Polymer 2 style iron-input.
-       var template = Polymer.DomModule.import('paper-input', 'template');
-       var inputTemplate = Polymer.DomModule.import('paper-input', 'template#' + version);
-       var inputPlaceholder = template.content.querySelector('#template-placeholder');
-@@ -30,7 +24,8 @@ Polymer({
-      * @return {!HTMLElement}
-      */
-     get _focusableElement() {
--      return Polymer.Element ? this.inputElement._inputElement : this.inputElement;
-+      // TODO(hcarmona): remove this patch after polymer is v2.
-+      return this.inputElement._inputElement;
-     },
- 
-     // Note: This event is only available in the 1.0 version of this element.
-diff --git a/components-chromium/paper-input/paper-textarea-extracted.js b/components-chromium/paper-input/paper-textarea-extracted.js
-index 11bc05a37471..8d425e02c30b 100644
---- a/components-chromium/paper-input/paper-textarea-extracted.js
-+++ b/components-chromium/paper-input/paper-textarea-extracted.js
-@@ -57,8 +57,8 @@ Polymer({
-       this.$.input.textarea.selectionEnd = end;
-     },
-
--    _ariaLabelledByChanged: function(ariaLabelledBy) {
--      this._focusableElement.setAttribute('aria-labelledby', ariaLabelledBy);
-+    _ariaLabelledByChanged: function() {
-+      this._focusableElement.setAttribute('aria-label', this.label);
-     },
-
-     _ariaDescribedByChanged: function(ariaDescribedBy) {
 diff --git a/components-chromium/iron-list/iron-list-extracted.js b/components-chromium/iron-list/iron-list-extracted.js
 index 43c59653a39b..26652936735c 100644
 --- a/components-chromium/iron-list/iron-list-extracted.js
@@ -128,10 +84,18 @@
 +</body></html>
 \ No newline at end of file
 diff --git a/components-chromium/paper-slider/paper-slider.html b/components-chromium/paper-slider/paper-slider.html
-index 646c22c2fb93..952818290c1e 100644
+index 233808adc822..4117f3590a61 100644
 --- a/components-chromium/paper-slider/paper-slider.html
 +++ b/components-chromium/paper-slider/paper-slider.html
-@@ -279,6 +279,7 @@ Custom property | Description | Default
+@@ -12,7 +12,6 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
+ <link rel="import" href="../iron-form-element-behavior/iron-form-element-behavior.html">
+ <link rel="import" href="../iron-range-behavior/iron-range-behavior.html">
+ <link rel="import" href="../paper-behaviors/paper-inky-focus-behavior.html">
+-<link rel="import" href="../paper-input/paper-input.html">
+ <link rel="import" href="../paper-progress/paper-progress.html">
+ <link rel="import" href="../paper-styles/color.html">
+ 
+@@ -279,6 +278,7 @@ Custom property | Description | Default
  
        .pin.expand > .slider-knob > .slider-knob-inner::after {
          transform: scale(1) translate(0, -17px);
@@ -139,6 +103,18 @@
        }
  
        /* paper-input */
+@@ -330,11 +330,6 @@ Custom property | Description | Default
+           <div class="slider-knob-inner" value$="[[immediateValue]]"></div>
+       </div>
+     </div>
+-
+-    <template is="dom-if" if="[[editable]]">
+-      <paper-input id="input" type="number" step="[[step]]" min="[[min]]" max="[[max]]" class="slider-input" disabled$="[[disabled]]" value="[[immediateValue]]" on-change="_changeValue" on-keydown="_inputKeyDown" no-label-float="">
+-      </paper-input>
+-    </template>
+   </template>
+ 
+   </dom-module>
 diff --git a/components-chromium/paper-slider/paper-slider-extracted.js b/components-chromium/paper-slider/paper-slider-extracted.js
 index 2e63d3731be1..217c7ff1414c 100644
 --- a/components-chromium/paper-slider/paper-slider-extracted.js
diff --git a/third_party/polymer/v1_0/components-chromium/iron-autogrow-textarea/BUILD.gn b/third_party/polymer/v1_0/components-chromium/iron-autogrow-textarea/BUILD.gn
deleted file mode 100644
index 390c4f6..0000000
--- a/third_party/polymer/v1_0/components-chromium/iron-autogrow-textarea/BUILD.gn
+++ /dev/null
@@ -1,14 +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.
-#
-# NOTE: Created with generate_gn.py, please do not edit.
-
-import("//third_party/closure_compiler/compile_js.gni")
-
-js_library("iron-autogrow-textarea-extracted") {
-  deps = [
-    "../iron-behaviors:iron-control-state-extracted",
-    "../iron-validatable-behavior:iron-validatable-behavior-extracted",
-  ]
-}
diff --git a/third_party/polymer/v1_0/components-chromium/iron-autogrow-textarea/bower.json b/third_party/polymer/v1_0/components-chromium/iron-autogrow-textarea/bower.json
deleted file mode 100644
index 1ed77375..0000000
--- a/third_party/polymer/v1_0/components-chromium/iron-autogrow-textarea/bower.json
+++ /dev/null
@@ -1,63 +0,0 @@
-{
-  "name": "iron-autogrow-textarea",
-  "version": "2.1.1",
-  "description": "A textarea element that automatically grows with input",
-  "authors": [
-    "The Polymer Authors"
-  ],
-  "keywords": [
-    "web-components",
-    "polymer",
-    "input",
-    "textarea"
-  ],
-  "main": "iron-autogrow-textarea.html",
-  "private": true,
-  "repository": {
-    "type": "git",
-    "url": "git://github.com/PolymerElements/iron-autogrow-textarea.git"
-  },
-  "license": "http://polymer.github.io/LICENSE.txt",
-  "homepage": "https://github.com/PolymerElements/iron-autogrow-textarea",
-  "ignore": [],
-  "dependencies": {
-    "iron-behaviors": "PolymerElements/iron-behaviors#1 - 2",
-    "iron-flex-layout": "PolymerElements/iron-flex-layout#1 - 2",
-    "iron-validatable-behavior": "PolymerElements/iron-validatable-behavior#1 - 2",
-    "polymer": "Polymer/polymer#1.9 - 2"
-  },
-  "devDependencies": {
-    "iron-component-page": "PolymerElements/iron-component-page#1 - 2",
-    "iron-demo-helpers": "PolymerElements/iron-demo-helpers#1 - 2",
-    "iron-test-helpers": "PolymerElements/iron-test-helpers#1 - 2",
-    "paper-styles": "PolymerElements/paper-styles#1 - 2",
-    "test-fixture": "PolymerElements/test-fixture#^3.0.0-rc.1",
-    "web-component-tester": "^6.0.0",
-    "webcomponentsjs": "webcomponents/webcomponentsjs#^1.0.0"
-  },
-  "variants": {
-    "1.x": {
-      "dependencies": {
-        "iron-behaviors": "PolymerElements/iron-behaviors#^1.0.0",
-        "iron-flex-layout": "PolymerElements/iron-flex-layout#^1.0.0",
-        "iron-validatable-behavior": "PolymerElements/iron-validatable-behavior#^1.0.0",
-        "polymer": "Polymer/polymer#^1.9"
-      },
-      "devDependencies": {
-        "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
-        "iron-demo-helpers": "PolymerElements/iron-demo-helpers#^1.0.0",
-        "iron-test-helpers": "PolymerElements/iron-test-helpers#^1.0.0",
-        "paper-styles": "PolymerElements/paper-styles#^1.0.0",
-        "test-fixture": "PolymerElements/test-fixture#^1.0.0",
-        "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0",
-        "web-component-tester": "Polymer/web-component-tester#^4.0.0"
-      },
-      "resolutions": {
-        "webcomponentsjs": "^0.7"
-      }
-    }
-  },
-  "resolutions": {
-    "webcomponentsjs": "^1.0.0"
-  }
-}
diff --git a/third_party/polymer/v1_0/components-chromium/iron-autogrow-textarea/iron-autogrow-textarea-extracted.js b/third_party/polymer/v1_0/components-chromium/iron-autogrow-textarea/iron-autogrow-textarea-extracted.js
deleted file mode 100644
index 274d3ff..0000000
--- a/third_party/polymer/v1_0/components-chromium/iron-autogrow-textarea/iron-autogrow-textarea-extracted.js
+++ /dev/null
@@ -1,262 +0,0 @@
-Polymer({
-
-    is: 'iron-autogrow-textarea',
-
-    behaviors: [
-      Polymer.IronValidatableBehavior,
-      Polymer.IronControlState
-    ],
-
-    properties: {
-      /**
-       * Use this property instead of `bind-value` for two-way data binding.
-       * @type {string|number}
-       */
-      value: {
-        observer: '_valueChanged',
-        type: String,
-        notify: true
-      },
-
-      /**
-       * This property is deprecated, and just mirrors `value`. Use `value` instead.
-       * @type {string|number}
-       */
-      bindValue: {
-        observer: '_bindValueChanged',
-        type: String,
-        notify: true
-      },
-
-      /**
-       * The initial number of rows.
-       *
-       * @attribute rows
-       * @type number
-       * @default 1
-       */
-      rows: {
-        type: Number,
-        value: 1,
-        observer: '_updateCached'
-      },
-
-      /**
-       * The maximum number of rows this element can grow to until it
-       * scrolls. 0 means no maximum.
-       *
-       * @attribute maxRows
-       * @type number
-       * @default 0
-       */
-      maxRows: {
-       type: Number,
-       value: 0,
-       observer: '_updateCached'
-      },
-
-      /**
-       * Bound to the textarea's `autocomplete` attribute.
-       */
-      autocomplete: {
-        type: String,
-        value: 'off'
-      },
-
-      /**
-       * Bound to the textarea's `autofocus` attribute.
-       */
-      autofocus: {
-        type: Boolean,
-        value: false
-      },
-
-      /**
-       * Bound to the textarea's `inputmode` attribute.
-       */
-      inputmode: {
-        type: String
-      },
-
-      /**
-       * Bound to the textarea's `placeholder` attribute.
-       */
-      placeholder: {
-        type: String
-      },
-
-      /**
-       * Bound to the textarea's `readonly` attribute.
-       */
-      readonly: {
-        type: String
-      },
-
-      /**
-       * Set to true to mark the textarea as required.
-       */
-      required: {
-        type: Boolean
-      },
-
-      /**
-       * The minimum length of the input value.
-       */
-      minlength: {
-        type: Number
-      },
-
-      /**
-       * The maximum length of the input value.
-       */
-      maxlength: {
-        type: Number
-      },
-
-      /**
-       * Bound to the textarea's `aria-label` attribute.
-       */
-      label: {
-        type: String
-      }
-
-    },
-
-    listeners: {
-      'input': '_onInput'
-    },
-
-    /**
-     * Returns the underlying textarea.
-     * @type HTMLTextAreaElement
-     */
-    get textarea() {
-      return this.$.textarea;
-    },
-
-    /**
-     * Returns textarea's selection start.
-     * @type Number
-     */
-    get selectionStart() {
-      return this.$.textarea.selectionStart;
-    },
-
-    /**
-     * Returns textarea's selection end.
-     * @type Number
-     */
-    get selectionEnd() {
-      return this.$.textarea.selectionEnd;
-    },
-
-    /**
-     * Sets the textarea's selection start.
-     */
-    set selectionStart(value) {
-      this.$.textarea.selectionStart = value;
-    },
-
-    /**
-     * Sets the textarea's selection end.
-     */
-    set selectionEnd(value) {
-      this.$.textarea.selectionEnd = value;
-    },
-
-    attached: function() {
-      /* iOS has an arbitrary left margin of 3px that isn't present
-       * in any other browser, and means that the paper-textarea's cursor
-       * overlaps the label.
-       * See https://github.com/PolymerElements/paper-input/issues/468.
-       */
-      var IS_IOS = navigator.userAgent.match(/iP(?:[oa]d|hone)/);
-      if (IS_IOS) {
-        this.$.textarea.style.marginLeft = '-3px';
-      }
-    },
-
-    /**
-     * Returns true if `value` is valid. The validator provided in `validator`
-     * will be used first, if it exists; otherwise, the `textarea`'s validity
-     * is used.
-     * @return {boolean} True if the value is valid.
-     */
-    validate: function() {
-      // Use the nested input's native validity.
-      var valid =  this.$.textarea.validity.valid;
-
-      // Only do extra checking if the browser thought this was valid.
-      if (valid) {
-        // Empty, required input is invalid
-        if (this.required && this.value === '') {
-          valid = false;
-        } else if (this.hasValidator()) {
-          valid = Polymer.IronValidatableBehavior.validate.call(this, this.value);
-        }
-      }
-
-      this.invalid = !valid;
-      this.fire('iron-input-validate');
-      return valid;
-    },
-
-    _bindValueChanged: function(bindValue) {
-      this.value = bindValue;
-    },
-
-    _valueChanged: function(value) {
-      var textarea = this.textarea;
-      if (!textarea) {
-        return;
-      }
-
-      // If the bindValue changed manually, then we need to also update
-      // the underlying textarea's value. Otherwise this change was probably
-      // generated from the _onInput handler, and the two values are already
-      // the same.
-      if (textarea.value !== value) {
-        textarea.value = !(value || value === 0) ? '' : value;
-      }
-
-      this.bindValue = value;
-      this.$.mirror.innerHTML = this._valueForMirror();
-
-      // Manually notify because we don't want to notify until after setting value.
-      this.fire('bind-value-changed', {value: this.bindValue});
-    },
-
-    _onInput: function(event) {
-      var eventPath = Polymer.dom(event).path;
-      this.value = eventPath ? eventPath[0].value : event.target.value;
-    },
-
-    _constrain: function(tokens) {
-      var _tokens;
-      tokens = tokens || [''];
-      // Enforce the min and max heights for a multiline input to avoid measurement
-      if (this.maxRows > 0 && tokens.length > this.maxRows) {
-        _tokens = tokens.slice(0, this.maxRows);
-      } else {
-        _tokens = tokens.slice(0);
-      }
-      while (this.rows > 0 && _tokens.length < this.rows) {
-        _tokens.push('');
-      }
-      // Use &#160; instead &nbsp; of to allow this element to be used in XHTML.
-      return _tokens.join('<br/>') + '&#160;';
-    },
-
-    _valueForMirror: function() {
-      var input = this.textarea;
-      if (!input) {
-        return;
-      }
-      this.tokens = (input && input.value) ? input.value.replace(/&/gm, '&amp;').replace(/"/gm, '&quot;').replace(/'/gm, '&#39;').replace(/</gm, '&lt;').replace(/>/gm, '&gt;').split('\n') : [''];
-      return this._constrain(this.tokens);
-    },
-
-    _updateCached: function() {
-      this.$.mirror.innerHTML = this._constrain(this.tokens);
-    },
-  });
\ No newline at end of file
diff --git a/third_party/polymer/v1_0/components-chromium/iron-autogrow-textarea/iron-autogrow-textarea.html b/third_party/polymer/v1_0/components-chromium/iron-autogrow-textarea/iron-autogrow-textarea.html
deleted file mode 100644
index 132bbde..0000000
--- a/third_party/polymer/v1_0/components-chromium/iron-autogrow-textarea/iron-autogrow-textarea.html
+++ /dev/null
@@ -1,105 +0,0 @@
-<!--
-@license
-Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
-This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
-The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
-The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
-Code distributed by Google as part of the polymer project is also
-subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
---><html><head><link rel="import" href="../polymer/polymer.html">
-<link rel="import" href="../iron-behaviors/iron-control-state.html">
-<link rel="import" href="../iron-flex-layout/iron-flex-layout.html">
-<link rel="import" href="../iron-validatable-behavior/iron-validatable-behavior.html">
-
-<!--
-`iron-autogrow-textarea` is an element containing a textarea that grows in height as more
-lines of input are entered. Unless an explicit height or the `maxRows` property is set, it will
-never scroll.
-
-Example:
-
-    <iron-autogrow-textarea></iron-autogrow-textarea>
-
-### Styling
-
-The following custom properties and mixins are available for styling:
-
-Custom property | Description | Default
-----------------|-------------|----------
-`--iron-autogrow-textarea` | Mixin applied to the textarea | `{}`
-`--iron-autogrow-textarea-placeholder` | Mixin applied to the textarea placeholder | `{}`
-
-@group Iron Elements
-@hero hero.svg
-@demo demo/index.html
--->
-
-</head><body><dom-module id="iron-autogrow-textarea">
-  <template>
-    <style>
-      :host {
-        display: inline-block;
-        position: relative;
-        width: 400px;
-        border: 1px solid;
-        padding: 2px;
-        -webkit-appearance: textarea;
-        overflow: hidden;
-      }
-
-      .mirror-text {
-        visibility: hidden;
-        word-wrap: break-word;
-        @apply --iron-autogrow-textarea;
-      }
-
-      .fit {
-        @apply --layout-fit;
-      }
-
-      textarea {
-        position: relative;
-        outline: none;
-        border: none;
-        resize: none;
-        background: inherit;
-        color: inherit;
-        /* see comments in template */
-        width: 100%;
-        height: 100%;
-        font-size: inherit;
-        font-family: inherit;
-        line-height: inherit;
-        text-align: inherit;
-        @apply --iron-autogrow-textarea;
-      }
-
-      textarea::-webkit-input-placeholder {
-        @apply --iron-autogrow-textarea-placeholder;
-      }
-
-      textarea:-moz-placeholder {
-        @apply --iron-autogrow-textarea-placeholder;
-      }
-
-      textarea::-moz-placeholder {
-        @apply --iron-autogrow-textarea-placeholder;
-      }
-
-      textarea:-ms-input-placeholder {
-        @apply --iron-autogrow-textarea-placeholder;
-      }
-    </style>
-
-    <!-- the mirror sizes the input/textarea so it grows with typing -->
-    <!-- use &#160; instead &nbsp; of to allow this element to be used in XHTML -->
-    <div id="mirror" class="mirror-text" aria-hidden="true">&nbsp;</div>
-
-    <!-- size the input/textarea with a div, because the textarea has intrinsic size in ff -->
-    <div class="textarea-container fit">
-      <textarea id="textarea" name$="[[name]]" aria-label$="[[label]]" autocomplete$="[[autocomplete]]" autofocus$="[[autofocus]]" inputmode$="[[inputmode]]" placeholder$="[[placeholder]]" readonly$="[[readonly]]" required$="[[required]]" disabled$="[[disabled]]" rows$="[[rows]]" minlength$="[[minlength]]" maxlength$="[[maxlength]]"></textarea>
-    </div>
-  </template>
-</dom-module>
-
-<script src="iron-autogrow-textarea-extracted.js"></script></body></html>
\ No newline at end of file
diff --git a/third_party/polymer/v1_0/components-chromium/paper-input/BUILD.gn b/third_party/polymer/v1_0/components-chromium/paper-input/BUILD.gn
index 6e4e1f6..60ef7be 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-input/BUILD.gn
+++ b/third_party/polymer/v1_0/components-chromium/paper-input/BUILD.gn
@@ -30,25 +30,3 @@
     ":paper-input-addon-behavior-extracted",
   ]
 }
-
-js_library("paper-input-extracted") {
-  deps = [
-    ":paper-input-behavior-extracted",
-    ":paper-input-char-counter-extracted",
-    ":paper-input-container-extracted",
-    ":paper-input-error-extracted",
-    "../iron-form-element-behavior:iron-form-element-behavior-extracted",
-    "../iron-input:iron-input-extracted",
-  ]
-}
-
-js_library("paper-textarea-extracted") {
-  deps = [
-    ":paper-input-behavior-extracted",
-    ":paper-input-char-counter-extracted",
-    ":paper-input-container-extracted",
-    ":paper-input-error-extracted",
-    "../iron-autogrow-textarea:iron-autogrow-textarea-extracted",
-    "../iron-form-element-behavior:iron-form-element-behavior-extracted",
-  ]
-}
diff --git a/third_party/polymer/v1_0/components-chromium/paper-input/paper-input-extracted.js b/third_party/polymer/v1_0/components-chromium/paper-input/paper-input-extracted.js
deleted file mode 100644
index 3cb605bba..0000000
--- a/third_party/polymer/v1_0/components-chromium/paper-input/paper-input-extracted.js
+++ /dev/null
@@ -1,54 +0,0 @@
-Polymer({
-    is: 'paper-input',
-
-    behaviors: [
-      Polymer.PaperInputBehavior,
-      Polymer.IronFormElementBehavior
-    ],
-
-    beforeRegister: function() {
-      var version = 'v1';  // Hard coded Polymer 2 style iron-input.
-      var template = Polymer.DomModule.import('paper-input', 'template');
-      var inputTemplate = Polymer.DomModule.import('paper-input', 'template#' + version);
-      var inputPlaceholder = template.content.querySelector('#template-placeholder');
-      if (inputPlaceholder) {
-        inputPlaceholder.parentNode.replaceChild(inputTemplate.content, inputPlaceholder);
-      }
-      // else it's already been processed, probably in superclass
-    },
-
-    /**
-     * Returns a reference to the focusable element. Overridden from PaperInputBehavior
-     * to correctly focus the native input.
-     *
-     * @return {!HTMLElement}
-     */
-    get _focusableElement() {
-      // TODO(hcarmona): remove this patch after polymer is v2.
-      return this.inputElement._inputElement;
-    },
-
-    // Note: This event is only available in the 1.0 version of this element.
-    // In 2.0, the functionality of `_onIronInputReady` is done in
-    // PaperInputBehavior::attached.
-    listeners: {
-      'iron-input-ready': '_onIronInputReady'
-    },
-
-    _onIronInputReady: function() {
-      // Even though this is only used in the next line, save this for
-      // backwards compatibility, since the native input had this ID until 2.0.5.
-      if (!this.$.nativeInput) {
-        this.$.nativeInput = this.$$('input');
-      }
-      if (this.inputElement &&
-          this._typesThatHaveText.indexOf(this.$.nativeInput.type) !== -1) {
-        this.alwaysFloatLabel = true;
-      }
-
-      // Only validate when attached if the input already has a value.
-      if (!!this.inputElement.bindValue) {
-        this.$.container._handleValueAndAutoValidate(this.inputElement);
-      }
-    },
-  });
\ No newline at end of file
diff --git a/third_party/polymer/v1_0/components-chromium/paper-input/paper-input.html b/third_party/polymer/v1_0/components-chromium/paper-input/paper-input.html
deleted file mode 100644
index 50fa063..0000000
--- a/third_party/polymer/v1_0/components-chromium/paper-input/paper-input.html
+++ /dev/null
@@ -1,195 +0,0 @@
-<!--
-@license
-Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
-This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
-The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
-The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
-Code distributed by Google as part of the polymer project is also
-subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
---><html><head><link rel="import" href="../polymer/polymer.html">
-<link rel="import" href="../iron-form-element-behavior/iron-form-element-behavior.html">
-<link rel="import" href="../iron-input/iron-input.html">
-<link rel="import" href="paper-input-behavior.html">
-<link rel="import" href="paper-input-char-counter.html">
-<link rel="import" href="paper-input-container.html">
-<link rel="import" href="paper-input-error.html">
-
-<!--
-Material design: [Text fields](https://www.google.com/design/spec/components/text-fields.html)
-
-`<paper-input>` is a single-line text field with Material Design styling.
-
-    <paper-input label="Input label"></paper-input>
-
-It may include an optional error message or character counter.
-
-    <paper-input error-message="Invalid input!" label="Input label"></paper-input>
-    <paper-input char-counter label="Input label"></paper-input>
-
-It can also include custom prefix or suffix elements, which are displayed
-before or after the text input itself. In order for an element to be
-considered as a prefix, it must have the `prefix` attribute (and similarly
-for `suffix`).
-
-    <paper-input label="total">
-      <div prefix>$</div>
-      <paper-icon-button slot="suffix" icon="clear"></paper-icon-button>
-    </paper-input>
-
-A `paper-input` can use the native `type=search` or `type=file` features.
-However, since we can't control the native styling of the input (search icon,
-file button, date placeholder, etc.), in these cases the label will be
-automatically floated. The `placeholder` attribute can still be used for
-additional informational text.
-
-    <paper-input label="search!" type="search"
-        placeholder="search for cats" autosave="test" results="5">
-    </paper-input>
-
-See `Polymer.PaperInputBehavior` for more API docs.
-
-### Focus
-
-To focus a paper-input, you can call the native `focus()` method as long as the
-paper input has a tab index. Similarly, `blur()` will blur the element.
-
-### Styling
-
-See `Polymer.PaperInputContainer` for a list of custom properties used to
-style this element.
-
-The following custom properties and mixins are available for styling:
-
-Custom property | Description | Default
-----------------|-------------|----------
-`--paper-input-container-ms-clear` | Mixin applied to the Internet Explorer reveal button (the eyeball) | {}
-
-@group Paper Elements
-@element paper-input
-@hero hero.svg
-@demo demo/index.html
-
--->
-
-</head><body><dom-module id="paper-input">
-  <template>
-    <style>
-      :host {
-        display: block;
-      }
-
-      :host([focused]) {
-        outline: none;
-      }
-
-      :host([hidden]) {
-        display: none !important;
-      }
-
-      input {
-        /* Firefox sets a min-width on the input, which can cause layout issues */
-        min-width: 0;
-      }
-
-      /* In 1.x, the <input> is distributed to paper-input-container, which styles it.
-      In 2.x the <iron-input> is distributed to paper-input-container, which styles
-      it, but in order for this to work correctly, we need to reset some
-      of the native input's properties to inherit (from the iron-input) */
-      iron-input > input {
-        @apply --paper-input-container-shared-input-style;
-        font-family: inherit;
-        font-weight: inherit;
-        font-size: inherit;
-        letter-spacing: inherit;
-        word-spacing: inherit;
-        line-height: inherit;
-        text-shadow: inherit;
-        color: inherit;
-        cursor: inherit;
-      }
-
-      input:disabled {
-        @apply --paper-input-container-input-disabled;
-      }
-
-      input::-webkit-outer-spin-button,
-      input::-webkit-inner-spin-button {
-        @apply --paper-input-container-input-webkit-spinner;
-      }
-
-      input::-webkit-clear-button {
-        @apply --paper-input-container-input-webkit-clear;
-      }
-
-      input::-webkit-calendar-picker-indicator {
-        @apply --paper-input-container-input-webkit-calendar-picker-indicator;
-      }
-
-      input::-webkit-input-placeholder {
-        color: var(--paper-input-container-color, var(--secondary-text-color));
-      }
-
-      input:-moz-placeholder {
-        color: var(--paper-input-container-color, var(--secondary-text-color));
-      }
-
-      input::-moz-placeholder {
-        color: var(--paper-input-container-color, var(--secondary-text-color));
-      }
-
-      input::-ms-clear {
-        @apply --paper-input-container-ms-clear;
-      }
-
-      input::-ms-reveal {
-        @apply --paper-input-container-ms-reveal;
-      }
-
-      input:-ms-input-placeholder {
-        color: var(--paper-input-container-color, var(--secondary-text-color));
-      }
-
-      label {
-        pointer-events: none;
-      }
-    </style>
-
-    <paper-input-container id="container" no-label-float="[[noLabelFloat]]" always-float-label="[[_computeAlwaysFloatLabel(alwaysFloatLabel,placeholder)]]" auto-validate$="[[autoValidate]]" disabled$="[[disabled]]" invalid="[[invalid]]">
-
-      <slot name="prefix" slot="prefix"></slot>
-
-      <label hidden$="[[!label]]" aria-hidden="true" for$="[[_inputId]]" slot="label">[[label]]</label>
-
-      <span id="template-placeholder"></span>
-
-      <slot name="suffix" slot="suffix"></slot>
-
-      <template is="dom-if" if="[[errorMessage]]">
-        <paper-input-error aria-live="assertive" slot="add-on">[[errorMessage]]</paper-input-error>
-      </template>
-
-      <template is="dom-if" if="[[charCounter]]">
-        <paper-input-char-counter slot="add-on"></paper-input-char-counter>
-      </template>
-
-    </paper-input-container>
-  </template>
-
-  <!-- This is a fresh new hell to make this element hybrid. Basically, in 2.0
-    we lost is=, so the example same template can't be used with iron-input 1.0 and 2.0.
-    Expect some conditional code (especially in the tests).
-   -->
-  <template id="v0">
-    <input is="iron-input" slot="input" class="input-element" id$="[[_inputId]]" aria-labelledby$="[[_ariaLabelledBy]]" aria-describedby$="[[_ariaDescribedBy]]" disabled$="[[disabled]]" title$="[[title]]" bind-value="{{value}}" invalid="{{invalid}}" prevent-invalid-input="[[preventInvalidInput]]" allowed-pattern="[[allowedPattern]]" validator="[[validator]]" type$="[[type]]" pattern$="[[pattern]]" required$="[[required]]" autocomplete$="[[autocomplete]]" autofocus$="[[autofocus]]" inputmode$="[[inputmode]]" minlength$="[[minlength]]" maxlength$="[[maxlength]]" min$="[[min]]" max$="[[max]]" step$="[[step]]" name$="[[name]]" placeholder$="[[placeholder]]" readonly$="[[readonly]]" list$="[[list]]" size$="[[size]]" autocapitalize$="[[autocapitalize]]" autocorrect$="[[autocorrect]]" on-change="_onChange" tabindex$="[[tabIndex]]" autosave$="[[autosave]]" results$="[[results]]" accept$="[[accept]]" multiple$="[[multiple]]">
-  </template>
-
-  <template id="v1">
-    <!-- Need to bind maxlength so that the paper-input-char-counter works correctly -->
-    <iron-input bind-value="{{value}}" slot="input" class="input-element" id$="[[_inputId]]" maxlength$="[[maxlength]]" allowed-pattern="[[allowedPattern]]" invalid="{{invalid}}" validator="[[validator]]">
-      <input aria-labelledby$="[[_ariaLabelledBy]]" aria-describedby$="[[_ariaDescribedBy]]" disabled$="[[disabled]]" title$="[[title]]" type$="[[type]]" pattern$="[[pattern]]" required$="[[required]]" autocomplete$="[[autocomplete]]" autofocus$="[[autofocus]]" inputmode$="[[inputmode]]" minlength$="[[minlength]]" maxlength$="[[maxlength]]" min$="[[min]]" max$="[[max]]" step$="[[step]]" name$="[[name]]" placeholder$="[[placeholder]]" readonly$="[[readonly]]" list$="[[list]]" size$="[[size]]" autocapitalize$="[[autocapitalize]]" autocorrect$="[[autocorrect]]" on-change="_onChange" tabindex$="[[tabIndex]]" autosave$="[[autosave]]" results$="[[results]]" accept$="[[accept]]" multiple$="[[multiple]]">
-    </iron-input>
-  </template>
-
-</dom-module>
-
-<script src="paper-input-extracted.js"></script></body></html>
\ No newline at end of file
diff --git a/third_party/polymer/v1_0/components-chromium/paper-input/paper-textarea-extracted.js b/third_party/polymer/v1_0/components-chromium/paper-input/paper-textarea-extracted.js
deleted file mode 100644
index 787ec08..0000000
--- a/third_party/polymer/v1_0/components-chromium/paper-input/paper-textarea-extracted.js
+++ /dev/null
@@ -1,77 +0,0 @@
-Polymer({
-    is: 'paper-textarea',
-
-    behaviors: [
-      Polymer.PaperInputBehavior,
-      Polymer.IronFormElementBehavior,
-    ],
-
-    properties: {
-      _ariaLabelledBy: {
-        observer: '_ariaLabelledByChanged',
-        type: String,
-      },
-
-      _ariaDescribedBy: {
-        observer: '_ariaDescribedByChanged',
-        type: String,
-      },
-
-      /**
-       * The initial number of rows.
-       *
-       * @attribute rows
-       * @type number
-       * @default 1
-       */
-      rows: {
-        type: Number,
-        value: 1,
-      },
-
-      /**
-       * The maximum number of rows this element can grow to until it
-       * scrolls. 0 means no maximum.
-       *
-       * @attribute maxRows
-       * @type number
-       * @default 0
-       */
-      maxRows: {
-        type: Number,
-        value: 0,
-      },
-    },
-
-    /**
-     * @return {number}
-     */
-    get selectionStart() {
-      return this.$.input.textarea.selectionStart;
-    },
-    set selectionStart(start) {
-      this.$.input.textarea.selectionStart = start;
-    },
-
-    /**
-     * @return {number}
-     */
-    get selectionEnd() {
-      return this.$.input.textarea.selectionEnd;
-    },
-    set selectionEnd(end) {
-      this.$.input.textarea.selectionEnd = end;
-    },
-
-    _ariaLabelledByChanged: function() {
-      this._focusableElement.setAttribute('aria-label', this.label);
-    },
-
-    _ariaDescribedByChanged: function(ariaDescribedBy) {
-      this._focusableElement.setAttribute('aria-describedby', ariaDescribedBy);
-    },
-
-    get _focusableElement() {
-      return this.inputElement.textarea;
-    },
-  });
\ No newline at end of file
diff --git a/third_party/polymer/v1_0/components-chromium/paper-input/paper-textarea.html b/third_party/polymer/v1_0/components-chromium/paper-input/paper-textarea.html
deleted file mode 100644
index f00b31c..0000000
--- a/third_party/polymer/v1_0/components-chromium/paper-input/paper-textarea.html
+++ /dev/null
@@ -1,68 +0,0 @@
-<!--
-@license
-Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
-This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
-The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
-The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
-Code distributed by Google as part of the polymer project is also
-subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
---><html><head><link rel="import" href="../polymer/polymer.html">
-<link rel="import" href="../iron-autogrow-textarea/iron-autogrow-textarea.html">
-<link rel="import" href="../iron-form-element-behavior/iron-form-element-behavior.html">
-<link rel="import" href="paper-input-behavior.html">
-<link rel="import" href="paper-input-char-counter.html">
-<link rel="import" href="paper-input-container.html">
-<link rel="import" href="paper-input-error.html">
-
-<!--
-`<paper-textarea>` is a multi-line text field with Material Design styling.
-
-    <paper-textarea label="Textarea label"></paper-textarea>
-
-See `Polymer.PaperInputBehavior` for more API docs.
-
-### Validation
-
-Currently only `required` and `maxlength` validation is supported.
-
-### Styling
-
-See `Polymer.PaperInputContainer` for a list of custom properties used to
-style this element.
--->
-
-</head><body><dom-module id="paper-textarea">
-  <template>
-    <style>
-      :host {
-        display: block;
-      }
-
-      :host([hidden]) {
-        display: none !important;
-      }
-
-      label {
-        pointer-events: none;
-      }
-    </style>
-
-    <paper-input-container no-label-float$="[[noLabelFloat]]" always-float-label="[[_computeAlwaysFloatLabel(alwaysFloatLabel,placeholder)]]" auto-validate$="[[autoValidate]]" disabled$="[[disabled]]" invalid="[[invalid]]">
-
-      <label hidden$="[[!label]]" aria-hidden="true" for$="[[_inputId]]" slot="label">[[label]]</label>
-
-      <iron-autogrow-textarea class="paper-input-input" slot="input" id$="[[_inputId]]" aria-labelledby$="[[_ariaLabelledBy]]" aria-describedby$="[[_ariaDescribedBy]]" bind-value="{{value}}" invalid="{{invalid}}" validator$="[[validator]]" disabled$="[[disabled]]" autocomplete$="[[autocomplete]]" autofocus$="[[autofocus]]" inputmode$="[[inputmode]]" name$="[[name]]" placeholder$="[[placeholder]]" readonly$="[[readonly]]" required$="[[required]]" minlength$="[[minlength]]" maxlength$="[[maxlength]]" autocapitalize$="[[autocapitalize]]" rows$="[[rows]]" max-rows$="[[maxRows]]" on-change="_onChange"></iron-autogrow-textarea>
-
-      <template is="dom-if" if="[[errorMessage]]">
-        <paper-input-error aria-live="assertive" slot="add-on">[[errorMessage]]</paper-input-error>
-      </template>
-
-      <template is="dom-if" if="[[charCounter]]">
-        <paper-input-char-counter slot="add-on"></paper-input-char-counter>
-      </template>
-
-    </paper-input-container>
-  </template>
-</dom-module>
-
-<script src="paper-textarea-extracted.js"></script></body></html>
\ No newline at end of file
diff --git a/third_party/polymer/v1_0/components-chromium/paper-listbox/BUILD.gn b/third_party/polymer/v1_0/components-chromium/paper-listbox/BUILD.gn
deleted file mode 100644
index 7bd6f14..0000000
--- a/third_party/polymer/v1_0/components-chromium/paper-listbox/BUILD.gn
+++ /dev/null
@@ -1,13 +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.
-#
-# NOTE: Created with generate_gn.py, please do not edit.
-
-import("//third_party/closure_compiler/compile_js.gni")
-
-js_library("paper-listbox-extracted") {
-  deps = [
-    "../iron-menu-behavior:iron-menu-behavior-extracted",
-  ]
-}
diff --git a/third_party/polymer/v1_0/components-chromium/paper-listbox/bower.json b/third_party/polymer/v1_0/components-chromium/paper-listbox/bower.json
deleted file mode 100644
index 84df575..0000000
--- a/third_party/polymer/v1_0/components-chromium/paper-listbox/bower.json
+++ /dev/null
@@ -1,58 +0,0 @@
-{
-  "name": "paper-listbox",
-  "version": "2.0.0",
-  "description": "Implements an accessible material design listbox",
-  "authors": "The Polymer Authors",
-  "keywords": [
-    "web-components",
-    "polymer",
-    "listbox"
-  ],
-  "main": "paper-listbox.html",
-  "private": true,
-  "repository": {
-    "type": "git",
-    "url": "git://github.com/PolymerElements/paper-listbox"
-  },
-  "license": "http://polymer.github.io/LICENSE.txt",
-  "homepage": "https://github.com/PolymerElements/paper-listbox",
-  "ignore": [],
-  "dependencies": {
-    "polymer": "Polymer/polymer#1.9 - 2",
-    "iron-behaviors": "PolymerElements/iron-behaviors#1 - 2",
-    "iron-menu-behavior": "PolymerElements/iron-menu-behavior#1 - 2",
-    "paper-styles": "PolymerElements/paper-styles#1 - 2"
-  },
-  "devDependencies": {
-    "iron-component-page": "PolymerElements/iron-component-page#1 - 2",
-    "iron-demo-helpers": "PolymerElements/iron-demo-helpers#1 - 2",
-    "iron-test-helpers": "PolymerElements/iron-test-helpers#1 - 2",
-    "paper-item": "PolymerElements/paper-item#1 - 2",
-    "web-component-tester": "^6.0.0",
-    "webcomponentsjs": "webcomponents/webcomponentsjs#^1.0.0"
-  },
-  "variants": {
-    "1.x": {
-      "dependencies": {
-        "polymer": "Polymer/polymer#^1.9",
-        "iron-behaviors": "PolymerElements/iron-behaviors#^1.0.0",
-        "iron-menu-behavior": "PolymerElements/iron-menu-behavior#^1.0.0",
-        "paper-styles": "PolymerElements/paper-styles#^1.0.0"
-      },
-      "devDependencies": {
-        "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
-        "iron-demo-helpers": "PolymerElements/iron-demo-helpers#^1.2.5",
-        "iron-test-helpers": "PolymerElements/iron-test-helpers#^1.0.0",
-        "paper-item": "PolymerElements/paper-item#^1.0.0",
-        "web-component-tester": "^4.0.0",
-        "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
-      },
-      "resolutions": {
-        "webcomponentsjs": "^0.7"
-      }
-    }
-  },
-  "resolutions": {
-    "webcomponentsjs": "^1.0.0"
-  }
-}
diff --git a/third_party/polymer/v1_0/components-chromium/paper-listbox/paper-listbox-extracted.js b/third_party/polymer/v1_0/components-chromium/paper-listbox/paper-listbox-extracted.js
deleted file mode 100644
index 51011988..0000000
--- a/third_party/polymer/v1_0/components-chromium/paper-listbox/paper-listbox-extracted.js
+++ /dev/null
@@ -1,13 +0,0 @@
-(function() {
-      Polymer({
-        is: 'paper-listbox',
-
-        behaviors: [
-          Polymer.IronMenuBehavior
-        ],
-
-        hostAttributes: {
-          role: 'listbox'
-        }
-      });
-    })();
\ No newline at end of file
diff --git a/third_party/polymer/v1_0/components-chromium/paper-listbox/paper-listbox.html b/third_party/polymer/v1_0/components-chromium/paper-listbox/paper-listbox.html
deleted file mode 100644
index 27e2538..0000000
--- a/third_party/polymer/v1_0/components-chromium/paper-listbox/paper-listbox.html
+++ /dev/null
@@ -1,80 +0,0 @@
-<!--
-@license
-Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
-This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
-The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
-The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
-Code distributed by Google as part of the polymer project is also
-subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
---><html><head><link rel="import" href="../polymer/polymer.html">
-<link rel="import" href="../iron-menu-behavior/iron-menu-behavior.html">
-<link rel="import" href="../paper-styles/default-theme.html">
-
-<!--
-Material design: [Menus](https://www.google.com/design/spec/components/menus.html)
-
-`<paper-listbox>` implements an accessible listbox control with Material Design styling. The focused item
-is highlighted, and the selected item has bolded text.
-
-    <paper-listbox>
-      <paper-item>Item 1</paper-item>
-      <paper-item>Item 2</paper-item>
-    </paper-listbox>
-
-An initial selection can be specified with the `selected` attribute.
-
-    <paper-listbox selected="0">
-      <paper-item>Item 1</paper-item>
-      <paper-item>Item 2</paper-item>
-    </paper-listbox>
-
-Make a multi-select listbox with the `multi` attribute. Items in a multi-select listbox can be deselected,
-and multiple item can be selected.
-
-    <paper-listbox multi>
-      <paper-item>Item 1</paper-item>
-      <paper-item>Item 2</paper-item>
-    </paper-listbox>
-
-### Styling
-
-The following custom properties and mixins are available for styling:
-
-Custom property | Description | Default
-----------------|-------------|----------
-`--paper-listbox-background-color`   | Menu background color                                            | `--primary-background-color`
-`--paper-listbox-color`              | Menu foreground color                                            | `--primary-text-color`
-`--paper-listbox`                    | Mixin applied to the listbox                                        | `{}`
-
-### Accessibility
-
-`<paper-listbox>` has `role="listbox"` by default. A multi-select listbox will also have
-`aria-multiselectable` set. It implements key bindings to navigate through the listbox with the up and
-down arrow keys, esc to exit the listbox, and enter to activate a listbox item. Typing the first letter
-of a listbox item will also focus it.
-
-@group Paper Elements
-@element paper-listbox
-@hero hero.svg
-@demo demo/index.html
--->
-
-</head><body><dom-module id="paper-listbox">
-  <template>
-    <style>
-      :host {
-        display: block;
-        padding: 8px 0;
-
-        background: var(--paper-listbox-background-color, var(--primary-background-color));
-        color: var(--paper-listbox-color, var(--primary-text-color));
-
-        @apply --paper-listbox;
-      }
-    </style>
-
-    <slot></slot>
-  </template>
-
-  </dom-module>
-<script src="paper-listbox-extracted.js"></script></body></html>
\ No newline at end of file
diff --git a/third_party/polymer/v1_0/components-chromium/paper-slider/BUILD.gn b/third_party/polymer/v1_0/components-chromium/paper-slider/BUILD.gn
index 4fd68c1..2868066 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-slider/BUILD.gn
+++ b/third_party/polymer/v1_0/components-chromium/paper-slider/BUILD.gn
@@ -12,7 +12,6 @@
     "../iron-form-element-behavior:iron-form-element-behavior-extracted",
     "../iron-range-behavior:iron-range-behavior-extracted",
     "../paper-behaviors:paper-inky-focus-behavior-extracted",
-    "../paper-input:paper-input-extracted",
     "../paper-progress:paper-progress-extracted",
   ]
 }
diff --git a/third_party/polymer/v1_0/components-chromium/paper-slider/paper-slider.html b/third_party/polymer/v1_0/components-chromium/paper-slider/paper-slider.html
index 9528182..42f2bee 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-slider/paper-slider.html
+++ b/third_party/polymer/v1_0/components-chromium/paper-slider/paper-slider.html
@@ -12,7 +12,6 @@
 <link rel="import" href="../iron-form-element-behavior/iron-form-element-behavior.html">
 <link rel="import" href="../iron-range-behavior/iron-range-behavior.html">
 <link rel="import" href="../paper-behaviors/paper-inky-focus-behavior.html">
-<link rel="import" href="../paper-input/paper-input.html">
 <link rel="import" href="../paper-progress/paper-progress.html">
 <link rel="import" href="../paper-styles/color.html">
 
@@ -331,11 +330,6 @@
           <div class="slider-knob-inner" value$="[[immediateValue]]"></div>
       </div>
     </div>
-
-    <template is="dom-if" if="[[editable]]">
-      <paper-input id="input" type="number" step="[[step]]" min="[[min]]" max="[[max]]" class="slider-input" disabled$="[[disabled]]" value="[[immediateValue]]" on-change="_changeValue" on-keydown="_inputKeyDown" no-label-float="">
-      </paper-input>
-    </template>
   </template>
 
   </dom-module>
diff --git a/third_party/polymer/v1_0/components_summary.txt b/third_party/polymer/v1_0/components_summary.txt
index a2d18966..aae0240 100644
--- a/third_party/polymer/v1_0/components_summary.txt
+++ b/third_party/polymer/v1_0/components_summary.txt
@@ -22,12 +22,6 @@
 Revision: b7e78a4a8bdd857780ecd8b54852bb27dbf8f216
 Tree link: https://github.com/PolymerElements/iron-a11y-keys-behavior/tree/v2.1.1
 
-Name: iron-autogrow-textarea
-Repository: https://github.com/PolymerElements/iron-autogrow-textarea.git
-Tree: v2.1.1
-Revision: ac2bf6158b2c52294c8bcc85c677ee13d06e7aaa
-Tree link: https://github.com/PolymerElements/iron-autogrow-textarea/tree/v2.1.1
-
 Name: iron-behaviors
 Repository: https://github.com/PolymerElements/iron-behaviors.git
 Tree: v2.1.1
@@ -214,12 +208,6 @@
 Revision: 07910f6f76e1042286e931da923bff8ceabc3dc6
 Tree link: https://github.com/PolymerElements/paper-item/tree/v2.0.0
 
-Name: paper-listbox
-Repository: https://github.com/PolymerelEments/paper-listbox.git
-Tree: v2.0.0
-Revision: 556e366eada2a75ad2c2df52a0b80baee66f9390
-Tree link: https://github.com/PolymerelEments/paper-listbox/tree/v2.0.0
-
 Name: paper-progress
 Repository: https://github.com/PolymerElements/paper-progress.git
 Tree: v2.0.1
diff --git a/third_party/polymer/v1_0/rsync_exclude.txt b/third_party/polymer/v1_0/rsync_exclude.txt
index c25b112a..8fdad60 100644
--- a/third_party/polymer/v1_0/rsync_exclude.txt
+++ b/third_party/polymer/v1_0/rsync_exclude.txt
@@ -28,6 +28,13 @@
 */site/
 */templates/
 
+# iron-autogrow-textarea
+iron-autogrow-textarea/*
+
+# paper-input
+paper-input/paper-input.html
+paper-input/paper-textarea.html
+
 # paper-spinner
 paper-spinner/paper-spinner.html
 
diff --git a/tools/grit/grit/format/resource_map.py b/tools/grit/grit/format/resource_map.py
index 5fee06b8..d245ca6 100755
--- a/tools/grit/grit/format/resource_map.py
+++ b/tools/grit/grit/format/resource_map.py
@@ -16,14 +16,16 @@
 def GetFormatter(type):
   if type == 'resource_map_header':
     return _FormatHeader
-  if type == 'resource_map_source':
-    return partial(_FormatSource, _GetItemName)
   if type == 'resource_file_map_source':
     return partial(_FormatSource, _GetItemPath)
+  if type == 'resource_map_source':
+    return partial(_FormatSource, _GetItemName)
   if type == 'gzipped_resource_map_header':
     return partial(_FormatHeader, include_gzipped=True)
   if type == 'gzipped_resource_file_map_source':
     return partial(_FormatSource, _GetItemPath, include_gzipped=True)
+  if type == 'gzipped_resource_map_source':
+    return partial(_FormatSource, _GetItemName, include_gzipped=True)
 
 
 def GetMapName(root):
diff --git a/tools/grit/grit/tool/build.py b/tools/grit/grit/tool/build.py
index 71f05d28..d23d72b 100755
--- a/tools/grit/grit/tool/build.py
+++ b/tools/grit/grit/tool/build.py
@@ -34,6 +34,7 @@
   'data_package': 'data_pack',
   'gzipped_resource_file_map_source': 'resource_map',
   'gzipped_resource_map_header': 'resource_map',
+  'gzipped_resource_map_source': 'resource_map',
   'js_map_format': 'js_map_format',
   'policy_templates': 'policy_templates_json',
   'rc_all': 'rc',
@@ -332,10 +333,12 @@
     # Microsoft's RC compiler can only deal with single-byte or double-byte
     # files (no UTF-8), so we make all RC files UTF-16 to support all
     # character sets.
-    if output_type in ('rc_header', 'resource_map_header',
-                       'resource_map_source', 'resource_file_map_source',
+    if output_type in ('rc_header', 'resource_file_map_source',
+                       'resource_map_header', 'resource_map_source',
+                       'gzipped_resource_file_map_source',
                        'gzipped_resource_map_header',
-                       'gzipped_resource_file_map_source'):
+                       'gzipped_resource_map_source',
+                      ):
       return 'cp1252'
     if output_type in ('android', 'c_format', 'js_map_format', 'plist',
                        'plist_strings', 'doc', 'json', 'android_policy',
diff --git a/tools/gritsettings/resource_ids b/tools/gritsettings/resource_ids
index 537db650..a055cd6 100644
--- a/tools/gritsettings/resource_ids
+++ b/tools/gritsettings/resource_ids
@@ -299,10 +299,10 @@
     "messages": [24050],
   },
   "ash/components/resources/ash_components_resources.grd": {
-    "structures": [24250],
+    "structures": [24270],
   },
   "ash/public/cpp/resources/ash_public_unscaled_resources.grd": {
-    "includes": [24260],
+    "includes": [24280],
   },
   "ash/shell/ash_shell_resources.grd": {
     "includes": [24290],
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index dd33e0c..9813542 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -29580,7 +29580,6 @@
   <int value="-872764392" label="ContextualSuggestionsBottomSheet:disabled"/>
   <int value="-867087281" label="enable-virtual-keyboard"/>
   <int value="-866993841" label="OfflinePagesCTV2:disabled"/>
-  <int value="-865390600" label="NativeSmb:enabled"/>
   <int value="-864266073" label="cros-regions-mode"/>
   <int value="-864234985" label="UseDdljsonApi:enabled"/>
   <int value="-864205629" label="enable-offline-load-stale-cache"/>
@@ -29604,7 +29603,6 @@
   <int value="-835672415" label="PointerEventV1SpecCapturing:disabled"/>
   <int value="-834661509" label="ModalPermissionPrompts:disabled"/>
   <int value="-832561975" label="enable-picture-in-picture"/>
-  <int value="-828070439" label="NativeSmb:disabled"/>
   <int value="-825942229" label="tab-management-experiment-type-elderberry"/>
   <int value="-823165021" label="MaterialDesignUserMenu:enabled"/>
   <int value="-820041355" label="enable-transition-compositing"/>
@@ -39622,6 +39620,12 @@
   <int value="2" label="Unified Plan"/>
 </enum>
 
+<enum name="PeerConnectionSdpUsageCategory">
+  <int value="0" label="Safe"/>
+  <int value="1" label="Unsafe"/>
+  <int value="2" label="Unknown"/>
+</enum>
+
 <enum name="PepperBrokerAction">
   <int value="0" label="Create"/>
   <int value="1" label="Connect"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 4236fae..4810785 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -120893,6 +120893,76 @@
   </summary>
 </histogram>
 
+<histogram name="WebRTC.PeerConnection.SdpComplexUsage.CreateAnswer"
+    enum="PeerConnectionSdpUsageCategory">
+  <owner>hbos@chromium.org</owner>
+  <summary>
+    The SDP usage category (&quot;safe&quot;, &quot;unsafe&quot; or
+    &quot;unknown&quot;) of createAnswer(). Using complex SDP without explicitly
+    specifying the sdpSemantics is considered unsafe in this context because
+    such usage is sensitive to the rollout of a different default SDP semantic.
+  </summary>
+</histogram>
+
+<histogram name="WebRTC.PeerConnection.SdpComplexUsage.CreateOffer"
+    enum="PeerConnectionSdpUsageCategory">
+  <owner>hbos@chromium.org</owner>
+  <summary>
+    The SDP usage category (&quot;safe&quot;, &quot;unsafe&quot; or
+    &quot;unknown&quot;) of createOffer(). Using complex SDP without explicitly
+    specifying the sdpSemantics is considered unsafe in this context because
+    such usage is sensitive to the rollout of a different default SDP semantic.
+  </summary>
+</histogram>
+
+<histogram name="WebRTC.PeerConnection.SdpComplexUsage.SetLocalAnswer"
+    enum="PeerConnectionSdpUsageCategory">
+  <owner>hbos@chromium.org</owner>
+  <summary>
+    The SDP usage category (&quot;safe&quot;, &quot;unsafe&quot; or
+    &quot;unknown&quot;) of setLocalDescription(answer). Using complex SDP
+    without explicitly specifying the sdpSemantics is considered unsafe in this
+    context because such usage is sensitive to the rollout of a different
+    default SDP semantic.
+  </summary>
+</histogram>
+
+<histogram name="WebRTC.PeerConnection.SdpComplexUsage.SetLocalOffer"
+    enum="PeerConnectionSdpUsageCategory">
+  <owner>hbos@chromium.org</owner>
+  <summary>
+    The SDP usage category (&quot;safe&quot;, &quot;unsafe&quot; or
+    &quot;unknown&quot;) of setLocalDescription(offer). Using complex SDP
+    without explicitly specifying the sdpSemantics is considered unsafe in this
+    context because such usage is sensitive to the rollout of a different
+    default SDP semantic.
+  </summary>
+</histogram>
+
+<histogram name="WebRTC.PeerConnection.SdpComplexUsage.SetRemoteAnswer"
+    enum="PeerConnectionSdpUsageCategory">
+  <owner>hbos@chromium.org</owner>
+  <summary>
+    The SDP usage category (&quot;safe&quot;, &quot;unsafe&quot; or
+    &quot;unknown&quot;) of setRemoteDescription(answer). Using complex SDP
+    without explicitly specifying the sdpSemantics is considered unsafe in this
+    context because such usage is sensitive to the rollout of a different
+    default SDP semantic.
+  </summary>
+</histogram>
+
+<histogram name="WebRTC.PeerConnection.SdpComplexUsage.SetRemoteOffer"
+    enum="PeerConnectionSdpUsageCategory">
+  <owner>hbos@chromium.org</owner>
+  <summary>
+    The SDP usage category (&quot;safe&quot;, &quot;unsafe&quot; or
+    &quot;unknown&quot;) of setRemoteDescription(offer). Using complex SDP
+    without explicitly specifying the sdpSemantics is considered unsafe in this
+    context because such usage is sensitive to the rollout of a different
+    default SDP semantic.
+  </summary>
+</histogram>
+
 <histogram name="WebRTC.PeerConnection.SdpFormatReceived"
     enum="PeerConnectionSdpFormatReceived">
   <owner>steveanton@chromium.org</owner>
diff --git a/ui/aura/client/aura_constants.cc b/ui/aura/client/aura_constants.cc
index 1ed7c6e..d826a4d 100644
--- a/ui/aura/client/aura_constants.cc
+++ b/ui/aura/client/aura_constants.cc
@@ -49,7 +49,6 @@
 DEFINE_UI_CLASS_PROPERTY_KEY(bool, kDrawAttentionKey, false);
 DEFINE_UI_CLASS_PROPERTY_KEY(FocusClient*, kFocusClientKey, nullptr);
 DEFINE_UI_CLASS_PROPERTY_KEY(Window*, kHostWindowKey, nullptr);
-DEFINE_UI_CLASS_PROPERTY_KEY(bool, kImmersiveFullscreenKey, false);
 DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(gfx::Size, kMinimumSize, nullptr);
 DEFINE_UI_CLASS_PROPERTY_KEY(bool, kMirroringEnabledKey, false);
 DEFINE_UI_CLASS_PROPERTY_KEY(Window*, kChildModalParentKey, nullptr);
diff --git a/ui/aura/client/aura_constants.h b/ui/aura/client/aura_constants.h
index 65dc33a5..fca4f1b 100644
--- a/ui/aura/client/aura_constants.h
+++ b/ui/aura/client/aura_constants.h
@@ -78,12 +78,6 @@
 // WebContentsViews find the windows that should constrain NPAPI plugins.
 AURA_EXPORT extern const WindowProperty<Window*>* const kHostWindowKey;
 
-// A property key to indicate that a window should be in immersive mode when the
-// window enters the fullscreen mode. The immersive fullscreen mode is slightly
-// different from the normal fullscreen mode by allowing the user to reveal the
-// top portion of the window through a touch / mouse gesture.
-AURA_EXPORT extern const WindowProperty<bool>* const kImmersiveFullscreenKey;
-
 // A property key to store the minimum size of the window.
 AURA_EXPORT extern const WindowProperty<gfx::Size*>* const kMinimumSize;
 
diff --git a/ui/aura/mus/property_converter.cc b/ui/aura/mus/property_converter.cc
index 0d0e3453..24a9e2e 100644
--- a/ui/aura/mus/property_converter.cc
+++ b/ui/aura/mus/property_converter.cc
@@ -81,10 +81,6 @@
   RegisterPrimitiveProperty(client::kDrawAttentionKey,
                             ws::mojom::WindowManager::kDrawAttention_Property,
                             CreateAcceptAnyValueCallback());
-  RegisterPrimitiveProperty(
-      client::kImmersiveFullscreenKey,
-      ws::mojom::WindowManager::kImmersiveFullscreen_Property,
-      CreateAcceptAnyValueCallback());
   RegisterPrimitiveProperty(client::kResizeBehaviorKey,
                             ws::mojom::WindowManager::kResizeBehavior_Property,
                             base::Bind(&ValidateResizeBehaviour));
diff --git a/ui/gfx/mojo/BUILD.gn b/ui/gfx/mojo/BUILD.gn
index fb02266..5a83915 100644
--- a/ui/gfx/mojo/BUILD.gn
+++ b/ui/gfx/mojo/BUILD.gn
@@ -23,6 +23,10 @@
     "//mojo/public/mojom/base",
     "//ui/gfx/geometry/mojo",
   ]
+
+  if (is_linux || is_chromeos) {
+    enabled_features = [ "supports_native_pixmap" ]
+  }
 }
 
 mojom("test_interfaces") {
diff --git a/ui/gfx/mojo/buffer_types.mojom b/ui/gfx/mojo/buffer_types.mojom
index 25a4a45..260b0e0 100644
--- a/ui/gfx/mojo/buffer_types.mojom
+++ b/ui/gfx/mojo/buffer_types.mojom
@@ -46,22 +46,13 @@
   BufferFormat format;
 };
 
-// gfx::GpuMemoryBufferType
-enum GpuMemoryBufferType {
-  EMPTY_BUFFER,
-  SHARED_MEMORY_BUFFER,
-  IO_SURFACE_BUFFER,
-  NATIVE_PIXMAP,
-  DXGI_SHARED_HANDLE,
-  ANDROID_HARDWARE_BUFFER,
-};
-
 // gfx::GpuMemoryBufferId
 struct GpuMemoryBufferId {
   int32 id;
 };
 
 // gfx::NativePixmapPlane
+[EnableIf=supports_native_pixmap]
 struct NativePixmapPlane {
   uint32 stride;
   int32 offset;
@@ -70,6 +61,7 @@
 };
 
 // gfx::NativePixmapHandle
+[EnableIf=supports_native_pixmap]
 struct NativePixmapHandle {
   // A file descriptor for the underlying memory object (usually dmabuf).
   array<handle> fds;
@@ -92,10 +84,12 @@
 };
 
 union GpuMemoryBufferPlatformHandle {
-  // TODO(676224): Use preprocessor to restrict platform-specific members to
-  // desired platform.
   mojo_base.mojom.UnsafeSharedMemoryRegion shared_memory_handle;
+
+  [EnableIf=supports_native_pixmap]
   NativePixmapHandle native_pixmap_handle;
+
+  [EnableIf=is_mac]
   handle mach_port;
 
   [EnableIf=is_win]
diff --git a/ui/gfx/mojo/buffer_types_struct_traits.cc b/ui/gfx/mojo/buffer_types_struct_traits.cc
index 9da0b07..0536672 100644
--- a/ui/gfx/mojo/buffer_types_struct_traits.cc
+++ b/ui/gfx/mojo/buffer_types_struct_traits.cc
@@ -28,14 +28,13 @@
   return data.ReadUsage(&out->usage) && data.ReadFormat(&out->format);
 }
 
+#if defined(OS_LINUX)
 std::vector<mojo::ScopedHandle>
 StructTraits<gfx::mojom::NativePixmapHandleDataView, gfx::NativePixmapHandle>::
     fds(const gfx::NativePixmapHandle& pixmap_handle) {
   std::vector<mojo::ScopedHandle> handles;
-#if defined(OS_LINUX)
   for (const base::FileDescriptor& fd : pixmap_handle.fds)
     handles.emplace_back(mojo::WrapPlatformFile(fd.fd));
-#endif  // defined(OS_LINUX)
   return handles;
 }
 
@@ -43,7 +42,6 @@
     gfx::mojom::NativePixmapHandleDataView,
     gfx::NativePixmapHandle>::Read(gfx::mojom::NativePixmapHandleDataView data,
                                    gfx::NativePixmapHandle* out) {
-#if defined(OS_LINUX)
   mojo::ArrayDataView<mojo::ScopedHandle> handles_data_view;
   data.GetFdsDataView(&handles_data_view);
   for (size_t i = 0; i < handles_data_view.size(); ++i) {
@@ -56,10 +54,8 @@
     out->fds.push_back(base::FileDescriptor(platform_file, auto_close));
   }
   return data.ReadPlanes(&out->planes);
-#else
-  return false;
-#endif
 }
+#endif  // defined(OS_LINUX)
 
 gfx::mojom::GpuMemoryBufferPlatformHandlePtr StructTraits<
     gfx::mojom::GpuMemoryBufferHandleDataView,
@@ -71,16 +67,13 @@
     case gfx::SHARED_MEMORY_BUFFER:
       return gfx::mojom::GpuMemoryBufferPlatformHandle::NewSharedMemoryHandle(
           std::move(handle.region));
-    case gfx::NATIVE_PIXMAP: {
+    case gfx::NATIVE_PIXMAP:
 #if defined(OS_LINUX)
       return gfx::mojom::GpuMemoryBufferPlatformHandle::NewNativePixmapHandle(
           handle.native_pixmap_handle);
 #else
-      static base::NoDestructor<gfx::NativePixmapHandle> pixmap_handle;
-      return gfx::mojom::GpuMemoryBufferPlatformHandle::NewNativePixmapHandle(
-          *pixmap_handle);
+      break;
 #endif
-    }
     case gfx::IO_SURFACE_BUFFER:
 #if defined(OS_MACOSX) && !defined(OS_IOS)
       return gfx::mojom::GpuMemoryBufferPlatformHandle::NewMachPort(
@@ -151,17 +144,14 @@
       out->type = gfx::SHARED_MEMORY_BUFFER;
       out->region = std::move(platform_handle->get_shared_memory_handle());
       return true;
+#if defined(OS_LINUX)
     case gfx::mojom::GpuMemoryBufferPlatformHandleDataView::Tag::
         NATIVE_PIXMAP_HANDLE:
-#if defined(OS_LINUX)
       out->type = gfx::NATIVE_PIXMAP;
       out->native_pixmap_handle = platform_handle->get_native_pixmap_handle();
       return true;
-#else
-      return false;
-#endif
+#elif defined(OS_MACOSX) && !defined(OS_IOS)
     case gfx::mojom::GpuMemoryBufferPlatformHandleDataView::Tag::MACH_PORT: {
-#if defined(OS_MACOSX) && !defined(OS_IOS)
       out->type = gfx::IO_SURFACE_BUFFER;
       mach_port_t mach_port;
       MojoResult unwrap_result = mojo::UnwrapMachPort(
@@ -170,11 +160,8 @@
         return false;
       out->mach_port.reset(mach_port);
       return true;
-#else
-      return false;
-#endif
     }
-#if defined(OS_WIN)
+#elif defined(OS_WIN)
     case gfx::mojom::GpuMemoryBufferPlatformHandleDataView::Tag::DXGI_HANDLE: {
       out->type = gfx::DXGI_SHARED_HANDLE;
       HANDLE handle;
@@ -185,8 +172,7 @@
       out->dxgi_handle = IPC::PlatformFileForTransit(handle);
       return true;
     }
-#endif
-#if defined(OS_ANDROID)
+#elif defined(OS_ANDROID)
     case gfx::mojom::GpuMemoryBufferPlatformHandleDataView::Tag::
         ANDROID_HARDWARE_BUFFER_HANDLE: {
       out->type = gfx::ANDROID_HARDWARE_BUFFER;
diff --git a/ui/gfx/mojo/buffer_types_struct_traits.h b/ui/gfx/mojo/buffer_types_struct_traits.h
index 1d5d972..98866074 100644
--- a/ui/gfx/mojo/buffer_types_struct_traits.h
+++ b/ui/gfx/mojo/buffer_types_struct_traits.h
@@ -189,6 +189,7 @@
   }
 };
 
+#if defined(OS_LINUX)
 template <>
 struct StructTraits<gfx::mojom::NativePixmapPlaneDataView,
                     gfx::NativePixmapPlane> {
@@ -217,14 +218,6 @@
 template <>
 struct StructTraits<gfx::mojom::NativePixmapHandleDataView,
                     gfx::NativePixmapHandle> {
-  static bool IsNull(const gfx::NativePixmapHandle& handle) {
-#if defined(OS_LINUX)
-    return false;
-#else
-    // NativePixmapHandle are not used on non-linux platforms.
-    return true;
-#endif
-  }
   static std::vector<mojo::ScopedHandle> fds(
       const gfx::NativePixmapHandle& pixmap_handle);
 
@@ -236,6 +229,7 @@
   static bool Read(gfx::mojom::NativePixmapHandleDataView data,
                    gfx::NativePixmapHandle* out);
 };
+#endif  // defined(OS_LINUX)
 
 template <>
 struct StructTraits<gfx::mojom::GpuMemoryBufferHandleDataView,
diff --git a/ui/webui/resources/polymer_resources.grdp b/ui/webui/resources/polymer_resources.grdp
index 82f93bd..82b179d 100644
--- a/ui/webui/resources/polymer_resources.grdp
+++ b/ui/webui/resources/polymer_resources.grdp
@@ -48,14 +48,6 @@
              file="../../../third_party/polymer/v1_0/components-chromium/iron-a11y-keys/iron-a11y-keys.html"
              type="chrome_html"
              compress="gzip" />
-  <structure name="IDR_POLYMER_1_0_IRON_AUTOGROW_TEXTAREA_IRON_AUTOGROW_TEXTAREA_EXTRACTED_JS"
-             file="../../../third_party/polymer/v1_0/components-chromium/iron-autogrow-textarea/iron-autogrow-textarea-extracted.js"
-             type="chrome_html"
-             compress="gzip" />
-  <structure name="IDR_POLYMER_1_0_IRON_AUTOGROW_TEXTAREA_IRON_AUTOGROW_TEXTAREA_HTML"
-             file="../../../third_party/polymer/v1_0/components-chromium/iron-autogrow-textarea/iron-autogrow-textarea.html"
-             type="chrome_html"
-             compress="gzip" />
   <structure name="IDR_POLYMER_1_0_IRON_BEHAVIORS_IRON_BUTTON_STATE_EXTRACTED_JS"
              file="../../../third_party/polymer/v1_0/components-chromium/iron-behaviors/iron-button-state-extracted.js"
              type="chrome_html"
@@ -604,22 +596,6 @@
              file="../../../third_party/polymer/v1_0/components-chromium/paper-input/paper-input-error.html"
              type="chrome_html"
              compress="gzip" />
-  <structure name="IDR_POLYMER_1_0_PAPER_INPUT_PAPER_INPUT_EXTRACTED_JS"
-             file="../../../third_party/polymer/v1_0/components-chromium/paper-input/paper-input-extracted.js"
-             type="chrome_html"
-             compress="gzip" />
-  <structure name="IDR_POLYMER_1_0_PAPER_INPUT_PAPER_INPUT_HTML"
-             file="../../../third_party/polymer/v1_0/components-chromium/paper-input/paper-input.html"
-             type="chrome_html"
-             compress="gzip" />
-  <structure name="IDR_POLYMER_1_0_PAPER_INPUT_PAPER_TEXTAREA_EXTRACTED_JS"
-             file="../../../third_party/polymer/v1_0/components-chromium/paper-input/paper-textarea-extracted.js"
-             type="chrome_html"
-             compress="gzip" />
-  <structure name="IDR_POLYMER_1_0_PAPER_INPUT_PAPER_TEXTAREA_HTML"
-             file="../../../third_party/polymer/v1_0/components-chromium/paper-input/paper-textarea.html"
-             type="chrome_html"
-             compress="gzip" />
   <structure name="IDR_POLYMER_1_0_PAPER_ITEM_PAPER_ICON_ITEM_EXTRACTED_JS"
              file="../../../third_party/polymer/v1_0/components-chromium/paper-item/paper-icon-item-extracted.js"
              type="chrome_html"
@@ -656,14 +632,6 @@
              file="../../../third_party/polymer/v1_0/components-chromium/paper-item/paper-item.html"
              type="chrome_html"
              compress="gzip" />
-  <structure name="IDR_POLYMER_1_0_PAPER_LISTBOX_PAPER_LISTBOX_EXTRACTED_JS"
-             file="../../../third_party/polymer/v1_0/components-chromium/paper-listbox/paper-listbox-extracted.js"
-             type="chrome_html"
-             compress="gzip" />
-  <structure name="IDR_POLYMER_1_0_PAPER_LISTBOX_PAPER_LISTBOX_HTML"
-             file="../../../third_party/polymer/v1_0/components-chromium/paper-listbox/paper-listbox.html"
-             type="chrome_html"
-             compress="gzip" />
   <structure name="IDR_POLYMER_1_0_PAPER_PROGRESS_PAPER_PROGRESS_EXTRACTED_JS"
              file="../../../third_party/polymer/v1_0/components-chromium/paper-progress/paper-progress-extracted.js"
              type="chrome_html"
diff --git a/webrunner/BUILD.gn b/webrunner/BUILD.gn
index e3324bc..36b28af5 100644
--- a/webrunner/BUILD.gn
+++ b/webrunner/BUILD.gn
@@ -17,7 +17,7 @@
 fuchsia_package("webrunner_pkg") {
   binary = ":webrunner_exe"
   package_name_override = "web_runner"
-  sandbox_policy = "app/sandbox_policy"
+  sandbox_policy = "app/web/sandbox_policy"
 }
 
 fuchsia_package_runner("webrunner") {
@@ -30,13 +30,12 @@
       ] ]
 }
 
-executable("webrunner_exe") {
+source_set("webrunner_common") {
   sources = [
-    "app/component_controller_impl.cc",
-    "app/component_controller_impl.h",
-    "app/main.cc",
-    "app/web_content_runner.cc",
-    "app/web_content_runner.h",
+    "app/common/web_component.cc",
+    "app/common/web_component.h",
+    "app/common/web_content_runner.cc",
+    "app/common/web_content_runner.h",
   ]
   deps = [
     ":web_fidl",
@@ -45,6 +44,17 @@
   ]
 }
 
+executable("webrunner_exe") {
+  sources = [
+    "app/web/main.cc",
+  ]
+  deps = [
+    ":web_fidl",
+    ":webrunner_common",
+    "//base",
+  ]
+}
+
 fuchsia_package("service_pkg") {
   binary = ":service_exe"
   package_name_override = "chromium"
diff --git a/webrunner/app/common/web_component.cc b/webrunner/app/common/web_component.cc
new file mode 100644
index 0000000..2fd5cc99
--- /dev/null
+++ b/webrunner/app/common/web_component.cc
@@ -0,0 +1,100 @@
+// 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 "webrunner/app/common/web_component.h"
+
+#include <fuchsia/sys/cpp/fidl.h>
+#include <lib/fidl/cpp/binding_set.h>
+#include <lib/fit/function.h>
+#include <utility>
+
+#include "base/fuchsia/scoped_service_binding.h"
+#include "base/fuchsia/service_directory.h"
+#include "base/logging.h"
+#include "webrunner/app/common/web_content_runner.h"
+#include "webrunner/fidl/chromium/web/cpp/fidl.h"
+
+namespace webrunner {
+
+WebComponent::~WebComponent() {
+  // Send process termination details to the client.
+  controller_binding_.events().OnTerminated(termination_exit_code_,
+                                            termination_reason_);
+}
+
+// static
+std::unique_ptr<WebComponent> WebComponent::ForUrlRequest(
+    WebContentRunner* runner,
+    const GURL& url,
+    fuchsia::sys::StartupInfo startup_info,
+    fidl::InterfaceRequest<fuchsia::sys::ComponentController>
+        controller_request) {
+  DCHECK(url.is_valid());
+  std::unique_ptr<WebComponent> component(new WebComponent(
+      runner, std::move(startup_info), std::move(controller_request)));
+  component->navigation_controller()->LoadUrl(url.spec(), nullptr);
+  return component;
+}
+
+WebComponent::WebComponent(
+    WebContentRunner* runner,
+    fuchsia::sys::StartupInfo startup_info,
+    fidl::InterfaceRequest<fuchsia::sys::ComponentController>
+        controller_request)
+    : runner_(runner), controller_binding_(this) {
+  DCHECK(runner);
+
+  // If the ComponentController request is valid then bind it, and configure it
+  // to destroy this component on error.
+  if (controller_request.is_valid()) {
+    controller_binding_.Bind(std::move(controller_request));
+    controller_binding_.set_error_handler([this] {
+      // Signal graceful process termination.
+      DestroyComponent(0, fuchsia::sys::TerminationReason::EXITED);
+    });
+  }
+
+  // Create the underlying Frame and get its NavigationController.
+  runner_->context()->CreateFrame(frame_.NewRequest());
+  frame_->GetNavigationController(navigation_controller_.NewRequest());
+
+  // Create a ServiceDirectory for this component, and publish a ViewProvider
+  // into it, for the caller to use to create a View for this component.
+  // Note that we must publish ViewProvider before returning control to the
+  // message-loop, to ensure that it is available before the ServiceDirectory
+  // starts processing requests.
+  service_directory_ = std::make_unique<base::fuchsia::ServiceDirectory>(
+      std::move(startup_info.launch_info.directory_request));
+  view_provider_binding_ = std::make_unique<
+      base::fuchsia::ScopedServiceBinding<fuchsia::ui::viewsv1::ViewProvider>>(
+      service_directory_.get(), this);
+}
+
+void WebComponent::Kill() {
+  // Signal abnormal process termination.
+  DestroyComponent(1, fuchsia::sys::TerminationReason::RUNNER_TERMINATED);
+}
+
+void WebComponent::Detach() {
+  controller_binding_.set_error_handler(nullptr);
+}
+
+void WebComponent::CreateView(
+    fidl::InterfaceRequest<fuchsia::ui::viewsv1token::ViewOwner> view_owner,
+    fidl::InterfaceRequest<fuchsia::sys::ServiceProvider> services) {
+  DCHECK(frame_);
+  DCHECK(!view_is_bound_);
+
+  frame_->CreateView(std::move(view_owner), std::move(services));
+  view_is_bound_ = true;
+}
+
+void WebComponent::DestroyComponent(int termination_exit_code,
+                                    fuchsia::sys::TerminationReason reason) {
+  termination_reason_ = reason;
+  termination_exit_code_ = termination_exit_code;
+  runner_->DestroyComponent(this);
+}
+
+}  // namespace webrunner
diff --git a/webrunner/app/common/web_component.h b/webrunner/app/common/web_component.h
new file mode 100644
index 0000000..ccd49593
--- /dev/null
+++ b/webrunner/app/common/web_component.h
@@ -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.
+
+#ifndef WEBRUNNER_APP_COMMON_WEB_COMPONENT_H_
+#define WEBRUNNER_APP_COMMON_WEB_COMPONENT_H_
+
+#include <fuchsia/sys/cpp/fidl.h>
+#include <fuchsia/ui/viewsv1/cpp/fidl.h>
+#include <lib/fidl/cpp/binding.h>
+#include <lib/fidl/cpp/binding_set.h>
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "base/fuchsia/scoped_service_binding.h"
+#include "base/fuchsia/service_directory.h"
+#include "base/logging.h"
+#include "url/gurl.h"
+#include "webrunner/fidl/chromium/web/cpp/fidl.h"
+
+namespace webrunner {
+
+class WebContentRunner;
+
+// Base component implementation for web-based content Runners. Each instance
+// manages the lifetime of its own chromium::web::Frame, including associated
+// resources and service bindings.  Runners for specialized web-based content
+// (e.g. Cast applications) can extend this class to configure the Frame to
+// their needs, publish additional APIs, etc.
+class WebComponent : public fuchsia::sys::ComponentController,
+                     public fuchsia::ui::viewsv1::ViewProvider {
+ public:
+  ~WebComponent() override;
+
+  // Creates a WebComponent and navigates its Frame to |url|.
+  static std::unique_ptr<WebComponent> ForUrlRequest(
+      WebContentRunner* runner,
+      const GURL& url,
+      fuchsia::sys::StartupInfo startup_info,
+      fidl::InterfaceRequest<fuchsia::sys::ComponentController>
+          controller_request);
+
+ protected:
+  // Creates a WebComponent encapsulating a web.Frame. A ViewProvider service
+  // will be published to the service-directory specified in |startup_info|, and
+  // if |controller_request| is valid then it will be bound to this component,
+  // and the component configured to teardown if that channel closes.
+  // |runner| must outlive this component.
+  WebComponent(WebContentRunner* runner,
+               fuchsia::sys::StartupInfo startup_info,
+               fidl::InterfaceRequest<fuchsia::sys::ComponentController>
+                   controller_request);
+
+  // fuchsia::sys::ComponentController implementation.
+  void Kill() override;
+  void Detach() override;
+
+  // fuchsia::ui::viewsv1::ViewProvider implementation.
+  void CreateView(
+      fidl::InterfaceRequest<::fuchsia::ui::viewsv1token::ViewOwner> view_owner,
+      fidl::InterfaceRequest<::fuchsia::sys::ServiceProvider> services)
+      override;
+
+  // Reports the supplied exit-code and reason to the |controller_binding_| and
+  // requests that the |runner_| delete this component.
+  void DestroyComponent(int termination_exit_code,
+                        fuchsia::sys::TerminationReason reason);
+
+  chromium::web::Frame* frame() { return frame_.get(); }
+  chromium::web::NavigationController* navigation_controller() {
+    return navigation_controller_.get();
+  }
+  base::fuchsia::ServiceDirectory* service_directory() {
+    return service_directory_.get();
+  }
+
+ private:
+  WebContentRunner* runner_ = nullptr;
+
+  chromium::web::FramePtr frame_;
+  chromium::web::NavigationControllerPtr navigation_controller_;
+
+  fidl::Binding<fuchsia::sys::ComponentController> controller_binding_;
+
+  // Objects used for binding and exporting the ViewProvider service.
+  std::unique_ptr<base::fuchsia::ServiceDirectory> service_directory_;
+  std::unique_ptr<
+      base::fuchsia::ScopedServiceBinding<fuchsia::ui::viewsv1::ViewProvider>>
+      view_provider_binding_;
+
+  // Termination reason and exit-code to be reported via the
+  // sys::ComponentController::OnTerminated event.
+  fuchsia::sys::TerminationReason termination_reason_ =
+      fuchsia::sys::TerminationReason::UNKNOWN;
+  int termination_exit_code_ = 0;
+
+  bool view_is_bound_ = false;
+
+  DISALLOW_COPY_AND_ASSIGN(WebComponent);
+};
+
+}  // namespace webrunner
+
+#endif  // WEBRUNNER_APP_COMMON_COMPONENT_CONTROLLER_IMPL_H_
diff --git a/webrunner/app/common/web_content_runner.cc b/webrunner/app/common/web_content_runner.cc
new file mode 100644
index 0000000..ac22662
--- /dev/null
+++ b/webrunner/app/common/web_content_runner.cc
@@ -0,0 +1,100 @@
+// 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 "webrunner/app/common/web_content_runner.h"
+
+#include <fuchsia/sys/cpp/fidl.h>
+#include <lib/fidl/cpp/binding_set.h>
+#include <utility>
+
+#include "base/files/file.h"
+#include "base/fuchsia/component_context.h"
+#include "base/fuchsia/file_utils.h"
+#include "base/fuchsia/scoped_service_binding.h"
+#include "base/fuchsia/service_directory.h"
+#include "base/logging.h"
+#include "url/gurl.h"
+#include "webrunner/app/common/web_component.h"
+#include "webrunner/fidl/chromium/web/cpp/fidl.h"
+
+namespace webrunner {
+
+// static
+chromium::web::ContextPtr WebContentRunner::CreateDefaultWebContext() {
+  auto web_context_provider =
+      base::fuchsia::ComponentContext::GetDefault()
+          ->ConnectToService<chromium::web::ContextProvider>();
+
+  chromium::web::CreateContextParams create_params;
+
+  // Clone /svc to the context.
+  create_params.service_directory =
+      zx::channel(base::fuchsia::GetHandleFromFile(
+          base::File(base::FilePath("/svc"),
+                     base::File::FLAG_OPEN | base::File::FLAG_READ)));
+
+  chromium::web::ContextPtr web_context;
+  web_context_provider->Create(std::move(create_params),
+                               web_context.NewRequest());
+  web_context.set_error_handler([]() {
+    // If the browser instance died, then exit everything and do not attempt
+    // to recover. appmgr will relaunch the runner when it is needed again.
+    LOG(ERROR) << "Connection to Context lost.";
+    exit(1);
+  });
+  return web_context;
+}
+
+WebContentRunner::WebContentRunner(
+    base::fuchsia::ServiceDirectory* service_directory,
+    chromium::web::ContextPtr context,
+    base::OnceClosure on_idle_closure)
+    : context_(std::move(context)),
+      service_binding_(service_directory, this),
+      on_idle_closure_(std::move(on_idle_closure)) {
+  DCHECK(context_);
+  DCHECK(on_idle_closure_);
+
+  // Signal that we're idle if the service manager connection is dropped.
+  service_binding_.SetOnLastClientCallback(base::BindOnce(
+      &WebContentRunner::RunOnIdleClosureIfValid, base::Unretained(this)));
+}
+
+WebContentRunner::~WebContentRunner() = default;
+
+void WebContentRunner::StartComponent(
+    fuchsia::sys::Package package,
+    fuchsia::sys::StartupInfo startup_info,
+    fidl::InterfaceRequest<fuchsia::sys::ComponentController>
+        controller_request) {
+  GURL url(*package.resolved_url);
+  if (!url.is_valid()) {
+    LOG(ERROR) << "Rejected invalid URL: " << url;
+    return;
+  }
+
+  RegisterComponent(WebComponent::ForUrlRequest(this, std::move(url),
+                                                std::move(startup_info),
+                                                std::move(controller_request)));
+}
+
+void WebContentRunner::DestroyComponent(WebComponent* component) {
+  components_.erase(components_.find(component));
+
+  if (components_.empty())
+    RunOnIdleClosureIfValid();
+}
+
+void WebContentRunner::RegisterComponent(
+    std::unique_ptr<WebComponent> component) {
+  if (component)
+    components_.insert(std::move(component));
+}
+
+void WebContentRunner::RunOnIdleClosureIfValid() {
+  if (on_idle_closure_)
+    std::move(on_idle_closure_).Run();
+}
+
+}  // namespace webrunner
diff --git a/webrunner/app/common/web_content_runner.h b/webrunner/app/common/web_content_runner.h
new file mode 100644
index 0000000..e2e54d4
--- /dev/null
+++ b/webrunner/app/common/web_content_runner.h
@@ -0,0 +1,79 @@
+// 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 WEBRUNNER_APP_COMMON_WEB_CONTENT_RUNNER_H_
+#define WEBRUNNER_APP_COMMON_WEB_CONTENT_RUNNER_H_
+
+#include <fuchsia/sys/cpp/fidl.h>
+#include <memory>
+#include <set>
+
+#include "base/callback.h"
+#include "base/containers/unique_ptr_adapters.h"
+#include "base/fuchsia/scoped_service_binding.h"
+#include "base/fuchsia/service_directory.h"
+#include "base/macros.h"
+#include "webrunner/fidl/chromium/web/cpp/fidl.h"
+
+namespace webrunner {
+
+class WebComponent;
+
+// sys::Runner that instantiates components hosting standard web content.
+class WebContentRunner : public fuchsia::sys::Runner {
+ public:
+  // Creates and returns a web.Context with a default path and parameters,
+  // and with access to the same services as this Runner. The returned binding
+  // is configured to exit this process on error.
+  static chromium::web::ContextPtr CreateDefaultWebContext();
+
+  // |service_directory|: ServiceDirectory into which this Runner will be
+  //   published. |on_idle_closure| will be invoked when the final client of the
+  //   published service disconnects, even if one or more Components are still
+  //   active.
+  // |content|: Context (e.g. persisted profile storage) under which all web
+  //   content launched through this Runner instance will be run.
+  // |on_idle_closure|: A callback which is invoked when the WebContentRunner
+  //   has entered an idle state and may be safely torn down.
+  WebContentRunner(base::fuchsia::ServiceDirectory* service_directory,
+                   chromium::web::ContextPtr context,
+                   base::OnceClosure on_idle_closure);
+  ~WebContentRunner() override;
+
+  chromium::web::Context* context() { return context_.get(); }
+
+  // Used by WebComponent instances to signal that the ComponentController
+  // channel was dropped, and therefore the component should be destroyed.
+  void DestroyComponent(WebComponent* component);
+
+  // fuchsia::sys::Runner implementation.
+  void StartComponent(fuchsia::sys::Package package,
+                      fuchsia::sys::StartupInfo startup_info,
+                      fidl::InterfaceRequest<fuchsia::sys::ComponentController>
+                          controller_request) override;
+
+ protected:
+  // Registers a WebComponent, or specialization, with this Runner.
+  void RegisterComponent(std::unique_ptr<WebComponent> component);
+
+ private:
+  void RunOnIdleClosureIfValid();
+
+  chromium::web::ContextPtr context_;
+  std::set<std::unique_ptr<WebComponent>, base::UniquePtrComparator>
+      components_;
+
+  // Publishes this Runner into the service directory specified at construction.
+  base::fuchsia::ScopedServiceBinding<fuchsia::sys::Runner> service_binding_;
+
+  // Run when no components remain, or the last |service_binding_| client
+  // disconnects, to quit the Runner.
+  base::OnceClosure on_idle_closure_;
+
+  DISALLOW_COPY_AND_ASSIGN(WebContentRunner);
+};
+
+}  // namespace webrunner
+
+#endif  // WEBRUNNER_APP_COMMON_WEB_CONTENT_RUNNER_H_
diff --git a/webrunner/app/component_controller_impl.cc b/webrunner/app/component_controller_impl.cc
deleted file mode 100644
index c0bbfe5..0000000
--- a/webrunner/app/component_controller_impl.cc
+++ /dev/null
@@ -1,116 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "webrunner/app/component_controller_impl.h"
-
-#include <fuchsia/sys/cpp/fidl.h>
-#include <lib/fidl/cpp/binding_set.h>
-#include <lib/fit/function.h>
-#include <utility>
-#include <vector>
-
-#include "base/fuchsia/scoped_service_binding.h"
-#include "base/fuchsia/service_directory.h"
-#include "base/logging.h"
-#include "webrunner/app/web_content_runner.h"
-#include "webrunner/fidl/chromium/web/cpp/fidl.h"
-
-namespace webrunner {
-
-// static
-std::unique_ptr<ComponentControllerImpl>
-ComponentControllerImpl::CreateForRequest(
-    WebContentRunner* runner,
-    fuchsia::sys::Package package,
-    fuchsia::sys::StartupInfo startup_info,
-    fidl::InterfaceRequest<fuchsia::sys::ComponentController>
-        controller_request) {
-  std::unique_ptr<ComponentControllerImpl> result{
-      new ComponentControllerImpl(runner)};
-  if (!result->BindToRequest(std::move(package), std::move(startup_info),
-                             std::move(controller_request))) {
-    return nullptr;
-  }
-  return result;
-}
-
-ComponentControllerImpl::ComponentControllerImpl(WebContentRunner* runner)
-    : runner_(runner), controller_binding_(this) {
-  DCHECK(runner);
-}
-
-ComponentControllerImpl::~ComponentControllerImpl() {
-  // Send process termination details to the client.
-  controller_binding_.events().OnTerminated(termination_exit_code_,
-                                            termination_reason_);
-}
-
-bool ComponentControllerImpl::BindToRequest(
-    fuchsia::sys::Package package,
-    fuchsia::sys::StartupInfo startup_info,
-    fidl::InterfaceRequest<fuchsia::sys::ComponentController>
-        controller_request) {
-  DCHECK(!service_directory_);
-  DCHECK(!view_provider_binding_);
-
-  url_ = GURL(*package.resolved_url);
-  if (!url_.is_valid()) {
-    LOG(ERROR) << "Rejected invalid URL: " << url_;
-    return false;
-  }
-
-  if (controller_request.is_valid()) {
-    controller_binding_.Bind(std::move(controller_request));
-    controller_binding_.set_error_handler([this] {
-      // Signal graceful process termination.
-      RequestTermination(0, fuchsia::sys::TerminationReason::EXITED);
-    });
-  }
-
-  runner_->context()->CreateFrame(frame_.NewRequest());
-  frame_->GetNavigationController(navigation_controller_.NewRequest());
-  navigation_controller_->LoadUrl(url_.spec(), nullptr);
-
-  // Create ServiceDirectory for the component and publish ViewProvider
-  // interface. ViewProvider will be used by the caller to create a view for the
-  // Frame. Note that these two operations must be done on the same/
-  // AsyncDispatcher in order to ensure that ServiceDirectory doesn't process
-  // incoming service requests before the service is published.
-  service_directory_ = std::make_unique<base::fuchsia::ServiceDirectory>(
-      std::move(startup_info.launch_info.directory_request));
-  view_provider_binding_ = std::make_unique<
-      base::fuchsia::ScopedServiceBinding<fuchsia::ui::viewsv1::ViewProvider>>(
-      service_directory_.get(), this);
-
-  return true;
-}
-
-void ComponentControllerImpl::Kill() {
-  // Signal abnormal process termination.
-  RequestTermination(1, fuchsia::sys::TerminationReason::RUNNER_TERMINATED);
-}
-
-void ComponentControllerImpl::Detach() {
-  controller_binding_.set_error_handler(nullptr);
-}
-
-void ComponentControllerImpl::CreateView(
-    fidl::InterfaceRequest<fuchsia::ui::viewsv1token::ViewOwner> view_owner,
-    fidl::InterfaceRequest<fuchsia::sys::ServiceProvider> services) {
-  DCHECK(frame_);
-  DCHECK(!view_is_bound_);
-
-  frame_->CreateView(std::move(view_owner), std::move(services));
-  view_is_bound_ = true;
-}
-
-void ComponentControllerImpl::RequestTermination(
-    int termination_exit_code,
-    fuchsia::sys::TerminationReason reason) {
-  termination_reason_ = reason;
-  termination_exit_code_ = termination_exit_code;
-  runner_->DestroyComponent(this);
-}
-
-}  // namespace webrunner
diff --git a/webrunner/app/component_controller_impl.h b/webrunner/app/component_controller_impl.h
deleted file mode 100644
index f3504f63..0000000
--- a/webrunner/app/component_controller_impl.h
+++ /dev/null
@@ -1,96 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef WEBRUNNER_APP_COMPONENT_CONTROLLER_IMPL_H_
-#define WEBRUNNER_APP_COMPONENT_CONTROLLER_IMPL_H_
-
-#include <fuchsia/sys/cpp/fidl.h>
-#include <fuchsia/ui/viewsv1/cpp/fidl.h>
-#include <lib/fidl/cpp/binding.h>
-#include <lib/fidl/cpp/binding_set.h>
-#include <memory>
-#include <utility>
-#include <vector>
-
-#include "base/fuchsia/scoped_service_binding.h"
-#include "base/fuchsia/service_directory.h"
-#include "base/logging.h"
-#include "url/gurl.h"
-#include "webrunner/fidl/chromium/web/cpp/fidl.h"
-
-namespace webrunner {
-
-class WebContentRunner;
-
-// Manages the resources and service bindings for a Runner Component creation
-// request. Each ComponentControllerImpl instance manages its own
-// chromium::web::Frame.
-class ComponentControllerImpl : public fuchsia::sys::ComponentController,
-                                public fuchsia::ui::viewsv1::ViewProvider {
- public:
-  ~ComponentControllerImpl() override;
-
-  // |runner| must outlive the returned object (normally it owns all
-  // ComponentControllerImpl). It's used by this class to get web::Context
-  // interface.
-  static std::unique_ptr<ComponentControllerImpl> CreateForRequest(
-      WebContentRunner* runner,
-      fuchsia::sys::Package package,
-      fuchsia::sys::StartupInfo startup_info,
-      fidl::InterfaceRequest<fuchsia::sys::ComponentController>
-          controller_request);
-
-  // fuchsia::sys::ComponentController implementation.
-  void Kill() override;
-  void Detach() override;
-
-  // fuchsia::ui::viewsv1::ViewProvider implementation.
-  void CreateView(
-      fidl::InterfaceRequest<::fuchsia::ui::viewsv1token::ViewOwner> view_owner,
-      fidl::InterfaceRequest<::fuchsia::sys::ServiceProvider> services)
-      override;
-
- private:
-  explicit ComponentControllerImpl(WebContentRunner* runner);
-
-  // Registers the termination reason for this Component and requests its
-  // termination from the parent WebContentRunner.
-  void RequestTermination(int termination_exit_code,
-                          fuchsia::sys::TerminationReason reason);
-
-  // Binds |this| to a Runner::StartComponent() call. Returns false on failure
-  // (e.g. when the URL in |startup_info| is invalid).
-  bool BindToRequest(fuchsia::sys::Package package,
-                     fuchsia::sys::StartupInfo startup_info,
-                     fidl::InterfaceRequest<fuchsia::sys::ComponentController>
-                         controller_request);
-
-  GURL url_;
-  WebContentRunner* runner_ = nullptr;
-
-  chromium::web::FramePtr frame_;
-  chromium::web::NavigationControllerPtr navigation_controller_;
-
-  fidl::Binding<fuchsia::sys::ComponentController> controller_binding_;
-
-  // Objects used for binding and exporting the ViewProvider service.
-  std::unique_ptr<base::fuchsia::ServiceDirectory> service_directory_;
-  std::unique_ptr<
-      base::fuchsia::ScopedServiceBinding<fuchsia::ui::viewsv1::ViewProvider>>
-      view_provider_binding_;
-
-  // Termination reason and exit-code to be reported via the
-  // sys::ComponentController::OnTerminated event.
-  fuchsia::sys::TerminationReason termination_reason_ =
-      fuchsia::sys::TerminationReason::UNKNOWN;
-  int termination_exit_code_ = 0;
-
-  bool view_is_bound_ = false;
-
-  DISALLOW_COPY_AND_ASSIGN(ComponentControllerImpl);
-};
-
-}  // namespace webrunner
-
-#endif  // WEBRUNNER_APP_COMPONENT_CONTROLLER_IMPL_H_
diff --git a/webrunner/app/main.cc b/webrunner/app/main.cc
deleted file mode 100644
index 214fbe6..0000000
--- a/webrunner/app/main.cc
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <fuchsia/ui/viewsv1/cpp/fidl.h>
-#include <lib/fidl/cpp/binding.h>
-#include <utility>
-
-#include "base/files/file.h"
-#include "base/fuchsia/component_context.h"
-#include "base/fuchsia/file_utils.h"
-#include "base/fuchsia/scoped_service_binding.h"
-#include "base/fuchsia/service_directory.h"
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/message_loop/message_loop.h"
-#include "base/run_loop.h"
-#include "webrunner/app/web_content_runner.h"
-#include "webrunner/fidl/chromium/web/cpp/fidl.h"
-
-namespace {
-
-chromium::web::ContextPtr CreateContext() {
-  auto web_context_provider =
-      base::fuchsia::ComponentContext::GetDefault()
-          ->ConnectToService<chromium::web::ContextProvider>();
-
-  chromium::web::CreateContextParams create_params;
-
-  // Clone /svc to the context.
-  create_params.service_directory =
-      zx::channel(base::fuchsia::GetHandleFromFile(
-          base::File(base::FilePath("/svc"),
-                     base::File::FLAG_OPEN | base::File::FLAG_READ)));
-
-  chromium::web::ContextPtr web_context;
-  web_context_provider->Create(std::move(create_params),
-                               web_context.NewRequest());
-  web_context.set_error_handler([]() {
-    // If the browser instance died, then exit everything and do not attempt
-    // to recover. appmgr will relaunch the runner when it is needed again.
-    LOG(ERROR) << "Connection to Context lost.";
-    exit(1);
-  });
-  return web_context;
-}
-
-}  // namespace
-
-int main(int argc, char** argv) {
-  base::MessageLoopForIO message_loop;
-
-  auto web_context = CreateContext();
-
-  // Run until the WebContentRunner is ready to exit.
-  base::RunLoop run_loop;
-
-  webrunner::WebContentRunner runner(std::move(web_context),
-                                     run_loop.QuitClosure());
-
-  base::fuchsia::ServiceDirectory* directory =
-      base::fuchsia::ServiceDirectory::GetDefault();
-
-  // Bind the Runner FIDL instance.
-  base::fuchsia::ScopedServiceBinding<fuchsia::sys::Runner> runner_binding(
-      directory, &runner);
-
-  runner_binding.SetOnLastClientCallback(run_loop.QuitClosure());
-
-  // The RunLoop runs until all Components have been closed, at which point the
-  // application will terminate.
-  run_loop.Run();
-
-  return 0;
-}
diff --git a/webrunner/app/web/main.cc b/webrunner/app/web/main.cc
new file mode 100644
index 0000000..29ba321
--- /dev/null
+++ b/webrunner/app/web/main.cc
@@ -0,0 +1,24 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/fuchsia/service_directory.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "webrunner/app/common/web_content_runner.h"
+
+int main(int argc, char** argv) {
+  base::MessageLoopForIO message_loop;
+  base::RunLoop run_loop;
+
+  webrunner::WebContentRunner runner(
+      base::fuchsia::ServiceDirectory::GetDefault(),
+      webrunner::WebContentRunner::CreateDefaultWebContext(),
+      run_loop.QuitClosure());
+
+  // Run until there are no Components, or the last service client channel is
+  // closed.
+  run_loop.Run();
+
+  return 0;
+}
diff --git a/webrunner/app/sandbox_policy b/webrunner/app/web/sandbox_policy
similarity index 100%
rename from webrunner/app/sandbox_policy
rename to webrunner/app/web/sandbox_policy
diff --git a/webrunner/app/web_content_runner.cc b/webrunner/app/web_content_runner.cc
deleted file mode 100644
index 9c968e6..0000000
--- a/webrunner/app/web_content_runner.cc
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "webrunner/app/web_content_runner.h"
-
-#include <fuchsia/sys/cpp/fidl.h>
-#include <lib/fidl/cpp/binding_set.h>
-#include <utility>
-
-#include "base/fuchsia/scoped_service_binding.h"
-#include "base/fuchsia/service_directory.h"
-#include "base/logging.h"
-#include "webrunner/app/component_controller_impl.h"
-#include "webrunner/fidl/chromium/web/cpp/fidl.h"
-
-namespace webrunner {
-
-WebContentRunner::WebContentRunner(chromium::web::ContextPtr context,
-                                   base::OnceClosure on_idle_closure)
-    : context_(std::move(context)),
-      on_idle_closure_(std::move(on_idle_closure)) {
-  DCHECK(context_);
-  DCHECK(on_idle_closure_);
-}
-
-WebContentRunner::~WebContentRunner() = default;
-
-void WebContentRunner::StartComponent(
-    fuchsia::sys::Package package,
-    fuchsia::sys::StartupInfo startup_info,
-    fidl::InterfaceRequest<fuchsia::sys::ComponentController>
-        controller_request) {
-  auto controller = ComponentControllerImpl::CreateForRequest(
-      this, std::move(package), std::move(startup_info),
-      std::move(controller_request));
-  controllers_.insert(std::move(controller));
-}
-
-void WebContentRunner::DestroyComponent(ComponentControllerImpl* component) {
-  controllers_.erase(controllers_.find(component));
-
-  // Quit the RunLoop if there are no more connected clients.
-  if (controllers_.empty() && on_idle_closure_) {
-    std::move(on_idle_closure_).Run();
-  }
-}
-
-}  // namespace webrunner
diff --git a/webrunner/app/web_content_runner.h b/webrunner/app/web_content_runner.h
deleted file mode 100644
index 93c50ec..0000000
--- a/webrunner/app/web_content_runner.h
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef WEBRUNNER_APP_WEB_CONTENT_RUNNER_H_
-#define WEBRUNNER_APP_WEB_CONTENT_RUNNER_H_
-
-#include <fuchsia/sys/cpp/fidl.h>
-#include <memory>
-#include <set>
-
-#include "base/callback.h"
-#include "base/containers/unique_ptr_adapters.h"
-#include "base/macros.h"
-#include "webrunner/fidl/chromium/web/cpp/fidl.h"
-
-namespace webrunner {
-
-class ComponentControllerImpl;
-
-// An implementation of a sys::Runner that launches web content and renders it
-// inside a View.
-class WebContentRunner : public fuchsia::sys::Runner {
- public:
-  // |content|: Context (e.g. persisted profile storage) under which all web
-  //   content launched through this Runner instance will be run.
-  // |on_idle_closure|: A callback which is invoked when the WebContentRunner
-  //   has entered an idle state and may be safely torn down.
-  WebContentRunner(chromium::web::ContextPtr context,
-                   base::OnceClosure on_idle_closure);
-  ~WebContentRunner() override;
-
-  chromium::web::Context* context() { return context_.get(); }
-
-  // Used by ComponentControllerImpls to signal that the controller's connection
-  // was dropped, and therefore the controller should be destroyed.
-  void DestroyComponent(ComponentControllerImpl* component);
-
-  // fuchsia::sys::Runner implementation.
-  void StartComponent(fuchsia::sys::Package package,
-                      fuchsia::sys::StartupInfo startup_info,
-                      fidl::InterfaceRequest<fuchsia::sys::ComponentController>
-                          controller_request) override;
-
- private:
-  chromium::web::ContextPtr context_;
-  std::set<std::unique_ptr<ComponentControllerImpl>, base::UniquePtrComparator>
-      controllers_;
-  base::OnceClosure on_idle_closure_;
-
-  DISALLOW_COPY_AND_ASSIGN(WebContentRunner);
-};
-
-}  // namespace webrunner
-
-#endif  // WEBRUNNER_APP_WEB_CONTENT_RUNNER_H_