diff --git a/BUILD.gn b/BUILD.gn
index 0f2e28a..37cf59b 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -309,7 +309,6 @@
       "//tools/android/customtabs_benchmark:customtabs_benchmark_apk",
       "//tools/android/errorprone_plugin:errorprone_plugin_java",
       "//tools/android/kerberos/SpnegoAuthenticator:spnego_authenticator_apk",
-      "//tools/cygprofile:cygprofile_unittests",
       "//ui/android:ui_junit_tests",
     ]
     deps -= [
diff --git a/DEPS b/DEPS
index 47520704..9e6ec67 100644
--- a/DEPS
+++ b/DEPS
@@ -79,11 +79,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '2388cd1f69e38c2ff2d275532f3afab1348fbbfe',
+  'skia_revision': 'bd6525304d448f9c1ce04bf6b10bc9306802823e',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': 'f4c401343e75692991a389491f784d1dfe1de9dc',
+  'v8_revision': '598a80edc4157838591a393a728a2f4f79a3b66f',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -91,7 +91,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': 'e05ffdd19837dc3782636fba164791091c92210e',
+  'angle_revision': 'd2cb7cec4f3e303880ab5d55f6a58165cd23a631',
   # 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.
@@ -103,7 +103,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': 'f3be555096b0b64917d27578e51c9e6c7d9c7083',
+  'pdfium_revision': '9600a771999de20fb22130cdb97088591508f89f',
   # 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.
diff --git a/android_webview/browser/net/aw_network_delegate.cc b/android_webview/browser/net/aw_network_delegate.cc
index 474a535e..1955b27 100644
--- a/android_webview/browser/net/aw_network_delegate.cc
+++ b/android_webview/browser/net/aw_network_delegate.cc
@@ -53,7 +53,7 @@
   DCHECK(headers);
   headers->SetHeaderIfMissing(
       "X-Requested-With",
-      base::android::BuildInfo::GetInstance()->package_name());
+      base::android::BuildInfo::GetInstance()->host_package_name());
   return net::OK;
 }
 
diff --git a/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumFactoryProvider.java b/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumFactoryProvider.java
index 4f432fb..02872d65b 100644
--- a/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumFactoryProvider.java
+++ b/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumFactoryProvider.java
@@ -36,6 +36,7 @@
 import org.chromium.android_webview.ResourcesContextWrapperFactory;
 import org.chromium.android_webview.WebViewChromiumRunQueue;
 import org.chromium.android_webview.command_line.CommandLineUtil;
+import org.chromium.base.BuildInfo;
 import org.chromium.base.CommandLine;
 import org.chromium.base.ContextUtils;
 import org.chromium.base.PackageUtils;
@@ -100,12 +101,6 @@
     // Initialization guarded by mAwInit.getLock()
     private Statics mStaticsAdapter;
 
-    // TODO(gsennton) remove this when downstream doesn't depend on it anymore
-    // Guards accees to adapters.
-    // This member is not private only because the downstream subclass needs to access it,
-    // it shouldn't be accessed from anywhere else.
-    /* package */ final Object mAdapterLock = new Object();
-
     /**
      * Thread-safe way to set the one and only WebViewChromiumFactoryProvider.
      */
@@ -202,11 +197,12 @@
         }
 
         ThreadUtils.setWillOverrideUiThread();
+        final PackageInfo packageInfo = WebViewFactory.getLoadedPackageInfo();
+        BuildInfo.setBrowserPackageInfo(packageInfo);
+
         // Load chromium library.
         AwBrowserProcess.loadLibrary(mWebViewDelegate.getDataDirectorySuffix());
 
-        final PackageInfo packageInfo = WebViewFactory.getLoadedPackageInfo();
-
         StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
         try {
             // Load glue-layer support library.
diff --git a/android_webview/lib/aw_main_delegate.cc b/android_webview/lib/aw_main_delegate.cc
index 4c81cb72..aade6bc96 100644
--- a/android_webview/lib/aw_main_delegate.cc
+++ b/android_webview/lib/aw_main_delegate.cc
@@ -241,11 +241,11 @@
 
   static ::crash_reporter::CrashKeyString<64> app_name_key(
       crash_keys::kAppPackageName);
-  app_name_key.Set(android_build_info->package_name());
+  app_name_key.Set(android_build_info->host_package_name());
 
   static ::crash_reporter::CrashKeyString<64> app_version_key(
       crash_keys::kAppPackageVersionCode);
-  app_version_key.Set(android_build_info->package_version_code());
+  app_version_key.Set(android_build_info->host_version_code());
 
   static ::crash_reporter::CrashKeyString<8> sdk_int_key(
       crash_keys::kAndroidSdkInt);
diff --git a/ash/components/shortcut_viewer_strings.grdp b/ash/components/shortcut_viewer_strings.grdp
index ad1a6b1b..36cb6417 100644
--- a/ash/components/shortcut_viewer_strings.grdp
+++ b/ash/components/shortcut_viewer_strings.grdp
@@ -74,10 +74,10 @@
     <ph name="key">$1<ex>Overview Mode Key</ex></ph>
   </message>
   <message name="IDS_KSV_SHORTCUT_ONE_MODIFIER_ONE_KEY" desc="Human readable version of the keyboard shortcut. This is for all single modifier shortcuts.">
-    <ph name="modifier">$1<ex>Ctrl</ex></ph><ph name="separator">$2<ex>+</ex></ph><ph name="key">$3<ex>V</ex></ph>
+    <ph name="modifier">$1<ex>Ctrl</ex></ph><ph name="separator">$2<ex>+</ex></ph><ph name="key">$3<ex>v</ex></ph>
   </message>
   <message name="IDS_KSV_SHORTCUT_TWO_MODIFIERS_ONE_KEY" desc="Human readable version of the keyboard shortcut. This is for all two modifiers shortcuts.">
-    <ph name="modifier1">$1<ex>Ctrl</ex></ph><ph name="separator1">$2<ex>+</ex></ph><ph name="modifier2">$3<ex>Alt</ex></ph><ph name="separator2">$4<ex>+</ex></ph><ph name="key">$5<ex>V</ex></ph>
+    <ph name="modifier1">$1<ex>Ctrl</ex></ph><ph name="separator1">$2<ex>+</ex></ph><ph name="modifier2">$3<ex>Alt</ex></ph><ph name="separator2">$4<ex>+</ex></ph><ph name="key">$5<ex>v</ex></ph>
   </message>
 
   <!-- Shortcuts descriptions -->
@@ -88,7 +88,7 @@
     Change screen resolution
   </message>
   <message name="IDS_KSV_SHORTCUT_CHANGE_SCREEN_RESOLUTION" desc="Human readable version of the keyboard shortcut.">
-    <ph name="ctrl">$1</ph><ph name="separator1">$2</ph><ph name="shift">$3</ph><ph name="separator2">$4</ph><ph name="plus">$5</ph> or <ph name="minus">$6</ph>
+    <ph name="ctrl">$1<ex>Ctrl</ex></ph><ph name="separator1">$2<ex>+</ex></ph><ph name="shift">$3<ex>Shift</ex></ph><ph name="separator2">$4<ex>+</ex></ph><ph name="plus">$5<ex>v</ex></ph> or <ph name="minus">$6<ex>v</ex></ph>
   </message>
   <message name="IDS_KSV_DESCRIPTION_DRAG_LINK_IN_SAME_TAB" desc="Description of the command in keyboard shortcut viewer.">
     Open the link in the tab
@@ -100,7 +100,7 @@
     Highlight the next item on your shelf
   </message>
   <message name="IDS_KSV_SHORTCUT_HIGHLIGHT_NEXT_ITEM_ON_SHELF" desc="Human readable version of the keyboard shortcut.">
-    <ph name="shift">$1</ph><ph name="separator1">$2</ph><ph name="alt">$3</ph><ph name="separator2">$4</ph><ph name="l">$5</ph>, then <ph name="tab">$6</ph> or <ph name="right">$7</ph>
+    <ph name="shift">$1<ex>Shift</ex></ph><ph name="separator1">$2<ex>+</ex></ph><ph name="alt">$3<ex>Alt</ex></ph><ph name="separator2">$4<ex>+</ex></ph><ph name="l">$5<ex>v</ex></ph>, then <ph name="tab">$6<ex>v</ex></ph> or <ph name="right">$7<ex>v</ex></ph>
   </message>
   <message name="IDS_KSV_DESCRIPTION_PREVIOUS_IME" desc="Description of the command in keyboard shortcut viewer.">
     Switch to the previous keyboard language you were using.
@@ -109,13 +109,13 @@
     Switch quickly between windows
   </message>
   <message name="IDS_KSV_SHORTCUT_CYCLE_FORWARD_MRU" desc="Human readable version of the keyboard shortcut.">
-    Press and hold <ph name="alt">$1</ph>, tap <ph name="tab">$2</ph> until you get to the window you want to open, then release.
+    Press and hold <ph name="alt">$1<ex>Alt</ex></ph>, tap <ph name="tab">$2<ex>v</ex></ph> until you get to the window you want to open, then release.
   </message>
   <message name="IDS_KSV_DESCRIPTION_CYCLE_BACKWARD_MRU" desc="Description of the command in keyboard shortcut viewer.">
     Open the window you used least recently
   </message>
   <message name="IDS_KSV_SHORTCUT_CYCLE_BACKWARD_MRU" desc="Human readable version of the keyboard shortcut.">
-    Press and hold <ph name="alt">$1</ph><ph name="separator">$2</ph><ph name="shift">$3</ph>, tap <ph name="tab">$4</ph> until you get to the window you want to open, then release.
+    Press and hold <ph name="alt">$1<ex>Alt</ex></ph><ph name="separator">$2<ex>+</ex></ph><ph name="shift">$3<ex>Shift</ex></ph>, tap <ph name="tab">$4<ex>v</ex></ph> until you get to the window you want to open, then release.
   </message>
   <message name="IDS_KSV_DESCRIPTION_TOGGLE_OVERVIEW" desc="Description of the command in keyboard shortcut viewer.">
     Overview mode
@@ -202,19 +202,19 @@
     Go to the next match for your search
   </message>
   <message name="IDS_KSV_SHORTCUT_IDC_FIND_NEXT" desc="Human readable version of the keyboard shortcut.">
-    <ph name="ctrl">$1</ph><ph name="separator">$2</ph><ph name="g">$3</ph> or <ph name="enter">$4</ph>
+    <ph name="ctrl">$1<ex>Ctrl</ex></ph><ph name="separator">$2<ex>+</ex></ph><ph name="g">$3<ex>v</ex></ph> or <ph name="enter">$4<ex>v</ex></ph>
   </message>
   <message name="IDS_KSV_DESCRIPTION_IDC_FIND_PREVIOUS" desc="Description of the command in keyboard shortcut viewer.">
     Go to the previous match for your search
   </message>
   <message name="IDS_KSV_SHORTCUT_IDC_FIND_PREVIOUS" desc="Human readable version of the keyboard shortcut.">
-    <ph name="ctrl">$1</ph><ph name="separator1">$2</ph><ph name="shift1">$3</ph><ph name="separator2">$4</ph><ph name="g">$5</ph> or <ph name="shift2">$6</ph><ph name="separator3">$7</ph><ph name="enter">$8</ph>
+    <ph name="ctrl">$1<ex>Ctrl</ex></ph><ph name="separator1">$2<ex>+</ex></ph><ph name="shift1">$3<ex>Shift</ex></ph><ph name="separator2">$4<ex>+</ex></ph><ph name="g">$5<ex>v</ex></ph> or <ph name="shift2">$6<ex>Shift</ex></ph><ph name="separator3">$7<ex>+</ex></ph><ph name="enter">$8<ex>v</ex></ph>
   </message>
   <message name="IDS_KSV_DESCRIPTION_IDC_FOCUS_LOCATION" desc="Description of the command in keyboard shortcut viewer.">
     Focus address bar
   </message>
   <message name="IDS_KSV_SHORTCUT_IDC_FOCUS_LOCATION" desc="Description of the command in keyboard shortcut viewer.">
-    <ph name="ctrl">$1</ph><ph name="separator1">$2</ph><ph name="l">$3</ph> or <ph name="alt">$4</ph><ph name="separator2">$5</ph><ph name="d">$6</ph>
+    <ph name="ctrl">$1<ex>Ctrl</ex></ph><ph name="separator1">$2<ex>+</ex></ph><ph name="l">$3<ex>v</ex></ph> or <ph name="alt">$4<ex>Alt</ex></ph><ph name="separator2">$5<ex>+</ex></ph><ph name="d">$6<ex>v</ex></ph>
   </message>
   <message name="IDS_KSV_DESCRIPTION_IDC_OPEN_FILE" desc="Description of the command in keyboard shortcut viewer.">
     Open a file in the browser
@@ -274,7 +274,7 @@
     Focus address bar on search
   </message>
   <message name="IDS_KSV_SHORTCUT_IDC_FOCUS_SEARCH" desc="Description of the command in keyboard shortcut viewer.">
-    <ph name="ctrl">$1</ph><ph name="separator">$2</ph><ph name="k">$3</ph> or <ph name="e">$4</ph>
+    <ph name="ctrl">$1<ex>Ctrl</ex></ph><ph name="separator">$2<ex>+</ex></ph><ph name="k">$3<ex>v</ex></ph> or <ph name="e">$4<ex>v</ex></ph>
   </message>
   <message name="IDS_KSV_DESCRIPTION_IDC_FOCUS_TOOLBAR" desc="Description of the command in keyboard shortcut viewer.">
     Highlight the row with the address bar
@@ -298,7 +298,7 @@
     Go to numbered tab
   </message>
   <message name="IDS_KSV_SHORTCUT_SELECT_NUMBERED_TAB" desc="Human readable version of the keyboard shortcut.">
-    <ph name="ctrl">$1</ph><ph name="separator">$2</ph> 1 through 8
+    <ph name="ctrl">$1<ex>Ctrl</ex></ph><ph name="separator">$2<ex>+</ex></ph> 1 through 8
   </message>
   <message name="IDS_KSV_DESCRIPTION_KEYBOARD_SHORTCUT_HELPER" desc="Description of the command in keyboard shortcut viewer.">
     See Keyboard Shortcut Helper
@@ -307,19 +307,19 @@
     Open the link in a new tab in the background
   </message>
   <message name="IDS_KSV_SHORTCUT_OPEN_LINK_IN_TAB_BACKGROUND" desc="Human readable version of the keyboard shortcut.">
-    Press <ph name="ctrl">$1</ph> and click a link
+    Press <ph name="ctrl">$1<ex>Ctrl</ex></ph> and click a link
   </message>
   <message name="IDS_KSV_DESCRIPTION_OPEN_LINK_IN_TAB" desc="Description of the command in keyboard shortcut viewer.">
     Open the link in a new tab and switch to the new tab
   </message>
   <message name="IDS_KSV_SHORTCUT_OPEN_LINK_IN_TAB" desc="Human readable version of the keyboard shortcut.">
-    Press <ph name="ctrl">$1</ph><ph name="separator">$2</ph><ph name="shift">$3</ph> and click a link
+    Press <ph name="ctrl">$1<ex>Ctrl</ex></ph><ph name="separator">$2<ex>+</ex></ph><ph name="shift">$3<ex>Shift</ex></ph> and click a link
   </message>
   <message name="IDS_KSV_DESCRIPTION_OPEN_LINK_IN_WINDOW" desc="Description of the command in keyboard shortcut viewer.">
     Open the link in a new window
   </message>
   <message name="IDS_KSV_SHORTCUT_OPEN_LINK_IN_WINDOW" desc="Human readable version of the keyboard shortcut.">
-    Press <ph name="shift">$1</ph> and click a link
+    Press <ph name="shift">$1<ex>Shift</ex></ph> and click a link
   </message>
   <message name="IDS_KSV_DESCRIPTION_DRAG_LINK_IN_NEW_TAB" desc="Description of the command in keyboard shortcut viewer.">
     Open the link in a new tab
@@ -331,25 +331,25 @@
     Open the webpage in a new tab
   </message>
   <message name="IDS_KSV_SHORTCUT_OPEN_PAGE_IN_NEW_TAB" desc="Human readable version of the keyboard shortcut.">
-    Type a web address in the address bar, then press <ph name="alt">$1</ph><ph name="separator">$2</ph><ph name="enter">$3</ph>
+    Type a web address in the address bar, then press <ph name="alt">$1<ex>Alt</ex></ph><ph name="separator">$2<ex>+</ex></ph><ph name="enter">$3<ex>v</ex></ph>
   </message>
   <message name="IDS_KSV_DESCRIPTION_STOP_DRAG_TAB" desc="Description of the command in keyboard shortcut viewer.">
     Return the tab to its original position
   </message>
   <message name="IDS_KSV_SHORTCUT_STOP_DRAG_TAB" desc="Human readable version of the keyboard shortcut.">
-    While dragging the tab, press <ph name="esc">$1</ph>
+    While dragging the tab, press <ph name="esc">$1<ex>v</ex></ph>
   </message>
   <message name="IDS_KSV_DESCRIPTION_PAGE_UP" desc="Description of the command in keyboard shortcut viewer.">
     Page up
   </message>
   <message name="IDS_KSV_SHORTCUT_PAGE_UP" desc="Human readable version of the keyboard shortcut.">
-    <ph name="alt">$1</ph> or <ph name="search">$2</ph><ph name="separator">$3</ph><ph name="up">$4</ph>
+    <ph name="alt">$1<ex>Alt</ex></ph> or <ph name="search">$2<ex>Search</ex></ph><ph name="separator">$3<ex>+</ex></ph><ph name="up">$4<ex>v</ex></ph>
   </message>
   <message name="IDS_KSV_DESCRIPTION_PAGE_DOWN" desc="Description of the command in keyboard shortcut viewer.">
     Page down
   </message>
   <message name="IDS_KSV_SHORTCUT_PAGE_DOWN" desc="Human readable version of the keyboard shortcut.">
-    <ph name="alt">$1</ph> or <ph name="search">$2</ph><ph name="separator">$3</ph><ph name="down">$4</ph>
+    <ph name="alt">$1<ex>Alt</ex></ph> or <ph name="search">$2<ex>Search</ex></ph><ph name="separator">$3<ex>+</ex></ph><ph name="down">$4<ex>v</ex></ph>
   </message>
   <message name="IDS_KSV_DESCRIPTION_SCROLL_DOWN_PAGE" desc="Description of the command in keyboard shortcut viewer.">
     Scroll down the web page
@@ -364,7 +364,7 @@
     Right-click a link
   </message>
   <message name="IDS_KSV_SHORTCUT_RIGHT_CLICK" desc="Human readable version of the keyboard shortcut.">
-    Press <ph name="alt">$1</ph> and click a link
+    Press <ph name="alt">$1<ex>Alt</ex></ph> and click a link
   </message>
   <message name="IDS_KSV_DESCRIPTION_SAVE_LINK_AS_BOOKMARK" desc="Description of the command in keyboard shortcut viewer.">
     Save the link as a bookmark
@@ -382,7 +382,7 @@
     Preview a file in the Files app
   </message>
   <message name="IDS_KSV_SHORTCUT_OPEN_FILE" desc="Human readable version of the keyboard shortcut.">
-    Select the file, then press <ph name="space">$1</ph>
+    Select the file, then press <ph name="space">$1<ex>v</ex></ph>
   </message>
   <message name="IDS_KSV_DESCRIPTION_DISPLAY_HIDDEN_FILES" desc="Description of the command in keyboard shortcut viewer.">
     Display hidden files in the Files app
@@ -391,19 +391,19 @@
     Click icons 1-8 on your shelf
   </message>
   <message name="IDS_KSV_SHORTCUT_LAUNCH_NUMBERED_APP" desc="Human readable version of the keyboard shortcut.">
-    <ph name="alt">$1</ph><ph name="separator">$2</ph> 1 through 8
+    <ph name="alt">$1<ex>Alt</ex></ph><ph name="separator">$2<ex>+</ex></ph> 1 through 8
   </message>
   <message name="IDS_KSV_DESCRIPTION_USE_F_KEYS" desc="Description of the command in keyboard shortcut viewer.">
     Use F keys (F1 to F12)
   </message>
   <message name="IDS_KSV_SHORTCUT_USE_F_KEYS" desc="Human readable version of the keyboard shortcut.">
-    <ph name="search">$1</ph><ph name="separator">$2</ph> 1 through =
+    <ph name="search">$1<ex>Search</ex></ph><ph name="separator">$2<ex>+</ex></ph> 1 through =
   </message>
   <message name="IDS_KSV_DESCRIPTION_SELECT_ADDRESS_BAR" desc="Description of the command in keyboard shortcut viewer.">
     Select the content in the address bar
   </message>
   <message name="IDS_KSV_SHORTCUT_SELECT_ADDRESS_BAR" desc="Human readable version of the keyboard shortcut.">
-    <ph name="ctrl">$1</ph><ph name="separator1">$2</ph><ph name="l">$3</ph> or <ph name="alt">$4</ph><ph name="separator2">$5</ph><ph name="d">$6</ph>
+    <ph name="ctrl">$1<ex>Ctrl</ex></ph><ph name="separator1">$2<ex>+</ex></ph><ph name="l">$3<ex>v</ex></ph> or <ph name="alt">$4<ex>Alt</ex></ph><ph name="separator2">$5<ex>+</ex></ph><ph name="d">$6<ex>v</ex></ph>
   </message>
   <message name="IDS_KSV_DESCRIPTION_SELECT_NEXT_WORD" desc="Description of the command in keyboard shortcut viewer.">
     Select the next word or letter
@@ -451,25 +451,25 @@
     Highlight the previous item on your shelf
   </message>
   <message name="IDS_KSV_SHORTCUT_HIGHLIGHT_PREVIOUS_ITEM_ON_SHELF" desc="Human readable version of the keyboard shortcut.">
-    <ph name="shift1">$1</ph><ph name="separator1">$2</ph><ph name="alt">$3</ph><ph name="separator2">$4</ph><ph name="l">$5</ph>, then <ph name="shift2">$6</ph><ph name="separator3">$7</ph><ph name="tab">$8</ph> or <ph name="left">$9</ph>
+    <ph name="shift1">$1<ex>Shift</ex></ph><ph name="separator1">$2<ex>+</ex></ph><ph name="alt">$3<ex>Alt</ex></ph><ph name="separator2">$4<ex>+</ex></ph><ph name="l">$5<ex>v</ex></ph>, then <ph name="shift2">$6<ex>Shift</ex></ph><ph name="separator3">$7<ex>+</ex></ph><ph name="tab">$8<ex>v</ex></ph> or <ph name="left">$9<ex>v</ex></ph>
   </message>
   <message name="IDS_KSV_DESCRIPTION_OPEN_HIGHLIGHTED_ITEM_ON_SHELF" desc="Description of the command in keyboard shortcut viewer.">
     Open the highlighted button on your shelf
   </message>
   <message name="IDS_KSV_SHORTCUT_OPEN_HIGHLIGHTED_ITEM_ON_SHELF" desc="Human readable version of the keyboard shortcut.">
-    <ph name="shift">$1</ph><ph name="separator1">$2</ph><ph name="alt">$3</ph><ph name="separator2">$4</ph><ph name="l">$5</ph>, then <ph name="space">$6</ph> or <ph name="enter">$7</ph>
+    <ph name="shift">$1<ex>Shift</ex></ph><ph name="separator1">$2<ex>+</ex></ph><ph name="alt">$3<ex>Alt</ex></ph><ph name="separator2">$4<ex>+</ex></ph><ph name="l">$5<ex>v</ex></ph>, then <ph name="space">$6<ex>v</ex></ph> or <ph name="enter">$7<ex>v</ex></ph>
   </message>
   <message name="IDS_KSV_DESCRIPTION_REMOVE_HIGHLIGHT_ON_SHELF" desc="Description of the command in keyboard shortcut viewer.">
     Remove the highlight from a button on your shelf
   </message>
   <message name="IDS_KSV_SHORTCUT_REMOVE_HIGHLIGHT_ON_SHELF" desc="Human readable version of the keyboard shortcut.">
-    <ph name="shift">$1</ph><ph name="separator1">$2</ph><ph name="alt">$3</ph><ph name="separator2">$4</ph><ph name="l">$5</ph>, then <ph name="esc">$6</ph>
+    <ph name="shift">$1<ex>Shift</ex></ph><ph name="separator1">$2<ex>+</ex></ph><ph name="alt">$3<ex>Alt</ex></ph><ph name="separator2">$4<ex>+</ex></ph><ph name="l">$5<ex>v</ex></ph>, then <ph name="esc">$6<ex>v</ex></ph>
   </message>
   <message name="IDS_KSV_DESCRIPTION_SWITCH_FOCUS" desc="Description of the command in keyboard shortcut viewer.">
     Switch focus between: Status area (where your account picture appears) Launcher Address bar Bookmarks bar (if visible) The webpage that's open Downloads bar (if visible)
   </message>
   <message name="IDS_KSV_SHORTCUT_SWITCH_FOCUS" desc="Human readable version of the keyboard shortcut.">
-    <ph name="ctrl1">$1</ph><ph name="separator1">$2</ph><ph name="left">$3</ph> or <ph name="ctrl2">$4</ph><ph name="separator2">$5</ph><ph name="right">$6</ph>
+    <ph name="ctrl1">$1<ex>Ctrl</ex></ph><ph name="separator1">$2<ex>+</ex></ph><ph name="left">$3<ex>v</ex></ph> or <ph name="ctrl2">$4<ex>Ctrl</ex></ph><ph name="separator2">$5<ex>+</ex></ph><ph name="right">$6<ex>v</ex></ph>
   </message>
   <message name="IDS_KSV_DESCRIPTION_OPEN_RIGHT_CLICK_MENU_FOR_HIGHLIGHTED_ITEM" desc="Description of the command in keyboard shortcut viewer.">
     Open right-click menu for highlighted item
diff --git a/ash/message_center/message_center_button_bar.cc b/ash/message_center/message_center_button_bar.cc
index 9a33c69..d16480d 100644
--- a/ash/message_center/message_center_button_bar.cc
+++ b/ash/message_center/message_center_button_bar.cc
@@ -6,6 +6,7 @@
 
 #include "ash/message_center/message_center_style.h"
 #include "ash/message_center/message_center_view.h"
+#include "ash/public/cpp/ash_features.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/system/tray/tray_popup_utils.h"
@@ -35,7 +36,6 @@
 #include "ui/views/controls/button/menu_button_listener.h"
 #include "ui/views/controls/label.h"
 #include "ui/views/controls/menu/menu_runner.h"
-#include "ui/views/controls/separator.h"
 #include "ui/views/layout/box_layout.h"
 #include "ui/views/layout/grid_layout.h"
 #include "ui/views/painter.h"
@@ -112,14 +112,15 @@
       notification_label_(nullptr),
       button_container_(nullptr),
       close_all_button_(nullptr),
-      settings_button_(nullptr),
-      quiet_mode_button_(nullptr) {
+      quiet_mode_button_(nullptr),
+      settings_button_(nullptr) {
   SetPaintToLayer();
   SetBackground(
       views::CreateSolidBackground(message_center_style::kBackgroundColor));
   SetBorder(views::CreateEmptyBorder(kButtonBarBorder));
 
-  notification_label_ = new views::Label(GetTitle(locked));
+  notification_label_ = new views::Label(
+      GetTitle(!locked || features::IsLockScreenNotificationsEnabled()));
   notification_label_->SetAutoColorReadabilityEnabled(false);
   notification_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
   notification_label_->SetEnabledColor(kTextColor);
@@ -148,7 +149,8 @@
   close_all_button_->SetTooltipText(l10n_util::GetStringUTF16(
       IDS_ASH_MESSAGE_CENTER_CLEAR_ALL_BUTTON_TOOLTIP));
   button_container_->AddChildView(close_all_button_);
-  button_container_->AddChildView(CreateVerticalSeparator());
+  separator_1_ = CreateVerticalSeparator();
+  button_container_->AddChildView(separator_1_);
 
   quiet_mode_button_ = new MessageCenterButton(this);
   quiet_mode_button_->SetImage(
@@ -166,7 +168,18 @@
       IDS_ASH_MESSAGE_CENTER_QUIET_MODE_BUTTON_TOOLTIP));
   SetQuietModeState(message_center->IsQuietMode());
   button_container_->AddChildView(quiet_mode_button_);
-  button_container_->AddChildView(CreateVerticalSeparator());
+  separator_2_ = CreateVerticalSeparator();
+  button_container_->AddChildView(separator_2_);
+
+  settings_button_ = new MessageCenterButton(this);
+  settings_button_->SetImage(
+      views::Button::STATE_NORMAL,
+      gfx::CreateVectorIcon(kNotificationCenterSettingsIcon,
+                            message_center_style::kActionIconSize,
+                            message_center_style::kActiveButtonColor));
+  settings_button_->SetTooltipText(l10n_util::GetStringUTF16(
+      IDS_ASH_MESSAGE_CENTER_SETTINGS_BUTTON_TOOLTIP));
+  button_container_->AddChildView(settings_button_);
 
   collapse_button_ = new MessageCenterButton(this);
   collapse_button_->SetVisible(false);
@@ -182,16 +195,6 @@
       IDS_ASH_MESSAGE_CENTER_COLLAPSE_BUTTON_TOOLTIP));
   AddChildView(collapse_button_);
 
-  settings_button_ = new MessageCenterButton(this);
-  settings_button_->SetImage(
-      views::Button::STATE_NORMAL,
-      gfx::CreateVectorIcon(kNotificationCenterSettingsIcon,
-                            message_center_style::kActionIconSize,
-                            message_center_style::kActiveButtonColor));
-  settings_button_->SetTooltipText(l10n_util::GetStringUTF16(
-      IDS_ASH_MESSAGE_CENTER_SETTINGS_BUTTON_TOOLTIP));
-  button_container_->AddChildView(settings_button_);
-
   AddChildView(button_container_);
 
   SetCloseAllButtonEnabled(!settings_initially_visible);
@@ -274,32 +277,36 @@
 }
 
 void MessageCenterButtonBar::SetIsLocked(bool locked) {
-  SetButtonsVisible(!locked);
-  UpdateLabel(locked);
+  SetButtonsVisible(locked);
+  UpdateLabel(!locked || features::IsLockScreenNotificationsEnabled());
 }
 
-base::string16 MessageCenterButtonBar::GetTitle(bool locked) const {
-  return locked
-             ? l10n_util::GetStringUTF16(
-                   IDS_ASH_MESSAGE_CENTER_FOOTER_LOCKSCREEN)
-             : l10n_util::GetStringUTF16(IDS_ASH_MESSAGE_CENTER_FOOTER_TITLE);
+base::string16 MessageCenterButtonBar::GetTitle(
+    bool message_center_visible) const {
+  return message_center_visible
+             ? l10n_util::GetStringUTF16(IDS_ASH_MESSAGE_CENTER_FOOTER_TITLE)
+             : l10n_util::GetStringUTF16(
+                   IDS_ASH_MESSAGE_CENTER_FOOTER_LOCKSCREEN);
 }
 
-void MessageCenterButtonBar::UpdateLabel(bool locked) {
-  notification_label_->SetText(GetTitle(locked));
+void MessageCenterButtonBar::UpdateLabel(bool message_center_visible) {
+  notification_label_->SetText(GetTitle(message_center_visible));
   // On lock screen button bar label contains hint for user to unlock device to
   // view notifications. Making it focusable will invoke ChromeVox spoken
   // feedback when shown.
-  notification_label_->SetFocusBehavior(locked ? FocusBehavior::ALWAYS
-                                               : FocusBehavior::NEVER);
+  notification_label_->SetFocusBehavior(
+      message_center_visible ? FocusBehavior::ALWAYS : FocusBehavior::NEVER);
 }
 
-void MessageCenterButtonBar::SetButtonsVisible(bool visible) {
-  settings_button_->SetVisible(visible);
-  quiet_mode_button_->SetVisible(visible);
-
+void MessageCenterButtonBar::SetButtonsVisible(bool locked) {
+  bool message_center_visible =
+      !locked || features::IsLockScreenNotificationsEnabled();
   if (close_all_button_)
-    close_all_button_->SetVisible(visible);
+    close_all_button_->SetVisible(message_center_visible);
+  separator_1_->SetVisible(message_center_visible);
+  quiet_mode_button_->SetVisible(message_center_visible);
+  separator_2_->SetVisible(!locked);
+  settings_button_->SetVisible(!locked);
 
   Layout();
 }
diff --git a/ash/message_center/message_center_button_bar.h b/ash/message_center/message_center_button_bar.h
index 210e0aa..1b7c7e6 100644
--- a/ash/message_center/message_center_button_bar.h
+++ b/ash/message_center/message_center_button_bar.h
@@ -10,6 +10,7 @@
 #include "ui/compositor/layer_animation_observer.h"
 #include "ui/views/controls/button/button.h"
 #include "ui/views/controls/button/image_button.h"
+#include "ui/views/controls/separator.h"
 #include "ui/views/view.h"
 
 namespace views {
@@ -77,13 +78,13 @@
     return message_center_;
   }
 
-  // Returns title for state specified by |locked|.
-  base::string16 GetTitle(bool locked) const;
+  // Returns title for state specified by |message_center_visible|.
+  base::string16 GetTitle(bool message_center_visible) const;
 
-  // Updates notification label for state specified by |locked|.
-  void UpdateLabel(bool locked);
+  // Updates notification label for state specified by |message_center_visible|.
+  void UpdateLabel(bool message_center_visible);
 
-  void SetButtonsVisible(bool visible);
+  void SetButtonsVisible(bool locked);
 
   MessageCenterView* message_center_view_;
   message_center::MessageCenter* message_center_;
@@ -92,8 +93,12 @@
   views::Label* notification_label_;
   views::View* button_container_;
   views::ToggleImageButton* close_all_button_;
-  views::ToggleImageButton* settings_button_;
+  // A view of a separator between |close_all_button_| and |quiet_mode_button_|.
+  views::Separator* separator_1_;
   views::ToggleImageButton* quiet_mode_button_;
+  // A view of a separator between |quiet_mode_button_| and |settings_button_|.
+  views::Separator* separator_2_;
+  views::ToggleImageButton* settings_button_;
   views::ToggleImageButton* collapse_button_;
 
   bool collapse_button_visible_ = false;
diff --git a/ash/message_center/message_center_view.cc b/ash/message_center/message_center_view.cc
index 6be9fffc..c8623ebb 100644
--- a/ash/message_center/message_center_view.cc
+++ b/ash/message_center/message_center_view.cc
@@ -10,6 +10,7 @@
 #include "ash/message_center/message_center_button_bar.h"
 #include "ash/message_center/message_center_style.h"
 #include "ash/message_center/notifier_settings_view.h"
+#include "ash/public/cpp/ash_features.h"
 #include "ash/public/cpp/ash_switches.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/session/session_controller.h"
@@ -191,7 +192,7 @@
       ui_controller_(ui_controller),
       settings_visible_(initially_settings_visible),
       is_locked_(Shell::Get()->session_controller()->IsScreenLocked()) {
-  if (is_locked_)
+  if (is_locked_ && !features::IsLockScreenNotificationsEnabled())
     mode_ = Mode::LOCKED;
   else if (initially_settings_visible)
     mode_ = Mode::SETTINGS;
@@ -580,7 +581,7 @@
 void MessageCenterView::Update(bool animate) {
   bool no_message_views = (message_list_view_->GetNotificationCount() == 0);
 
-  if (is_locked_)
+  if (is_locked_ && !features::IsLockScreenNotificationsEnabled())
     SetVisibilityMode(Mode::LOCKED, animate);
   else if (settings_visible_)
     SetVisibilityMode(Mode::SETTINGS, animate);
@@ -684,8 +685,7 @@
   button_bar_->SetBackArrowVisible(mode_ == Mode::SETTINGS);
   button_bar_->SetIsLocked(is_locked_);
 
-  if (!is_locked_)
-    EnableCloseAllIfAppropriate();
+  EnableCloseAllIfAppropriate();
 }
 
 void MessageCenterView::EnableCloseAllIfAppropriate() {
diff --git a/ash/message_center/message_center_view_unittest.cc b/ash/message_center/message_center_view_unittest.cc
index 67c7a27..24cc06b8 100644
--- a/ash/message_center/message_center_view_unittest.cc
+++ b/ash/message_center/message_center_view_unittest.cc
@@ -11,11 +11,13 @@
 #include "ash/message_center/message_center_button_bar.h"
 #include "ash/message_center/message_center_style.h"
 #include "ash/message_center/message_list_view.h"
+#include "ash/public/cpp/ash_features.h"
 #include "ash/test/ash_test_base.h"
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_feature_list.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/message_center/fake_message_center.h"
 #include "ui/message_center/notification_list.h"
@@ -43,6 +45,12 @@
 const char* kNotificationId1 = "notification id 1";
 const char* kNotificationId2 = "notification id 2";
 
+// Plain button bar height (56)
+const int kLockedMessageCenterViewHeight = 56;
+
+// Plain button bar height (56) + Empty view (96)
+const int kEmptyMessageCenterViewHeight = 152;
+
 /* Types **********************************************************************/
 
 enum CallType { GET_PREFERRED_SIZE, GET_HEIGHT_FOR_WIDTH, LAYOUT };
@@ -158,6 +166,7 @@
 /* Test fixture ***************************************************************/
 
 class MessageCenterViewTest : public AshTestBase,
+                              public testing::WithParamInterface<bool>,
                               public MockNotificationView::Test,
                               views::BoundsAnimatorObserver {
  public:
@@ -204,6 +213,8 @@
   void WaitForAnimationToFinish();
 
  private:
+  void SetLockScreenNotificationsEnabled();
+
   views::View* MakeParent(views::View* child1, views::View* child2);
 
   // The ownership map of notifications; the key is the id.
@@ -215,15 +226,23 @@
 
   std::unique_ptr<base::RunLoop> run_loop_;
 
+  bool is_lock_screen_notifications_enabled_;
+  base::test::ScopedFeatureList scoped_feature_list_;
+
   DISALLOW_COPY_AND_ASSIGN(MessageCenterViewTest);
 };
 
-MessageCenterViewTest::MessageCenterViewTest() = default;
+MessageCenterViewTest::MessageCenterViewTest()
+    : is_lock_screen_notifications_enabled_(GetParam()) {}
 
 MessageCenterViewTest::~MessageCenterViewTest() = default;
 
 void MessageCenterViewTest::SetUp() {
   AshTestBase::SetUp();
+
+  if (is_lock_screen_notifications_enabled_)
+    SetLockScreenNotificationsEnabled();
+
   MessageCenterView::disable_animation_for_testing = true;
   message_center_.reset(new FakeMessageCenterImpl());
 
@@ -400,9 +419,13 @@
   }
 }
 
+void MessageCenterViewTest::SetLockScreenNotificationsEnabled() {
+  scoped_feature_list_.InitAndEnableFeature(features::kLockScreenNotifications);
+}
+
 /* Unit tests *****************************************************************/
 
-TEST_F(MessageCenterViewTest, CallTest) {
+TEST_P(MessageCenterViewTest, CallTest) {
   // Verify that this didn't generate more than 2 Layout() call per descendant
   // NotificationView or more than a total of 20 GetPreferredSize() and
   // GetHeightForWidth() calls per descendant NotificationView. 20 is a very
@@ -414,7 +437,7 @@
       GetNotificationCount() * 20);
 }
 
-TEST_F(MessageCenterViewTest, Size) {
+TEST_P(MessageCenterViewTest, Size) {
   EXPECT_EQ(2, GetMessageListView()->child_count());
   EXPECT_EQ(GetMessageListView()->height(),
             GetCalculatedMessageListViewHeight());
@@ -432,7 +455,7 @@
 // TODO(tetsui): The test is broken because there's no guarantee anymore that
 // height would change after setting longer message, as NotificationViewMD
 // implements collapse / expand functionality of long message.
-TEST_F(MessageCenterViewTest, DISABLED_SizeAfterUpdate) {
+TEST_P(MessageCenterViewTest, DISABLED_SizeAfterUpdate) {
   EXPECT_EQ(2, GetMessageListView()->child_count());
   int width =
       GetMessageListView()->width() - GetMessageListView()->GetInsets().width();
@@ -473,7 +496,7 @@
           GetMessageListView()->GetInsets().height());
 }
 
-TEST_F(MessageCenterViewTest, SizeAfterUpdateBelowWithRepositionTarget) {
+TEST_P(MessageCenterViewTest, SizeAfterUpdateBelowWithRepositionTarget) {
   EXPECT_EQ(2, GetMessageListView()->child_count());
   // Make sure that notification 2 is placed above notification 1.
   EXPECT_LT(GetNotificationView(kNotificationId2)->bounds().y(),
@@ -503,7 +526,7 @@
           GetMessageListView()->GetInsets().height());
 }
 
-TEST_F(MessageCenterViewTest, SizeAfterUpdateOfRepositionTarget) {
+TEST_P(MessageCenterViewTest, SizeAfterUpdateOfRepositionTarget) {
   EXPECT_EQ(2, GetMessageListView()->child_count());
   // Make sure that notification 2 is placed above notification 1.
   EXPECT_LT(GetNotificationView(kNotificationId2)->bounds().y(),
@@ -533,7 +556,7 @@
           GetMessageListView()->GetInsets().height());
 }
 
-TEST_F(MessageCenterViewTest, SizeAfterRemove) {
+TEST_P(MessageCenterViewTest, SizeAfterRemove) {
   int original_height = GetMessageListView()->height();
   EXPECT_EQ(2, GetMessageListView()->child_count());
   RemoveNotification(kNotificationId1, false);
@@ -547,7 +570,7 @@
   EXPECT_EQ(original_height, GetMessageListView()->height());
 }
 
-TEST_F(MessageCenterViewTest, PositionAfterUpdate) {
+TEST_P(MessageCenterViewTest, PositionAfterUpdate) {
   // Make sure that the notification 2 is placed above the notification 1.
   EXPECT_LT(GetNotificationView(kNotificationId2)->bounds().y(),
             GetNotificationView(kNotificationId1)->bounds().y());
@@ -577,7 +600,7 @@
             current_vertical_pos_from_bottom);
 }
 
-TEST_F(MessageCenterViewTest, PositionAfterRemove) {
+TEST_P(MessageCenterViewTest, PositionAfterRemove) {
   // Make sure that the notification 2 is placed above the notification 1.
   EXPECT_LT(GetNotificationView(kNotificationId2)->bounds().y(),
             GetNotificationView(kNotificationId1)->bounds().y());
@@ -614,7 +637,7 @@
   EXPECT_EQ(previous_height, GetMessageListView()->height());
 }
 
-TEST_F(MessageCenterViewTest, CloseButton) {
+TEST_P(MessageCenterViewTest, CloseButton) {
   views::Button* close_button = GetButtonBar()->GetCloseAllButtonForTest();
   EXPECT_NE(nullptr, close_button);
 
@@ -623,7 +646,7 @@
   EXPECT_TRUE(GetMessageCenter()->remove_all_closable_notification_called_);
 }
 
-TEST_F(MessageCenterViewTest, CloseButtonEnablity) {
+TEST_P(MessageCenterViewTest, CloseButtonEnablity) {
   views::Button* close_button = GetButtonBar()->GetCloseAllButtonForTest();
   EXPECT_NE(nullptr, close_button);
 
@@ -720,7 +743,7 @@
   EXPECT_FALSE(close_button->enabled());
 }
 
-TEST_F(MessageCenterViewTest, CheckModeWithSettingsVisibleAndHidden) {
+TEST_P(MessageCenterViewTest, CheckModeWithSettingsVisibleAndHidden) {
   // Check the initial state.
   EXPECT_EQ(Mode::NOTIFICATIONS, GetMessageCenterViewInternalMode());
   // Show the settings.
@@ -731,7 +754,7 @@
   EXPECT_EQ(Mode::NOTIFICATIONS, GetMessageCenterViewInternalMode());
 }
 
-TEST_F(MessageCenterViewTest, CheckModeWithRemovingAndAddingNotifications) {
+TEST_P(MessageCenterViewTest, CheckModeWithRemovingAndAddingNotifications) {
   // Check the initial state.
   EXPECT_EQ(Mode::NOTIFICATIONS, GetMessageCenterViewInternalMode());
 
@@ -750,7 +773,7 @@
   EXPECT_EQ(Mode::NOTIFICATIONS, GetMessageCenterViewInternalMode());
 }
 
-TEST_F(MessageCenterViewTest, CheckModeWithSettingsVisibleAndHiddenOnEmpty) {
+TEST_P(MessageCenterViewTest, CheckModeWithSettingsVisibleAndHiddenOnEmpty) {
   // Set up by removing all existing notifications.
   RemoveDefaultNotifications();
 
@@ -764,7 +787,7 @@
   EXPECT_EQ(Mode::NO_NOTIFICATIONS, GetMessageCenterViewInternalMode());
 }
 
-TEST_F(MessageCenterViewTest,
+TEST_P(MessageCenterViewTest,
        CheckModeWithRemovingNotificationDuringSettingsVisible) {
   // Check the initial state.
   EXPECT_EQ(Mode::NOTIFICATIONS, GetMessageCenterViewInternalMode());
@@ -782,7 +805,7 @@
   EXPECT_EQ(Mode::NO_NOTIFICATIONS, GetMessageCenterViewInternalMode());
 }
 
-TEST_F(MessageCenterViewTest,
+TEST_P(MessageCenterViewTest,
        CheckModeWithAddingNotificationDuringSettingsVisible) {
   // Set up by removing all existing notifications.
   RemoveDefaultNotifications();
@@ -809,13 +832,15 @@
   EXPECT_EQ(Mode::NOTIFICATIONS, GetMessageCenterViewInternalMode());
 }
 
-TEST_F(MessageCenterViewTest, CheckModeWithLockingAndUnlocking) {
+TEST_P(MessageCenterViewTest, CheckModeWithLockingAndUnlocking) {
   // Check the initial state.
   EXPECT_EQ(Mode::NOTIFICATIONS, GetMessageCenterViewInternalMode());
 
   // Lock!
   SetLockedState(true);
-  EXPECT_EQ(Mode::LOCKED, GetMessageCenterViewInternalMode());
+  EXPECT_EQ(features::IsLockScreenNotificationsEnabled() ? Mode::NOTIFICATIONS
+                                                         : Mode::LOCKED,
+            GetMessageCenterViewInternalMode());
 
   // Unlock!
   SetLockedState(false);
@@ -827,24 +852,32 @@
 
   // Lock!
   SetLockedState(true);
-  EXPECT_EQ(Mode::LOCKED, GetMessageCenterViewInternalMode());
+  EXPECT_EQ(features::IsLockScreenNotificationsEnabled()
+                ? Mode::NO_NOTIFICATIONS
+                : Mode::LOCKED,
+            GetMessageCenterViewInternalMode());
 
   // Unlock!
   SetLockedState(false);
   EXPECT_EQ(Mode::NO_NOTIFICATIONS, GetMessageCenterViewInternalMode());
 }
 
-TEST_F(MessageCenterViewTest, CheckModeWithRemovingNotificationDuringLock) {
+TEST_P(MessageCenterViewTest, CheckModeWithRemovingNotificationDuringLock) {
   // Check the initial state.
   EXPECT_EQ(Mode::NOTIFICATIONS, GetMessageCenterViewInternalMode());
 
   // Lock!
   SetLockedState(true);
-
-  EXPECT_EQ(Mode::LOCKED, GetMessageCenterViewInternalMode());
+  EXPECT_EQ(features::IsLockScreenNotificationsEnabled() ? Mode::NOTIFICATIONS
+                                                         : Mode::LOCKED,
+            GetMessageCenterViewInternalMode());
 
   // Remove all existing notifications.
   RemoveDefaultNotifications();
+  EXPECT_EQ(features::IsLockScreenNotificationsEnabled()
+                ? Mode::NO_NOTIFICATIONS
+                : Mode::LOCKED,
+            GetMessageCenterViewInternalMode());
 
   // Unlock!
   SetLockedState(false);
@@ -852,22 +885,19 @@
   EXPECT_EQ(Mode::NO_NOTIFICATIONS, GetMessageCenterViewInternalMode());
 }
 
-TEST_F(MessageCenterViewTest, LockScreen) {
-  // Plain button bar height (56)
-  const int kLockedMessageCenterViewHeight = 56;
-
+TEST_P(MessageCenterViewTest, LockScreen) {
   EXPECT_TRUE(GetNotificationView(kNotificationId1)->IsDrawn());
   EXPECT_TRUE(GetNotificationView(kNotificationId2)->IsDrawn());
 
   views::Button* close_button = GetButtonBar()->GetCloseAllButtonForTest();
-  ASSERT_NE(nullptr, close_button);
+  ASSERT_TRUE(close_button);
   views::Button* quiet_mode_button =
       GetButtonBar()->GetQuietModeButtonForTest();
-  ASSERT_NE(nullptr, quiet_mode_button);
+  ASSERT_TRUE(quiet_mode_button);
   views::Button* settings_button = GetButtonBar()->GetSettingsButtonForTest();
-  ASSERT_NE(nullptr, settings_button);
+  ASSERT_TRUE(settings_button);
   views::Button* collapse_button = GetButtonBar()->GetCollapseButtonForTest();
-  ASSERT_NE(nullptr, collapse_button);
+  ASSERT_TRUE(collapse_button);
 
   EXPECT_TRUE(close_button->visible());
   EXPECT_TRUE(quiet_mode_button->visible());
@@ -876,21 +906,39 @@
   // Lock!
   SetLockedState(true);
 
-  EXPECT_FALSE(GetNotificationView(kNotificationId1)->IsDrawn());
-  EXPECT_FALSE(GetNotificationView(kNotificationId2)->IsDrawn());
+  if (features::IsLockScreenNotificationsEnabled()) {
+    EXPECT_TRUE(GetNotificationView(kNotificationId1)->IsDrawn());
+    EXPECT_TRUE(GetNotificationView(kNotificationId2)->IsDrawn());
+  } else {
+    EXPECT_FALSE(GetNotificationView(kNotificationId1)->IsDrawn());
+    EXPECT_FALSE(GetNotificationView(kNotificationId2)->IsDrawn());
+  }
 
   GetMessageCenterView()->SizeToPreferredSize();
-  EXPECT_EQ(kLockedMessageCenterViewHeight, GetMessageCenterView()->height());
+  if (features::IsLockScreenNotificationsEnabled()) {
+    EXPECT_NE(kLockedMessageCenterViewHeight, GetMessageCenterView()->height());
+    EXPECT_NE(kEmptyMessageCenterViewHeight, GetMessageCenterView()->height());
+  } else {
+    EXPECT_EQ(kLockedMessageCenterViewHeight, GetMessageCenterView()->height());
+  }
 
   RemoveNotification(kNotificationId1, false);
 
   GetMessageCenterView()->SizeToPreferredSize();
-  EXPECT_EQ(kLockedMessageCenterViewHeight, GetMessageCenterView()->height());
+  if (features::IsLockScreenNotificationsEnabled()) {
+    EXPECT_NE(kLockedMessageCenterViewHeight, GetMessageCenterView()->height());
+    EXPECT_NE(kEmptyMessageCenterViewHeight, GetMessageCenterView()->height());
+  } else {
+    EXPECT_EQ(kLockedMessageCenterViewHeight, GetMessageCenterView()->height());
+  }
 
   RemoveNotification(kNotificationId2, false);
 
   GetMessageCenterView()->SizeToPreferredSize();
-  EXPECT_EQ(kLockedMessageCenterViewHeight, GetMessageCenterView()->height());
+  if (features::IsLockScreenNotificationsEnabled())
+    EXPECT_EQ(kEmptyMessageCenterViewHeight, GetMessageCenterView()->height());
+  else
+    EXPECT_EQ(kLockedMessageCenterViewHeight, GetMessageCenterView()->height());
 
   AddNotification(std::make_unique<Notification>(
       NOTIFICATION_TYPE_SIMPLE, std::string(kNotificationId1),
@@ -898,13 +946,26 @@
       base::UTF8ToUTF16("display source"), GURL(),
       NotifierId(NotifierId::APPLICATION, "extension_id"),
       message_center::RichNotificationData(), nullptr));
-  EXPECT_FALSE(GetNotificationView(kNotificationId1)->IsDrawn());
+  if (features::IsLockScreenNotificationsEnabled())
+    EXPECT_TRUE(GetNotificationView(kNotificationId1)->IsDrawn());
+  else
+    EXPECT_FALSE(GetNotificationView(kNotificationId1)->IsDrawn());
 
   GetMessageCenterView()->SizeToPreferredSize();
-  EXPECT_EQ(kLockedMessageCenterViewHeight, GetMessageCenterView()->height());
+  if (features::IsLockScreenNotificationsEnabled()) {
+    EXPECT_NE(kLockedMessageCenterViewHeight, GetMessageCenterView()->height());
+    EXPECT_NE(kEmptyMessageCenterViewHeight, GetMessageCenterView()->height());
+  } else {
+    EXPECT_EQ(kLockedMessageCenterViewHeight, GetMessageCenterView()->height());
+  }
 
-  EXPECT_FALSE(close_button->visible());
-  EXPECT_FALSE(quiet_mode_button->visible());
+  if (features::IsLockScreenNotificationsEnabled()) {
+    EXPECT_TRUE(close_button->visible());
+    EXPECT_TRUE(quiet_mode_button->visible());
+  } else {
+    EXPECT_FALSE(close_button->visible());
+    EXPECT_FALSE(quiet_mode_button->visible());
+  }
   EXPECT_FALSE(settings_button->visible());
   EXPECT_FALSE(collapse_button->visible());
 
@@ -915,6 +976,7 @@
 
   GetMessageCenterView()->SizeToPreferredSize();
   EXPECT_NE(kLockedMessageCenterViewHeight, GetMessageCenterView()->height());
+  EXPECT_NE(kEmptyMessageCenterViewHeight, GetMessageCenterView()->height());
 
   EXPECT_TRUE(close_button->visible());
   EXPECT_TRUE(quiet_mode_button->visible());
@@ -923,21 +985,31 @@
   // Lock!
   SetLockedState(true);
 
-  EXPECT_FALSE(GetNotificationView(kNotificationId1)->IsDrawn());
+  if (features::IsLockScreenNotificationsEnabled())
+    EXPECT_TRUE(GetNotificationView(kNotificationId1)->IsDrawn());
+  else
+    EXPECT_FALSE(GetNotificationView(kNotificationId1)->IsDrawn());
 
   GetMessageCenterView()->SizeToPreferredSize();
-  EXPECT_EQ(kLockedMessageCenterViewHeight, GetMessageCenterView()->height());
+  if (features::IsLockScreenNotificationsEnabled()) {
+    EXPECT_NE(kLockedMessageCenterViewHeight, GetMessageCenterView()->height());
+    EXPECT_NE(kEmptyMessageCenterViewHeight, GetMessageCenterView()->height());
+  } else {
+    EXPECT_EQ(kLockedMessageCenterViewHeight, GetMessageCenterView()->height());
+  }
 
-  EXPECT_FALSE(close_button->visible());
-  EXPECT_FALSE(quiet_mode_button->visible());
+  if (features::IsLockScreenNotificationsEnabled()) {
+    EXPECT_TRUE(close_button->visible());
+    EXPECT_TRUE(quiet_mode_button->visible());
+  } else {
+    EXPECT_FALSE(close_button->visible());
+    EXPECT_FALSE(quiet_mode_button->visible());
+  }
   EXPECT_FALSE(settings_button->visible());
   EXPECT_FALSE(collapse_button->visible());
 }
 
-TEST_F(MessageCenterViewTest, NoNotification) {
-  // Plain button bar height (56) + Empty view (96)
-  const int kEmptyMessageCenterViewHeight = 152;
-
+TEST_P(MessageCenterViewTest, NoNotification) {
   GetMessageCenterView()->SizeToPreferredSize();
   EXPECT_NE(kEmptyMessageCenterViewHeight, GetMessageCenterView()->height());
   RemoveNotification(kNotificationId1, false);
@@ -958,4 +1030,8 @@
   EXPECT_NE(kEmptyMessageCenterViewHeight, GetMessageCenterView()->height());
 }
 
+INSTANTIATE_TEST_CASE_P(IsLockScreenNotificationsEnabled,
+                        MessageCenterViewTest,
+                        testing::Bool());
+
 }  // namespace ash
diff --git a/ash/public/cpp/ash_features.cc b/ash/public/cpp/ash_features.cc
index cebb067..a335c2e 100644
--- a/ash/public/cpp/ash_features.cc
+++ b/ash/public/cpp/ash_features.cc
@@ -19,6 +19,9 @@
 const base::Feature kSystemTrayUnified{"SystemTrayUnified",
                                        base::FEATURE_DISABLED_BY_DEFAULT};
 
+const base::Feature kLockScreenNotifications{"LockScreenNotifications",
+                                             base::FEATURE_DISABLED_BY_DEFAULT};
+
 bool IsDockedMagnifierEnabled() {
   return base::FeatureList::IsEnabled(kDockedMagnifier);
 }
@@ -35,5 +38,9 @@
   return base::FeatureList::IsEnabled(kSystemTrayUnified);
 }
 
+bool IsLockScreenNotificationsEnabled() {
+  return base::FeatureList::IsEnabled(kLockScreenNotifications);
+}
+
 }  // namespace features
 }  // namespace ash
diff --git a/ash/public/cpp/ash_features.h b/ash/public/cpp/ash_features.h
index ccc0974..55a4366 100644
--- a/ash/public/cpp/ash_features.h
+++ b/ash/public/cpp/ash_features.h
@@ -29,6 +29,9 @@
 // Enables new system menu.
 ASH_PUBLIC_EXPORT extern const base::Feature kSystemTrayUnified;
 
+// Enables notifications on the lock screen.
+ASH_PUBLIC_EXPORT extern const base::Feature kLockScreenNotifications;
+
 ASH_PUBLIC_EXPORT bool IsDockedMagnifierEnabled();
 
 ASH_PUBLIC_EXPORT bool IsKeyboardShortcutViewerEnabled();
@@ -37,6 +40,8 @@
 
 ASH_PUBLIC_EXPORT bool IsSystemTrayUnifiedEnabled();
 
+ASH_PUBLIC_EXPORT bool IsLockScreenNotificationsEnabled();
+
 }  // namespace features
 }  // namespace ash
 
diff --git a/ash/system/web_notification/session_state_notification_blocker.cc b/ash/system/web_notification/session_state_notification_blocker.cc
index 97919f2..e01c4b3 100644
--- a/ash/system/web_notification/session_state_notification_blocker.cc
+++ b/ash/system/web_notification/session_state_notification_blocker.cc
@@ -4,6 +4,7 @@
 
 #include "ash/system/web_notification/session_state_notification_blocker.h"
 
+#include "ash/public/cpp/ash_features.h"
 #include "ash/session/session_controller.h"
 #include "ash/shell.h"
 #include "ui/message_center/message_center.h"
@@ -19,7 +20,8 @@
       Shell::Get()->session_controller();
 
   return !session_controller->IsRunningInAppMode() &&
-         !session_controller->IsScreenLocked();
+         (!session_controller->IsScreenLocked() ||
+          features::IsLockScreenNotificationsEnabled());
 }
 
 bool CalculateShouldShowPopup() {
diff --git a/ash/wm/window_positioner.cc b/ash/wm/window_positioner.cc
index a40a557..880eaa2 100644
--- a/ash/wm/window_positioner.cc
+++ b/ash/wm/window_positioner.cc
@@ -34,9 +34,6 @@
 // WindowPositioner::SetIgnoreActivations().
 static bool disable_auto_positioning = false;
 
-// If set to true, by default the first window in ASH will be maximized.
-static bool maximize_first_window = false;
-
 // Check if any management should be performed (with a given |window|).
 bool UseAutoWindowManager(const aura::Window* window) {
   if (disable_auto_positioning)
@@ -240,7 +237,6 @@
       // We want to always open maximized on "small screens" or when policy
       // tells us to.
       const bool set_maximized =
-          maximize_first_window ||
           ((work_area.width() <= GetForceMaximizedWidthLimit() ||
             maximize_first_window_on_first_run) &&
            (!new_window || !wm::GetWindowState(new_window)->IsFullscreen()));
@@ -414,11 +410,6 @@
   return NormalPopupPosition(popup_size, work_area);
 }
 
-// static
-void WindowPositioner::SetMaximizeFirstWindow(bool maximize) {
-  maximize_first_window = maximize;
-}
-
 gfx::Rect WindowPositioner::NormalPopupPosition(const gfx::Size& popup_size,
                                                 const gfx::Rect& work_area) {
   int w = popup_size.width();
diff --git a/ash/wm/window_positioner.h b/ash/wm/window_positioner.h
index fe8ce9c..e0aa78e 100644
--- a/ash/wm/window_positioner.h
+++ b/ash/wm/window_positioner.h
@@ -66,10 +66,6 @@
   // operating systems do (default cascading style).
   gfx::Rect GetPopupPosition(const gfx::Size& popup_size);
 
-  // Accessor to set a flag indicating whether the first window in ASH should
-  // be maximized.
-  static void SetMaximizeFirstWindow(bool maximize);
-
  protected:
   friend class WindowPositionerTest;
 
diff --git a/base/android/build_info.cc b/base/android/build_info.cc
index 1d26a090..80800ea 100644
--- a/base/android/build_info.cc
+++ b/base/android/build_info.cc
@@ -61,16 +61,18 @@
       model_(StrDupParam(params, 4)),
       sdk_int_(SdkIntParam(params, 5)),
       build_type_(StrDupParam(params, 6)),
-      package_label_(StrDupParam(params, 7)),
-      package_name_(StrDupParam(params, 8)),
-      package_version_code_(StrDupParam(params, 9)),
-      package_version_name_(StrDupParam(params, 10)),
-      android_build_fp_(StrDupParam(params, 11)),
-      gms_version_code_(StrDupParam(params, 12)),
-      installer_package_name_(StrDupParam(params, 13)),
-      abi_name_(StrDupParam(params, 14)),
-      firebase_app_id_(StrDupParam(params, 15)),
-      extracted_file_suffix_(params[16]),
+      host_package_name_(StrDupParam(params, 7)),
+      host_version_code_(StrDupParam(params, 8)),
+      host_package_label_(StrDupParam(params, 9)),
+      package_name_(StrDupParam(params, 10)),
+      package_version_code_(StrDupParam(params, 11)),
+      package_version_name_(StrDupParam(params, 12)),
+      android_build_fp_(StrDupParam(params, 13)),
+      gms_version_code_(StrDupParam(params, 14)),
+      installer_package_name_(StrDupParam(params, 15)),
+      abi_name_(StrDupParam(params, 16)),
+      firebase_app_id_(StrDupParam(params, 17)),
+      extracted_file_suffix_(params[18]),
       java_exception_info_(NULL) {}
 
 // static
diff --git a/base/android/build_info.h b/base/android/build_info.h
index e8cf555e..4daca9c4 100644
--- a/base/android/build_info.h
+++ b/base/android/build_info.h
@@ -82,6 +82,12 @@
     return gms_version_code_;
   }
 
+  const char* host_package_name() const { return host_package_name_; }
+
+  const char* host_version_code() const { return host_version_code_; }
+
+  const char* host_package_label() const { return host_package_label_; }
+
   const char* package_version_code() const {
     return package_version_code_;
   }
@@ -90,10 +96,6 @@
     return package_version_name_;
   }
 
-  const char* package_label() const {
-    return package_label_;
-  }
-
   const char* package_name() const {
     return package_name_;
   }
@@ -139,7 +141,9 @@
   const char* const model_;
   const int sdk_int_;
   const char* const build_type_;
-  const char* const package_label_;
+  const char* const host_package_name_;
+  const char* const host_version_code_;
+  const char* const host_package_label_;
   const char* const package_name_;
   const char* const package_version_code_;
   const char* const package_version_name_;
diff --git a/base/android/java/src/org/chromium/base/BuildInfo.java b/base/android/java/src/org/chromium/base/BuildInfo.java
index 5c2a062..b32e288 100644
--- a/base/android/java/src/org/chromium/base/BuildInfo.java
+++ b/base/android/java/src/org/chromium/base/BuildInfo.java
@@ -4,6 +4,7 @@
 
 package org.chromium.base;
 
+import android.content.Context;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
@@ -18,112 +19,116 @@
  * primarily of use for accessing package information from native code.
  */
 public class BuildInfo {
-    /**
-     * Array index to access field in {@link BuildInfo#getAll()}.
-     */
-    public static final int BRAND_INDEX = 0;
-    public static final int DEVICE_INDEX = 1;
-    public static final int ANDROID_BUILD_ID_INDEX = 2;
-    public static final int MODEL_INDEX = 4;
-    public static final int ANDROID_BUILD_FP_INDEX = 11;
-    public static final int GMS_CORE_VERSION_INDEX = 12;
-    public static final int INSTALLER_PACKAGE_NAME_INDEX = 13;
-    public static final int ABI_NAME_INDEX = 14;
-
     private static final String TAG = "BuildInfo";
     private static final int MAX_FINGERPRINT_LENGTH = 128;
 
-    /**
-     * BuildInfo is a static utility class and therefore shouldn't be instantiated.
-     */
-    private BuildInfo() {}
+    private static PackageInfo sBrowserPackageInfo;
+    private static boolean sInitialized;
 
-    @SuppressWarnings("deprecation")
+    /** The application name (e.g. "Chrome"). For WebView, this is name of the embedding app. */
+    public final String hostPackageLabel;
+    /** By default: same as versionCode. For WebView: versionCode of the embedding app. */
+    public final int hostVersionCode;
+    /** The packageName of Chrome/WebView. Use application context for host app packageName. */
+    public final String packageName;
+    /** The versionCode of the apk. */
+    public final int versionCode;
+    /** The versionName of Chrome/WebView. Use application context for host app versionName. */
+    public final String versionName;
+    /** Result of PackageManager.getInstallerPackageName(). Never null, but may be "". */
+    public final String installerPackageName;
+    /** The versionCode of Play Services (for crash reporting). */
+    public final String gmsVersionCode;
+    /** Formatted ABI string (for crash reporting). */
+    public final String abiString;
+    /** Truncated version of Build.FINGERPRINT (for crash reporting). */
+    public final String androidBuildFingerprint;
+    /** A string that is different each time the apk changes. */
+    public final String extractedFileSuffix;
+
+    private static class Holder { private static BuildInfo sInstance = new BuildInfo(); }
+
     @CalledByNative
-    public static String[] getAll() {
+    private static String[] getAll() {
+        BuildInfo buildInfo = getInstance();
+        String hostPackageName = ContextUtils.getApplicationContext().getPackageName();
+        return new String[] {
+                Build.BRAND, Build.DEVICE, Build.ID, Build.MANUFACTURER, Build.MODEL,
+                String.valueOf(Build.VERSION.SDK_INT), Build.TYPE, hostPackageName,
+                String.valueOf(buildInfo.hostVersionCode), buildInfo.hostPackageLabel,
+                buildInfo.packageName, String.valueOf(buildInfo.versionCode), buildInfo.versionName,
+                buildInfo.androidBuildFingerprint, buildInfo.gmsVersionCode,
+                buildInfo.installerPackageName, buildInfo.abiString, BuildConfig.FIREBASE_APP_ID,
+                buildInfo.extractedFileSuffix,
+        };
+    }
+
+    /**
+     * @param packageInfo Package for Chrome/WebView (as opposed to host app).
+     */
+    public static void setBrowserPackageInfo(PackageInfo packageInfo) {
+        assert !sInitialized;
+        sBrowserPackageInfo = packageInfo;
+    }
+
+    public static BuildInfo getInstance() {
+        return Holder.sInstance;
+    }
+
+    private BuildInfo() {
+        sInitialized = true;
         try {
-            String packageName = ContextUtils.getApplicationContext().getPackageName();
-            PackageManager pm = ContextUtils.getApplicationContext().getPackageManager();
-            PackageInfo pi = pm.getPackageInfo(packageName, 0);
-            String versionCode = pi.versionCode <= 0 ? "" : Integer.toString(pi.versionCode);
-            String versionName = pi.versionName == null ? "" : pi.versionName;
-
-            CharSequence label = pm.getApplicationLabel(pi.applicationInfo);
-            String packageLabel = label == null ? "" : label.toString();
-
-            String installerPackageName = pm.getInstallerPackageName(packageName);
-            if (installerPackageName == null) {
-                installerPackageName = "";
+            Context appContext = ContextUtils.getApplicationContext();
+            String hostPackageName = appContext.getPackageName();
+            PackageManager pm = appContext.getPackageManager();
+            PackageInfo pi = pm.getPackageInfo(hostPackageName, 0);
+            hostVersionCode = pi.versionCode;
+            if (sBrowserPackageInfo != null) {
+                packageName = sBrowserPackageInfo.packageName;
+                versionCode = sBrowserPackageInfo.versionCode;
+                versionName = sBrowserPackageInfo.versionName;
+                sBrowserPackageInfo = null;
+            } else {
+                packageName = hostPackageName;
+                versionCode = hostVersionCode;
+                versionName = pi.versionName;
             }
 
-            String abiString = null;
+            CharSequence label = pm.getApplicationLabel(pi.applicationInfo);
+            hostPackageLabel = label == null ? "" : label.toString();
+
+            String value = pm.getInstallerPackageName(packageName);
+            installerPackageName = value == null ? "" : value;
+
+            PackageInfo gmsPackageInfo = null;
+            try {
+                gmsPackageInfo = pm.getPackageInfo("com.google.android.gms", 0);
+            } catch (NameNotFoundException e) {
+                Log.d(TAG, "GMS package is not found.", e);
+            }
+            gmsVersionCode = gmsPackageInfo != null ? String.valueOf(gmsPackageInfo.versionCode)
+                                                    : "gms versionCode not available.";
+
             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                 abiString = TextUtils.join(", ", Build.SUPPORTED_ABIS);
             } else {
-                abiString = "ABI1: " + Build.CPU_ABI + ", ABI2: " + Build.CPU_ABI2;
+                abiString = String.format("ABI1: %s, ABI2: %s", Build.CPU_ABI, Build.CPU_ABI2);
             }
 
             // Use lastUpdateTime when developing locally, since versionCode does not normally
             // change in this case.
-            long version = pi.versionCode > 10 ? pi.versionCode : pi.lastUpdateTime;
-            String extractedFileSuffix = String.format("@%s", Long.toHexString(version));
+            long version = versionCode > 10 ? versionCode : pi.lastUpdateTime;
+            extractedFileSuffix = String.format("@%x", version);
 
-            // Do not alter this list without updating callers of it.
-            return new String[] {
-                    Build.BRAND, Build.DEVICE, Build.ID, Build.MANUFACTURER, Build.MODEL,
-                    String.valueOf(Build.VERSION.SDK_INT), Build.TYPE, packageLabel, packageName,
-                    versionCode, versionName, getAndroidBuildFingerprint(), getGMSVersionCode(pm),
-                    installerPackageName, abiString, BuildConfig.FIREBASE_APP_ID,
-                    extractedFileSuffix,
-            };
+            // The value is truncated, as this is used for crash and UMA reporting.
+            androidBuildFingerprint = Build.FINGERPRINT.substring(
+                    0, Math.min(Build.FINGERPRINT.length(), MAX_FINGERPRINT_LENGTH));
         } catch (NameNotFoundException e) {
             throw new RuntimeException(e);
         }
     }
 
     /**
-     * @return The build fingerprint for the current Android install.  The value is truncated to a
-     * 128 characters as this is used for crash and UMA reporting, which should avoid huge
-     * strings.
-     */
-    private static String getAndroidBuildFingerprint() {
-        return Build.FINGERPRINT.substring(
-                0, Math.min(Build.FINGERPRINT.length(), MAX_FINGERPRINT_LENGTH));
-    }
-
-    private static String getGMSVersionCode(PackageManager packageManager) {
-        String msg = "gms versionCode not available.";
-        try {
-            PackageInfo packageInfo = packageManager.getPackageInfo("com.google.android.gms", 0);
-            msg = Integer.toString(packageInfo.versionCode);
-        } catch (NameNotFoundException e) {
-            Log.d(TAG, "GMS package is not found.", e);
-        }
-        return msg;
-    }
-
-    public static String getPackageVersionCode() {
-        return getAll()[9];
-    }
-
-    public static String getPackageVersionName() {
-        return getAll()[10];
-    }
-
-    /** Returns a string that is different each time the apk changes. */
-    public static String getExtractedFileSuffix() {
-        return getAll()[16];
-    }
-
-    public static String getPackageLabel() {
-        return getAll()[7];
-    }
-
-    public static String getPackageName() {
-        return ContextUtils.getApplicationContext().getPackageName();
-    }
-
-    /**
      * Check if this is a debuggable build of Android. Use this to enable developer-only features.
      */
     public static boolean isDebugAndroid() {
diff --git a/base/android/java/src/org/chromium/base/ResourceExtractor.java b/base/android/java/src/org/chromium/base/ResourceExtractor.java
index 6f6a84c..fbb703b 100644
--- a/base/android/java/src/org/chromium/base/ResourceExtractor.java
+++ b/base/android/java/src/org/chromium/base/ResourceExtractor.java
@@ -64,7 +64,7 @@
 
             // Use a suffix for extracted files in order to guarantee that the version of the file
             // on disk matches up with the version of the APK.
-            String extractSuffix = BuildInfo.getExtractedFileSuffix();
+            String extractSuffix = BuildInfo.getInstance().extractedFileSuffix;
             String[] existingFileNames = outputDir.list();
             boolean allFilesExist = existingFileNames != null;
             if (allFilesExist) {
diff --git a/base/android/library_loader/library_prefetcher.cc b/base/android/library_loader/library_prefetcher.cc
index dda25778..fefbb5e 100644
--- a/base/android/library_loader/library_prefetcher.cc
+++ b/base/android/library_loader/library_prefetcher.cc
@@ -184,9 +184,9 @@
 
 // static
 bool NativeLibraryPrefetcher::ForkAndPrefetchNativeLibrary() {
-  // Avoid forking with cygprofile instrumentation because the latter performs
-  // memory allocations.
 #if defined(CYGPROFILE_INSTRUMENTATION)
+  // Avoid forking with cygprofile instrumentation because the child process
+  // would create a dump as well.
   return false;
 #endif
 
diff --git a/base/strings/strcat.h b/base/strings/strcat.h
index b249d49..44c6211 100644
--- a/base/strings/strcat.h
+++ b/base/strings/strcat.h
@@ -11,6 +11,12 @@
 #include "base/compiler_specific.h"
 #include "base/containers/span.h"
 #include "base/strings/string_piece.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+// To resolve a conflict with Win32 API StrCat macro.
+#include "base/win/windows_types.h"
+#endif
 
 namespace base {
 
diff --git a/base/strings/string_piece.h b/base/strings/string_piece.h
index 0362381..d6236d1 100644
--- a/base/strings/string_piece.h
+++ b/base/strings/string_piece.h
@@ -219,31 +219,16 @@
     length_ = str ? STRING_TYPE::traits_type::length(str) : 0;
   }
 
-  constexpr value_type operator[](size_type i) const {
-    CHECK(i < length_);
-    return ptr_[i];
-  }
-
-  value_type front() const {
-    CHECK_NE(0UL, length_);
-    return ptr_[0];
-  }
-
-  value_type back() const {
-    CHECK_NE(0UL, length_);
-    return ptr_[length_ - 1];
-  }
+  constexpr value_type operator[](size_type i) const { return ptr_[i]; }
+  value_type front() const { return ptr_[0]; }
+  value_type back() const { return ptr_[length_ - 1]; }
 
   constexpr void remove_prefix(size_type n) {
-    CHECK(n <= length_);
     ptr_ += n;
     length_ -= n;
   }
 
-  constexpr void remove_suffix(size_type n) {
-    CHECK(n <= length_);
-    length_ -= n;
-  }
+  constexpr void remove_suffix(size_type n) { length_ -= n; }
 
   int compare(const BasicStringPiece<STRING_TYPE>& x) const {
     int r = wordmemcmp(
@@ -372,7 +357,7 @@
 
  protected:
   const value_type* ptr_;
-  size_type length_;
+  size_type     length_;
 };
 
 template <typename STRING_TYPE>
diff --git a/base/trace_event/auto_open_close_event.cc b/base/trace_event/auto_open_close_event.cc
index f2794f4..1879700 100644
--- a/base/trace_event/auto_open_close_event.cc
+++ b/base/trace_event/auto_open_close_event.cc
@@ -28,7 +28,7 @@
 
 void AutoOpenCloseEvent::Begin() {
   DCHECK(thread_checker_.CalledOnValidThread());
-  start_time_ = base::TimeTicks::Now();
+  start_time_ = TRACE_TIME_TICKS_NOW();
   TRACE_EVENT_ASYNC_BEGIN_WITH_TIMESTAMP0(
       category_, event_name_, static_cast<void*>(this), start_time_);
 }
@@ -49,4 +49,4 @@
 void AutoOpenCloseEvent::OnTraceLogDisabled() {}
 
 }  // namespace trace_event
-}  // namespace base
\ No newline at end of file
+}  // namespace base
diff --git a/base/trace_event/common/trace_event_common.h b/base/trace_event/common/trace_event_common.h
index 51869ee9..8f0e7ba 100644
--- a/base/trace_event/common/trace_event_common.h
+++ b/base/trace_event/common/trace_event_common.h
@@ -1020,6 +1020,14 @@
     }                                                                      \
   } while (0)
 
+// Macro for getting the real base::TimeTicks::Now() which can be overridden in
+// headless when VirtualTime is enabled.
+#define TRACE_TIME_TICKS_NOW() INTERNAL_TRACE_TIME_TICKS_NOW()
+
+// Macro for getting the real base::Time::Now() which can be overridden in
+// headless when VirtualTime is enabled.
+#define TRACE_TIME_NOW() INTERNAL_TRACE_TIME_NOW()
+
 // Notes regarding the following definitions:
 // New values can be added and propagated to third party libraries, but existing
 // definitions must never be changed, because third party libraries may use old
diff --git a/base/trace_event/trace_event.h b/base/trace_event/trace_event.h
index d1f3fc6..38528aa 100644
--- a/base/trace_event/trace_event.h
+++ b/base/trace_event/trace_event.h
@@ -18,6 +18,7 @@
 #include "base/debug/debugging_buildflags.h"
 #include "base/macros.h"
 #include "base/time/time.h"
+#include "base/time/time_override.h"
 #include "base/trace_event/common/trace_event_common.h"
 #include "base/trace_event/heap_profiler.h"
 #include "base/trace_event/trace_category.h"
@@ -249,6 +250,17 @@
         INTERNAL_TRACE_EVENT_UID(atomic), \
         INTERNAL_TRACE_EVENT_UID(category_group_enabled));
 
+// Implementation detail: internal macro to return unoverridden
+// base::TimeTicks::Now(). This is important because in headless VirtualTime can
+// override base:TimeTicks::Now().
+#define INTERNAL_TRACE_TIME_TICKS_NOW() \
+  base::subtle::TimeTicksNowIgnoringOverride()
+
+// Implementation detail: internal macro to return unoverridden
+// base::Time::Now(). This is important because in headless VirtualTime can
+// override base:TimeTicks::Now().
+#define INTERNAL_TRACE_TIME_NOW() base::subtle::TimeNowIgnoringOverride()
+
 // Implementation detail: internal macro to create static category and add
 // event if the category is enabled.
 #define INTERNAL_TRACE_EVENT_ADD(phase, category_group, name, flags, ...)  \
@@ -878,7 +890,7 @@
     unsigned int flags,
     unsigned long long bind_id) {
   const int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
-  const base::TimeTicks now = base::TimeTicks::Now();
+  const base::TimeTicks now = TRACE_TIME_TICKS_NOW();
   return AddTraceEventWithThreadIdAndTimestamp(
       phase, category_group_enabled, name, scope, id, thread_id, now, flags,
       bind_id);
@@ -919,7 +931,7 @@
     const char* arg1_name,
     const ARG1_TYPE& arg1_val) {
   int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
-  base::TimeTicks now = base::TimeTicks::Now();
+  base::TimeTicks now = TRACE_TIME_TICKS_NOW();
   return AddTraceEventWithThreadIdAndTimestamp(
       phase, category_group_enabled, name, scope, id, thread_id, now, flags,
       bind_id, arg1_name, arg1_val);
@@ -937,7 +949,7 @@
     const char* arg1_name,
     std::unique_ptr<ARG1_CONVERTABLE_TYPE> arg1_val) {
   int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
-  base::TimeTicks now = base::TimeTicks::Now();
+  base::TimeTicks now = TRACE_TIME_TICKS_NOW();
   return AddTraceEventWithThreadIdAndTimestamp(
       phase, category_group_enabled, name, scope, id, thread_id, now, flags,
       bind_id, arg1_name, std::move(arg1_val));
@@ -984,7 +996,7 @@
     const char* arg2_name,
     const ARG2_TYPE& arg2_val) {
   int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
-  base::TimeTicks now = base::TimeTicks::Now();
+  base::TimeTicks now = TRACE_TIME_TICKS_NOW();
   return AddTraceEventWithThreadIdAndTimestamp(
       phase, category_group_enabled, name, scope, id, thread_id, now, flags,
       bind_id, arg1_name, std::move(arg1_val), arg2_name, arg2_val);
@@ -1004,7 +1016,7 @@
     const char* arg2_name,
     std::unique_ptr<ARG2_CONVERTABLE_TYPE> arg2_val) {
   int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
-  base::TimeTicks now = base::TimeTicks::Now();
+  base::TimeTicks now = TRACE_TIME_TICKS_NOW();
   return AddTraceEventWithThreadIdAndTimestamp(
       phase, category_group_enabled, name, scope, id, thread_id, now, flags,
       bind_id, arg1_name, arg1_val, arg2_name, std::move(arg2_val));
@@ -1024,7 +1036,7 @@
     const char* arg2_name,
     std::unique_ptr<ARG2_CONVERTABLE_TYPE> arg2_val) {
   int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
-  base::TimeTicks now = base::TimeTicks::Now();
+  base::TimeTicks now = TRACE_TIME_TICKS_NOW();
   return AddTraceEventWithThreadIdAndTimestamp(
       phase, category_group_enabled, name, scope, id, thread_id, now, flags,
       bind_id, arg1_name, std::move(arg1_val), arg2_name, std::move(arg2_val));
@@ -1044,7 +1056,7 @@
     const char* arg2_name,
     const ARG2_TYPE& arg2_val) {
   int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
-  base::TimeTicks now = base::TimeTicks::Now();
+  base::TimeTicks now = TRACE_TIME_TICKS_NOW();
   return AddTraceEventWithThreadIdAndTimestamp(
       phase, category_group_enabled, name, scope, id, thread_id, now, flags,
       bind_id, arg1_name, arg1_val, arg2_name, arg2_val);
diff --git a/base/trace_event/trace_event_android.cc b/base/trace_event/trace_event_android.cc
index 0a4e6ea..30d9c74 100644
--- a/base/trace_event/trace_event_android.cc
+++ b/base/trace_event/trace_event_android.cc
@@ -205,7 +205,7 @@
   // debugfs that takes the written data and pushes it onto the trace
   // buffer. So, to establish clock sync, we write our monotonic clock into that
   // trace buffer.
-  double now_in_seconds = (TimeTicks::Now() - TimeTicks()).InSecondsF();
+  double now_in_seconds = (TRACE_TIME_TICKS_NOW() - TimeTicks()).InSecondsF();
   std::string marker = StringPrintf(
       "trace_event_clock_sync: parent_ts=%f\n", now_in_seconds);
   WriteToATrace(atrace_fd, marker.c_str(), marker.size());
diff --git a/base/trace_event/trace_log.cc b/base/trace_event/trace_log.cc
index 718383b0..578bbde0 100644
--- a/base/trace_event/trace_log.cc
+++ b/base/trace_event/trace_log.cc
@@ -85,7 +85,9 @@
 }
 
 ThreadTicks ThreadNow() {
-  return ThreadTicks::IsSupported() ? ThreadTicks::Now() : ThreadTicks();
+  return ThreadTicks::IsSupported()
+             ? base::subtle::ThreadTicksNowIgnoringOverride()
+             : ThreadTicks();
 }
 
 template <typename T>
@@ -369,7 +371,7 @@
   process_creation_time_ = CurrentProcessInfo::CreationTime();
 #else
   // Use approximate time when creation time is not available.
-  process_creation_time_ = Time::Now();
+  process_creation_time_ = TRACE_TIME_NOW();
 #endif
 
   logged_events_.reset(CreateTraceBuffer());
@@ -1031,7 +1033,7 @@
     std::unique_ptr<ConvertableToTraceFormat>* convertable_values,
     unsigned int flags) {
   int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
-  base::TimeTicks now = base::TimeTicks::Now();
+  base::TimeTicks now = TRACE_TIME_TICKS_NOW();
   return AddTraceEventWithThreadIdAndTimestamp(
       phase,
       category_group_enabled,
@@ -1063,7 +1065,7 @@
     std::unique_ptr<ConvertableToTraceFormat>* convertable_values,
     unsigned int flags) {
   int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
-  base::TimeTicks now = base::TimeTicks::Now();
+  base::TimeTicks now = TRACE_TIME_TICKS_NOW();
   return AddTraceEventWithThreadIdAndTimestamp(
       phase,
       category_group_enabled,
@@ -1094,7 +1096,7 @@
     const unsigned long long* arg_values,
     std::unique_ptr<ConvertableToTraceFormat>* convertable_values,
     unsigned int flags) {
-  base::TimeTicks now = base::TimeTicks::Now();
+  base::TimeTicks now = TRACE_TIME_TICKS_NOW();
   return AddTraceEventWithThreadIdAndTimestamp(
       phase,
       category_group_enabled,
@@ -1493,7 +1495,7 @@
         current_thread_id, "process_name", "name", process_name_);
   }
 
-  TimeDelta process_uptime = Time::Now() - process_creation_time_;
+  TimeDelta process_uptime = TRACE_TIME_NOW() - process_creation_time_;
   InitializeMetadataEvent(
       AddEventToThreadSharedChunkWhileLocked(nullptr, false), current_thread_id,
       "process_uptime_seconds", "uptime", process_uptime.InSeconds());
@@ -1701,19 +1703,12 @@
   if (*category_group_enabled_) {
     event_handle_ =
         TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(
-            TRACE_EVENT_PHASE_COMPLETE,
-            category_group_enabled_,
-            name,
-            trace_event_internal::kGlobalScope,  // scope
-            trace_event_internal::kNoId,  // id
+            TRACE_EVENT_PHASE_COMPLETE, category_group_enabled_, name,
+            trace_event_internal::kGlobalScope,                   // scope
+            trace_event_internal::kNoId,                          // id
             static_cast<int>(base::PlatformThread::CurrentId()),  // thread_id
-            base::TimeTicks::Now(),
-            trace_event_internal::kZeroNumArgs,
-            nullptr,
-            nullptr,
-            nullptr,
-            nullptr,
-            TRACE_EVENT_FLAG_NONE);
+            TRACE_TIME_TICKS_NOW(), trace_event_internal::kZeroNumArgs, nullptr,
+            nullptr, nullptr, nullptr, TRACE_EVENT_FLAG_NONE);
   }
 }
 
diff --git a/base/trace_event/trace_log.h b/base/trace_event/trace_log.h
index b8041d4d..06c5848 100644
--- a/base/trace_event/trace_log.h
+++ b/base/trace_event/trace_log.h
@@ -17,6 +17,7 @@
 #include "base/containers/stack.h"
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
+#include "base/time/time_override.h"
 #include "base/trace_event/memory_dump_provider.h"
 #include "base/trace_event/trace_config.h"
 #include "base/trace_event/trace_event_impl.h"
@@ -431,7 +432,10 @@
   }
   void UseNextTraceBuffer();
 
-  TimeTicks OffsetNow() const { return OffsetTimestamp(TimeTicks::Now()); }
+  TimeTicks OffsetNow() const {
+    // This should be TRACE_TIME_TICKS_NOW but include order makes that hard.
+    return OffsetTimestamp(base::subtle::TimeTicksNowIgnoringOverride());
+  }
   TimeTicks OffsetTimestamp(const TimeTicks& timestamp) const {
     return timestamp - time_offset_;
   }
diff --git a/base/win/windows_types.h b/base/win/windows_types.h
index 8060f03..2a86195f 100644
--- a/base/win/windows_types.h
+++ b/base/win/windows_types.h
@@ -248,5 +248,6 @@
 #define SendMessageCallback SendMessageCallbackW
 #define SetCurrentDirectory SetCurrentDirectoryW
 #define StartService StartServiceW
+#define StrCat StrCatW
 
 #endif  // BASE_WIN_WINDOWS_TYPES_H
diff --git a/build/android/pylib/base/output_manager.py b/build/android/pylib/base/output_manager.py
index 5606e7a..b4dd018f 100644
--- a/build/android/pylib/base/output_manager.py
+++ b/build/android/pylib/base/output_manager.py
@@ -14,6 +14,7 @@
   HTML = 'html'
   IMAGE = 'image'
   TEXT = 'text'
+  JSON = 'json'
 
 
 class OutputManager(object):
diff --git a/build/android/pylib/instrumentation/instrumentation_test_instance.py b/build/android/pylib/instrumentation/instrumentation_test_instance.py
index ddc80f7..3b6774057 100644
--- a/build/android/pylib/instrumentation/instrumentation_test_instance.py
+++ b/build/android/pylib/instrumentation/instrumentation_test_instance.py
@@ -676,7 +676,6 @@
   def _initializeTestControlAttributes(self, args):
     self._screenshot_dir = args.screenshot_dir
     self._timeout_scale = args.timeout_scale or 1
-    self._ui_screenshot_dir = args.ui_screenshot_dir
     self._wait_for_java_debugger = args.wait_for_java_debugger
 
   def _initializeTestCoverageAttributes(self, args):
@@ -809,10 +808,6 @@
     return self._total_external_shards
 
   @property
-  def ui_screenshot_dir(self):
-    return self._ui_screenshot_dir
-
-  @property
   def wait_for_java_debugger(self):
     return self._wait_for_java_debugger
 
diff --git a/build/android/pylib/local/device/local_device_instrumentation_test_run.py b/build/android/pylib/local/device/local_device_instrumentation_test_run.py
index 664bb8d..b3517ba 100644
--- a/build/android/pylib/local/device/local_device_instrumentation_test_run.py
+++ b/build/android/pylib/local/device/local_device_instrumentation_test_run.py
@@ -321,23 +321,9 @@
 
       valgrind_tools.SetChromeTimeoutScale(dev, None)
 
-      if self._test_instance.ui_screenshot_dir:
-        pull_ui_screen_captures(dev)
-
       if self._replace_package_contextmanager:
         self._replace_package_contextmanager.__exit__(*sys.exc_info())
 
-    @trace_event.traced
-    def pull_ui_screen_captures(dev):
-      file_names = dev.ListDirectory(self._ui_capture_dir[dev])
-      target_path = self._test_instance.ui_screenshot_dir
-      if not os.path.exists(target_path):
-        os.makedirs(target_path)
-
-      for file_name in file_names:
-        dev.PullFile(posixpath.join(self._ui_capture_dir[dev], file_name),
-                     target_path)
-
     self._env.parallel_devices.pMap(individual_device_tear_down)
 
   def _CreateFlagChangerIfNeeded(self, device):
@@ -530,12 +516,41 @@
           device.RemovePath(render_tests_device_output_dir,
                             recursive=True, force=True)
 
+    def pull_ui_screen_captures():
+      screenshots = []
+      for filename in device.ListDirectory(self._ui_capture_dir[device]):
+        if filename.endswith('.json'):
+          screenshots.append(pull_ui_screenshot(filename))
+      if screenshots:
+        json_archive_name = 'ui_capture_%s_%s.json' % (
+            test_name.replace('#', '.'),
+            time.strftime('%Y%m%dT%H%M%S-UTC', time.gmtime()))
+        with self._env.output_manager.ArchivedTempfile(
+            json_archive_name, 'ui_capture', output_manager.Datatype.JSON
+            ) as json_archive:
+          json.dump(screenshots, json_archive)
+        for result in results:
+          result.SetLink('ui screenshot', json_archive.Link())
+
+    def pull_ui_screenshot(filename):
+      source_dir = self._ui_capture_dir[device]
+      json_path = posixpath.join(source_dir, filename)
+      json_data = json.loads(device.ReadFile(json_path))
+      image_file_path = posixpath.join(source_dir, json_data['location'])
+      with self._env.output_manager.ArchivedTempfile(
+          json_data['location'], 'ui_capture', output_manager.Datatype.IMAGE
+          ) as image_archive:
+        device.PullFile(image_file_path, image_archive.name)
+      json_data['image_link'] = image_archive.Link()
+      return json_data
+
     # While constructing the TestResult objects, we can parallelize several
     # steps that involve ADB. These steps should NOT depend on any info in
     # the results! Things such as whether the test CRASHED have not yet been
     # determined.
     post_test_steps = [restore_flags, restore_timeout_scale,
-                       handle_coverage_data, handle_render_test_data]
+                       handle_coverage_data, handle_render_test_data,
+                       pull_ui_screen_captures]
     if self._env.concurrent_adb:
       post_test_step_thread_group = reraiser_thread.ReraiserThreadGroup(
           reraiser_thread.ReraiserThread(f) for f in post_test_steps)
diff --git a/build/android/pylib/output/remote_output_manager.py b/build/android/pylib/output/remote_output_manager.py
index 425f143..b726cb0 100644
--- a/build/android/pylib/output/remote_output_manager.py
+++ b/build/android/pylib/output/remote_output_manager.py
@@ -66,7 +66,8 @@
   def _PrepareArchive(self):
     self._content_addressed = (self._datatype in (
         output_manager.Datatype.HTML,
-        output_manager.Datatype.IMAGE))
+        output_manager.Datatype.IMAGE,
+        output_manager.Datatype.JSON))
     if self._content_addressed:
       sha1 = hashlib.sha1()
       with open(self.name, 'rb') as f:
@@ -87,5 +88,7 @@
     content_type = None
     if self._datatype == output_manager.Datatype.HTML:
       content_type = 'text/html'
+    elif self._datatype == output_manager.Datatype.JSON:
+      content_type = 'application/json'
     google_storage_helper.upload(
         self._upload_path, self.name, self._bucket, content_type=content_type)
diff --git a/build/android/test_runner.py b/build/android/test_runner.py
index 1789466d..97c31b8 100755
--- a/build/android/test_runner.py
+++ b/build/android/test_runner.py
@@ -494,10 +494,6 @@
       type=float,
       help='Factor by which timeouts should be scaled.')
   parser.add_argument(
-      '--ui-screenshot-directory',
-      dest='ui_screenshot_dir', type=os.path.realpath,
-      help='Destination for screenshots captured by the tests')
-  parser.add_argument(
       '-w', '--wait-for-java-debugger', action='store_true',
       help='Wait for java debugger to attach before running any application '
            'code. Also disables test timeouts and sets retries=0.')
diff --git a/build/config/android/BUILD.gn b/build/config/android/BUILD.gn
index 4e73318..fabde6c 100644
--- a/build/config/android/BUILD.gn
+++ b/build/config/android/BUILD.gn
@@ -216,11 +216,7 @@
 
 config("cygprofile_instrumentation") {
   defines = [ "CYGPROFILE_INSTRUMENTATION=1" ]
-  if (use_lightweight_order_profiling) {
-    cflags = [ "-finstrument-function-entry-bare" ]
-  } else {
-    cflags = [ "-finstrument-functions-after-inlining" ]
-  }
+  cflags = [ "-finstrument-function-entry-bare" ]
 }
 
 config("no_cygprofile_instrumentation") {
diff --git a/build/config/android/abi.gni b/build/config/android/abi.gni
index 24bef19..877c3f74 100644
--- a/build/config/android/abi.gni
+++ b/build/config/android/abi.gni
@@ -12,11 +12,6 @@
   # functions are called at startup.
   use_order_profiling = false
 
-  # Use a lightweight variant of order profiling. Does nothing without
-  # use_order_profiling set above. Will either replace use_order_profiling
-  # or be removed.
-  use_lightweight_order_profiling = false
-
   # Builds secondary abi for APKs, supports build 32-bit arch as secondary
   # abi in 64-bit Monochrome and WebView.
   build_apk_secondary_abi = true
diff --git a/build/util/lastchange.py b/build/util/lastchange.py
index 4467df7..9ade784 100755
--- a/build/util/lastchange.py
+++ b/build/util/lastchange.py
@@ -46,7 +46,7 @@
     return None
 
 
-def FetchGitRevision(directory):
+def FetchGitRevision(directory, filter):
   """
   Fetch the Git hash (and Cr-Commit-Position if any) for a given directory.
 
@@ -57,6 +57,8 @@
   """
   hsh = ''
   git_args = ['log', '-1', '--format=%H']
+  if filter is not None:
+    git_args.append('--grep=' + filter)
   proc = RunGitCommand(directory, git_args)
   if proc:
     output = proc.communicate()[0].strip()
@@ -76,12 +78,12 @@
   return VersionInfo(hsh, '%s-%s' % (hsh, pos))
 
 
-def FetchVersionInfo(directory=None):
+def FetchVersionInfo(directory=None, filter=None):
   """
   Returns the last change (as a VersionInfo object)
   from some appropriate revision control system.
   """
-  version_info = FetchGitRevision(directory)
+  version_info = FetchGitRevision(directory, filter)
   if not version_info:
     version_info = VersionInfo('0', '0')
   return version_info
@@ -165,10 +167,16 @@
                     "file-output-related options.")
   parser.add_option("-s", "--source-dir", metavar="DIR",
                     help="Use repository in the given directory.")
+  parser.add_option("", "--filter", metavar="REGEX",
+                    help="Only use log entries where the commit message " +
+                    "matches the supplied filter regex. Defaults to " +
+                    "'^Change-Id:' to suppress local commits.",
+                    default='^Change-Id:')
   opts, args = parser.parse_args(argv[1:])
 
   out_file = opts.output
   header = opts.header
+  filter=opts.filter
 
   while len(args) and out_file is None:
     if out_file is None:
@@ -183,7 +191,7 @@
   else:
     src_dir = os.path.dirname(os.path.abspath(__file__))
 
-  version_info = FetchVersionInfo(directory=src_dir)
+  version_info = FetchVersionInfo(directory=src_dir, filter=filter)
   revision_string = version_info.revision
   if opts.revision_id_only:
     revision_string = version_info.revision_id
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 5dd1cc2f..bdff8d3 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -40,8 +40,6 @@
     [ "manifest_package=org.chromium.chrome.sync_shell" ]
 
 app_hooks_impl = "java/src/org/chromium/chrome/browser/AppHooksImpl.java"
-class_register_impl =
-    "java/src/org/chromium/chrome/browser/ClassRegisterImpl.java"
 
 if (enable_resource_whitelist_generation) {
   monochrome_resource_whitelist =
@@ -172,13 +170,6 @@
   ]
 }
 
-android_library("class_register_java") {
-  java_files = [ class_register_impl ]
-  deps = [
-    ":chrome_java",
-  ]
-}
-
 android_aidl("photo_picker_aidl") {
   import_include = [ "java/src/org/chromium/chrome/browser/photo_picker" ]
   sources = [
@@ -331,10 +322,7 @@
   android_manifest_for_lint = chrome_public_android_manifest
 
   # From java_sources.gni.
-  java_files = chrome_java_sources + [
-                 app_hooks_impl,
-                 class_register_impl,
-               ]
+  java_files = chrome_java_sources + [ app_hooks_impl ]
 
   if (enable_vr) {
     java_files += chrome_vr_java_sources
@@ -348,10 +336,7 @@
 
   # Add the actual implementation where necessary so that downstream targets
   # can provide their own implementations.
-  jar_excluded_patterns = [
-    "*/AppHooksImpl.class",
-    "*/ClassRegisterImpl.class",
-  ]
+  jar_excluded_patterns = [ "*/AppHooksImpl.class" ]
 }
 
 action("chrome_android_java_google_api_keys_srcjar") {
@@ -432,7 +417,6 @@
     ":app_hooks_java",
     ":chrome_java",
     ":chrome_java_resources",
-    ":class_register_java",
     ":partner_location_descriptor_proto_java",
     "$google_play_services_package:google_play_services_base_java",
     "$google_play_services_package:google_play_services_basement_java",
@@ -520,7 +504,6 @@
     "//base:base_java_test_support",
     "//chrome/android:app_hooks_java",
     "//chrome/android:chrome_java",
-    "//chrome/android:class_register_java",
     "//chrome/android/third_party/compositor_animator:compositor_animator_java",
     "//chrome/android/third_party/widget_bottomsheet_base:widget_bottomsheet_base_java",
     "//chrome/android/webapk/libs/client:client_java",
@@ -672,7 +655,6 @@
       "//base:base_java_test_support",
       "//chrome/android:app_hooks_java",
       "//chrome/android:chrome_java",
-      "//chrome/android:class_register_java",
       "//chrome/test/android:chrome_java_test_support",
       "//components/policy/android:policy_java",
       "//content/public/android:content_java",
@@ -796,8 +778,8 @@
       deps += [ "//tools/cygprofile" ]
     }
 
-    # See crbug.com/705088, crbug.com/717815.
-    if (target_cpu == "arm" && (is_asan || use_order_profiling)) {
+    # See crbug.com/705088.
+    if (target_cpu == "arm" && is_asan) {
       ldflags = [ "-Wl,--long-plt" ]
     }
 
@@ -1076,7 +1058,6 @@
       ":chrome_public_apk_resources",
       ":chrome_public_non_pak_assets",
       ":chrome_public_pak_assets",
-      ":class_register_java",
       "//base:base_java",
     ]
   }
@@ -1143,7 +1124,6 @@
     "//base:base_java",
     "//chrome/android:app_hooks_java",
     "//chrome/android:chrome_java",
-    "//chrome/android:class_register_java",
   ]
 }
 
@@ -1295,7 +1275,6 @@
     "//base:base_java_test_support",
     "//chrome/android:app_hooks_java",
     "//chrome/android:chrome_java",
-    "//chrome/android:class_register_java",
     "//chrome/test/android:chrome_java_test_support",
     "//components/bookmarks/common/android:bookmarks_java",
     "//components/policy/android:policy_java",
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 294fa1e..254172a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
@@ -156,6 +156,7 @@
     public static final String CAPTIVE_PORTAL_CERTIFICATE_LIST = "CaptivePortalCertificateList";
     public static final String CCT_BACKGROUND_TAB = "CCTBackgroundTab";
     public static final String CCT_EXTERNAL_LINK_HANDLING = "CCTExternalLinkHandling";
+    public static final String CCT_PARALLEL_REQUEST = "CCTParallelRequest";
     public static final String CCT_POST_MESSAGE_API = "CCTPostMessageAPI";
     public static final String CCT_REDIRECT_PRECONNECT = "CCTRedirectPreconnect";
     public static final String CHROME_DUPLEX = "ChromeDuplex";
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ClassRegister.java b/chrome/android/java/src/org/chromium/chrome/browser/ClassRegister.java
deleted file mode 100644
index 4dd3709..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/ClassRegister.java
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser;
-
-/**
- * Base class for defining methods where different behavior is required by downstream targets.
- * The difference to AppHooks is we need to upstream changes here later.
- */
-public abstract class ClassRegister {
-    private static ClassRegisterImpl sInstance;
-
-    public static ClassRegister get() {
-        if (sInstance == null) {
-            sInstance = new ClassRegisterImpl();
-        }
-        return sInstance;
-    }
-
-    /**
-     * Register the {@link ContentClassFactory} so {@link SelectionInsertionHandleObserver} can be
-     * set properly.
-     */
-    public void registerContentClassFactory() {
-        /* no-op */
-    }
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ClassRegisterImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/ClassRegisterImpl.java
deleted file mode 100644
index 8a68212..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/ClassRegisterImpl.java
+++ /dev/null
@@ -1,11 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser;
-
-/**
- * Implementation of {@link ClassRegister}, don't add anything to this class.
- * Downstream targets may provide a different implemenation.
- */
-public class ClassRegisterImpl extends ClassRegister {}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/DefaultBrowserInfo.java b/chrome/android/java/src/org/chromium/chrome/browser/DefaultBrowserInfo.java
index acc71f7e..41cc1bff 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/DefaultBrowserInfo.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/DefaultBrowserInfo.java
@@ -92,8 +92,8 @@
                         Context context = ContextUtils.getApplicationContext();
                         ArrayList<String> menuTitles = new ArrayList<String>(2);
                         // Store the package label of current application.
-                        menuTitles.add(
-                                getTitleFromPackageLabel(context, BuildInfo.getPackageLabel()));
+                        menuTitles.add(getTitleFromPackageLabel(
+                                context, BuildInfo.getInstance().hostPackageLabel));
 
                         PackageManager pm = context.getPackageManager();
                         ResolveInfo info = getResolveInfoForViewIntent(pm);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkUtils.java
index bb8c863..57d96de28 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkUtils.java
@@ -95,7 +95,7 @@
                     createSnackbarControllerForEditButton(activity, bookmarkId);
             if (getLastUsedParent(activity) == null) {
                 if (fromCustomTab) {
-                    String packageLabel = BuildInfo.getPackageLabel();
+                    String packageLabel = BuildInfo.getInstance().hostPackageLabel;
                     snackbar = Snackbar.make(
                             activity.getString(R.string.bookmark_page_saved, packageLabel),
                             snackbarController, Snackbar.TYPE_ACTION, Snackbar.UMA_BOOKMARK_ADDED);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/crash/PureJavaExceptionReporter.java b/chrome/android/java/src/org/chromium/chrome/browser/crash/PureJavaExceptionReporter.java
index 5bfee3d..9a9e8fd 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/crash/PureJavaExceptionReporter.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/crash/PureJavaExceptionReporter.java
@@ -7,6 +7,7 @@
 import android.app.ActivityManager;
 import android.app.ActivityManager.RunningAppProcessInfo;
 import android.content.Context;
+import android.os.Build;
 import android.util.Log;
 
 import org.chromium.base.ApiCompatibilityUtils;
@@ -116,24 +117,24 @@
             processName = "browser";
         }
 
-        String[] allInfo = BuildInfo.getAll();
+        BuildInfo buildInfo = BuildInfo.getInstance();
         addPairedString(PRODUCT, "Chrome_Android");
         addPairedString(PROCESS_TYPE, processName);
-        addPairedString(DEVICE, allInfo[BuildInfo.DEVICE_INDEX]);
+        addPairedString(DEVICE, Build.DEVICE);
         addPairedString(VERSION, ChromeVersionInfo.getProductVersion());
         addPairedString(CHANNEL, getChannel());
-        addPairedString(ANDROID_BUILD_ID, allInfo[BuildInfo.ANDROID_BUILD_ID_INDEX]);
-        addPairedString(MODEL, allInfo[BuildInfo.MODEL_INDEX]);
-        addPairedString(BRAND, allInfo[BuildInfo.BRAND_INDEX]);
-        addPairedString(ANDROID_BUILD_FP, allInfo[BuildInfo.ANDROID_BUILD_FP_INDEX]);
-        addPairedString(GMS_CORE_VERSION, allInfo[BuildInfo.GMS_CORE_VERSION_INDEX]);
-        addPairedString(INSTALLER_PACKAGE_NAME, allInfo[BuildInfo.INSTALLER_PACKAGE_NAME_INDEX]);
-        addPairedString(ABI_NAME, allInfo[BuildInfo.ABI_NAME_INDEX]);
+        addPairedString(ANDROID_BUILD_ID, Build.ID);
+        addPairedString(MODEL, Build.MODEL);
+        addPairedString(BRAND, Build.BRAND);
+        addPairedString(ANDROID_BUILD_FP, buildInfo.androidBuildFingerprint);
+        addPairedString(GMS_CORE_VERSION, buildInfo.gmsVersionCode);
+        addPairedString(INSTALLER_PACKAGE_NAME, buildInfo.installerPackageName);
+        addPairedString(ABI_NAME, buildInfo.abiString);
         addPairedString(EXCEPTION_INFO, Log.getStackTraceString(javaException));
         addPairedString(EARLY_JAVA_EXCEPTION, "true");
         addPairedString(PACKAGE,
-                BuildConfig.FIREBASE_APP_ID + " v" + BuildInfo.getPackageVersionCode() + " ("
-                        + BuildInfo.getPackageVersionName() + ")");
+                String.format("%s v%s (%s)", BuildConfig.FIREBASE_APP_ID, buildInfo.versionCode,
+                        buildInfo.versionName));
 
         addString(mBoundary);
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java
index 7fbb804d..faa96be 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java
@@ -36,6 +36,7 @@
 import org.chromium.base.TimeUtils;
 import org.chromium.base.TraceEvent;
 import org.chromium.base.VisibleForTesting;
+import org.chromium.base.annotations.JNINamespace;
 import org.chromium.base.library_loader.LibraryProcessType;
 import org.chromium.base.library_loader.ProcessInitException;
 import org.chromium.base.metrics.RecordHistogram;
@@ -83,6 +84,7 @@
  * Note: This class is meant to be package private, and is public to be
  * accessible from {@link ChromeApplication}.
  */
+@JNINamespace("customtabs")
 public class CustomTabsConnection {
     private static final String TAG = "ChromeConnection";
     private static final String LOG_SERVICE_REQUESTS = "custom-tabs-log-service-requests";
@@ -935,6 +937,43 @@
                 Profile.getLastUsedProfile(), redirectEndpoint.toString());
     }
 
+    /** @return Whether {@code session} can create a parallel request for a given {@code origin}. */
+    @VisibleForTesting
+    boolean canDoParallelRequest(CustomTabsSessionToken session, String origin) {
+        ThreadUtils.assertOnUiThread();
+        // The restrictions are:
+        // - Native initialization: Required to get the profile, and the feature state.
+        // - Feature check
+        // - The origin is allowed.
+        //
+        // TODO(lizeb): Relax the restrictions.
+        return ChromeBrowserInitializer.getInstance(mContext).hasNativeInitializationCompleted()
+                && ChromeFeatureList.isEnabled(ChromeFeatureList.CCT_PARALLEL_REQUEST)
+                && mClientManager.isFirstPartyOriginForSession(session, Uri.parse(origin));
+    }
+
+    /**
+     * Starts a parallel request.
+     *
+     * @param session Calling context session.
+     * @param url URL to send the request to.
+     * @param origin Origin to use.
+     * @return Whether the request started. False if the session is not authorized to use the
+     *         provided origin, if Chrome hasn't been initialized, or the feature is disabled.
+     *         Also fails if the URL is neither HTTPS not HTTP.
+     */
+    @VisibleForTesting
+    boolean startParallelRequest(CustomTabsSessionToken session, String url, String origin) {
+        ThreadUtils.assertOnUiThread();
+        if (TextUtils.isEmpty(url) || !isValid(Uri.parse(url))
+                || !canDoParallelRequest(session, origin)) {
+            return false;
+        }
+
+        nativeCreateAndStartDetachedResourceRequest(Profile.getLastUsedProfile(), url, origin);
+        return true;
+    }
+
     /** See {@link ClientManager#getReferrerForSession(CustomTabsSessionToken)} */
     public Referrer getReferrerForSession(CustomTabsSessionToken session) {
         return mClientManager.getReferrerForSession(session);
@@ -1495,4 +1534,7 @@
         RecordHistogram.recordEnumeratedHistogram(
                 "CustomTabs.SpeculationStatusOnSwap", status, SPECULATION_STATUS_ON_SWAP_MAX);
     }
+
+    private static native void nativeCreateAndStartDetachedResourceRequest(
+            Profile profile, String url, String origin);
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadSnackbarController.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadSnackbarController.java
index eaf0625..e99bc42 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadSnackbarController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadSnackbarController.java
@@ -94,7 +94,7 @@
         if (getSnackbarManager() == null) return;
         Snackbar snackbar;
         if (getActivity() instanceof CustomTabActivity) {
-            String packageLabel = BuildInfo.getPackageLabel();
+            String packageLabel = BuildInfo.getInstance().hostPackageLabel;
             snackbar = Snackbar.make(mContext.getString(R.string.download_succeeded_message,
                     downloadInfo.getFileName(), packageLabel),
                     this, Snackbar.TYPE_NOTIFICATION, Snackbar.UMA_DOWNLOAD_SUCCEEDED);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandler.java
index 8584da1..534e2b9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandler.java
@@ -339,7 +339,7 @@
         // pairing code URL, since these match the current tab with a device (Chromecast
         // or similar) it is supposed to be controlling. Using a different application
         // that isn't expecting this (in particular YouTube) doesn't work.
-        if (params.getUrl().matches(".*youtube\\.com.*[?&]pairingCode=.*")) {
+        if (params.getUrl().matches(".*youtube\\.com(\\/.*)?\\?(.+&)?pairingCode=[^&].+")) {
             if (DEBUG) Log.i(TAG, "NO_OVERRIDE: YouTube URL with a pairing code");
             return OverrideUrlLoadingResult.NO_OVERRIDE;
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omaha/RequestGenerator.java b/chrome/android/java/src/org/chromium/chrome/browser/omaha/RequestGenerator.java
index 6eaf21d..16ad618 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omaha/RequestGenerator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omaha/RequestGenerator.java
@@ -180,7 +180,8 @@
      * these strings when building their own custom Android ROMs.
      */
     public String getAdditionalParameters() {
-        String applicationLabel = StringSanitizer.sanitize(BuildInfo.getPackageLabel());
+        String applicationLabel =
+                StringSanitizer.sanitize(BuildInfo.getInstance().hostPackageLabel);
         String brand = StringSanitizer.sanitize(Build.BRAND);
         String model = StringSanitizer.sanitize(Build.MODEL);
         return applicationLabel + ";" + brand + ";" + model;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omaha/VersionNumberGetter.java b/chrome/android/java/src/org/chromium/chrome/browser/omaha/VersionNumberGetter.java
index 6f0101c8..f5431d56 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omaha/VersionNumberGetter.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omaha/VersionNumberGetter.java
@@ -60,7 +60,7 @@
      * @return The latest version if we retrieved one from the Omaha server, or "" if we haven't.
      */
     public String getCurrentlyUsedVersion(Context context) {
-        return BuildInfo.getPackageVersionName();
+        return BuildInfo.getInstance().versionName;
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/EditorTextField.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/EditorTextField.java
index 869b875..6da704a7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/EditorTextField.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/EditorTextField.java
@@ -16,6 +16,7 @@
 import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodManager;
 import android.widget.ArrayAdapter;
 import android.widget.AutoCompleteTextView;
 import android.widget.FrameLayout;
@@ -66,6 +67,19 @@
         mInput.setText(fieldModel.getValue());
         mInput.setContentDescription(label);
         mInput.setOnEditorActionListener(mEditorActionListener);
+        // AutoCompleteTextView requires and explicit onKeyListener to show the OSK upon receiving
+        // a KEYCODE_DPAD_CENTER.
+        mInput.setOnKeyListener((v, keyCode, event) -> {
+            if (!(keyCode == KeyEvent.KEYCODE_DPAD_CENTER
+                        && event.getAction() == KeyEvent.ACTION_UP)) {
+                return false;
+            }
+            InputMethodManager imm = (InputMethodManager) v.getContext().getSystemService(
+                    Context.INPUT_METHOD_SERVICE);
+            imm.viewClicked(v);
+            imm.showSoftInput(v, 0);
+            return true;
+        });
 
         mIconsLayer = findViewById(R.id.icons_layer);
         mIconsLayer.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/MainPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/MainPreferences.java
index 42c08b2..7b7cb92 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/MainPreferences.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/MainPreferences.java
@@ -12,7 +12,7 @@
 import android.preference.PreferenceFragment;
 import android.provider.Settings;
 
-import org.chromium.base.BuildInfo;
+import org.chromium.base.ContextUtils;
 import org.chromium.base.VisibleForTesting;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeFeatureList;
@@ -103,7 +103,8 @@
             notifications.setOnPreferenceClickListener(preference -> {
                 Intent intent = new Intent();
                 intent.setAction(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
-                intent.putExtra(Settings.EXTRA_APP_PACKAGE, BuildInfo.getPackageName());
+                intent.putExtra(Settings.EXTRA_APP_PACKAGE,
+                        ContextUtils.getApplicationContext().getPackageName());
                 startActivity(intent);
                 // We handle the click so the default action (opening NotificationsPreference)
                 // isn't triggered.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/SyncPreference.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/SyncPreference.java
index fb32eba..89f0e6d1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/SyncPreference.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/SyncPreference.java
@@ -101,7 +101,8 @@
 
         if (profileSyncService.getProtocolErrorClientAction()
                 == ProtocolErrorClientAction.UPGRADE_CLIENT) {
-            return res.getString(R.string.sync_error_upgrade_client, BuildInfo.getPackageLabel());
+            return res.getString(
+                    R.string.sync_error_upgrade_client, BuildInfo.getInstance().hostPackageLabel);
         }
 
         if (profileSyncService.hasUnrecoverableError()) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/PassphraseDialogFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/PassphraseDialogFragment.java
index 9657b20..7791870 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/PassphraseDialogFragment.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/PassphraseDialogFragment.java
@@ -30,7 +30,7 @@
 import android.widget.TextView.OnEditorActionListener;
 
 import org.chromium.base.ApiCompatibilityUtils;
-import org.chromium.base.BuildInfo;
+import org.chromium.base.ContextUtils;
 import org.chromium.base.Log;
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.chrome.R;
@@ -202,7 +202,7 @@
                         recordPassphraseDialogDismissal(PASSPHRASE_DIALOG_RESET_LINK);
                         Uri syncDashboardUrl = Uri.parse(ChromeStringConstants.SYNC_DASHBOARD_URL);
                         Intent intent = new Intent(Intent.ACTION_VIEW, syncDashboardUrl);
-                        intent.setPackage(BuildInfo.getPackageName());
+                        intent.setPackage(ContextUtils.getApplicationContext().getPackageName());
                         IntentUtils.safePutBinderExtra(
                                 intent, CustomTabsIntent.EXTRA_SESSION, null);
                         context.startActivity(intent);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/PassphraseTypeDialogFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/PassphraseTypeDialogFragment.java
index cc39787..7b6645c4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/PassphraseTypeDialogFragment.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/PassphraseTypeDialogFragment.java
@@ -26,7 +26,7 @@
 import android.widget.ListView;
 import android.widget.TextView;
 
-import org.chromium.base.BuildInfo;
+import org.chromium.base.ContextUtils;
 import org.chromium.base.VisibleForTesting;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeStringConstants;
@@ -195,7 +195,7 @@
                     public void onClick(View view) {
                         Uri syncDashboardUrl = Uri.parse(ChromeStringConstants.SYNC_DASHBOARD_URL);
                         Intent intent = new Intent(Intent.ACTION_VIEW, syncDashboardUrl);
-                        intent.setPackage(BuildInfo.getPackageName());
+                        intent.setPackage(ContextUtils.getApplicationContext().getPackageName());
                         IntentUtils.safePutBinderExtra(
                                 intent, CustomTabsIntent.EXTRA_SESSION, null);
                         context.startActivity(intent);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/SyncCustomizationFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/SyncCustomizationFragment.java
index c618339..28a2968 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/SyncCustomizationFragment.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/SyncCustomizationFragment.java
@@ -31,6 +31,7 @@
 
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.base.BuildInfo;
+import org.chromium.base.ContextUtils;
 import org.chromium.base.VisibleForTesting;
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.chrome.R;
@@ -679,7 +680,8 @@
             case SYNC_AUTH_ERROR:
                 return res.getString(R.string.hint_sync_auth_error);
             case SYNC_CLIENT_OUT_OF_DATE:
-                return res.getString(R.string.hint_client_out_of_date, BuildInfo.getPackageLabel());
+                return res.getString(
+                        R.string.hint_client_out_of_date, BuildInfo.getInstance().hostPackageLabel);
             case SYNC_OTHER_ERRORS:
                 return res.getString(R.string.hint_other_sync_errors);
             case SYNC_PASSPHRASE_REQUIRED:
@@ -716,7 +718,8 @@
         if (mCurrentSyncError == SYNC_CLIENT_OUT_OF_DATE) {
             // Opens the client in play store for update.
             Intent intent = new Intent(Intent.ACTION_VIEW);
-            intent.setData(Uri.parse("market://details?id=" + BuildInfo.getPackageName()));
+            intent.setData(Uri.parse("market://details?id="
+                    + ContextUtils.getApplicationContext().getPackageName()));
             startActivity(intent);
             return;
         }
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index 4bd190c..887b320 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -34,7 +34,6 @@
   "java/src/org/chromium/chrome/browser/ChromeTabbedActivity2.java",
   "java/src/org/chromium/chrome/browser/ChromeVersionInfo.java",
   "java/src/org/chromium/chrome/browser/ChromeWindow.java",
-  "java/src/org/chromium/chrome/browser/ClassRegister.java",
   "java/src/org/chromium/chrome/browser/DefaultBrowserInfo.java",
   "java/src/org/chromium/chrome/browser/DeferredStartupHandler.java",
   "java/src/org/chromium/chrome/browser/DevToolsServer.java",
@@ -1552,6 +1551,7 @@
   "javatests/src/org/chromium/chrome/browser/customtabs/CustomTabsTestUtils.java",
   "javatests/src/org/chromium/chrome/browser/customtabs/CustomTabTabPersistenceIntegrationTest.java",
   "javatests/src/org/chromium/chrome/browser/customtabs/CustomTabTabPersistencePolicyTest.java",
+  "javatests/src/org/chromium/chrome/browser/customtabs/DetachedResourceRequestTest.java",
   "javatests/src/org/chromium/chrome/browser/customtabs/RequestThrottlerTest.java",
   "javatests/src/org/chromium/chrome/browser/document/LauncherActivityTest.java",
   "javatests/src/org/chromium/chrome/browser/dom_distiller/DistillabilityServiceTest.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ProcessIsolationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ProcessIsolationTest.java
index 359310e8..886318e 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/ProcessIsolationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ProcessIsolationTest.java
@@ -13,7 +13,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import org.chromium.base.BuildInfo;
+import org.chromium.base.ContextUtils;
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.DisableIf;
 import org.chromium.base.test.util.Feature;
@@ -53,7 +53,7 @@
         // in the RunningAppProcessInfo for isolated processes is the same as the parent process
         // (see b/7724486, closed as "Working as intended").
         // So we have to resort to parsing the ps output.
-        String packageName = BuildInfo.getPackageName();
+        String packageName = ContextUtils.getApplicationContext().getPackageName();
         Assert.assertFalse("Failed to retrieve package name for current version of Chrome.",
                 TextUtils.isEmpty(packageName));
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/DetachedResourceRequestTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/DetachedResourceRequestTest.java
new file mode 100644
index 0000000..69f4d77
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/DetachedResourceRequestTest.java
@@ -0,0 +1,137 @@
+// 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.customtabs;
+
+import android.content.Context;
+import android.net.Uri;
+import android.support.customtabs.CustomTabsService;
+import android.support.customtabs.CustomTabsSessionToken;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestRule;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.PathUtils;
+import org.chromium.base.ThreadUtils;
+import org.chromium.base.library_loader.LibraryLoader;
+import org.chromium.base.library_loader.LibraryProcessType;
+import org.chromium.base.test.util.CallbackHelper;
+import org.chromium.chrome.browser.ChromeFeatureList;
+import org.chromium.chrome.browser.browserservices.OriginVerifier;
+import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.util.browser.Features;
+import org.chromium.chrome.test.util.browser.Features.EnableFeatures;
+import org.chromium.net.test.EmbeddedTestServer;
+
+/** Tests for detached resource requests. */
+@RunWith(ChromeJUnit4ClassRunner.class)
+public class DetachedResourceRequestTest {
+    @Rule
+    public TestRule processor = new Features.InstrumentationProcessor();
+
+    private CustomTabsConnection mConnection;
+    private Context mContext;
+
+    private static final String PRIVATE_DATA_DIRECTORY_SUFFIX = "chrome";
+    private static final String ORIGIN = "http://cats.google.com";
+
+    @Before
+    public void setUp() throws Exception {
+        PathUtils.setPrivateDataDirectorySuffix(PRIVATE_DATA_DIRECTORY_SUFFIX);
+        LibraryLoader.get(LibraryProcessType.PROCESS_BROWSER).ensureInitialized();
+        mConnection = CustomTabsTestUtils.setUpConnection();
+        mContext = InstrumentationRegistry.getInstrumentation()
+                           .getTargetContext()
+                           .getApplicationContext();
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        CustomTabsTestUtils.cleanupSessions(mConnection);
+    }
+
+    @Test
+    @SmallTest
+    @EnableFeatures(ChromeFeatureList.CCT_PARALLEL_REQUEST)
+    public void testCanDoParallelRequest() throws Exception {
+        CustomTabsSessionToken session = CustomTabsSessionToken.createMockSessionTokenForTesting();
+        Assert.assertTrue(mConnection.newSession(session));
+        ThreadUtils.runOnUiThreadBlocking(
+                () -> { Assert.assertFalse(mConnection.canDoParallelRequest(session, ORIGIN)); });
+        CustomTabsTestUtils.warmUpAndWait();
+        ThreadUtils.runOnUiThreadBlocking(
+                () -> { Assert.assertFalse(mConnection.canDoParallelRequest(session, ORIGIN)); });
+        ThreadUtils.runOnUiThreadBlocking(() -> {
+            String packageName = mContext.getPackageName();
+            OriginVerifier.addVerifiedOriginForPackage(
+                    packageName, Uri.parse(ORIGIN), CustomTabsService.RELATION_USE_AS_ORIGIN);
+            Assert.assertTrue(mConnection.canDoParallelRequest(session, ORIGIN));
+        });
+    }
+
+    @Test
+    @SmallTest
+    @EnableFeatures(ChromeFeatureList.CCT_PARALLEL_REQUEST)
+    public void testStartParallelRequestValidation() throws Exception {
+        CustomTabsSessionToken session = prepareSession();
+        ThreadUtils.runOnUiThreadBlocking(() -> {
+            Assert.assertFalse("Should not allow android-app:// scheme",
+                    mConnection.startParallelRequest(
+                            session, "android-app://this.is.an.android.app", ORIGIN));
+            Assert.assertFalse("Should not allow an empty URL",
+                    mConnection.startParallelRequest(session, "", ORIGIN));
+            Assert.assertFalse("Should not allow an arbitrary origin",
+                    mConnection.startParallelRequest(session, "HTTPS://foo.bar", "wrong://origin"));
+            Assert.assertTrue(mConnection.startParallelRequest(session, "HTTP://foo.bar", ORIGIN));
+        });
+    }
+
+    @Test
+    @SmallTest
+    @EnableFeatures(ChromeFeatureList.CCT_PARALLEL_REQUEST)
+    public void testCanStartParallelRequest() throws Exception {
+        CustomTabsSessionToken session = prepareSession();
+
+        final CallbackHelper cb = new CallbackHelper();
+        EmbeddedTestServer server = new EmbeddedTestServer();
+        try {
+            server.initializeNative(mContext, EmbeddedTestServer.ServerHTTPSSetting.USE_HTTP);
+            server.setConnectionListener(new EmbeddedTestServer.ConnectionListener() {
+                @Override
+                public void readFromSocket(long socketId) {
+                    cb.notifyCalled();
+                }
+            });
+            server.start();
+
+            ThreadUtils.runOnUiThread(() -> {
+                String url = server.getURL("/echotitle");
+                Assert.assertTrue(mConnection.startParallelRequest(session, url, ORIGIN));
+            });
+            cb.waitForCallback(0, 1);
+        } finally {
+            server.stopAndDestroyServer();
+        }
+    }
+
+    private CustomTabsSessionToken prepareSession() throws Exception {
+        final CustomTabsSessionToken session =
+                CustomTabsSessionToken.createMockSessionTokenForTesting();
+        Assert.assertTrue(mConnection.newSession(session));
+        CustomTabsTestUtils.warmUpAndWait();
+        ThreadUtils.runOnUiThreadBlocking(() -> {
+            OriginVerifier.addVerifiedOriginForPackage(mContext.getPackageName(), Uri.parse(ORIGIN),
+                    CustomTabsService.RELATION_USE_AS_ORIGIN);
+            Assert.assertTrue(mConnection.canDoParallelRequest(session, ORIGIN));
+        });
+        return session;
+    }
+}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandlerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandlerTest.java
index 8dc7e2e8..d0e2070 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandlerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandlerTest.java
@@ -409,17 +409,39 @@
 
         int transitionTypeIncomingIntent = PageTransition.LINK
                 | PageTransition.FROM_API;
-        String url = "http://m.youtube.com/watch?v=1234&pairingCode=5678";
+        final String[] goodUrls = {"http://m.youtube.com/watch?v=1234&pairingCode=5678",
+                "youtube.com?pairingCode=xyz", "youtube.com/tv?pairingCode=xyz",
+                "youtube.com/watch?v=1234&version=3&autohide=1&pairingCode=xyz",
+                "youtube.com/watch?v=1234&pairingCode=xyz&version=3&autohide=1"};
+        final String[] badUrls = {"youtube.com.foo.com/tv?pairingCode=xyz",
+                "youtube.com.foo.com?pairingCode=xyz",
+                "youtube.com/watch?v=tEsT&version=3&autohide=1&pairingCode=",
+                "youtube.com&pairingCode=xyz",
+                "youtube.com/watch?v=tEsT?version=3&pairingCode=&autohide=1"};
 
-        // http://crbug/386600 - it makes no sense to switch activities for pairing code URLs.
-        checkUrl(url)
-                .withIsRedirect(true)
-                .expecting(OverrideUrlLoadingResult.NO_OVERRIDE, IGNORE);
+        // Make sure we don't override when faced with valid pairing code URLs.
+        for (String url : goodUrls) {
+            // http://crbug/386600 - it makes no sense to switch activities for pairing code URLs.
+            checkUrl(url).withIsRedirect(true).expecting(
+                    OverrideUrlLoadingResult.NO_OVERRIDE, IGNORE);
 
-        checkUrl(url)
-                .withPageTransition(transitionTypeIncomingIntent)
-                .withIsRedirect(true)
-                .expecting(OverrideUrlLoadingResult.NO_OVERRIDE, IGNORE);
+            checkUrl(url)
+                    .withPageTransition(transitionTypeIncomingIntent)
+                    .withIsRedirect(true)
+                    .expecting(OverrideUrlLoadingResult.NO_OVERRIDE, IGNORE);
+        }
+
+        // The pairing code URL regex shouldn't cause NO_OVERRIDE on invalid URLs.
+        for (String url : badUrls) {
+            checkUrl(url).withIsRedirect(true).expecting(
+                    OverrideUrlLoadingResult.OVERRIDE_WITH_EXTERNAL_INTENT, START_OTHER_ACTIVITY);
+
+            checkUrl(url)
+                    .withPageTransition(transitionTypeIncomingIntent)
+                    .withIsRedirect(true)
+                    .expecting(OverrideUrlLoadingResult.OVERRIDE_WITH_EXTERNAL_INTENT,
+                            START_OTHER_ACTIVITY);
+        }
     }
 
     @Test
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/autofill/AutofillProfilesFragmentTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/autofill/AutofillProfilesFragmentTest.java
index 64614fd2..e6833bc8 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/autofill/AutofillProfilesFragmentTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/autofill/AutofillProfilesFragmentTest.java
@@ -7,6 +7,8 @@
 import android.preference.PreferenceFragment;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.MediumTest;
+import android.view.KeyEvent;
+import android.widget.EditText;
 
 import org.junit.Assert;
 import org.junit.Before;
@@ -22,7 +24,11 @@
 import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
 import org.chromium.chrome.browser.preferences.Preferences;
 import org.chromium.chrome.browser.preferences.PreferencesTest;
+import org.chromium.content.browser.test.util.Criteria;
+import org.chromium.content.browser.test.util.CriteriaHelper;
+import org.chromium.ui.UiUtils;
 
+import java.util.List;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeoutException;
 
@@ -228,4 +234,59 @@
         Assert.assertTrue(oldProfile == null);
         activity.finish();
     }
+
+    @Test
+    @MediumTest
+    @Feature({"Preferences"})
+    public void testKeyboardShownOnDpadCenter() {
+        Preferences activity =
+                PreferencesTest.startPreferences(InstrumentationRegistry.getInstrumentation(),
+                        AutofillProfilesFragment.class.getName());
+
+        PreferenceFragment fragment = (PreferenceFragment) activity.getFragmentForTest();
+        AutofillProfileEditorPreference addProfile =
+                (AutofillProfileEditorPreference) fragment.findPreference(
+                        AutofillProfilesFragment.PREF_NEW_PROFILE);
+        Assert.assertNotNull(addProfile);
+
+        // Open AutofillProfileEditorPreference.
+        ThreadUtils.runOnUiThreadBlocking(() -> {
+            PreferencesTest.clickPreference(fragment, addProfile);
+            rule.setEditorDialog(addProfile.getEditorDialog());
+        });
+        // The keyboard is shown as soon as AutofillProfileEditorPreference comes into view.
+        waitForKeyboardStatus(true, activity);
+
+        // Hide the keyboard.
+        ThreadUtils.runOnUiThreadBlocking(() -> {
+            List<EditText> fields = addProfile.getEditorDialog().getEditableTextFieldsForTest();
+            UiUtils.hideKeyboard(fields.get(0));
+        });
+        // Check that the keyboard is hidden.
+        waitForKeyboardStatus(false, activity);
+
+        // Send a d-pad key event to one of the text fields
+        ThreadUtils.runOnUiThreadBlocking(() -> {
+            try {
+                rule.sendKeycodeToTextFieldInEditorAndWait(KeyEvent.KEYCODE_DPAD_CENTER, 0);
+            } catch (Exception ex) {
+                ex.printStackTrace();
+            }
+        });
+        // Check that the keyboard was shown.
+        waitForKeyboardStatus(true, activity);
+        activity.finish();
+    }
+
+    private void waitForKeyboardStatus(final boolean keyboardVisible, final Preferences activity) {
+        CriteriaHelper.pollUiThread(
+                new Criteria("Keyboard was not " + (keyboardVisible ? "shown." : "hidden.")) {
+                    @Override
+                    public boolean isSatisfied() {
+                        return keyboardVisible
+                                == UiUtils.isKeyboardShowing(
+                                           activity, activity.findViewById(android.R.id.content));
+                    }
+                });
+    }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/autofill/AutofillTestRule.java b/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/autofill/AutofillTestRule.java
index 695a789..0c71c27 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/autofill/AutofillTestRule.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/autofill/AutofillTestRule.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser.preferences.autofill;
 
+import android.view.KeyEvent;
 import android.widget.EditText;
 
 import org.chromium.base.ThreadUtils;
@@ -62,6 +63,18 @@
         mValidationUpdate.waitForCallback(callCount);
     }
 
+    protected void sendKeycodeToTextFieldInEditorAndWait(final int keycode,
+            final int textFieldIndex) throws InterruptedException, TimeoutException {
+        int callCount = mClickUpdate.getCallCount();
+        ThreadUtils.runOnUiThreadBlocking(() -> {
+            List<EditText> fields = mEditorDialog.getEditableTextFieldsForTest();
+            fields.get(textFieldIndex)
+                    .dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, keycode));
+            fields.get(textFieldIndex).dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, keycode));
+        });
+        mClickUpdate.waitForCallback(callCount);
+    }
+
     protected void waitForThePreferenceUpdate() throws InterruptedException, TimeoutException {
         int callCount = mPreferenceUpdate.getCallCount();
         mPreferenceUpdate.waitForCallback(callCount);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/WebVrTransitionTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/WebVrTransitionTest.java
index bd3a4868..9f6e0eb8 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/WebVrTransitionTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr_shell/WebVrTransitionTest.java
@@ -129,17 +129,21 @@
         CriteriaHelper.pollInstrumentationThread(new Criteria() {
             @Override
             public boolean isSatisfied() {
-                Bitmap bmpCurrentScreen = InstrumentationRegistry.getInstrumentation()
-                                                  .getUiAutomation()
-                                                  .takeScreenshot();
+                Bitmap screenshot = InstrumentationRegistry.getInstrumentation()
+                                            .getUiAutomation()
+                                            .takeScreenshot();
 
-                if (bmpCurrentScreen != null) {
+                if (screenshot != null) {
                     // Calculate center of eye coordinates.
-                    int iheight = uiDevice.getDisplayHeight() / 2;
-                    int iwidth = uiDevice.getDisplayWidth() / 4;
+                    int height = uiDevice.getDisplayHeight() / 2;
+                    int width = uiDevice.getDisplayWidth() / 4;
 
                     // Verify screen is blue.
-                    return Color.BLUE == bmpCurrentScreen.getPixel(iwidth, iheight);
+                    int pixel = screenshot.getPixel(width, height);
+                    // Workaround for the immersive mode popup sometimes being rendered over the
+                    // screen on K, which causes the pure blue to be darkened to (0, 0, 127).
+                    // TODO(https://crbug.com/819021): Only check pure blue.
+                    return pixel == Color.BLUE || pixel == Color.rgb(0, 0, 127);
                 }
                 return false;
             }
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 3ca1d0f..3b75e50 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -25,7 +25,6 @@
 import("//sandbox/features.gni")
 import("//third_party/protobuf/proto_library.gni")
 import("//ui/base/ui_features.gni")
-import("//build/buildflag_header.gni")
 
 # //build/config/android/rules.gni imports //tools/grit/grit_rule.gni, which
 # produces a conflict for the "grit" template so we have to only include one.
@@ -35,10 +34,6 @@
   import("//tools/grit/grit_rule.gni")
 }
 
-if (enable_vr) {
-  import("//chrome/browser/vr/features.gni")
-}
-
 additional_modules_list_file =
     "$root_gen_dir/chrome/browser/internal/additional_modules_list.txt"
 
@@ -61,13 +56,6 @@
   }
 }
 
-if (enable_vr) {
-  buildflag_header("vr_build_features") {
-    header = "vr_features.h"
-    flags = [ "USE_VR_ASSETS_COMPONENT=$use_vr_assets_component" ]
-  }
-}
-
 # Use a static library here because many test binaries depend on this but don't
 # require many files from it. This makes linking more efficient.
 jumbo_split_static_library("browser") {
@@ -1755,8 +1743,8 @@
     "//content/app/resources",
     "//content/public/browser",
     "//content/public/common",
+    "//content/public/common:buildflags",
     "//content/public/common:feature_h264_with_openh264_ffmpeg",
-    "//content/public/common:features",
     "//content/public/common:service_names",
     "//courgette:courgette_lib",
     "//crypto",
@@ -1946,6 +1934,7 @@
       "android/crash/pure_java_exception_handler.h",
       "android/customtabs/detached_resource_request.cc",
       "android/customtabs/detached_resource_request.h",
+      "android/customtabs/detached_resource_request_android.cc",
       "android/customtabs/origin_verifier.cc",
       "android/customtabs/origin_verifier.h",
       "android/data_usage/data_use_matcher.cc",
@@ -4098,12 +4087,8 @@
     sources += [
       "component_updater/vr_assets_component_installer.cc",
       "component_updater/vr_assets_component_installer.h",
-      "vr_features.h",
     ]
-    deps += [
-      ":vr_build_features",
-      "//chrome/browser/vr:vr_common",
-    ]
+    deps += [ "//chrome/browser/vr:vr_common" ]
   }
 
   if (enable_wayland_server) {
@@ -4248,6 +4233,7 @@
       "../android/java/src/org/chromium/chrome/browser/cookies/CookiesFetcher.java",
       "../android/java/src/org/chromium/chrome/browser/crash/MinidumpUploadService.java",
       "../android/java/src/org/chromium/chrome/browser/crash/PureJavaExceptionHandler.java",
+      "../android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java",
       "../android/java/src/org/chromium/chrome/browser/customtabs/LoadingPredictor.java",
       "../android/java/src/org/chromium/chrome/browser/database/SQLiteCursor.java",
       "../android/java/src/org/chromium/chrome/browser/datausage/DataUseTabUIManager.java",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 706fce99..6794d242 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -90,10 +90,10 @@
 #include "components/translate/core/browser/translate_ranker_impl.h"
 #include "components/version_info/version_info.h"
 #include "components/viz/common/features.h"
+#include "content/public/common/buildflags.h"
 #include "content/public/common/content_features.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/feature_h264_with_openh264_ffmpeg.h"
-#include "content/public/common/features.h"
 #include "device/base/features.h"
 #include "device/vr/features/features.h"
 #include "extensions/features/features.h"
@@ -1962,6 +1962,10 @@
     {"enable-system-tray-unified", flag_descriptions::kSystemTrayUnifiedName,
      flag_descriptions::kSystemTrayUnifiedDescription, kOsCrOS,
      FEATURE_VALUE_TYPE(ash::features::kSystemTrayUnified)},
+    {"enable-lock-screen-notification",
+     flag_descriptions::kLockScreenNotificationName,
+     flag_descriptions::kLockScreenNotificationDescription, kOsCrOS,
+     FEATURE_VALUE_TYPE(ash::features::kLockScreenNotifications)},
 #endif  // OS_CHROMEOS
     {"enable-message-center-new-style-notification",
      flag_descriptions::kMessageCenterNewStyleNotificationName,
diff --git a/chrome/browser/android/chrome_feature_list.cc b/chrome/browser/android/chrome_feature_list.cc
index 9813ee9..d11f9e5 100644
--- a/chrome/browser/android/chrome_feature_list.cc
+++ b/chrome/browser/android/chrome_feature_list.cc
@@ -60,6 +60,7 @@
     &kAndroidPaymentApps,
     &kCCTBackgroundTab,
     &kCCTExternalLinkHandling,
+    &kCCTParallelRequest,
     &kCCTPostMessageAPI,
     &kCCTRedirectPreconnect,
     &kChromeDuplexFeature,
@@ -181,6 +182,9 @@
 const base::Feature kCCTExternalLinkHandling{"CCTExternalLinkHandling",
                                              base::FEATURE_ENABLED_BY_DEFAULT};
 
+const base::Feature kCCTParallelRequest{"CCTParallelRequest",
+                                        base::FEATURE_DISABLED_BY_DEFAULT};
+
 const base::Feature kCCTPostMessageAPI{"CCTPostMessageAPI",
                                        base::FEATURE_ENABLED_BY_DEFAULT};
 
diff --git a/chrome/browser/android/chrome_feature_list.h b/chrome/browser/android/chrome_feature_list.h
index a2990b1..168b475b 100644
--- a/chrome/browser/android/chrome_feature_list.h
+++ b/chrome/browser/android/chrome_feature_list.h
@@ -19,6 +19,7 @@
 extern const base::Feature kAndroidPaymentApps;
 extern const base::Feature kCCTBackgroundTab;
 extern const base::Feature kCCTExternalLinkHandling;
+extern const base::Feature kCCTParallelRequest;
 extern const base::Feature kCCTPostMessageAPI;
 extern const base::Feature kCCTRedirectPreconnect;
 extern const base::Feature kChromeDuplexFeature;
diff --git a/chrome/browser/android/customtabs/detached_resource_request_android.cc b/chrome/browser/android/customtabs/detached_resource_request_android.cc
new file mode 100644
index 0000000..33283554
--- /dev/null
+++ b/chrome/browser/android/customtabs/detached_resource_request_android.cc
@@ -0,0 +1,36 @@
+// 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/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "base/android/scoped_java_ref.h"
+#include "chrome/browser/android/customtabs/detached_resource_request.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_android.h"
+#include "jni/CustomTabsConnection_jni.h"
+#include "url/gurl.h"
+
+namespace customtabs {
+
+static void JNI_CustomTabsConnection_CreateAndStartDetachedResourceRequest(
+    JNIEnv* env,
+    const base::android::JavaParamRef<jclass>& jcaller,
+    const base::android::JavaParamRef<jobject>& profile,
+    const base::android::JavaParamRef<jstring>& url,
+    const base::android::JavaParamRef<jstring>& origin) {
+  DCHECK(profile && url && origin);
+
+  Profile* native_profile = ProfileAndroid::FromProfileAndroid(profile);
+  DCHECK(native_profile);
+
+  GURL native_url(base::android::ConvertJavaStringToUTF8(env, url));
+  GURL native_origin(base::android::ConvertJavaStringToUTF8(env, origin));
+  DCHECK(native_url.is_valid());
+  DCHECK(native_origin.is_valid());
+
+  DetachedResourceRequest::CreateAndStart(native_profile, native_url,
+                                          native_origin);
+}
+
+}  // namespace customtabs
diff --git a/chrome/browser/android/preferences/pref_service_bridge.cc b/chrome/browser/android/preferences/pref_service_bridge.cc
index 74a6c30..0780e56 100644
--- a/chrome/browser/android/preferences/pref_service_bridge.cc
+++ b/chrome/browser/android/preferences/pref_service_bridge.cc
@@ -989,7 +989,7 @@
 
   base::android::BuildInfo* android_build_info =
         base::android::BuildInfo::GetInstance();
-  std::string application(android_build_info->package_label());
+  std::string application(android_build_info->host_package_label());
   application.append(" ");
   application.append(version_info::GetVersionNumber());
 
diff --git a/chrome/browser/android/vr/vr_gl_thread.cc b/chrome/browser/android/vr/vr_gl_thread.cc
index fd8de652..d2e7bfb 100644
--- a/chrome/browser/android/vr/vr_gl_thread.cc
+++ b/chrome/browser/android/vr/vr_gl_thread.cc
@@ -143,6 +143,12 @@
                                 base::Passed(std::move(event)), content_id));
 }
 
+void VrGLThread::ClearFocusedElement() {
+  DCHECK(OnGlThread());
+  main_thread_task_runner_->PostTask(
+      FROM_HERE, base::BindOnce(&VrShell::ClearFocusedElement, weak_vr_shell_));
+}
+
 void VrGLThread::OnWebInputEdited(const TextEdits& edits) {
   DCHECK(OnGlThread());
   DCHECK(weak_input_connection_);
@@ -270,12 +276,6 @@
       FROM_HERE, base::BindOnce(&VrShell::StopAutocomplete, weak_vr_shell_));
 }
 
-void VrGLThread::LoadAssets() {
-  DCHECK(OnGlThread());
-  main_thread_task_runner_->PostTask(
-      FROM_HERE, base::BindOnce(&VrShell::LoadAssets, weak_vr_shell_));
-}
-
 void VrGLThread::SetFullscreen(bool enabled) {
   DCHECK(OnMainThread());
   task_runner()->PostTask(FROM_HERE,
@@ -407,13 +407,6 @@
                      weak_browser_ui_, base::Passed(std::move(suggestions))));
 }
 
-void VrGLThread::OnAssetsComponentReady() {
-  DCHECK(OnMainThread());
-  task_runner()->PostTask(
-      FROM_HERE, base::BindOnce(&BrowserUiInterface::OnAssetsComponentReady,
-                                weak_browser_ui_));
-}
-
 void VrGLThread::OnAssetsLoaded(AssetsLoadStatus status,
                                 std::unique_ptr<Assets> assets,
                                 const base::Version& component_version) {
diff --git a/chrome/browser/android/vr/vr_gl_thread.h b/chrome/browser/android/vr/vr_gl_thread.h
index 4e95c5c..3c39270a 100644
--- a/chrome/browser/android/vr/vr_gl_thread.h
+++ b/chrome/browser/android/vr/vr_gl_thread.h
@@ -69,6 +69,7 @@
   void ForwardEvent(std::unique_ptr<blink::WebInputEvent> event,
                     int content_id) override;
   void ForwardDialogEvent(std::unique_ptr<blink::WebInputEvent> event) override;
+  void ClearFocusedElement() override;
   void OnWebInputEdited(const TextEdits& edits) override;
   void SubmitWebInput() override;
   void RequestWebInputText(TextStateUpdateCallback callback) override;
@@ -87,7 +88,6 @@
   void SetVoiceSearchActive(bool active) override;
   void StartAutocomplete(const AutocompleteRequest& request) override;
   void StopAutocomplete() override;
-  void LoadAssets() override;
 
   // BrowserUiInterface implementation (Browser calling to UI).
   void SetWebVrMode(bool enabled, bool show_toast) override;
@@ -109,7 +109,6 @@
   void OnSpeechRecognitionStateChanged(int new_state) override;
   void SetOmniboxSuggestions(
       std::unique_ptr<OmniboxSuggestions> result) override;
-  void OnAssetsComponentReady() override;
   void OnAssetsLoaded(AssetsLoadStatus status,
                       std::unique_ptr<Assets> assets,
                       const base::Version& component_version) override;
diff --git a/chrome/browser/android/vr/vr_shell.cc b/chrome/browser/android/vr/vr_shell.cc
index 37021782..740f86e5 100644
--- a/chrome/browser/android/vr/vr_shell.cc
+++ b/chrome/browser/android/vr/vr_shell.cc
@@ -918,6 +918,13 @@
   high_accuracy_location_ = high_accuracy_location;
 }
 
+void VrShell::ClearFocusedElement() {
+  if (!web_contents_)
+    return;
+
+  web_contents_->ClearFocusedElement();
+}
+
 void VrShell::ProcessContentGesture(std::unique_ptr<blink::WebInputEvent> event,
                                     int content_id) {
   // Block the events if they don't belong to the current content
@@ -1005,11 +1012,6 @@
       base::android::ConvertUTF8ToJavaString(env, url.spec()));
 }
 
-void VrShell::LoadAssets() {
-  AssetsLoader::GetInstance()->Load(
-      base::BindOnce(&VrShell::OnAssetsLoaded, base::Unretained(this)));
-}
-
 void VrShell::OnAssetsLoaded(AssetsLoadStatus status,
                              std::unique_ptr<Assets> assets,
                              const base::Version& component_version) {
@@ -1025,12 +1027,18 @@
       status, component_version);
 }
 
+void VrShell::LoadAssets() {
+  AssetsLoader::GetInstance()->Load(
+      base::BindOnce(&VrShell::OnAssetsLoaded, base::Unretained(this)));
+}
+
 void VrShell::OnAssetsComponentReady() {
+  // We don't apply updates after the timer expires because that would lead to
+  // replacing the user's environment. New updates will be applied when
+  // re-entering VR.
   if (waiting_for_assets_component_timer_.IsRunning()) {
     waiting_for_assets_component_timer_.Stop();
     LoadAssets();
-  } else {
-    ui_->OnAssetsComponentReady();
   }
 }
 
@@ -1075,7 +1083,7 @@
       has_or_can_request_audio_permission;
   ui_initial_state.skips_redraw_when_not_dirty =
       base::FeatureList::IsEnabled(features::kVrBrowsingExperimentalRendering);
-  ui_initial_state.assets_available = true;
+  ui_initial_state.assets_supported = AssetsLoader::AssetsSupported();
 
   return reinterpret_cast<intptr_t>(new VrShell(
       env, obj, ui_initial_state,
diff --git a/chrome/browser/android/vr/vr_shell.h b/chrome/browser/android/vr/vr_shell.h
index ddeaa3ba..520315d5 100644
--- a/chrome/browser/android/vr/vr_shell.h
+++ b/chrome/browser/android/vr/vr_shell.h
@@ -187,6 +187,7 @@
   void StopAutocomplete();
   bool HasAudioPermission();
 
+  void ClearFocusedElement();
   void ProcessContentGesture(std::unique_ptr<blink::WebInputEvent> event,
                              int content_id);
 
@@ -223,7 +224,6 @@
 
   void OnVoiceResults(const base::string16& result) override;
 
-  void LoadAssets();
   void OnAssetsLoaded(AssetsLoadStatus status,
                       std::unique_ptr<Assets> assets,
                       const base::Version& component_version);
@@ -247,6 +247,7 @@
 
   content::WebContents* GetNonNativePageWebContents() const;
 
+  void LoadAssets();
   void OnAssetsComponentReady();
   void OnAssetsComponentWaitTimeout();
 
diff --git a/chrome/browser/android/vr/vr_shell_gl.cc b/chrome/browser/android/vr/vr_shell_gl.cc
index 635b402..185d5ae 100644
--- a/chrome/browser/android/vr/vr_shell_gl.cc
+++ b/chrome/browser/android/vr/vr_shell_gl.cc
@@ -1571,7 +1571,7 @@
   gfx::Transform head_mat;
   device::mojom::VRPosePtr pose =
       device::GvrDelegate::GetVRPosePtrWithNeckModel(gvr_api_.get(), &head_mat,
-                                                     0, prediction_nanos);
+                                                     prediction_nanos);
 
   webvr_head_pose_[frame_index % kPoseRingBufferSize] = head_mat;
   webvr_frame_oustanding_[frame_index % kPoseRingBufferSize] = true;
diff --git a/chrome/browser/component_updater/vr_assets_component_installer.cc b/chrome/browser/component_updater/vr_assets_component_installer.cc
index 1d2ad29..caebc2e 100644
--- a/chrome/browser/component_updater/vr_assets_component_installer.cc
+++ b/chrome/browser/component_updater/vr_assets_component_installer.cc
@@ -19,7 +19,7 @@
 #include "base/version.h"
 #include "chrome/browser/vr/assets_loader.h"
 #include "chrome/browser/vr/metrics_helper.h"
-#include "chrome/browser/vr_features.h"
+#include "chrome/browser/vr/vr_features.h"
 #include "chrome/common/safe_browsing/file_type_policies.h"
 #include "components/component_updater/component_updater_paths.h"
 #include "components/component_updater/component_updater_service.h"
diff --git a/chrome/browser/download/download_browsertest.cc b/chrome/browser/download/download_browsertest.cc
index 4bbcf8f..ff27b9ff 100644
--- a/chrome/browser/download/download_browsertest.cc
+++ b/chrome/browser/download/download_browsertest.cc
@@ -32,6 +32,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/sys_info.h"
+#include "base/test/histogram_tester.h"
 #include "base/test/test_file_util.h"
 #include "base/threading/thread_restrictions.h"
 #include "build/build_config.h"
@@ -89,6 +90,7 @@
 #include "components/prefs/pref_service.h"
 #include "components/safe_browsing/common/safe_browsing_prefs.h"
 #include "components/safe_browsing/proto/csd.pb.h"
+#include "components/security_state/core/security_state.h"
 #include "content/public/browser/download_manager.h"
 #include "content/public/browser/download_request_utils.h"
 #include "content/public/browser/notification_source.h"
@@ -3447,6 +3449,37 @@
   DownloadAndWait(browser(), url);
 }
 
+// Test that the SecurityLevel of the initiating page is used for the histogram
+// rather than the SecurityLevel of the download URL, and that downloads in new
+// tabs are not tracked.
+IN_PROC_BROWSER_TEST_F(DownloadTest, SecurityLevels) {
+  base::HistogramTester histogram_tester;
+  net::EmbeddedTestServer http_server(net::EmbeddedTestServer::TYPE_HTTP);
+  net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
+  http_server.ServeFilesFromDirectory(GetTestDataDirectory());
+  https_server.ServeFilesFromDirectory(GetTestDataDirectory());
+  ASSERT_TRUE(http_server.Start());
+  ASSERT_TRUE(https_server.Start());
+
+  ui_test_utils::NavigateToURL(browser(), http_server.GetURL("/simple.html"));
+  DownloadAndWait(browser(), https_server.GetURL("/downloads/a_zip_file.zip"));
+  histogram_tester.ExpectBucketCount("Security.SecurityLevel.DownloadStarted",
+                                     security_state::NONE, 1);
+
+  ui_test_utils::NavigateToURL(browser(), https_server.GetURL("/simple.html"));
+  DownloadAndWait(browser(), http_server.GetURL("/downloads/a_zip_file.zip"));
+  histogram_tester.ExpectBucketCount("Security.SecurityLevel.DownloadStarted",
+                                     security_state::SECURE, 1);
+
+  ui_test_utils::NavigateToURL(browser(), http_server.GetURL("/simple.html"));
+  DownloadAndWaitWithDisposition(
+      browser(), https_server.GetURL("/downloads/a_zip_file.zip"),
+      WindowOpenDisposition::NEW_BACKGROUND_TAB,
+      ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB);
+  histogram_tester.ExpectTotalCount("Security.SecurityLevel.DownloadStarted",
+                                    2);
+}
+
 #if defined(FULL_SAFE_BROWSING)
 
 namespace {
diff --git a/chrome/browser/download/download_ui_controller.cc b/chrome/browser/download/download_ui_controller.cc
index 3406dcb..15279d7 100644
--- a/chrome/browser/download/download_ui_controller.cc
+++ b/chrome/browser/download/download_ui_controller.cc
@@ -7,15 +7,18 @@
 #include <utility>
 
 #include "base/callback.h"
+#include "base/metrics/histogram_macros.h"
 #include "build/build_config.h"
 #include "chrome/browser/devtools/devtools_window.h"
 #include "chrome/browser/download/download_item_model.h"
 #include "chrome/browser/download/download_shelf.h"
+#include "chrome/browser/ssl/security_state_tab_helper.h"
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_tabstrip.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "components/download/public/common/download_item.h"
+#include "components/security_state/core/security_state.h"
 #include "content/public/browser/download_item_utils.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_delegate.h"
@@ -133,6 +136,26 @@
 
 void DownloadUIController::OnDownloadCreated(content::DownloadManager* manager,
                                              download::DownloadItem* item) {
+  // Record the security level of the page triggering the download. Only record
+  // when the download occurs in the WebContents that initiated the download
+  // (e.g., not downloads in new tabs or windows, which have a different
+  // WebContents).
+  content::WebContents* web_contents =
+      content::DownloadItemUtils::GetWebContents(item);
+  if (web_contents && (item->IsSavePackageDownload() ||
+                       (web_contents->GetURL() != item->GetOriginalUrl() &&
+                        web_contents->GetURL() != item->GetURL()))) {
+    auto* security_state_tab_helper =
+        SecurityStateTabHelper::FromWebContents(web_contents);
+    if (security_state_tab_helper) {
+      security_state::SecurityInfo security_info;
+      security_state_tab_helper->GetSecurityInfo(&security_info);
+      UMA_HISTOGRAM_ENUMERATION("Security.SecurityLevel.DownloadStarted",
+                                security_info.security_level,
+                                security_state::SECURITY_LEVEL_COUNT);
+    }
+  }
+
   // SavePackage downloads are created in a state where they can be shown in the
   // browser. Call OnDownloadUpdated() once to notify the UI immediately.
   OnDownloadUpdated(manager, item);
diff --git a/chrome/browser/download/save_page_browsertest.cc b/chrome/browser/download/save_page_browsertest.cc
index 7f7fb586..ae67d9c5 100644
--- a/chrome/browser/download/save_page_browsertest.cc
+++ b/chrome/browser/download/save_page_browsertest.cc
@@ -20,6 +20,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/histogram_tester.h"
 #include "base/test/test_file_util.h"
 #include "base/threading/thread_restrictions.h"
 #include "build/build_config.h"
@@ -46,6 +47,7 @@
 #include "components/history/core/browser/download_row.h"
 #include "components/prefs/pref_member.h"
 #include "components/prefs/pref_service.h"
+#include "components/security_state/core/security_state.h"
 #include "content/public/browser/download_manager.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/notification_types.h"
@@ -684,6 +686,17 @@
 }
 #endif
 
+// Tests that the SecurityLevel histograms are logged for save page downloads.
+IN_PROC_BROWSER_TEST_F(SavePageBrowserTest, SecurityLevelHistogram) {
+  base::HistogramTester histogram_tester;
+  GURL url = NavigateToMockURL("a");
+  base::FilePath full_file_name, dir;
+  SaveCurrentTab(url, content::SAVE_PAGE_TYPE_AS_ONLY_HTML, "a", 1, &dir,
+                 &full_file_name);
+  histogram_tester.ExpectUniqueSample("Security.SecurityLevel.DownloadStarted",
+                                      security_state::NONE, 1);
+}
+
 class SavePageAsMHTMLBrowserTest : public SavePageBrowserTest {
  public:
   SavePageAsMHTMLBrowserTest() {}
diff --git a/chrome/browser/extensions/chrome_extension_web_contents_observer.cc b/chrome/browser/extensions/chrome_extension_web_contents_observer.cc
index 0044910..56e34e8 100644
--- a/chrome/browser/extensions/chrome_extension_web_contents_observer.cc
+++ b/chrome/browser/extensions/chrome_extension_web_contents_observer.cc
@@ -40,8 +40,19 @@
 
 ChromeExtensionWebContentsObserver::~ChromeExtensionWebContentsObserver() {}
 
+// static
+void ChromeExtensionWebContentsObserver::CreateForWebContents(
+    content::WebContents* web_contents) {
+  content::WebContentsUserData<
+      ChromeExtensionWebContentsObserver>::CreateForWebContents(web_contents);
+
+  // Initialize this instance if necessary.
+  FromWebContents(web_contents)->Initialize();
+}
+
 void ChromeExtensionWebContentsObserver::RenderFrameCreated(
     content::RenderFrameHost* render_frame_host) {
+  DCHECK(initialized());
   ReloadIfTerminated(render_frame_host);
   ExtensionWebContentsObserver::RenderFrameCreated(render_frame_host);
 
@@ -82,12 +93,14 @@
 
 void ChromeExtensionWebContentsObserver::DidFinishNavigation(
     content::NavigationHandle* navigation_handle) {
+  DCHECK(initialized());
   ExtensionWebContentsObserver::DidFinishNavigation(navigation_handle);
 }
 
 bool ChromeExtensionWebContentsObserver::OnMessageReceived(
     const IPC::Message& message,
     content::RenderFrameHost* render_frame_host) {
+  DCHECK(initialized());
   if (ExtensionWebContentsObserver::OnMessageReceived(message,
                                                       render_frame_host)) {
     return true;
@@ -109,6 +122,7 @@
     const base::string16& source,
     const StackTrace& stack_trace,
     int32_t severity_level) {
+  DCHECK(initialized());
   if (!IsSourceFromAnExtension(source))
     return;
 
@@ -127,6 +141,7 @@
 
 void ChromeExtensionWebContentsObserver::InitializeRenderFrame(
     content::RenderFrameHost* render_frame_host) {
+  DCHECK(initialized());
   ExtensionWebContentsObserver::InitializeRenderFrame(render_frame_host);
   WindowController* controller = dispatcher()->GetExtensionWindowController();
   if (controller) {
@@ -137,6 +152,7 @@
 
 void ChromeExtensionWebContentsObserver::ReloadIfTerminated(
     content::RenderFrameHost* render_frame_host) {
+  DCHECK(initialized());
   std::string extension_id = GetExtensionIdFromFrame(render_frame_host);
   if (extension_id.empty())
     return;
diff --git a/chrome/browser/extensions/chrome_extension_web_contents_observer.h b/chrome/browser/extensions/chrome_extension_web_contents_observer.h
index d6d97fb6..1ecf8ae4 100644
--- a/chrome/browser/extensions/chrome_extension_web_contents_observer.h
+++ b/chrome/browser/extensions/chrome_extension_web_contents_observer.h
@@ -29,6 +29,10 @@
  public:
   ~ChromeExtensionWebContentsObserver() override;
 
+  // Creates and initializes an instance of this class for the given
+  // |web_contents|, if it doesn't already exist.
+  static void CreateForWebContents(content::WebContents* web_contents);
+
  private:
   friend class content::WebContentsUserData<ChromeExtensionWebContentsObserver>;
 
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index c63b2f1..334daec 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -2683,6 +2683,10 @@
     "Enable IME extensions to supply custom views for user input such as "
     "virtual keyboards.";
 
+const char kLockScreenNotificationName[] = "Lock screen notification";
+const char kLockScreenNotificationDescription[] =
+    "Enable notifications on the lock screen.";
+
 const char kMemoryPressureThresholdName[] =
     "Memory discard strategy for advanced pressure handling";
 const char kMemoryPressureThresholdDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index cd90f621..a3333853 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -1662,6 +1662,9 @@
 extern const char kInputViewName[];
 extern const char kInputViewDescription[];
 
+extern const char kLockScreenNotificationName[];
+extern const char kLockScreenNotificationDescription[];
+
 extern const char kMemoryPressureThresholdName[];
 extern const char kMemoryPressureThresholdDescription[];
 extern const char kConservativeThresholds[];
diff --git a/chrome/browser/media/webrtc/webrtc_browsertest.cc b/chrome/browser/media/webrtc/webrtc_browsertest.cc
index 70b5ba7..94cd801f 100644
--- a/chrome/browser/media/webrtc/webrtc_browsertest.cc
+++ b/chrome/browser/media/webrtc/webrtc_browsertest.cc
@@ -12,9 +12,9 @@
 #include "chrome/common/chrome_switches.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
+#include "content/public/common/buildflags.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/feature_h264_with_openh264_ffmpeg.h"
-#include "content/public/common/features.h"
 #include "content/public/test/browser_test_utils.h"
 #include "media/base/media_switches.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
diff --git a/chrome/browser/media/webrtc/webrtc_desktop_capture_browsertest.cc b/chrome/browser/media/webrtc/webrtc_desktop_capture_browsertest.cc
index ed531ca..cee51750 100644
--- a/chrome/browser/media/webrtc/webrtc_desktop_capture_browsertest.cc
+++ b/chrome/browser/media/webrtc/webrtc_desktop_capture_browsertest.cc
@@ -12,9 +12,9 @@
 #include "chrome/common/chrome_switches.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
+#include "content/public/common/buildflags.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/feature_h264_with_openh264_ffmpeg.h"
-#include "content/public/common/features.h"
 #include "content/public/test/browser_test_utils.h"
 #include "media/base/media_switches.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
diff --git a/chrome/browser/media/webrtc/webrtc_internals_perf_browsertest.cc b/chrome/browser/media/webrtc/webrtc_internals_perf_browsertest.cc
index f92760f9..9f8b40a 100644
--- a/chrome/browser/media/webrtc/webrtc_internals_perf_browsertest.cc
+++ b/chrome/browser/media/webrtc/webrtc_internals_perf_browsertest.cc
@@ -22,9 +22,9 @@
 #include "chrome/common/chrome_switches.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
+#include "content/public/common/buildflags.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/feature_h264_with_openh264_ffmpeg.h"
-#include "content/public/common/features.h"
 #include "content/public/test/browser_test_utils.h"
 #include "media/base/media_switches.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
diff --git a/chrome/browser/media/webrtc/webrtc_video_quality_browsertest.cc b/chrome/browser/media/webrtc/webrtc_video_quality_browsertest.cc
index 7cf813df..eda6c34 100644
--- a/chrome/browser/media/webrtc/webrtc_video_quality_browsertest.cc
+++ b/chrome/browser/media/webrtc/webrtc_video_quality_browsertest.cc
@@ -31,8 +31,8 @@
 #include "chrome/test/base/in_process_browser_test.h"
 #include "components/infobars/core/infobar.h"
 #include "content/public/browser/notification_service.h"
+#include "content/public/common/buildflags.h"
 #include "content/public/common/feature_h264_with_openh264_ffmpeg.h"
-#include "content/public/common/features.h"
 #include "content/public/test/browser_test_utils.h"
 #include "media/base/media_switches.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
diff --git a/chrome/browser/password_manager/password_manager_browsertest.cc b/chrome/browser/password_manager/password_manager_browsertest.cc
index 2739c86..21b388e 100644
--- a/chrome/browser/password_manager/password_manager_browsertest.cc
+++ b/chrome/browser/password_manager/password_manager_browsertest.cc
@@ -1791,6 +1791,40 @@
   WaitForElementValue("username_id", "temp");
 }
 
+// Test that if the same dynamic form is created multiple times then all of them
+// are autofilled and no unnecessary PasswordStore requests are fired.
+IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTestBase,
+                       DuplicateFormsGetFilled) {
+  // At first let us save a credential to the password store.
+  scoped_refptr<password_manager::TestPasswordStore> password_store =
+      static_cast<password_manager::TestPasswordStore*>(
+          PasswordStoreFactory::GetForProfile(
+              browser()->profile(), ServiceAccessType::IMPLICIT_ACCESS)
+              .get());
+  autofill::PasswordForm signin_form;
+  signin_form.signon_realm = embedded_test_server()->base_url().spec();
+  signin_form.origin = embedded_test_server()->base_url();
+  signin_form.action = embedded_test_server()->base_url();
+  signin_form.username_value = base::ASCIIToUTF16("temp");
+  signin_form.password_value = base::ASCIIToUTF16("random");
+  password_store->AddLogin(signin_form);
+
+  NavigateToFile("/password/recurring_dynamic_form.html");
+  ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), "addForm();"));
+  // Wait until the username is filled, to make sure autofill kicked in.
+  WaitForJsElementValue("document.body.children[0].children[0]", "temp");
+  WaitForJsElementValue("document.body.children[0].children[1]", "random");
+
+  // It's a trick. There should be no second request to the password store since
+  // the existing PasswordFormManager will manage the new form.
+  password_store->Clear();
+  // Add one more form.
+  ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), "addForm();"));
+  // Wait until the username is filled, to make sure autofill kicked in.
+  WaitForJsElementValue("document.body.children[1].children[0]", "temp");
+  WaitForJsElementValue("document.body.children[1].children[1]", "random");
+}
+
 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTestBase,
                        PromptForPushStateWhenFormDisappears) {
   NavigateToFile("/password/password_push_state.html");
diff --git a/chrome/browser/password_manager/password_manager_test_base.cc b/chrome/browser/password_manager/password_manager_test_base.cc
index a9fc753f..757d888 100644
--- a/chrome/browser/password_manager/password_manager_test_base.cc
+++ b/chrome/browser/password_manager/password_manager_test_base.cc
@@ -583,12 +583,21 @@
     const std::string& form_id,
     size_t elements_index,
     const std::string& expected_value) {
+  const std::string element_selector =
+      base::StringPrintf("document.getElementById('%s').elements['%zu']",
+                         form_id.c_str(), elements_index);
+  WaitForJsElementValue(element_selector, expected_value);
+}
+
+void PasswordManagerBrowserTestBase::WaitForJsElementValue(
+    const std::string& element_selector,
+    const std::string& expected_value) {
   const std::string value_check_function = base::StringPrintf(
       "function valueCheck() {"
-      "  var element = document.getElementById('%s').elements['%zu'];"
+      "  var element = %s;"
       "  return element && element.value == '%s';"
       "}",
-      form_id.c_str(), elements_index, expected_value.c_str());
+      element_selector.c_str(), expected_value.c_str());
   const std::string script =
       value_check_function +
       base::StringPrintf(
@@ -596,7 +605,7 @@
           "  /* Spin the event loop with setTimeout. */"
           "  setTimeout(window.domAutomationController.send(%d), 0);"
           "} else {"
-          "  var element = document.getElementById('%s').elements['%zu'];"
+          "  var element = %s;"
           "  if (!element)"
           "    window.domAutomationController.send(%d);"
           "  element.onchange = function() {"
@@ -614,13 +623,13 @@
           "    element.onchange = undefined;"
           "  };"
           "}",
-          RETURN_CODE_OK, form_id.c_str(), elements_index,
-          RETURN_CODE_NO_ELEMENT, RETURN_CODE_OK, RETURN_CODE_WRONG_VALUE);
+          RETURN_CODE_OK, element_selector.c_str(), RETURN_CODE_NO_ELEMENT,
+          RETURN_CODE_OK, RETURN_CODE_WRONG_VALUE);
   int return_value = RETURN_CODE_INVALID;
   ASSERT_TRUE(content::ExecuteScriptWithoutUserGestureAndExtractInt(
       RenderFrameHost(), script, &return_value));
   EXPECT_EQ(RETURN_CODE_OK, return_value)
-      << "form_id = " << form_id << "elements_index=" << elements_index
+      << "element_selector = " << element_selector
       << ", expected_value = " << expected_value;
 }
 
diff --git a/chrome/browser/password_manager/password_manager_test_base.h b/chrome/browser/password_manager/password_manager_test_base.h
index cd9af29..3e8d25b 100644
--- a/chrome/browser/password_manager/password_manager_test_base.h
+++ b/chrome/browser/password_manager/password_manager_test_base.h
@@ -175,6 +175,11 @@
                            size_t element_index,
                            const std::string& expected_value);
 
+  // Same as above except the element is selected with |element_selector| JS
+  // expression.
+  void WaitForJsElementValue(const std::string& element_selector,
+                             const std::string& expected_value);
+
   // Make sure that the password store processed all the previous calls which
   // are executed on another thread.
   void WaitForPasswordStore();
diff --git a/chrome/browser/policy/policy_network_browsertest.cc b/chrome/browser/policy/policy_network_browsertest.cc
index 57a51ca..56e589c 100644
--- a/chrome/browser/policy/policy_network_browsertest.cc
+++ b/chrome/browser/policy/policy_network_browsertest.cc
@@ -18,7 +18,6 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/test/base/in_process_browser_test.h"
-#include "components/grpc_support/test/quic_test_server.h"
 #include "components/network_session_configurator/common/network_switches.h"
 #include "components/policy/core/browser/browser_policy_connector.h"
 #include "components/policy/core/common/mock_configuration_policy_provider.h"
@@ -34,6 +33,7 @@
 #include "net/cert/test_root_certs.h"
 #include "net/dns/mock_host_resolver.h"
 #include "net/http/http_transaction_factory.h"
+#include "net/test/quic_simple_test_server.h"
 #include "net/test/test_data_directory.h"
 #include "net/url_request/url_request_context.h"
 #include "net/url_request/url_request_context_getter.h"
@@ -76,10 +76,8 @@
 }
 
 bool IsQuicEnabled(network::mojom::NetworkContext* network_context) {
-  GURL url =
-      GURL(std::string("https://") + grpc_support::kTestServerHost + ":" +
-           base::NumberToString(grpc_support::GetQuicTestServerPort()) +
-           grpc_support::kHelloPath);
+  GURL url = net::QuicSimpleTestServer::GetFileURL(
+      net::QuicSimpleTestServer::GetHelloPath());
   int rv = content::LoadBasicRequest(network_context, url);
   return rv == net::OK;
 }
@@ -138,7 +136,7 @@
     net::TestRootCerts* root_certs = net::TestRootCerts::GetInstance();
     root_certs->AddFromFile(
         net::GetTestCertsDirectory().AppendASCII("quic-root.pem"));
-    grpc_support::StartQuicTestServer();
+    net::QuicSimpleTestServer::Start();
     host_resolver()->AddRule("*", "127.0.0.1");
   }
 };
diff --git a/chrome/browser/prerender/prerender_nostate_prefetch_browsertest.cc b/chrome/browser/prerender/prerender_nostate_prefetch_browsertest.cc
index 65481d1..6c4ec622 100644
--- a/chrome/browser/prerender/prerender_nostate_prefetch_browsertest.cc
+++ b/chrome/browser/prerender/prerender_nostate_prefetch_browsertest.cc
@@ -47,60 +47,13 @@
 #include "net/url_request/url_request_context.h"
 #include "net/url_request/url_request_context_getter.h"
 #include "services/network/public/cpp/features.h"
+#include "services/network/public/mojom/cookie_manager.mojom.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 using prerender::test_utils::DestructionWaiter;
 using prerender::test_utils::RequestCounter;
 using prerender::test_utils::TestPrerender;
 
-namespace {
-
-// Helper method that verifies cookies for PrefetchCookies* tests. When the
-// cookies expected from loading test/data/prerender/cookie.{js,html}. |loop| is
-// notified when the cookies are found; if the cookies are not found this will
-// wait forever.
-void CheckCookiesForPrefetchCookieTest(base::RunLoop* loop,
-                                       GURL url,
-                                       net::CookieStore* cookie_store,
-                                       const net::CookieList& cookies) {
-  bool found_chocolate = false;
-  bool found_oatmeal = false;
-  for (const auto& c : cookies) {
-    if (c.Name() == "chocolate-chip") {
-      EXPECT_EQ("the-best", c.Value());
-      found_chocolate = true;
-    }
-    if (c.Name() == "oatmeal") {
-      EXPECT_EQ("sublime", c.Value());
-      found_oatmeal = true;
-    }
-  }
-  if (found_oatmeal && found_chocolate) {
-    loop->Quit();
-  } else {
-    content::BrowserThread::PostDelayedTask(
-        content::BrowserThread::IO, FROM_HERE,
-        base::BindOnce(&net::CookieStore::GetAllCookiesForURLAsync,
-                       base::Unretained(cookie_store), url,
-                       base::BindOnce(CheckCookiesForPrefetchCookieTest, loop,
-                                      url, cookie_store)),
-        base::TimeDelta::FromMilliseconds(250));
-  }
-}
-
-// Launches the CheckCookiesForPrefetchCookieTest from the IO thread.
-void LaunchPrefetchCookieTestFromIO(content::StoragePartition* storage,
-                                    base::RunLoop* loop,
-                                    GURL url) {
-  net::CookieStore* cookie_store =
-      storage->GetURLRequestContext()->GetURLRequestContext()->cookie_store();
-  cookie_store->GetAllCookiesForURLAsync(
-      url, base::BindOnce(CheckCookiesForPrefetchCookieTest, loop, url,
-                          cookie_store));
-}
-
-}  // namespace
-
 namespace prerender {
 
 const char k302RedirectPage[] = "/prerender/302_redirect.html";
@@ -276,6 +229,24 @@
   WaitForRequestCount(src_server()->GetURL(kPrefetchScript2), 0);
 }
 
+void GetCookieCallback(base::RepeatingClosure callback,
+                       const net::CookieList& cookie_list) {
+  bool found_chocolate = false;
+  bool found_oatmeal = false;
+  for (const auto& c : cookie_list) {
+    if (c.Name() == "chocolate-chip") {
+      EXPECT_EQ("the-best", c.Value());
+      found_chocolate = true;
+    }
+    if (c.Name() == "oatmeal") {
+      EXPECT_EQ("sublime", c.Value());
+      found_oatmeal = true;
+    }
+  }
+  CHECK(found_chocolate && found_oatmeal);
+  callback.Run();
+}
+
 // Check cookie loading for prefetched pages.
 IN_PROC_BROWSER_TEST_P(NoStatePrefetchBrowserTest, PrefetchCookie) {
   GURL url = src_server()->GetURL(kPrefetchCookiePage);
@@ -285,13 +256,11 @@
   content::StoragePartition* storage_partition =
       content::BrowserContext::GetStoragePartitionForSite(
           current_browser()->profile(), url, false);
+  net::CookieOptions options;
   base::RunLoop loop;
-  content::BrowserThread::PostTask(
-      content::BrowserThread::IO, FROM_HERE,
-      base::BindOnce(LaunchPrefetchCookieTestFromIO, storage_partition, &loop,
-                     url));
+  storage_partition->GetCookieManagerForBrowserProcess()->GetCookieList(
+      url, options, base::BindOnce(GetCookieCallback, loop.QuitClosure()));
   loop.Run();
-  // Will timeout if cookies aren't found.
 }
 
 // Check cookie loading for a cross-domain prefetched pages.
@@ -307,13 +276,12 @@
   content::StoragePartition* storage_partition =
       content::BrowserContext::GetStoragePartitionForSite(
           current_browser()->profile(), cross_domain_url, false);
+  net::CookieOptions options;
   base::RunLoop loop;
-  content::BrowserThread::PostTask(
-      content::BrowserThread::IO, FROM_HERE,
-      base::BindOnce(LaunchPrefetchCookieTestFromIO, storage_partition, &loop,
-                     cross_domain_url));
+  storage_partition->GetCookieManagerForBrowserProcess()->GetCookieList(
+      cross_domain_url, options,
+      base::BindOnce(GetCookieCallback, loop.QuitClosure()));
   loop.Run();
-  // Will timeout if cookies aren't found.
 }
 
 // Check that the LOAD_PREFETCH flag is set.
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_predicate.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_predicate.js
index d79272d..ac05c71 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_predicate.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_predicate.js
@@ -237,6 +237,24 @@
        AutomationPredicate.formField(node)))
     return true;
 
+  // Containers who have name from contents should be treated like objects if
+  // the contents is all static text and not large.
+  if (node.name && node.nameFrom == 'contents') {
+    var onlyStaticText = true;
+    var textLength = 0;
+    for (var i = 0, child; child = node.children[i]; i++) {
+      if (child.role != Role.STATIC_TEXT) {
+        onlyStaticText = false;
+        break;
+      }
+      textLength += child.name ? child.name.length + textLength : textLength;
+    }
+
+    if (onlyStaticText && textLength > 0 &&
+        textLength < constants.OBJECT_MAX_CHARCOUNT)
+      return true;
+  }
+
   // Otherwise, leaf or static text nodes that don't contain only whitespace
   // should be visited with the exception of non-text only nodes. This covers
   // cases where an author might make a link with a name of ' '.
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs
index bc3b7943..8f0e620 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background_test.extjs
@@ -175,6 +175,8 @@
         .expectSpeech('foxtraut', 'Heading 2')
         .expectBraille('foxtraut h2');
     mockFeedback.call(doCmd('nextLine'))
+        .expectSpeech('foxtraut');
+    mockFeedback.call(doCmd('nextLine'))
         .expectSpeech('end', 'of test')
         .expectBraille('endof test');
 
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js
index 69f23733..d0bbf33 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js
@@ -1083,12 +1083,19 @@
           options.annotation.push('name');
           this.append_(buff, node.name || '', options);
         } else if (token == 'nameOrDescendants') {
+          // This token is similar to nameOrTextContent except it gathers rich
+          // output for descendants. It also lets name from contents override
+          // the descendants text if |node| has only static text children.
           options.annotation.push(token);
           if (node.name &&
-              node.nameFrom != chrome.automation.NameFromType.CONTENTS)
+              (node.nameFrom != 'contents' ||
+               node.children.every(function(child) {
+                 return child.role == RoleType.STATIC_TEXT;
+               }))) {
             this.append_(buff, node.name || '', options);
-          else
+          } else {
             this.format_(node, '$descendants', buff);
+          }
         } else if (token == 'description') {
           if (node.name == node.description || node.value == node.description)
             return;
@@ -1280,7 +1287,7 @@
             }
           }
         } else if (token == 'nameOrTextContent') {
-          if (node.name) {
+          if (node.name && node.nameFrom != 'contents') {
             this.format_(node, '$name', buff);
             return;
           }
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/output_test.extjs b/chrome/browser/resources/chromeos/chromevox/cvox2/background/output_test.extjs
index 0a80a128..b887ea09 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/output_test.extjs
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/output_test.extjs
@@ -190,12 +190,11 @@
         var letter = String.fromCharCode('a'.charCodeAt(0) + i -1);
         assertEqualsJSON({string_: letter + '|Heading ' + i, 'spans_': [
           // Attributes.
-          {value: 'name', start: 0, end: 1}
+          {value: 'nameOrDescendants', start: 0, end: 1}
         ]}, o.speechOutputForTest);
         checkBrailleOutput(
             letter + ' h' + i,
             [
-              {value: new Output.NodeSpan(el.firstChild), start: 0, end: 1},
               {value: new Output.NodeSpan(el), start: 0, end: 4}
             ],
             o);
@@ -624,7 +623,7 @@
           {value: {'relativePitch': toFixed(-0.1 * i)}, start: 0, end: 0},
 
           // Attributes.
-          {value: 'name', start: 0, end: 1},
+          {value: 'nameOrDescendants', start: 0, end: 1},
 
           {value: {'relativePitch': -0.2}, start: 2, end: 2}
         ]}, o.speechOutputForTest);
diff --git a/chrome/browser/sync/test/integration/sync_test.cc b/chrome/browser/sync/test/integration/sync_test.cc
index 78a2a58..49c54db 100644
--- a/chrome/browser/sync/test/integration/sync_test.cc
+++ b/chrome/browser/sync/test/integration/sync_test.cc
@@ -1206,16 +1206,6 @@
   ui_test_utils::NavigateToURL(browser(), sync_server_.GetURL(path));
 }
 
-void SyncTest::TriggerCreateSyncedBookmarks() {
-  ASSERT_TRUE(ServerSupportsErrorTriggering());
-  std::string path = "chromiumsync/createsyncedbookmarks";
-  ui_test_utils::NavigateToURL(browser(), sync_server_.GetURL(path));
-  ASSERT_EQ("Synced Bookmarks",
-            base::UTF16ToASCII(
-                browser()->tab_strip_model()->GetActiveWebContents()->
-                    GetTitle()));
-}
-
 fake_server::FakeServer* SyncTest::GetFakeServer() const {
   return fake_server_.get();
 }
diff --git a/chrome/browser/sync/test/integration/sync_test.h b/chrome/browser/sync/test/integration/sync_test.h
index 6e1fac1..03adc6eef 100644
--- a/chrome/browser/sync/test/integration/sync_test.h
+++ b/chrome/browser/sync/test/integration/sync_test.h
@@ -244,9 +244,6 @@
   // stay in this state until shut down.
   void TriggerXmppAuthError();
 
-  // Triggers the creation the Synced Bookmarks folder on the server.
-  void TriggerCreateSyncedBookmarks();
-
   // Returns the FakeServer being used for the test or null if FakeServer is
   // not being used.
   fake_server::FakeServer* GetFakeServer() const;
diff --git a/chrome/browser/sync/test/integration/two_client_bookmarks_sync_test.cc b/chrome/browser/sync/test/integration/two_client_bookmarks_sync_test.cc
index d5169eb..ff2a813 100644
--- a/chrome/browser/sync/test/integration/two_client_bookmarks_sync_test.cc
+++ b/chrome/browser/sync/test/integration/two_client_bookmarks_sync_test.cc
@@ -28,6 +28,7 @@
 #include "components/policy/policy_constants.h"
 #include "components/sync/driver/sync_service.h"
 #include "components/sync/engine/cycle/sync_cycle_snapshot.h"
+#include "components/sync/engine_impl/loopback_server/persistent_permanent_entity.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "ui/base/layout.h"
 
@@ -94,15 +95,6 @@
   DISALLOW_COPY_AND_ASSIGN(TwoClientBookmarksSyncTest);
 };
 
-class LegacyTwoClientBookmarksSyncTest : public SyncTest {
- public:
-  LegacyTwoClientBookmarksSyncTest() : SyncTest(TWO_CLIENT_LEGACY) {}
-  ~LegacyTwoClientBookmarksSyncTest() override {}
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(LegacyTwoClientBookmarksSyncTest);
-};
-
 IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, Sanity) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
   ASSERT_TRUE(AllModelsMatchVerifier());
@@ -1600,8 +1592,7 @@
   ASSERT_FALSE(ContainsDuplicateBookmarks(0));
 }
 
-// This test fails when run with FakeServer and FakeServerInvalidationService.
-IN_PROC_BROWSER_TEST_F(LegacyTwoClientBookmarksSyncTest, MC_DeleteBookmark) {
+IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, MC_DeleteBookmark) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
   ASSERT_TRUE(GetClient(1)->DisableSyncForDatatype(syncer::BOOKMARKS));
 
@@ -1926,13 +1917,15 @@
 
 // Trigger the server side creation of Synced Bookmarks. Ensure both clients
 // remain syncing afterwards. Add bookmarks to the synced bookmarks folder
-// and ensure both clients receive the boomkmark.
-IN_PROC_BROWSER_TEST_F(LegacyTwoClientBookmarksSyncTest,
-                       CreateSyncedBookmarks) {
+// and ensure both clients receive the bookmark.
+IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, CreateSyncedBookmarks) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
   ASSERT_TRUE(AllModelsMatchVerifier());
 
-  TriggerCreateSyncedBookmarks();
+  fake_server_->InjectEntity(syncer::PersistentPermanentEntity::CreateNew(
+      syncer::BOOKMARKS, "synced_bookmarks", "Synced Bookmarks",
+      "google_chrome_bookmarks"));
+  ASSERT_TRUE(BookmarksMatchChecker().Wait());
 
   // Add a bookmark on Client 0 and ensure it syncs over. This will also trigger
   // both clients downloading the new Synced Bookmarks folder.
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 43b689d..3c4217e 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -1396,6 +1396,8 @@
       "omnibox/clipboard_utils.h",
       "omnibox/favicon_cache.cc",
       "omnibox/favicon_cache.h",
+      "omnibox/omnibox_theme.cc",
+      "omnibox/omnibox_theme.h",
       "overlay/overlay_surface_embedder.cc",
       "overlay/overlay_surface_embedder.h",
       "overlay/overlay_window.h",
diff --git a/chrome/browser/ui/omnibox/omnibox_theme.cc b/chrome/browser/ui/omnibox/omnibox_theme.cc
new file mode 100644
index 0000000..b552b81
--- /dev/null
+++ b/chrome/browser/ui/omnibox/omnibox_theme.cc
@@ -0,0 +1,87 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/omnibox/omnibox_theme.h"
+
+#include "base/logging.h"
+#include "ui/base/material_design/material_design_controller.h"
+#include "ui/gfx/color_palette.h"
+#include "ui/gfx/color_utils.h"
+#include "ui/native_theme/native_theme.h"
+
+#if defined(USE_AURA)
+#include "ui/native_theme/native_theme_dark_aura.h"
+#endif
+
+namespace {
+
+constexpr ui::NativeTheme::ColorId kInvalidColorId =
+    ui::NativeTheme::kColorId_NumColors;
+
+template <class T>
+constexpr T NormalHoveredSelectedOrBoth(OmniboxState state,
+                                        T normal,
+                                        T hovered,
+                                        T selected,
+                                        T hovered_and_selected) {
+  const T args[] = {normal, hovered, selected, hovered_and_selected};
+  return args[static_cast<size_t>(state)];
+}
+
+template <class T>
+constexpr T NormalHoveredSelected(OmniboxState state,
+                                  T normal,
+                                  T hovered,
+                                  T selected) {
+  // Use selected if state is HOVERED_AND_SELECTED.
+  const T args[] = {normal, hovered, selected, selected};
+  return args[static_cast<size_t>(state)];
+}
+
+ui::NativeTheme::ColorId GetLegacyColorId(OmniboxPart part,
+                                          OmniboxState state) {
+  using NativeId = ui::NativeTheme::ColorId;
+  switch (part) {
+    case OmniboxPart::RESULTS_BACKGROUND:
+      return NormalHoveredSelected(
+          state, NativeId::kColorId_ResultsTableNormalBackground,
+          NativeId::kColorId_ResultsTableHoveredBackground,
+          NativeId::kColorId_ResultsTableSelectedBackground);
+  }
+  return kInvalidColorId;
+}
+
+SkColor GetLegacyColor(OmniboxPart part, OmniboxTint tint, OmniboxState state) {
+  ui::NativeTheme* native_theme = ui::NativeTheme::GetInstanceForNativeUi();
+#if defined(USE_AURA)
+  if (tint == OmniboxTint::DARK)
+    native_theme = ui::NativeThemeDarkAura::instance();
+#endif
+
+  ui::NativeTheme::ColorId color_id = GetLegacyColorId(part, state);
+  return color_id == kInvalidColorId ? gfx::kPlaceholderColor
+                                     : native_theme->GetSystemColor(color_id);
+}
+
+}  // namespace
+
+SkColor GetOmniboxColor(OmniboxPart part,
+                        OmniboxTint tint,
+                        OmniboxState state) {
+  if (!ui::MaterialDesignController::IsTouchOptimizedUiEnabled())
+    return GetLegacyColor(part, tint, state);
+
+  const bool dark = tint == OmniboxTint::DARK;
+
+  switch (part) {
+    case OmniboxPart::RESULTS_BACKGROUND:
+      // The spec calls for transparent black (or white) overlays for hover (6%)
+      // and select (8%), which can overlap (for 14%). Pre-blend these with the
+      // background for the best text AA result.
+      return color_utils::BlendTowardOppositeLuma(
+          dark ? gfx::kGoogleGrey800 : SK_ColorWHITE,
+          NormalHoveredSelectedOrBoth<SkAlpha>(state, 0x00, 0x0f, 0x14, 0x24));
+  }
+  return gfx::kPlaceholderColor;
+}
diff --git a/chrome/browser/ui/omnibox/omnibox_theme.h b/chrome/browser/ui/omnibox/omnibox_theme.h
new file mode 100644
index 0000000..8fb24cd8
--- /dev/null
+++ b/chrome/browser/ui/omnibox/omnibox_theme.h
@@ -0,0 +1,27 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_OMNIBOX_OMNIBOX_THEME_H_
+#define CHROME_BROWSER_UI_OMNIBOX_OMNIBOX_THEME_H_
+
+#include "third_party/skia/include/core/SkColor.h"
+
+// A part of the omnibox (location bar, location bar decoration, or dropdown).
+enum class OmniboxPart {
+  RESULTS_BACKGROUND,  // Background of the results dropdown.
+};
+
+// The tint of the omnibox theme. E.g. Incognito may use a DARK tint.
+enum class OmniboxTint { DARK, LIGHT };
+
+// An optional state for a given |OmniboxPart|.
+enum class OmniboxState { NORMAL, HOVERED, SELECTED, HOVERED_AND_SELECTED };
+
+// Returns the color for the given |part| and |tint|. An optional |state| can be
+// provided for OmniboxParts that support stateful colors.
+SkColor GetOmniboxColor(OmniboxPart part,
+                        OmniboxTint tint,
+                        OmniboxState state = OmniboxState::NORMAL);
+
+#endif  // CHROME_BROWSER_UI_OMNIBOX_OMNIBOX_THEME_H_
diff --git a/chrome/browser/ui/overlay/overlay_surface_embedder.cc b/chrome/browser/ui/overlay/overlay_surface_embedder.cc
index 888c17c..79d7f07e 100644
--- a/chrome/browser/ui/overlay/overlay_surface_embedder.cc
+++ b/chrome/browser/ui/overlay/overlay_surface_embedder.cc
@@ -13,9 +13,14 @@
   surface_layer_->SetMasksToBounds(true);
 
   // The frame provided by the parent window's layer needs to show through
-  // the surface layer.
+  // |surface_layer_|.
   surface_layer_->SetFillsBoundsOpaquely(false);
-  surface_layer_->SetBounds(window_->GetBounds());
+  // |surface_layer_| bounds are set with the (0, 0) origin point. The
+  // positioning of |window_| is dictated by itself.
+  // TODO(apacible): Update |surface_layer_| size when the window is resized.
+  // http://crbug.com/726621
+  surface_layer_->SetBounds(
+      gfx::Rect(gfx::Point(0, 0), window_->GetBounds().size()));
   window_->GetLayer()->Add(surface_layer_.get());
 }
 
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_mac.mm b/chrome/browser/ui/views/frame/browser_non_client_frame_view_mac.mm
index 381e8b5..3562bf8 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_mac.mm
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_mac.mm
@@ -128,18 +128,6 @@
 // BrowserNonClientFrameViewMac, protected:
 
 // views::View:
-void BrowserNonClientFrameViewMac::OnPaint(gfx::Canvas* canvas) {
-  if (!browser_view()->IsBrowserTypeNormal())
-    return;
-
-  canvas->DrawColor(GetFrameColor());
-
-  if (!GetThemeProvider()->UsingSystemTheme())
-    PaintThemedFrame(canvas);
-
-  if (browser_view()->IsToolbarVisible())
-    PaintToolbarBackground(canvas);
-}
 
 void BrowserNonClientFrameViewMac::Layout() {
   DCHECK(browser_view());
@@ -166,6 +154,19 @@
   BrowserNonClientFrameView::Layout();
 }
 
+void BrowserNonClientFrameViewMac::OnPaint(gfx::Canvas* canvas) {
+  if (!browser_view()->IsBrowserTypeNormal())
+    return;
+
+  canvas->DrawColor(GetFrameColor());
+
+  if (!GetThemeProvider()->UsingSystemTheme())
+    PaintThemedFrame(canvas);
+
+  if (browser_view()->IsToolbarVisible())
+    PaintToolbarBackground(canvas);
+}
+
 // BrowserNonClientFrameView:
 AvatarButtonStyle BrowserNonClientFrameViewMac::GetAvatarButtonStyle() const {
   return AvatarButtonStyle::NATIVE;
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 b4c9e443..889cb49 100644
--- a/chrome/browser/ui/views/location_bar/location_bar_view.cc
+++ b/chrome/browser/ui/views/location_bar/location_bar_view.cc
@@ -23,6 +23,7 @@
 #include "chrome/browser/search_engines/template_url_service_factory.h"
 #include "chrome/browser/themes/theme_properties.h"
 #include "chrome/browser/themes/theme_service.h"
+#include "chrome/browser/themes/theme_service_factory.h"
 #include "chrome/browser/translate/chrome_translate_client.h"
 #include "chrome/browser/translate/translate_service.h"
 #include "chrome/browser/ui/autofill/save_card_bubble_controller_impl.h"
@@ -35,6 +36,7 @@
 #include "chrome/browser/ui/find_bar/find_bar_controller.h"
 #include "chrome/browser/ui/layout_constants.h"
 #include "chrome/browser/ui/omnibox/chrome_omnibox_client.h"
+#include "chrome/browser/ui/omnibox/omnibox_theme.h"
 #include "chrome/browser/ui/passwords/manage_passwords_ui_controller.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/views/autofill/save_card_icon_view.h"
@@ -123,6 +125,16 @@
          ui::MaterialDesignController::MATERIAL_TOUCH_OPTIMIZED;
 }
 
+OmniboxTint GetTintForProfile(Profile* profile) {
+  if (ThemeServiceFactory::GetForProfile(profile)->UsingDefaultTheme()) {
+    return profile->GetProfileType() == Profile::INCOGNITO_PROFILE
+               ? OmniboxTint::DARK
+               : OmniboxTint::LIGHT;
+  }
+  // TODO(tapted): Infer a tint from theme colors?
+  return OmniboxTint::LIGHT;
+}
+
 }  // namespace
 
 // LocationBarView -----------------------------------------------------------
@@ -139,7 +151,8 @@
       ChromeOmniboxEditController(command_updater),
       browser_(browser),
       delegate_(delegate),
-      is_popup_mode_(is_popup_mode) {
+      is_popup_mode_(is_popup_mode),
+      tint_(GetTintForProfile(profile)) {
   edit_bookmarks_enabled_.Init(
       bookmarks::prefs::kEditBookmarksEnabled, profile->GetPrefs(),
       base::Bind(&LocationBarView::UpdateWithoutTabRestore,
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 22abc9b5..b11b7c55 100644
--- a/chrome/browser/ui/views/location_bar/location_bar_view.h
+++ b/chrome/browser/ui/views/location_bar/location_bar_view.h
@@ -40,6 +40,7 @@
 class KeywordHintView;
 class LocationIconView;
 class ManagePasswordsIconViews;
+enum class OmniboxTint;
 class Profile;
 class SelectedKeywordView;
 class StarView;
@@ -129,6 +130,9 @@
   SkColor GetSecureTextColor(
       security_state::SecurityLevel security_level) const;
 
+  // Returns the theme color tint for the location bar and results.
+  OmniboxTint tint() const { return tint_; }
+
   // Returns the delegate.
   Delegate* delegate() const { return delegate_; }
 
@@ -422,6 +426,9 @@
   // bar is read-only.
   const bool is_popup_mode_;
 
+  // The theme tint. Initialized based on the profile and theme settings.
+  const OmniboxTint tint_;
+
   // True if we should show a focus rect while the location entry field is
   // focused. Used when the toolbar is in full keyboard accessibility mode.
   bool show_focus_rect_ = false;
diff --git a/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc b/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc
index 74cc2b3..4ccf59c 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc
@@ -15,6 +15,7 @@
 #include "build/build_config.h"
 #include "chrome/browser/search/search.h"
 #include "chrome/browser/themes/theme_properties.h"
+#include "chrome/browser/ui/omnibox/omnibox_theme.h"
 #include "chrome/browser/ui/views/location_bar/location_bar_view.h"
 #include "chrome/browser/ui/views/omnibox/omnibox_result_view.h"
 #include "chrome/browser/ui/views/omnibox/rounded_omnibox_results_frame.h"
@@ -146,6 +147,8 @@
     : public ThemeCopyingWidget,
       public base::SupportsWeakPtr<AutocompletePopupWidget> {
  public:
+  // TODO(tapted): Remove |role_model| when the omnibox is completely decoupled
+  // from NativeTheme.
   explicit AutocompletePopupWidget(views::Widget* role_model)
       : ThemeCopyingWidget(role_model) {}
   ~AutocompletePopupWidget() override {}
@@ -240,6 +243,11 @@
   return model_->GetMatchIcon(match, vector_icon_color);
 }
 
+OmniboxTint OmniboxPopupContentsView::GetTint() const {
+  // Use LIGHT in tests.
+  return location_bar_view_ ? location_bar_view_->tint() : OmniboxTint::LIGHT;
+}
+
 void OmniboxPopupContentsView::SetSelectedLine(size_t index) {
   DCHECK(HasMatchAt(index));
 
@@ -310,8 +318,8 @@
 
   gfx::Rect new_target_bounds = UpdateMarginsAndGetTargetBounds();
   if (IsNarrow() && !IsRounded()) {
-    SkColor background_color = GetNativeTheme()->GetSystemColor(
-        ui::NativeTheme::kColorId_ResultsTableNormalBackground);
+    SkColor background_color =
+        GetOmniboxColor(OmniboxPart::RESULTS_BACKGROUND, GetTint());
     auto border = std::make_unique<views::BubbleBorder>(
         views::BubbleBorder::NONE, views::BubbleBorder::SMALL_SHADOW,
         background_color);
@@ -590,8 +598,8 @@
       paint_info.paint_recording_scale_y()));
   {
     ui::PaintRecorder recorder(paint_info.context(), size());
-    SkColor background_color = result_view_at(0)->GetColor(
-        OmniboxResultView::NORMAL, OmniboxResultView::BACKGROUND);
+    SkColor background_color =
+        GetOmniboxColor(OmniboxPart::RESULTS_BACKGROUND, GetTint());
     recorder.canvas()->DrawColor(background_color);
   }
   View::PaintChildren(paint_info);
diff --git a/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.h b/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.h
index 7ac6c44..37c36333 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.h
+++ b/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.h
@@ -20,6 +20,7 @@
 class LocationBarView;
 class OmniboxEditModel;
 class OmniboxResultView;
+enum class OmniboxTint;
 class OmniboxView;
 
 // A view representing the contents of the autocomplete popup.
@@ -40,6 +41,9 @@
   gfx::Image GetMatchIcon(const AutocompleteMatch& match,
                           SkColor vector_icon_color) const;
 
+  // Returns the theme color tint (e.g. dark or light).
+  OmniboxTint GetTint() const;
+
   // Sets the line specified by |index| as selected.
   virtual void SetSelectedLine(size_t index);
 
diff --git a/chrome/browser/ui/views/omnibox/omnibox_result_view.cc b/chrome/browser/ui/views/omnibox/omnibox_result_view.cc
index e4924dd01..a1a6fdd6 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_result_view.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_result_view.cc
@@ -22,6 +22,7 @@
 #include "base/metrics/field_trial_params.h"
 #include "base/strings/string_util.h"
 #include "chrome/browser/ui/layout_constants.h"
+#include "chrome/browser/ui/omnibox/omnibox_theme.h"
 #include "chrome/browser/ui/views/location_bar/background_with_1_px_border.h"
 #include "chrome/browser/ui/views/location_bar/location_bar_view.h"
 #include "chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.h"
@@ -74,12 +75,6 @@
   OmniboxResultView::ResultViewState state;
   OmniboxResultView::ColorKind kind;
 } static const kTranslationTable[] = {
-  { NativeTheme::kColorId_ResultsTableNormalBackground,
-    OmniboxResultView::NORMAL, OmniboxResultView::BACKGROUND },
-  { NativeTheme::kColorId_ResultsTableHoveredBackground,
-    OmniboxResultView::HOVERED, OmniboxResultView::BACKGROUND },
-  { NativeTheme::kColorId_ResultsTableSelectedBackground,
-    OmniboxResultView::SELECTED, OmniboxResultView::BACKGROUND },
   { NativeTheme::kColorId_ResultsTableNormalText,
     OmniboxResultView::NORMAL, OmniboxResultView::TEXT },
   { NativeTheme::kColorId_ResultsTableHoveredText,
@@ -231,7 +226,9 @@
   if (state == NORMAL) {
     SetBackground(nullptr);
   } else {
-    SetBackground(CreateBackgroundWithColor(GetColor(state, BACKGROUND)));
+    SkColor color = GetOmniboxColor(OmniboxPart::RESULTS_BACKGROUND, GetTint(),
+                                    GetThemeState());
+    SetBackground(CreateBackgroundWithColor(color));
   }
 
   if (match_.answer) {
@@ -278,6 +275,18 @@
   return is_hovered_ ? HOVERED : NORMAL;
 }
 
+OmniboxState OmniboxResultView::GetThemeState() const {
+  if (model_->IsSelectedIndex(model_index_)) {
+    return is_hovered_ ? OmniboxState::HOVERED_AND_SELECTED
+                       : OmniboxState::SELECTED;
+  }
+  return is_hovered_ ? OmniboxState::HOVERED : OmniboxState::NORMAL;
+}
+
+OmniboxTint OmniboxResultView::GetTint() const {
+  return model_->GetTint();
+}
+
 void OmniboxResultView::OnMatchIconUpdated() {
   // The new icon will be fetched during repaint.
   SchedulePaint();
diff --git a/chrome/browser/ui/views/omnibox/omnibox_result_view.h b/chrome/browser/ui/views/omnibox/omnibox_result_view.h
index 1d41078..6acf300 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_result_view.h
+++ b/chrome/browser/ui/views/omnibox/omnibox_result_view.h
@@ -22,6 +22,8 @@
 #include "ui/views/view.h"
 
 class OmniboxPopupContentsView;
+enum class OmniboxState;
+enum class OmniboxTint;
 
 namespace gfx {
 class Canvas;
@@ -36,6 +38,7 @@
  public:
   // Keep these ordered from least dominant (normal) to most dominant
   // (selected).
+  // TODO(tapted): Remove these: replace with OmniboxState.
   enum ResultViewState {
     NORMAL = 0,
     HOVERED,
@@ -44,7 +47,6 @@
   };
 
   enum ColorKind {
-    BACKGROUND = 0,
     TEXT,
     DIMMED_TEXT,
     URL,
@@ -72,6 +74,8 @@
   void OnSelected();
 
   ResultViewState GetState() const;
+  OmniboxState GetThemeState() const;
+  OmniboxTint GetTint() const;
 
   // Notification that the match icon has changed and schedules a repaint.
   void OnMatchIconUpdated();
diff --git a/chrome/browser/ui/views/omnibox/omnibox_tab_switch_button.cc b/chrome/browser/ui/views/omnibox/omnibox_tab_switch_button.cc
index 99d8da7..463d97a 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_tab_switch_button.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_tab_switch_button.cc
@@ -4,23 +4,37 @@
 
 #include "chrome/browser/ui/views/omnibox/omnibox_tab_switch_button.h"
 
+#include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/ui/layout_constants.h"
+#include "chrome/browser/ui/omnibox/omnibox_theme.h"
+#include "chrome/browser/ui/views/location_bar/background_with_1_px_border.h"
+#include "chrome/browser/ui/views/omnibox/omnibox_result_view.h"
+#include "components/omnibox/browser/vector_icons.h"
 #include "ui/gfx/color_utils.h"
+#include "ui/gfx/paint_vector_icon.h"
+#include "ui/views/controls/button/label_button_border.h"
+
+OmniboxTabSwitchButton::OmniboxTabSwitchButton(OmniboxResultView* result_view)
+    : LabelButton(this, base::ASCIIToUTF16("Switch to open tab")),
+      result_view_(result_view) {
+  // TODO: SetTooltipText(text);
+  //       SetImageAlignment(ALIGN_CENTER, ALIGN_MIDDLE);
+  SetBackground(std::make_unique<BackgroundWith1PxBorder>(GetBackgroundColor(),
+                                                          SK_ColorBLACK));
+  SetImage(STATE_NORMAL,
+           gfx::CreateVectorIcon(omnibox::kSwitchIcon, 16, SK_ColorBLACK));
+}
 
 void OmniboxTabSwitchButton::SetPressed() {
-  const SkColor bg_color = result_view_->GetColor(
-      OmniboxResultView::SELECTED, OmniboxResultView::BACKGROUND);
   // Using transparent does nothing, since the result view is also selected.
-  const SkColor pressed_color =
-      color_utils::AlphaBlend(bg_color, SK_ColorBLACK, 0.8 * 255);
-  SetBackground(
-      std::make_unique<BackgroundWith1PxBorder>(pressed_color, SK_ColorBLACK));
+  background()->SetNativeControlColor(color_utils::AlphaBlend(
+      GetOmniboxColor(OmniboxPart::RESULTS_BACKGROUND, result_view_->GetTint()),
+      SK_ColorBLACK, 0.8 * 255));
   SchedulePaint();
 }
 
 void OmniboxTabSwitchButton::ClearState() {
-  // TODO: Consider giving this a non-transparent background.
-  SetBackground(nullptr);
+  background()->SetNativeControlColor(GetBackgroundColor());
   SchedulePaint();
 }
 
@@ -62,11 +76,12 @@
 }
 
 void OmniboxTabSwitchButton::StateChanged(ButtonState old_state) {
-  const SkColor bg_color = result_view_->GetColor(
-      state() == STATE_HOVERED ? OmniboxResultView::HOVERED
-                               : OmniboxResultView::NORMAL,
-      OmniboxResultView::BACKGROUND);
-  SetBackground(
-      std::make_unique<BackgroundWith1PxBorder>(bg_color, SK_ColorBLACK));
+  background()->SetNativeControlColor(GetBackgroundColor());
   LabelButton::StateChanged(old_state);
 }
+
+SkColor OmniboxTabSwitchButton::GetBackgroundColor() const {
+  return GetOmniboxColor(
+      OmniboxPart::RESULTS_BACKGROUND, result_view_->GetTint(),
+      state() == STATE_HOVERED ? OmniboxState::HOVERED : OmniboxState::NORMAL);
+}
diff --git a/chrome/browser/ui/views/omnibox/omnibox_tab_switch_button.h b/chrome/browser/ui/views/omnibox/omnibox_tab_switch_button.h
index 16ef7ff..d2e9a72 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_tab_switch_button.h
+++ b/chrome/browser/ui/views/omnibox/omnibox_tab_switch_button.h
@@ -5,29 +5,14 @@
 #ifndef CHROME_BROWSER_UI_VIEWS_OMNIBOX_OMNIBOX_TAB_SWITCH_BUTTON_H_
 #define CHROME_BROWSER_UI_VIEWS_OMNIBOX_OMNIBOX_TAB_SWITCH_BUTTON_H_
 
-#include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/ui/views/location_bar/background_with_1_px_border.h"
-#include "chrome/browser/ui/views/omnibox/omnibox_result_view.h"
-#include "components/omnibox/browser/vector_icons.h"
-#include "ui/gfx/paint_vector_icon.h"
 #include "ui/views/controls/button/label_button.h"
-#include "ui/views/controls/button/label_button_border.h"
+
+class OmniboxResultView;
 
 class OmniboxTabSwitchButton : public views::LabelButton,
-                               views::ButtonListener {
+                               public views::ButtonListener {
  public:
-  explicit OmniboxTabSwitchButton(OmniboxResultView* result_view)
-      : LabelButton(this, base::ASCIIToUTF16("Switch to open tab")),
-        result_view_(result_view) {
-    // TODO: SetTooltipText(text);
-    //       SetImageAlignment(ALIGN_CENTER, ALIGN_MIDDLE);
-    const SkColor bg_color = result_view_->GetColor(
-        OmniboxResultView::NORMAL, OmniboxResultView::BACKGROUND);
-    SetBackground(
-        std::make_unique<BackgroundWith1PxBorder>(bg_color, SK_ColorBLACK));
-    SetImage(STATE_NORMAL,
-             gfx::CreateVectorIcon(omnibox::kSwitchIcon, 16, SK_ColorBLACK));
-  }
+  explicit OmniboxTabSwitchButton(OmniboxResultView* result_view);
 
   void SetPressed();
   void ClearState();
@@ -45,6 +30,8 @@
   void StateChanged(ButtonState old_state) override;
 
  private:
+  SkColor GetBackgroundColor() const;
+
   OmniboxResultView* result_view_;
 
   DISALLOW_COPY_AND_ASSIGN(OmniboxTabSwitchButton);
diff --git a/chrome/browser/ui/views/omnibox/rounded_omnibox_results_frame.cc b/chrome/browser/ui/views/omnibox/rounded_omnibox_results_frame.cc
index 7850680..370a14a 100644
--- a/chrome/browser/ui/views/omnibox/rounded_omnibox_results_frame.cc
+++ b/chrome/browser/ui/views/omnibox/rounded_omnibox_results_frame.cc
@@ -6,6 +6,7 @@
 
 #include "build/build_config.h"
 #include "chrome/browser/ui/layout_constants.h"
+#include "chrome/browser/ui/omnibox/omnibox_theme.h"
 #include "chrome/browser/ui/views/location_bar/background_with_1_px_border.h"
 #include "chrome/browser/ui/views/location_bar/location_bar_view.h"
 #include "ui/compositor/layer.h"
@@ -57,8 +58,8 @@
   contents_host_->layer()->SetFillsBoundsOpaquely(false);
 
   // Use a solid background. Note this is clipped to get rounded corners.
-  SkColor background_color = GetNativeTheme()->GetSystemColor(
-      ui::NativeTheme::kColorId_ResultsTableNormalBackground);
+  SkColor background_color =
+      GetOmniboxColor(OmniboxPart::RESULTS_BACKGROUND, location_bar->tint());
   contents_host_->SetBackground(views::CreateSolidBackground(background_color));
 
   // Use a textured mask to clip contents. This doesn't work on Windows
diff --git a/chrome/browser/ui/views/passwords/account_chooser_dialog_view.cc b/chrome/browser/ui/views/passwords/account_chooser_dialog_view.cc
index 7b6120c..f017f274 100644
--- a/chrome/browser/ui/views/passwords/account_chooser_dialog_view.cc
+++ b/chrome/browser/ui/views/passwords/account_chooser_dialog_view.cc
@@ -109,8 +109,10 @@
 }
 
 void AccountChooserDialogView::ControllerGone() {
-  controller_ = nullptr;
+  // During Widget::Close() phase some accessibility event may occur. Thus,
+  // |controller_| should be kept around.
   GetWidget()->Close();
+  controller_ = nullptr;
 }
 
 ui::ModalType AccountChooserDialogView::GetModalType() const {
@@ -170,15 +172,22 @@
 void AccountChooserDialogView::StyledLabelLinkClicked(views::StyledLabel* label,
                                                       const gfx::Range& range,
                                                       int event_flags) {
-  controller_->OnSmartLockLinkClicked();
+  // On Mac the button click event may be dispatched after the dialog was
+  // hidden. Thus, the controller can be NULL.
+  if (controller_)
+    controller_->OnSmartLockLinkClicked();
 }
 
 void AccountChooserDialogView::ButtonPressed(views::Button* sender,
                                              const ui::Event& event) {
   CredentialsItemView* view = static_cast<CredentialsItemView*>(sender);
-  controller_->OnChooseCredentials(
-      *view->form(),
-      password_manager::CredentialType::CREDENTIAL_TYPE_PASSWORD);
+  // On Mac the button click event may be dispatched after the dialog was
+  // hidden. Thus, the controller can be NULL.
+  if (controller_) {
+    controller_->OnChooseCredentials(
+        *view->form(),
+        password_manager::CredentialType::CREDENTIAL_TYPE_PASSWORD);
+  }
 }
 
 void AccountChooserDialogView::InitWindow() {
diff --git a/chrome/browser/ui/views/profiles/avatar_button.cc b/chrome/browser/ui/views/profiles/avatar_button.cc
index 8f7525d..55318383 100644
--- a/chrome/browser/ui/views/profiles/avatar_button.cc
+++ b/chrome/browser/ui/views/profiles/avatar_button.cc
@@ -46,7 +46,9 @@
 
 namespace {
 
+#if !defined(OS_MACOSX)
 constexpr int kGenericAvatarIconSize = 16;
+#endif
 
 // TODO(emx): Calculate width based on caption button [http://crbug.com/716365]
 constexpr int kCondensibleButtonMinWidth = 46;
@@ -76,10 +78,6 @@
 }
 #endif
 
-#if defined(OS_MACOSX)
-constexpr int kHoverCornerRadius = 2;
-#endif
-
 // This class draws the border (and background) of the avatar button for
 // "themed" browser windows, i.e. OpaqueBrowserFrameView. Currently it's only
 // used on Linux as the shape specifically matches the Linux caption buttons.
@@ -276,7 +274,7 @@
 AvatarButton::~AvatarButton() {}
 
 void AvatarButton::SetupThemeColorButton() {
-#if defined(OS_WIN) || defined(OS_MACOSX)
+#if defined(OS_WIN)
   if (IsCondensible()) {
     // TODO(bsep): This needs to also be called when the Windows accent color
     // updates, but there is currently no signal for that.
@@ -290,7 +288,13 @@
     generic_avatar_ = gfx::CreateVectorIcon(kAccountCircleIcon,
                                             kGenericAvatarIconSize, icon_color);
   }
-#endif  // defined(OS_WIN) || defined(OS_MACOSX)
+#elif defined(OS_MACOSX)
+  const SkColor text_color = color_utils::IsDark(GetThemeProvider()->GetColor(
+                                 ThemeProperties::COLOR_FRAME))
+                                 ? SK_ColorWHITE
+                                 : SK_ColorBLACK;
+  SetEnabledTextColors(text_color);
+#endif
 }
 
 void AvatarButton::OnAvatarButtonPressed(const ui::Event* event) {
@@ -352,13 +356,17 @@
 
 std::unique_ptr<views::InkDropMask> AvatarButton::CreateInkDropMask() const {
 #if defined(OS_MACOSX)
+  // On Mac, this looks and behaves like a regular MD button, so we need a hover
+  // background.
   // TODO (lgrey): Determine and set the correct insets.
+  constexpr int kHoverCornerRadius = 2;
   return std::make_unique<views::RoundRectInkDropMask>(size(), gfx::Insets(),
                                                        kHoverCornerRadius);
-#endif
+#else
   if (button_style_ == AvatarButtonStyle::THEMED)
     return AvatarButtonThemedBorder::CreateInkDropMask(size());
   return MenuButton::CreateInkDropMask();
+#endif
 }
 
 std::unique_ptr<views::InkDropHighlight> AvatarButton::CreateInkDropHighlight()
@@ -374,12 +382,14 @@
   return ink_drop_highlight;
 }
 
-#if defined(OS_MACOSX)
 SkColor AvatarButton::GetInkDropBaseColor() const {
+#if defined(OS_MACOSX)
   return GetThemeProvider()->GetColor(
       ThemeProperties::COLOR_TOOLBAR_BUTTON_ICON);
-}
+#else
+  return MenuButton::GetInkDropBaseColor();
 #endif
+}
 
 bool AvatarButton::ShouldEnterPushedState(const ui::Event& event) {
   if (ProfileChooserView::IsShowing())
@@ -515,8 +525,9 @@
   return true;
 #elif defined(OS_MACOSX)
   return true;
-#endif
+#else
   if (render_native_nav_buttons_)
     return false;
   return IsCondensible();
+#endif
 }
diff --git a/chrome/browser/ui/views/profiles/avatar_button.h b/chrome/browser/ui/views/profiles/avatar_button.h
index 48c3197..e1b127198 100644
--- a/chrome/browser/ui/views/profiles/avatar_button.h
+++ b/chrome/browser/ui/views/profiles/avatar_button.h
@@ -45,10 +45,8 @@
   gfx::Size CalculatePreferredSize() const override;
   std::unique_ptr<views::InkDropHighlight> CreateInkDropHighlight()
       const override;
-  std::unique_ptr<views::InkDropMask> CreateInkDropMask() const override;
-#if defined(OS_MACOSX)
   SkColor GetInkDropBaseColor() const override;
-#endif
+  std::unique_ptr<views::InkDropMask> CreateInkDropMask() const override;
 
  protected:
   // views::LabelButton:
diff --git a/chrome/browser/ui/views/session_crashed_bubble_view.cc b/chrome/browser/ui/views/session_crashed_bubble_view.cc
index 81f303b..18989e5c3 100644
--- a/chrome/browser/ui/views/session_crashed_bubble_view.cc
+++ b/chrome/browser/ui/views/session_crashed_bubble_view.cc
@@ -222,13 +222,6 @@
 views::View* SessionCrashedBubbleView::CreateUmaOptInView() {
   RecordBubbleHistogramValue(SESSION_CRASHED_BUBBLE_OPTIN_BAR_SHOWN);
 
-  // Checkbox for metric reporting setting.
-  // Since the text to the right of the checkbox can't be a simple string (needs
-  // a hyperlink in it), this checkbox contains an empty string as its label,
-  // and the real text will be added as a separate view.
-  uma_option_ = new views::Checkbox(base::string16());
-  uma_option_->SetChecked(false);
-
   // The text to the right of the checkbox.
   size_t offset;
   base::string16 link_text =
@@ -251,6 +244,11 @@
   // Shift the text down by 1px to align with the checkbox.
   uma_label->SetBorder(views::CreateEmptyBorder(1, 0, 0, 0));
 
+  // Checkbox for metric reporting setting.
+  uma_option_ = new views::Checkbox(base::string16());
+  uma_option_->SetChecked(false);
+  uma_option_->SetAssociatedLabel(uma_label);
+
   // Create a view to hold the checkbox and the text.
   views::View* uma_view = new views::View();
   GridLayout* uma_layout =
diff --git a/chrome/browser/ui/views_mode_controller.cc b/chrome/browser/ui/views_mode_controller.cc
index 6452151..9a673df 100644
--- a/chrome/browser/ui/views_mode_controller.cc
+++ b/chrome/browser/ui/views_mode_controller.cc
@@ -5,13 +5,14 @@
 #include "chrome/browser/ui/views_mode_controller.h"
 
 #include "chrome/common/chrome_features.h"
+#include "ui/base/ui_base_features.h"
 
 #if defined(OS_MACOSX) && BUILDFLAG(MAC_VIEWS_BROWSER)
 
 namespace views_mode_controller {
 
 bool IsViewsBrowserCocoa() {
-  return !base::FeatureList::IsEnabled(features::kViewsBrowserWindows);
+  return features::IsViewsBrowserCocoa();
 }
 
 }  // namespace views_mode_controller
diff --git a/chrome/browser/ui/webui/signin/dice_turn_sync_on_helper.cc b/chrome/browser/ui/webui/signin/dice_turn_sync_on_helper.cc
index bfcdab0..b664c08 100644
--- a/chrome/browser/ui/webui/signin/dice_turn_sync_on_helper.cc
+++ b/chrome/browser/ui/webui/signin/dice_turn_sync_on_helper.cc
@@ -5,11 +5,13 @@
 #include "chrome/browser/ui/webui/signin/dice_turn_sync_on_helper.h"
 
 #include "base/bind.h"
+#include "base/location.h"
 #include "base/logging.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/metrics/user_metrics.h"
 #include "base/metrics/user_metrics_action.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/threading/sequenced_task_runner_handle.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/policy/cloud/user_policy_signin_service.h"
 #include "chrome/browser/policy/cloud/user_policy_signin_service_factory.h"
@@ -71,7 +73,10 @@
   DCHECK(!signin_util::IsForceSigninEnabled());
 
   if (HasCanOfferSigninError()) {
-    AbortAndDelete();
+    // Do not self-destruct synchronously in the constructor.
+    base::SequencedTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::BindOnce(&DiceTurnSyncOnHelper::AbortAndDelete,
+                                  base::Unretained(this)));
     return;
   }
 
diff --git a/chrome/browser/ui/webui/signin/dice_turn_sync_on_helper_unittest.cc b/chrome/browser/ui/webui/signin/dice_turn_sync_on_helper_unittest.cc
index 5e964de..d3925d2 100644
--- a/chrome/browser/ui/webui/signin/dice_turn_sync_on_helper_unittest.cc
+++ b/chrome/browser/ui/webui/signin/dice_turn_sync_on_helper_unittest.cc
@@ -428,6 +428,7 @@
   // Signin flow.
   CreateDiceTurnOnSyncHelper(
       DiceTurnSyncOnHelper::SigninAbortedMode::KEEP_ACCOUNT);
+  base::RunLoop().RunUntilIdle();
   // Check expectations.
   EXPECT_FALSE(signin_manager()->IsAuthenticated());
   EXPECT_TRUE(token_service()->RefreshTokenIsAvailable(account_id()));
@@ -443,6 +444,7 @@
   // Signin flow.
   CreateDiceTurnOnSyncHelper(
       DiceTurnSyncOnHelper::SigninAbortedMode::REMOVE_ACCOUNT);
+  base::RunLoop().RunUntilIdle();
   // Check expectations.
   EXPECT_FALSE(signin_manager()->IsAuthenticated());
   EXPECT_FALSE(token_service()->RefreshTokenIsAvailable(account_id()));
diff --git a/chrome/browser/ui/window_sizer/window_sizer.cc b/chrome/browser/ui/window_sizer/window_sizer.cc
index 3adf2a6..a653307 100644
--- a/chrome/browser/ui/window_sizer/window_sizer.cc
+++ b/chrome/browser/ui/window_sizer/window_sizer.cc
@@ -172,10 +172,10 @@
     std::unique_ptr<StateProvider> state_provider,
     std::unique_ptr<TargetDisplayProvider> target_display_provider,
     const Browser* browser)
-    : state_provider_(std::move(state_provider)),
-      target_display_provider_(std::move(target_display_provider)),
-      screen_(display::Screen::GetScreen()),
-      browser_(browser) {}
+    : WindowSizer(std::move(state_provider),
+                  std::move(target_display_provider),
+                  display::Screen::GetScreen(),
+                  browser) {}
 
 WindowSizer::WindowSizer(
     std::unique_ptr<StateProvider> state_provider,
@@ -189,8 +189,7 @@
   DCHECK(screen_);
 }
 
-WindowSizer::~WindowSizer() {
-}
+WindowSizer::~WindowSizer() {}
 
 // static
 void WindowSizer::GetBrowserWindowBoundsAndShowState(
@@ -404,25 +403,18 @@
   if (!browser_)
     return ui::SHOW_STATE_DEFAULT;
 
-  // Only tabbed browsers use the command line or preference state, with the
-  // exception of devtools.
-  bool show_state = !browser_->is_type_tabbed() && !browser_->is_devtools();
+  // Only tabbed browsers and dev tools use the command line.
+  bool use_command_line = browser_->is_type_tabbed() || browser_->is_devtools();
 
 #if defined(USE_AURA)
-  // We use the apps save state on aura.
-  show_state &= !browser_->is_app();
+  // We use the apps save state as well on aura.
+  use_command_line = use_command_line || browser_->is_app();
 #endif
 
-  if (show_state)
-    return browser_->initial_show_state();
-
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kStartMaximized))
+  if (use_command_line && base::CommandLine::ForCurrentProcess()->HasSwitch(
+                              switches::kStartMaximized)) {
     return ui::SHOW_STATE_MAXIMIZED;
+  }
 
-  if (browser_->initial_show_state() != ui::SHOW_STATE_DEFAULT)
-    return browser_->initial_show_state();
-
-  // Otherwise we use the default which can be overridden later on.
-  return ui::SHOW_STATE_DEFAULT;
+  return browser_->initial_show_state();
 }
diff --git a/chrome/browser/ui/window_sizer/window_sizer.h b/chrome/browser/ui/window_sizer/window_sizer.h
index ab64ec02..fc2d96a 100644
--- a/chrome/browser/ui/window_sizer/window_sizer.h
+++ b/chrome/browser/ui/window_sizer/window_sizer.h
@@ -34,21 +34,6 @@
   class StateProvider;
   class TargetDisplayProvider;
 
-  // WindowSizer owns |state_provider| and |target_display_provider|,
-  // and will use the platforms's display::Screen.
-  WindowSizer(std::unique_ptr<StateProvider> state_provider,
-              std::unique_ptr<TargetDisplayProvider> target_display_provider,
-              const Browser* browser);
-
-  // WindowSizer owns |state_provider| and |target_display_provider|,
-  // and will use the supplied |screen|. Used only for testing.
-  WindowSizer(std::unique_ptr<StateProvider> state_provider,
-              std::unique_ptr<TargetDisplayProvider> target_display_provider,
-              display::Screen* screen,
-              const Browser* browser);
-
-  virtual ~WindowSizer();
-
   // An interface implemented by an object that can retrieve state from either a
   // persistent store or an existing window.
   class StateProvider {
@@ -129,6 +114,21 @@
 #endif
 
  private:
+  friend class WindowSizerTestUtil;
+
+  // WindowSizer will use the platforms's display::Screen.
+  WindowSizer(std::unique_ptr<StateProvider> state_provider,
+              std::unique_ptr<TargetDisplayProvider> target_display_provider,
+              const Browser* browser);
+
+  // As above, but uses the supplied |screen|. Used only for testing.
+  WindowSizer(std::unique_ptr<StateProvider> state_provider,
+              std::unique_ptr<TargetDisplayProvider> target_display_provider,
+              display::Screen* screen,
+              const Browser* browser);
+
+  virtual ~WindowSizer();
+
   // The edge of the screen to check for out-of-bounds.
   enum Edge { TOP, LEFT, BOTTOM, RIGHT };
 
diff --git a/chrome/browser/ui/window_sizer/window_sizer_ash.cc b/chrome/browser/ui/window_sizer/window_sizer_ash.cc
index 05e2f64..09dd86a8 100644
--- a/chrome/browser/ui/window_sizer/window_sizer_ash.cc
+++ b/chrome/browser/ui/window_sizer/window_sizer_ash.cc
@@ -32,15 +32,12 @@
       if (!GetSavedWindowBounds(bounds, show_state))
         *bounds = GetDefaultWindowBoundsAsh(GetTargetDisplay(gfx::Rect()));
       determined = true;
-    } else {
+    } else if (state_provider_) {
       // In Ash, prioritize the last saved |show_state|. If you have questions
       // or comments about this behavior please contact oshima@chromium.org.
-      if (state_provider_) {
-        gfx::Rect ignored_bounds, ignored_work_area;
-        state_provider_->GetPersistentState(&ignored_bounds,
-                                            &ignored_work_area,
-                                            show_state);
-      }
+      gfx::Rect ignored_bounds, ignored_work_area;
+      state_provider_->GetPersistentState(&ignored_bounds, &ignored_work_area,
+                                          show_state);
     }
   } else if (browser_->is_type_popup() && bounds->origin().IsOrigin()) {
     // In case of a popup with an 'unspecified' location in ash, we are
diff --git a/chrome/browser/ui/window_sizer/window_sizer_ash_unittest.cc b/chrome/browser/ui/window_sizer/window_sizer_ash_unittest.cc
index 3102492b..7e6d73d 100644
--- a/chrome/browser/ui/window_sizer/window_sizer_ash_unittest.cc
+++ b/chrome/browser/ui/window_sizer/window_sizer_ash_unittest.cc
@@ -30,6 +30,8 @@
 
 namespace {
 
+using util = WindowSizerTestUtil;
+
 // Shorten identifiers to improve line wrapping.
 const int kDesktopBorderSize = WindowSizer::kDesktopBorderSize;
 const int kMaximumWindowWidth = WindowSizer::kMaximumWindowWidth;
@@ -56,8 +58,9 @@
 TEST_F(WindowSizerAshTest, DefaultSizeCase) {
   { // 4:3 monitor case, 1024x768, no taskbar
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(), gfx::Rect(),
-                    gfx::Rect(), DEFAULT, NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, gfx::Rect(), gfx::Rect(),
+                          gfx::Rect(), DEFAULT, NULL, gfx::Rect(),
+                          &window_bounds);
     EXPECT_EQ(
         gfx::Rect(kDesktopBorderSize, kDesktopBorderSize,
                   1024 - kDesktopBorderSize * 2, 768 - kDesktopBorderSize),
@@ -66,9 +69,9 @@
 
   { // 4:3 monitor case, 1024x768, taskbar on bottom
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, taskbar_bottom_work_area, gfx::Rect(),
-                    gfx::Rect(), gfx::Rect(), DEFAULT, NULL, gfx::Rect(),
-                    &window_bounds);
+    util::GetWindowBounds(p1024x768, taskbar_bottom_work_area, gfx::Rect(),
+                          gfx::Rect(), gfx::Rect(), DEFAULT, NULL, gfx::Rect(),
+                          &window_bounds);
     EXPECT_EQ(gfx::Rect(kDesktopBorderSize, kDesktopBorderSize,
                         1024 - kDesktopBorderSize * 2,
                         taskbar_bottom_work_area.height() - kDesktopBorderSize),
@@ -77,9 +80,9 @@
 
   { // 4:3 monitor case, 1024x768, taskbar on right
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, taskbar_right_work_area, gfx::Rect(),
-                    gfx::Rect(), gfx::Rect(), DEFAULT, NULL, gfx::Rect(),
-                    &window_bounds);
+    util::GetWindowBounds(p1024x768, taskbar_right_work_area, gfx::Rect(),
+                          gfx::Rect(), gfx::Rect(), DEFAULT, NULL, gfx::Rect(),
+                          &window_bounds);
     EXPECT_EQ(
         gfx::Rect(kDesktopBorderSize, kDesktopBorderSize,
                   taskbar_right_work_area.width() - kDesktopBorderSize * 2,
@@ -89,9 +92,9 @@
 
   { // 4:3 monitor case, 1024x768, taskbar on left
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, taskbar_left_work_area, gfx::Rect(),
-                    gfx::Rect(), gfx::Rect(), DEFAULT, NULL, gfx::Rect(),
-                    &window_bounds);
+    util::GetWindowBounds(p1024x768, taskbar_left_work_area, gfx::Rect(),
+                          gfx::Rect(), gfx::Rect(), DEFAULT, NULL, gfx::Rect(),
+                          &window_bounds);
     EXPECT_EQ(gfx::Rect(taskbar_left_work_area.x() + kDesktopBorderSize,
                         kDesktopBorderSize,
                         taskbar_left_work_area.width() - kDesktopBorderSize * 2,
@@ -101,9 +104,9 @@
 
   { // 4:3 monitor case, 1024x768, taskbar on top
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, taskbar_top_work_area, gfx::Rect(),
-                    gfx::Rect(), gfx::Rect(), DEFAULT, NULL, gfx::Rect(),
-                    &window_bounds);
+    util::GetWindowBounds(p1024x768, taskbar_top_work_area, gfx::Rect(),
+                          gfx::Rect(), gfx::Rect(), DEFAULT, NULL, gfx::Rect(),
+                          &window_bounds);
     EXPECT_EQ(gfx::Rect(kDesktopBorderSize,
                         taskbar_top_work_area.y() + kDesktopBorderSize,
                         1024 - kDesktopBorderSize * 2,
@@ -113,8 +116,9 @@
 
   { // 4:3 monitor case, 1280x1024
     gfx::Rect window_bounds;
-    GetWindowBounds(p1280x1024, p1280x1024, gfx::Rect(), gfx::Rect(),
-                    gfx::Rect(), DEFAULT, NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1280x1024, p1280x1024, gfx::Rect(), gfx::Rect(),
+                          gfx::Rect(), DEFAULT, NULL, gfx::Rect(),
+                          &window_bounds);
     EXPECT_EQ(gfx::Rect((1280 - kMaximumWindowWidth) / 2, kDesktopBorderSize,
                         kMaximumWindowWidth, 1024 - kDesktopBorderSize),
               window_bounds);
@@ -122,8 +126,9 @@
 
   { // 4:3 monitor case, 1600x1200
     gfx::Rect window_bounds;
-    GetWindowBounds(p1600x1200, p1600x1200, gfx::Rect(), gfx::Rect(),
-                    gfx::Rect(), DEFAULT, NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1600x1200, p1600x1200, gfx::Rect(), gfx::Rect(),
+                          gfx::Rect(), DEFAULT, NULL, gfx::Rect(),
+                          &window_bounds);
     EXPECT_EQ(gfx::Rect((1600 - kMaximumWindowWidth) / 2, kDesktopBorderSize,
                         kMaximumWindowWidth, 1200 - kDesktopBorderSize),
               window_bounds);
@@ -131,8 +136,9 @@
 
   { // 16:10 monitor case, 1680x1050
     gfx::Rect window_bounds;
-    GetWindowBounds(p1680x1050, p1680x1050, gfx::Rect(), gfx::Rect(),
-                    gfx::Rect(), DEFAULT, NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1680x1050, p1680x1050, gfx::Rect(), gfx::Rect(),
+                          gfx::Rect(), DEFAULT, NULL, gfx::Rect(),
+                          &window_bounds);
     EXPECT_EQ(gfx::Rect((1680 - kMaximumWindowWidth) / 2, kDesktopBorderSize,
                         kMaximumWindowWidth, 1050 - kDesktopBorderSize),
               window_bounds);
@@ -140,8 +146,9 @@
 
   { // 16:10 monitor case, 1920x1200
     gfx::Rect window_bounds;
-    GetWindowBounds(p1920x1200, p1920x1200, gfx::Rect(), gfx::Rect(),
-                    gfx::Rect(), DEFAULT, NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1920x1200, p1920x1200, gfx::Rect(), gfx::Rect(),
+                          gfx::Rect(), DEFAULT, NULL, gfx::Rect(),
+                          &window_bounds);
     EXPECT_EQ(gfx::Rect((1920 - kMaximumWindowWidth) / 2, kDesktopBorderSize,
                         kMaximumWindowWidth, 1200 - kDesktopBorderSize),
               window_bounds);
@@ -153,10 +160,10 @@
 TEST_F(WindowSizerAshTest, LastWindowBoundsCase) {
   { // normal, in the middle of the screen somewhere.
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
-                    gfx::Rect(kDesktopBorderSize, kDesktopBorderSize, 500, 400),
-                    gfx::Rect(), LAST_ACTIVE, NULL, gfx::Rect(),
-                    &window_bounds);
+    util::GetWindowBounds(
+        p1024x768, p1024x768, gfx::Rect(),
+        gfx::Rect(kDesktopBorderSize, kDesktopBorderSize, 500, 400),
+        gfx::Rect(), LAST_ACTIVE, NULL, gfx::Rect(), &window_bounds);
     EXPECT_EQ(gfx::Rect(kWindowTilePixels + kDesktopBorderSize,
                         kWindowTilePixels + kDesktopBorderSize, 500, 400)
                   .ToString(),
@@ -165,10 +172,10 @@
 
   { // taskbar on top.
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, taskbar_top_work_area, gfx::Rect(),
-                    gfx::Rect(kDesktopBorderSize, kDesktopBorderSize, 500, 400),
-                    gfx::Rect(), LAST_ACTIVE, NULL, gfx::Rect(),
-                    &window_bounds);
+    util::GetWindowBounds(
+        p1024x768, taskbar_top_work_area, gfx::Rect(),
+        gfx::Rect(kDesktopBorderSize, kDesktopBorderSize, 500, 400),
+        gfx::Rect(), LAST_ACTIVE, NULL, gfx::Rect(), &window_bounds);
     EXPECT_EQ(gfx::Rect(kWindowTilePixels + kDesktopBorderSize,
                         std::max(kWindowTilePixels + kDesktopBorderSize,
                                  34 /* toolbar height */),
@@ -179,10 +186,10 @@
 
   { // Too small to satisify the minimum visibility condition.
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
-                    gfx::Rect(kDesktopBorderSize, kDesktopBorderSize, 29, 29),
-                    gfx::Rect(), LAST_ACTIVE, NULL, gfx::Rect(),
-                    &window_bounds);
+    util::GetWindowBounds(
+        p1024x768, p1024x768, gfx::Rect(),
+        gfx::Rect(kDesktopBorderSize, kDesktopBorderSize, 29, 29), gfx::Rect(),
+        LAST_ACTIVE, NULL, gfx::Rect(), &window_bounds);
     EXPECT_EQ(gfx::Rect(kWindowTilePixels + kDesktopBorderSize,
                         kWindowTilePixels + kDesktopBorderSize, 30 /* not 29 */,
                         30 /* not 29 */)
@@ -193,10 +200,10 @@
 
   { // Normal.
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
-                    gfx::Rect(kDesktopBorderSize, kDesktopBorderSize, 500, 400),
-                    gfx::Rect(), LAST_ACTIVE, NULL, gfx::Rect(),
-                    &window_bounds);
+    util::GetWindowBounds(
+        p1024x768, p1024x768, gfx::Rect(),
+        gfx::Rect(kDesktopBorderSize, kDesktopBorderSize, 500, 400),
+        gfx::Rect(), LAST_ACTIVE, NULL, gfx::Rect(), &window_bounds);
     EXPECT_EQ(gfx::Rect(kWindowTilePixels + kDesktopBorderSize,
                         kWindowTilePixels + kDesktopBorderSize, 500, 400)
                   .ToString(),
@@ -210,8 +217,9 @@
     gfx::Rect initial_bounds(kDesktopBorderSize, kDesktopBorderSize, 500, 400);
 
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(), initial_bounds,
-                    gfx::Rect(), PERSISTED, NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, gfx::Rect(), initial_bounds,
+                          gfx::Rect(), PERSISTED, NULL, gfx::Rect(),
+                          &window_bounds);
     EXPECT_EQ(initial_bounds.ToString(), window_bounds.ToString());
   }
 
@@ -219,8 +227,9 @@
     gfx::Rect initial_bounds(0, 0, 1024, 768);
 
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(), initial_bounds,
-                    gfx::Rect(), PERSISTED, NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, gfx::Rect(), initial_bounds,
+                          gfx::Rect(), PERSISTED, NULL, gfx::Rect(),
+                          &window_bounds);
     EXPECT_EQ(initial_bounds.ToString(), window_bounds.ToString());
   }
 
@@ -228,9 +237,9 @@
     gfx::Rect initial_bounds(-600, 10, 500, 400);
 
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, left_s1024x768,
-                    initial_bounds, gfx::Rect(), PERSISTED, NULL, gfx::Rect(),
-                    &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, left_s1024x768, initial_bounds,
+                          gfx::Rect(), PERSISTED, NULL, gfx::Rect(),
+                          &window_bounds);
     EXPECT_EQ(initial_bounds.ToString(), window_bounds.ToString());
   }
 
@@ -238,9 +247,9 @@
     gfx::Rect initial_bounds(-1024, 0, 1024, 768);
 
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, left_s1024x768,
-                    initial_bounds, gfx::Rect(), PERSISTED, NULL, gfx::Rect(),
-                    &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, left_s1024x768, initial_bounds,
+                          gfx::Rect(), PERSISTED, NULL, gfx::Rect(),
+                          &window_bounds);
     EXPECT_EQ(initial_bounds.ToString(), window_bounds.ToString());
   }
 
@@ -250,9 +259,9 @@
     gfx::Rect initial_bounds(1074, 50, 600, 500);
 
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(1024, 0, 800, 600),
-                    initial_bounds, right_s1024x768, PERSISTED, NULL,
-                    gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, gfx::Rect(1024, 0, 800, 600),
+                          initial_bounds, right_s1024x768, PERSISTED, NULL,
+                          gfx::Rect(), &window_bounds);
     EXPECT_EQ(initial_bounds.ToString(), window_bounds.ToString());
   }
 
@@ -262,9 +271,9 @@
     gfx::Rect initial_bounds(1274, 50, 600, 500);
 
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(1024, 0, 800, 600),
-                    initial_bounds, right_s1024x768, PERSISTED,
-                    NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, gfx::Rect(1024, 0, 800, 600),
+                          initial_bounds, right_s1024x768, PERSISTED, NULL,
+                          gfx::Rect(), &window_bounds);
     EXPECT_EQ("1224,50 600x500", window_bounds.ToString());
   }
 
@@ -274,17 +283,18 @@
     gfx::Rect initial_bounds(1274, 50, 900, 700);
 
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(1024, 0, 800, 600),
-                    initial_bounds, right_s1024x768, PERSISTED,
-                    NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, gfx::Rect(1024, 0, 800, 600),
+                          initial_bounds, right_s1024x768, PERSISTED, NULL,
+                          gfx::Rect(), &window_bounds);
     EXPECT_EQ("1024,0 800x600", window_bounds.ToString());
   }
 
   { // width and height too small
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
-                    gfx::Rect(kDesktopBorderSize, kDesktopBorderSize, 29, 29),
-                    gfx::Rect(), PERSISTED, NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(
+        p1024x768, p1024x768, gfx::Rect(),
+        gfx::Rect(kDesktopBorderSize, kDesktopBorderSize, 29, 29), gfx::Rect(),
+        PERSISTED, NULL, gfx::Rect(), &window_bounds);
     EXPECT_EQ(gfx::Rect(kDesktopBorderSize, kDesktopBorderSize, 30 /* not 29 */,
                         30 /* not 29 */)
                   .ToString(),
@@ -295,10 +305,10 @@
 TEST_F(WindowSizerAshTest, LastWindowOffscreenWithNonAggressiveRepositioning) {
   { // taskbar on left.
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, taskbar_left_work_area, gfx::Rect(),
-                    gfx::Rect(kDesktopBorderSize, kDesktopBorderSize, 500, 400),
-                    gfx::Rect(), LAST_ACTIVE, NULL, gfx::Rect(),
-                    &window_bounds);
+    util::GetWindowBounds(
+        p1024x768, taskbar_left_work_area, gfx::Rect(),
+        gfx::Rect(kDesktopBorderSize, kDesktopBorderSize, 500, 400),
+        gfx::Rect(), LAST_ACTIVE, NULL, gfx::Rect(), &window_bounds);
     EXPECT_EQ(gfx::Rect(kWindowTilePixels + kDesktopBorderSize,
                         kWindowTilePixels + kDesktopBorderSize, 500, 400)
                   .ToString(),
@@ -308,9 +318,9 @@
   { // offset would put the new window offscreen at the bottom but the minimum
     // visibility condition is barely satisfied without relocation.
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
-                    gfx::Rect(10, 728, 500, 400), gfx::Rect(), LAST_ACTIVE,
-                    NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
+                          gfx::Rect(10, 728, 500, 400), gfx::Rect(),
+                          LAST_ACTIVE, NULL, gfx::Rect(), &window_bounds);
     EXPECT_EQ(gfx::Rect(10 + kWindowTilePixels, 738, 500, 400).ToString(),
               window_bounds.ToString());
   }
@@ -318,9 +328,9 @@
   { // offset would put the new window offscreen at the bottom and the minimum
     // visibility condition is satisified by relocation.
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
-                    gfx::Rect(10, 729, 500, 400), gfx::Rect(), LAST_ACTIVE,
-                    NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
+                          gfx::Rect(10, 729, 500, 400), gfx::Rect(),
+                          LAST_ACTIVE, NULL, gfx::Rect(), &window_bounds);
     EXPECT_EQ(gfx::Rect(10 + kWindowTilePixels,
                         738 /* not 739 */,
                         500,
@@ -331,9 +341,9 @@
   { // offset would put the new window offscreen at the right but the minimum
     // visibility condition is barely satisfied without relocation.
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
-                    gfx::Rect(984, 10, 500, 400), gfx::Rect(), LAST_ACTIVE,
-                    NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
+                          gfx::Rect(984, 10, 500, 400), gfx::Rect(),
+                          LAST_ACTIVE, NULL, gfx::Rect(), &window_bounds);
     EXPECT_EQ(gfx::Rect(994, 10 + kWindowTilePixels, 500, 400).ToString(),
               window_bounds.ToString());
   }
@@ -341,9 +351,9 @@
   { // offset would put the new window offscreen at the right and the minimum
     // visibility condition is satisified by relocation.
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
-                    gfx::Rect(985, 10, 500, 400), gfx::Rect(), LAST_ACTIVE,
-                    NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
+                          gfx::Rect(985, 10, 500, 400), gfx::Rect(),
+                          LAST_ACTIVE, NULL, gfx::Rect(), &window_bounds);
     EXPECT_EQ(gfx::Rect(994 /* not 995 */,
                         10 + kWindowTilePixels,
                         500,
@@ -354,9 +364,9 @@
   { // offset would put the new window offscreen at the bottom right and the
     // minimum visibility condition is satisified by relocation.
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
-                    gfx::Rect(985, 729, 500, 400), gfx::Rect(), LAST_ACTIVE,
-                    NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
+                          gfx::Rect(985, 729, 500, 400), gfx::Rect(),
+                          LAST_ACTIVE, NULL, gfx::Rect(), &window_bounds);
     EXPECT_EQ(gfx::Rect(994 /* not 995 */,
                         738 /* not 739 */,
                         500,
@@ -367,7 +377,7 @@
 
 // Test the placement of newly created windows.
 TEST_F(WindowSizerAshTest, PlaceNewWindows) {
-  // Create a browser to pass into the GetWindowBounds function.
+  // Create a browser to pass into the util::GetWindowBounds function.
   std::unique_ptr<TestingProfile> profile(new TestingProfile());
   // Creating a popup handler here to make sure it does not interfere with the
   // existing windows.
@@ -397,26 +407,28 @@
   browser_window->Show();
   { // Make sure that popups do not get changed.
     gfx::Rect window_bounds;
-    GetWindowBounds(p1600x1200, p1600x1200, gfx::Rect(),
-                    gfx::Rect(50, 100, 300, 150), bottom_s1600x1200, PERSISTED,
-                    browser_popup.get(), gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1600x1200, p1600x1200, gfx::Rect(),
+                          gfx::Rect(50, 100, 300, 150), bottom_s1600x1200,
+                          PERSISTED, browser_popup.get(), gfx::Rect(),
+                          &window_bounds);
     EXPECT_EQ("50,100 300x150", window_bounds.ToString());
   }
 
   browser_window->Hide();
   { // If a window is there but not shown the persisted default should be used.
     gfx::Rect window_bounds;
-    GetWindowBounds(p1600x1200, p1600x1200, gfx::Rect(),
-                    gfx::Rect(50, 100, 300, 150), bottom_s1600x1200,
-                    PERSISTED, browser.get(), gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1600x1200, p1600x1200, gfx::Rect(),
+                          gfx::Rect(50, 100, 300, 150), bottom_s1600x1200,
+                          PERSISTED, browser.get(), gfx::Rect(),
+                          &window_bounds);
     EXPECT_EQ("50,100 300x150", window_bounds.ToString());
   }
 
   { // If a window is there but not shown the default should be returned.
     gfx::Rect window_bounds;
-    GetWindowBounds(p1600x1200, p1600x1200, gfx::Rect(),
-                    gfx::Rect(), bottom_s1600x1200,
-                    DEFAULT, browser.get(), gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1600x1200, p1600x1200, gfx::Rect(), gfx::Rect(),
+                          bottom_s1600x1200, DEFAULT, browser.get(),
+                          gfx::Rect(), &window_bounds);
     // Note: We need to also take the defaults maximum width into account here
     // since that might get used if the resolution is too big.
     EXPECT_EQ(
@@ -434,7 +446,8 @@
 // This test supplements "PlaceNewWindows" by testing the creation of a newly
 // created browser window on an empty desktop.
 TEST_F(WindowSizerAshTest, PlaceNewBrowserWindowOnEmptyDesktop) {
-  // Create a browser to pass into the GetWindowBoundsAndShowState function.
+  // Create a browser to pass into the util::GetWindowBoundsAndShowState
+  // function.
   std::unique_ptr<TestingProfile> profile(new TestingProfile());
   Browser::CreateParams native_params(profile.get(), true);
   std::unique_ptr<Browser> browser(
@@ -448,7 +461,7 @@
   // screen is less than or equal to our limit (1366 pixels width).
   gfx::Rect window_bounds;
   ui::WindowShowState out_show_state1 = ui::SHOW_STATE_DEFAULT;
-  GetWindowBoundsAndShowState(
+  util::GetWindowBoundsAndShowState(
       p1366x768,               // The screen resolution.
       p1366x768,               // The monitor work area.
       gfx::Rect(),             // The second monitor.
@@ -465,7 +478,7 @@
 
   // If there is a stored coordinate however, that should be taken instead.
   ui::WindowShowState out_show_state2 = ui::SHOW_STATE_DEFAULT;
-  GetWindowBoundsAndShowState(
+  util::GetWindowBoundsAndShowState(
       p1366x768,                     // The screen resolution.
       p1366x768,                     // The monitor work area.
       gfx::Rect(),                   // The second monitor.
@@ -483,7 +496,7 @@
 
   // A larger monitor should not trigger auto-maximize.
   ui::WindowShowState out_show_state3 = ui::SHOW_STATE_DEFAULT;
-  GetWindowBoundsAndShowState(
+  util::GetWindowBoundsAndShowState(
       p1600x1200,              // The screen resolution.
       p1600x1200,              // The monitor work area.
       gfx::Rect(),             // The second monitor.
@@ -540,9 +553,9 @@
   // First new window should be in the primary.
   {
     gfx::Rect window_bounds;
-    GetWindowBounds(p1600x1200, p1600x1200, secondary_bounds, gfx::Rect(),
-                    secondary_bounds, PERSISTED, new_browser.get(), gfx::Rect(),
-                    &window_bounds);
+    util::GetWindowBounds(p1600x1200, p1600x1200, secondary_bounds, gfx::Rect(),
+                          secondary_bounds, PERSISTED, new_browser.get(),
+                          gfx::Rect(), &window_bounds);
     // TODO(oshima): Use exact bounds when the window_sizer_ash is
     // moved to ash and changed to include the result from
     // RearrangeVisibleWindowOnShow.
@@ -564,7 +577,7 @@
               ash::Shell::GetRootWindowForNewWindows());
     gfx::Rect window_bounds;
     ui::WindowShowState out_show_state = ui::SHOW_STATE_DEFAULT;
-    GetWindowBoundsAndShowState(
+    util::GetWindowBoundsAndShowState(
         p1600x1200, p1600x1200, secondary_bounds, gfx::Rect(), secondary_bounds,
         ui::SHOW_STATE_DEFAULT, ui::SHOW_STATE_DEFAULT, PERSISTED,
         new_browser.get(), gfx::Rect(), 1u, &window_bounds, &out_show_state);
@@ -583,9 +596,9 @@
               ash::Shell::GetRootWindowForNewWindows());
 
     gfx::Rect window_bounds;
-    GetWindowBounds(p1600x1200, p1600x1200, secondary_bounds, gfx::Rect(),
-                    secondary_bounds, PERSISTED, new_browser.get(), gfx::Rect(),
-                    &window_bounds);
+    util::GetWindowBounds(p1600x1200, p1600x1200, secondary_bounds, gfx::Rect(),
+                          secondary_bounds, PERSISTED, new_browser.get(),
+                          gfx::Rect(), &window_bounds);
     // TODO(oshima): Use exact bounds when the window_sizer_ash is
     // moved to ash and changed to include the result from
     // RearrangeVisibleWindowOnShow.
@@ -610,27 +623,30 @@
 
   // Tabbed windows should retrieve the saved window state - since there is a
   // top window.
-  EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED,
-            GetWindowShowState(ui::SHOW_STATE_MAXIMIZED, ui::SHOW_STATE_NORMAL,
-                               BOTH, browser.get(), p1600x1200, p1600x1200));
-  // A window that is smaller than the whole work area is set to default state.
-  EXPECT_EQ(ui::SHOW_STATE_DEFAULT,
-            GetWindowShowState(ui::SHOW_STATE_DEFAULT, ui::SHOW_STATE_NORMAL,
-                               BOTH, browser.get(), p1280x1024, p1600x1200));
-  // A window that is sized to occupy the whole work area is maximized.
-  EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED,
-            GetWindowShowState(ui::SHOW_STATE_DEFAULT, ui::SHOW_STATE_NORMAL,
-                               BOTH, browser.get(), p1600x1200, p1600x1200));
-  // Non tabbed windows should always follow the window saved visibility state.
   EXPECT_EQ(
       ui::SHOW_STATE_MAXIMIZED,
-      GetWindowShowState(ui::SHOW_STATE_MAXIMIZED, ui::SHOW_STATE_NORMAL, BOTH,
-                         browser_popup.get(), p1600x1200, p1600x1200));
-  // The non tabbed window will take the status of the last active of its kind.
+      util::GetWindowShowState(ui::SHOW_STATE_MAXIMIZED, ui::SHOW_STATE_NORMAL,
+                               BOTH, browser.get(), p1600x1200, p1600x1200));
+  // A window that is smaller than the whole work area is set to default state.
   EXPECT_EQ(
-      ui::SHOW_STATE_NORMAL,
-      GetWindowShowState(ui::SHOW_STATE_DEFAULT, ui::SHOW_STATE_NORMAL, BOTH,
-                         browser_popup.get(), p1600x1200, p1600x1200));
+      ui::SHOW_STATE_DEFAULT,
+      util::GetWindowShowState(ui::SHOW_STATE_DEFAULT, ui::SHOW_STATE_NORMAL,
+                               BOTH, browser.get(), p1280x1024, p1600x1200));
+  // A window that is sized to occupy the whole work area is maximized.
+  EXPECT_EQ(
+      ui::SHOW_STATE_MAXIMIZED,
+      util::GetWindowShowState(ui::SHOW_STATE_DEFAULT, ui::SHOW_STATE_NORMAL,
+                               BOTH, browser.get(), p1600x1200, p1600x1200));
+  // Non tabbed windows should always follow the window saved visibility state.
+  EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED,
+            util::GetWindowShowState(
+                ui::SHOW_STATE_MAXIMIZED, ui::SHOW_STATE_NORMAL, BOTH,
+                browser_popup.get(), p1600x1200, p1600x1200));
+  // The non tabbed window will take the status of the last active of its kind.
+  EXPECT_EQ(ui::SHOW_STATE_NORMAL,
+            util::GetWindowShowState(
+                ui::SHOW_STATE_DEFAULT, ui::SHOW_STATE_NORMAL, BOTH,
+                browser_popup.get(), p1600x1200, p1600x1200));
 
   // Now create a top level window and check again for both. Only the tabbed
   // window should follow the top level window's state.
@@ -640,29 +656,30 @@
       CreateTestWindowInShellWithId(3), gfx::Rect(16, 32, 640, 320), &params2));
 
   // A tabbed window should now take the top level window state.
-  EXPECT_EQ(ui::SHOW_STATE_DEFAULT,
-            GetWindowShowState(ui::SHOW_STATE_MAXIMIZED, ui::SHOW_STATE_DEFAULT,
+  EXPECT_EQ(
+      ui::SHOW_STATE_DEFAULT,
+      util::GetWindowShowState(ui::SHOW_STATE_MAXIMIZED, ui::SHOW_STATE_DEFAULT,
                                BOTH, browser.get(), p1600x1200, p1600x1200));
   // Non tabbed windows should always follow the window saved visibility state.
-  EXPECT_EQ(
-      ui::SHOW_STATE_MAXIMIZED,
-      GetWindowShowState(ui::SHOW_STATE_MAXIMIZED, ui::SHOW_STATE_MINIMIZED,
-                         BOTH, browser_popup.get(), p1600x1200, p1600x1200));
+  EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED,
+            util::GetWindowShowState(
+                ui::SHOW_STATE_MAXIMIZED, ui::SHOW_STATE_MINIMIZED, BOTH,
+                browser_popup.get(), p1600x1200, p1600x1200));
 
   // In smaller screen resolutions we default to maximized if there is no other
   // window visible.
   int min_size = ash::WindowPositioner::GetForceMaximizedWidthLimit() / 2;
   if (min_size > 0) {
     const gfx::Rect tiny_screen(0, 0, min_size, min_size);
-    EXPECT_EQ(
-        ui::SHOW_STATE_DEFAULT,
-        GetWindowShowState(ui::SHOW_STATE_MAXIMIZED, ui::SHOW_STATE_DEFAULT,
-                           BOTH, browser.get(), tiny_screen, tiny_screen));
+    EXPECT_EQ(ui::SHOW_STATE_DEFAULT,
+              util::GetWindowShowState(
+                  ui::SHOW_STATE_MAXIMIZED, ui::SHOW_STATE_DEFAULT, BOTH,
+                  browser.get(), tiny_screen, tiny_screen));
     browser->window()->Hide();
-    EXPECT_EQ(
-        ui::SHOW_STATE_MAXIMIZED,
-        GetWindowShowState(ui::SHOW_STATE_MAXIMIZED, ui::SHOW_STATE_DEFAULT,
-                           BOTH, browser2.get(), tiny_screen, tiny_screen));
+    EXPECT_EQ(ui::SHOW_STATE_MAXIMIZED,
+              util::GetWindowShowState(
+                  ui::SHOW_STATE_MAXIMIZED, ui::SHOW_STATE_DEFAULT, BOTH,
+                  browser2.get(), tiny_screen, tiny_screen));
   }
 }
 
@@ -684,25 +701,26 @@
 
   // Check that a browser creation state always get used if not given as
   // SHOW_STATE_DEFAULT.
-  ui::WindowShowState window_show_state =
-      GetWindowShowState(ui::SHOW_STATE_MAXIMIZED, ui::SHOW_STATE_MAXIMIZED,
-                         DEFAULT, browser.get(), p1600x1200, p1600x1200);
+  ui::WindowShowState window_show_state = util::GetWindowShowState(
+      ui::SHOW_STATE_MAXIMIZED, ui::SHOW_STATE_MAXIMIZED, DEFAULT,
+      browser.get(), p1600x1200, p1600x1200);
   EXPECT_EQ(window_show_state, ui::SHOW_STATE_DEFAULT);
 
   browser->set_initial_show_state(ui::SHOW_STATE_MINIMIZED);
-  EXPECT_EQ(
-      GetWindowShowState(ui::SHOW_STATE_MAXIMIZED, ui::SHOW_STATE_MAXIMIZED,
-                         BOTH, browser.get(), p1600x1200, p1600x1200),
-      ui::SHOW_STATE_MINIMIZED);
+  EXPECT_EQ(util::GetWindowShowState(ui::SHOW_STATE_MAXIMIZED,
+                                     ui::SHOW_STATE_MAXIMIZED, BOTH,
+                                     browser.get(), p1600x1200, p1600x1200),
+            ui::SHOW_STATE_MINIMIZED);
   browser->set_initial_show_state(ui::SHOW_STATE_NORMAL);
-  EXPECT_EQ(
-      GetWindowShowState(ui::SHOW_STATE_MAXIMIZED, ui::SHOW_STATE_MAXIMIZED,
-                         BOTH, browser.get(), p1600x1200, p1600x1200),
-      ui::SHOW_STATE_NORMAL);
+  EXPECT_EQ(util::GetWindowShowState(ui::SHOW_STATE_MAXIMIZED,
+                                     ui::SHOW_STATE_MAXIMIZED, BOTH,
+                                     browser.get(), p1600x1200, p1600x1200),
+            ui::SHOW_STATE_NORMAL);
   browser->set_initial_show_state(ui::SHOW_STATE_MAXIMIZED);
-  EXPECT_EQ(GetWindowShowState(ui::SHOW_STATE_NORMAL, ui::SHOW_STATE_NORMAL,
+  EXPECT_EQ(
+      util::GetWindowShowState(ui::SHOW_STATE_NORMAL, ui::SHOW_STATE_NORMAL,
                                BOTH, browser.get(), p1600x1200, p1600x1200),
-            ui::SHOW_STATE_MAXIMIZED);
+      ui::SHOW_STATE_MAXIMIZED);
 
   // Check that setting the maximized command line option is forcing the
   // maximized state.
@@ -710,19 +728,20 @@
       switches::kStartMaximized);
 
   browser->set_initial_show_state(ui::SHOW_STATE_NORMAL);
-  EXPECT_EQ(GetWindowShowState(ui::SHOW_STATE_NORMAL, ui::SHOW_STATE_NORMAL,
+  EXPECT_EQ(
+      util::GetWindowShowState(ui::SHOW_STATE_NORMAL, ui::SHOW_STATE_NORMAL,
                                BOTH, browser.get(), p1600x1200, p1600x1200),
-            ui::SHOW_STATE_MAXIMIZED);
+      ui::SHOW_STATE_MAXIMIZED);
 
   // The popup should favor the initial show state over the command line.
-  EXPECT_EQ(
-      GetWindowShowState(ui::SHOW_STATE_NORMAL, ui::SHOW_STATE_NORMAL, BOTH,
-                         browser_popup.get(), p1600x1200, p1600x1200),
-      ui::SHOW_STATE_NORMAL);
+  EXPECT_EQ(util::GetWindowShowState(
+                ui::SHOW_STATE_NORMAL, ui::SHOW_STATE_NORMAL, BOTH,
+                browser_popup.get(), p1600x1200, p1600x1200),
+            ui::SHOW_STATE_NORMAL);
 }
 
 TEST_F(WindowSizerAshTest, DefaultStateBecomesMaximized) {
-  // Create a browser to pass into the GetWindowBounds function.
+  // Create a browser to pass into the util::GetWindowBounds function.
   std::unique_ptr<TestingProfile> profile(new TestingProfile());
   Browser::CreateParams native_params(profile.get(), true);
   std::unique_ptr<Browser> browser(
@@ -798,13 +817,13 @@
       &trusted_popup_create_params));
   // Trusted popup windows should follow the saved show state and ignore the
   // last show state.
-  EXPECT_EQ(
-      ui::SHOW_STATE_DEFAULT,
-      GetWindowShowState(ui::SHOW_STATE_DEFAULT, ui::SHOW_STATE_NORMAL, BOTH,
-                         trusted_popup.get(), p1280x1024, p1600x1200));
+  EXPECT_EQ(ui::SHOW_STATE_DEFAULT,
+            util::GetWindowShowState(
+                ui::SHOW_STATE_DEFAULT, ui::SHOW_STATE_NORMAL, BOTH,
+                trusted_popup.get(), p1280x1024, p1600x1200));
   // A popup that is sized to occupy the whole work area has default state.
-  EXPECT_EQ(
-      ui::SHOW_STATE_DEFAULT,
-      GetWindowShowState(ui::SHOW_STATE_DEFAULT, ui::SHOW_STATE_NORMAL, BOTH,
-                         trusted_popup.get(), p1600x1200, p1600x1200));
+  EXPECT_EQ(ui::SHOW_STATE_DEFAULT,
+            util::GetWindowShowState(
+                ui::SHOW_STATE_DEFAULT, ui::SHOW_STATE_NORMAL, BOTH,
+                trusted_popup.get(), p1600x1200, p1600x1200));
 }
diff --git a/chrome/browser/ui/window_sizer/window_sizer_common_unittest.cc b/chrome/browser/ui/window_sizer/window_sizer_common_unittest.cc
index 2406dbc..87889980 100644
--- a/chrome/browser/ui/window_sizer/window_sizer_common_unittest.cc
+++ b/chrome/browser/ui/window_sizer/window_sizer_common_unittest.cc
@@ -23,6 +23,8 @@
 
 namespace {
 
+using util = WindowSizerTestUtil;
+
 // TODO(rjkroege): Use the common TestScreen.
 class TestScreen : public display::Screen {
  public:
@@ -185,20 +187,21 @@
 
 int kWindowTilePixels = WindowSizer::kWindowTilePixels;
 
-// The window sizer commonly used test functions.
-void GetWindowBoundsAndShowState(const gfx::Rect& monitor1_bounds,
-                                 const gfx::Rect& monitor1_work_area,
-                                 const gfx::Rect& monitor2_bounds,
-                                 const gfx::Rect& bounds,
-                                 const gfx::Rect& work_area,
-                                 ui::WindowShowState show_state_persisted,
-                                 ui::WindowShowState show_state_last,
-                                 Source source,
-                                 const Browser* browser,
-                                 const gfx::Rect& passed_in,
-                                 size_t display_index,
-                                 gfx::Rect* out_bounds,
-                                 ui::WindowShowState* out_show_state) {
+// static
+void WindowSizerTestUtil::GetWindowBoundsAndShowState(
+    const gfx::Rect& monitor1_bounds,
+    const gfx::Rect& monitor1_work_area,
+    const gfx::Rect& monitor2_bounds,
+    const gfx::Rect& bounds,
+    const gfx::Rect& work_area,
+    ui::WindowShowState show_state_persisted,
+    ui::WindowShowState show_state_last,
+    Source source,
+    const Browser* browser,
+    const gfx::Rect& passed_in,
+    size_t display_index,
+    gfx::Rect* out_bounds,
+    ui::WindowShowState* out_show_state) {
   DCHECK(out_show_state);
   TestScreen test_screen;
   test_screen.AddDisplay(monitor1_bounds, monitor1_work_area);
@@ -218,23 +221,9 @@
                                           out_bounds,
                                           out_show_state);
 }
-void GetWindowBounds(const gfx::Rect& monitor1_bounds,
-                            const gfx::Rect& monitor1_work_area,
-                            const gfx::Rect& monitor2_bounds,
-                            const gfx::Rect& bounds,
-                            const gfx::Rect& work_area,
-                            Source source,
-                            const Browser* browser,
-                            const gfx::Rect& passed_in,
-                            gfx::Rect* out_bounds) {
-  ui::WindowShowState out_show_state = ui::SHOW_STATE_DEFAULT;
-  GetWindowBoundsAndShowState(
-      monitor1_bounds, monitor1_work_area, monitor2_bounds, bounds, work_area,
-      ui::SHOW_STATE_DEFAULT, ui::SHOW_STATE_DEFAULT, source, browser,
-      passed_in, 0u, out_bounds, &out_show_state);
-}
 
-ui::WindowShowState GetWindowShowState(
+// static
+ui::WindowShowState WindowSizerTestUtil::GetWindowShowState(
     ui::WindowShowState show_state_persisted,
     ui::WindowShowState show_state_last,
     Source source,
@@ -262,6 +251,23 @@
   return out_show_state;
 }
 
+// static
+void WindowSizerTestUtil::GetWindowBounds(const gfx::Rect& monitor1_bounds,
+                                          const gfx::Rect& monitor1_work_area,
+                                          const gfx::Rect& monitor2_bounds,
+                                          const gfx::Rect& bounds,
+                                          const gfx::Rect& work_area,
+                                          Source source,
+                                          const Browser* browser,
+                                          const gfx::Rect& passed_in,
+                                          gfx::Rect* out_bounds) {
+  ui::WindowShowState out_show_state = ui::SHOW_STATE_DEFAULT;
+  GetWindowBoundsAndShowState(
+      monitor1_bounds, monitor1_work_area, monitor2_bounds, bounds, work_area,
+      ui::SHOW_STATE_DEFAULT, ui::SHOW_STATE_DEFAULT, source, browser,
+      passed_in, 0u, out_bounds, &out_show_state);
+}
+
 #if !defined(OS_MACOSX)
 TEST(WindowSizerTestCommon,
      PersistedWindowOffscreenWithNonAggressiveRepositioning) {
@@ -270,27 +276,27 @@
     gfx::Rect initial_bounds(-470, 50, 500, 400);
 
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
-                    initial_bounds, gfx::Rect(), PERSISTED,
-                    NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, gfx::Rect(), initial_bounds,
+                          gfx::Rect(), PERSISTED, NULL, gfx::Rect(),
+                          &window_bounds);
     EXPECT_EQ(initial_bounds.ToString(), window_bounds.ToString());
   }
 
   { // off the left and the minimum visibility condition is satisfied by
     // relocation.
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
-                    gfx::Rect(-471, 50, 500, 400), gfx::Rect(), PERSISTED,
-                    NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
+                          gfx::Rect(-471, 50, 500, 400), gfx::Rect(), PERSISTED,
+                          NULL, gfx::Rect(), &window_bounds);
     EXPECT_EQ(gfx::Rect(-470 /* not -471 */, 50, 500, 400).ToString(),
               window_bounds.ToString());
   }
 
   { // off the top
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
-                    gfx::Rect(50, -370, 500, 400), gfx::Rect(), PERSISTED,
-                    NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
+                          gfx::Rect(50, -370, 500, 400), gfx::Rect(), PERSISTED,
+                          NULL, gfx::Rect(), &window_bounds);
     EXPECT_EQ("50,0 500x400", window_bounds.ToString());
   }
 
@@ -299,18 +305,18 @@
     gfx::Rect initial_bounds(994, 50, 500, 400);
 
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
-                    initial_bounds, gfx::Rect(), PERSISTED,
-                    NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, gfx::Rect(), initial_bounds,
+                          gfx::Rect(), PERSISTED, NULL, gfx::Rect(),
+                          &window_bounds);
     EXPECT_EQ(initial_bounds.ToString(), window_bounds.ToString());
   }
 
   { // off the right and the minimum visibility condition is satisified by
     // relocation.
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
-                    gfx::Rect(995, 50, 500, 400), gfx::Rect(), PERSISTED,
-                    NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
+                          gfx::Rect(995, 50, 500, 400), gfx::Rect(), PERSISTED,
+                          NULL, gfx::Rect(), &window_bounds);
     EXPECT_EQ(gfx::Rect(994 /* not 995 */, 50, 500, 400).ToString(),
               window_bounds.ToString());
   }
@@ -320,27 +326,27 @@
     gfx::Rect initial_bounds(50, 738, 500, 400);
 
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
-                    initial_bounds, gfx::Rect(), PERSISTED,
-                    NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, gfx::Rect(), initial_bounds,
+                          gfx::Rect(), PERSISTED, NULL, gfx::Rect(),
+                          &window_bounds);
     EXPECT_EQ(initial_bounds.ToString(), window_bounds.ToString());
   }
 
   { // off the bottom and the minimum visibility condition is satisified by
     // relocation.
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
-                    gfx::Rect(50, 739, 500, 400), gfx::Rect(), PERSISTED,
-                    NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
+                          gfx::Rect(50, 739, 500, 400), gfx::Rect(), PERSISTED,
+                          NULL, gfx::Rect(), &window_bounds);
     EXPECT_EQ(gfx::Rect(50, 738 /* not 739 */, 500, 400).ToString(),
               window_bounds.ToString());
   }
 
   { // off the topleft
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
-                    gfx::Rect(-471, -371, 500, 400), gfx::Rect(), PERSISTED,
-                    NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
+                          gfx::Rect(-471, -371, 500, 400), gfx::Rect(),
+                          PERSISTED, NULL, gfx::Rect(), &window_bounds);
     EXPECT_EQ(gfx::Rect(-470 /* not -471 */, 0, 500, 400).ToString(),
               window_bounds.ToString());
   }
@@ -348,9 +354,9 @@
   { // off the topright and the minimum visibility condition is satisified by
     // relocation.
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
-                    gfx::Rect(995, -371, 500, 400), gfx::Rect(), PERSISTED,
-                    NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
+                          gfx::Rect(995, -371, 500, 400), gfx::Rect(),
+                          PERSISTED, NULL, gfx::Rect(), &window_bounds);
     EXPECT_EQ(gfx::Rect(994 /* not 995 */, 0, 500, 400).ToString(),
               window_bounds.ToString());
   }
@@ -358,9 +364,9 @@
   { // off the bottomleft and the minimum visibility condition is satisified by
     // relocation.
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
-                    gfx::Rect(-471, 739, 500, 400), gfx::Rect(), PERSISTED,
-                    NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
+                          gfx::Rect(-471, 739, 500, 400), gfx::Rect(),
+                          PERSISTED, NULL, gfx::Rect(), &window_bounds);
     EXPECT_EQ(gfx::Rect(-470 /* not -471 */,
                         738 /* not 739 */,
                         500,
@@ -371,9 +377,9 @@
   { // off the bottomright and the minimum visibility condition is satisified by
     // relocation.
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
-                    gfx::Rect(995, 739, 500, 400), gfx::Rect(), PERSISTED,
-                    NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
+                          gfx::Rect(995, 739, 500, 400), gfx::Rect(), PERSISTED,
+                          NULL, gfx::Rect(), &window_bounds);
     EXPECT_EQ(gfx::Rect(994 /* not 995 */,
                         738 /* not 739 */,
                         500,
@@ -383,68 +389,68 @@
 
   { // entirely off left
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
-                    gfx::Rect(-700, 50, 500, 400), gfx::Rect(), PERSISTED,
-                    NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
+                          gfx::Rect(-700, 50, 500, 400), gfx::Rect(), PERSISTED,
+                          NULL, gfx::Rect(), &window_bounds);
     EXPECT_EQ(gfx::Rect(-470 /* not -700 */, 50, 500, 400).ToString(),
               window_bounds.ToString());
   }
 
   { // entirely off left (monitor was detached since last run)
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
-                    gfx::Rect(-700, 50, 500, 400), left_s1024x768, PERSISTED,
-                    NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
+                          gfx::Rect(-700, 50, 500, 400), left_s1024x768,
+                          PERSISTED, NULL, gfx::Rect(), &window_bounds);
     EXPECT_EQ("0,50 500x400", window_bounds.ToString());
   }
 
   { // entirely off top
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
-                    gfx::Rect(50, -500, 500, 400), gfx::Rect(), PERSISTED,
-                    NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
+                          gfx::Rect(50, -500, 500, 400), gfx::Rect(), PERSISTED,
+                          NULL, gfx::Rect(), &window_bounds);
     EXPECT_EQ("50,0 500x400", window_bounds.ToString());
   }
 
   { // entirely off top (monitor was detached since last run)
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
-                    gfx::Rect(50, -500, 500, 400), top_s1024x768,
-                    PERSISTED, NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
+                          gfx::Rect(50, -500, 500, 400), top_s1024x768,
+                          PERSISTED, NULL, gfx::Rect(), &window_bounds);
     EXPECT_EQ("50,0 500x400", window_bounds.ToString());
   }
 
   { // entirely off right
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
-                    gfx::Rect(1200, 50, 500, 400), gfx::Rect(), PERSISTED,
-                    NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
+                          gfx::Rect(1200, 50, 500, 400), gfx::Rect(), PERSISTED,
+                          NULL, gfx::Rect(), &window_bounds);
     EXPECT_EQ(gfx::Rect(994 /* not 1200 */, 50, 500, 400).ToString(),
               window_bounds.ToString());
   }
 
   { // entirely off right (monitor was detached since last run)
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
-                    gfx::Rect(1200, 50, 500, 400), right_s1024x768,
-                    PERSISTED, NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
+                          gfx::Rect(1200, 50, 500, 400), right_s1024x768,
+                          PERSISTED, NULL, gfx::Rect(), &window_bounds);
     EXPECT_EQ("524,50 500x400", window_bounds.ToString());
   }
 
   { // entirely off bottom
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
-                    gfx::Rect(50, 800, 500, 400), gfx::Rect(), PERSISTED,
-                    NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
+                          gfx::Rect(50, 800, 500, 400), gfx::Rect(), PERSISTED,
+                          NULL, gfx::Rect(), &window_bounds);
     EXPECT_EQ(gfx::Rect(50, 738 /* not 800 */, 500, 400).ToString(),
               window_bounds.ToString());
   }
 
   { // entirely off bottom (monitor was detached since last run)
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
-                    gfx::Rect(50, 800, 500, 400), bottom_s1024x768,
-                    PERSISTED, NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
+                          gfx::Rect(50, 800, 500, 400), bottom_s1024x768,
+                          PERSISTED, NULL, gfx::Rect(), &window_bounds);
     EXPECT_EQ("50,368 500x400", window_bounds.ToString());
   }
 }
@@ -454,17 +460,17 @@
 TEST(WindowSizerTestCommon, AdjustFitSize) {
   { // Check that the window gets resized to the screen.
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(), gfx::Rect(),
-                    gfx::Rect(), DEFAULT, NULL,
-                    gfx::Rect(-10, -10, 1024 + 20, 768 + 20), &window_bounds);
+    util::GetWindowBounds(
+        p1024x768, p1024x768, gfx::Rect(), gfx::Rect(), gfx::Rect(), DEFAULT,
+        NULL, gfx::Rect(-10, -10, 1024 + 20, 768 + 20), &window_bounds);
     EXPECT_EQ("0,0 1024x768", window_bounds.ToString());
   }
 
   { // Check that a window which hangs out of the screen get moved back in.
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(), gfx::Rect(),
-                    gfx::Rect(), DEFAULT, NULL,
-                    gfx::Rect(1020, 700, 100, 100), &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, gfx::Rect(), gfx::Rect(),
+                          gfx::Rect(), DEFAULT, NULL,
+                          gfx::Rect(1020, 700, 100, 100), &window_bounds);
     EXPECT_EQ("924,668 100x100", window_bounds.ToString());
   }
 }
diff --git a/chrome/browser/ui/window_sizer/window_sizer_common_unittest.h b/chrome/browser/ui/window_sizer/window_sizer_common_unittest.h
index 5e10dd2b..e58bdc6 100644
--- a/chrome/browser/ui/window_sizer/window_sizer_common_unittest.h
+++ b/chrome/browser/ui/window_sizer/window_sizer_common_unittest.h
@@ -88,54 +88,63 @@
 
 enum Source { DEFAULT, LAST_ACTIVE, PERSISTED, BOTH };
 
-// Sets up the window bounds, monitor bounds, show states and more to get the
-// resulting |out_bounds| and |out_show_state| from the WindowSizer.
-// |source| specifies which type of data gets set for the test: Either the
-// last active window, the persisted value which was stored earlier, both or
-// none. For all these states the |bounds| and |work_area| get used, for the
-// show states either |show_state_persisted| or |show_state_last| will be used.
-// |display_index| is the index of the display to return from
-// GetDisplayNearestWindow(), and is only used on aura.
-void GetWindowBoundsAndShowState(const gfx::Rect& monitor1_bounds,
-                                 const gfx::Rect& monitor1_work_area,
-                                 const gfx::Rect& monitor2_bounds,
-                                 const gfx::Rect& bounds,
-                                 const gfx::Rect& work_area,
-                                 ui::WindowShowState show_state_persisted,
-                                 ui::WindowShowState show_state_last,
-                                 Source source,
-                                 const Browser* browser,
-                                 const gfx::Rect& passed_in,
-                                 size_t display_index,
-                                 gfx::Rect* out_bounds,
-                                 ui::WindowShowState* out_show_state);
+class WindowSizerTestUtil {
+ public:
+  // Sets up the window bounds, monitor bounds, show states and more to get the
+  // resulting |out_bounds| and |out_show_state| from the WindowSizer.
+  // |source| specifies which type of data gets set for the test: Either the
+  // last active window, the persisted value which was stored earlier, both or
+  // none. For all these states the |bounds| and |work_area| get used, for the
+  // show states either |show_state_persisted| or |show_state_last| will be
+  // used. |display_index| is the index of the display to return from
+  // GetDisplayNearestWindow(), and is only used on aura.
+  static void GetWindowBoundsAndShowState(
+      const gfx::Rect& monitor1_bounds,
+      const gfx::Rect& monitor1_work_area,
+      const gfx::Rect& monitor2_bounds,
+      const gfx::Rect& bounds,
+      const gfx::Rect& work_area,
+      ui::WindowShowState show_state_persisted,
+      ui::WindowShowState show_state_last,
+      Source source,
+      const Browser* browser,
+      const gfx::Rect& passed_in,
+      size_t display_index,
+      gfx::Rect* out_bounds,
+      ui::WindowShowState* out_show_state);
 
-// Sets up the window bounds, monitor bounds, and work area to get the
-// resulting |out_bounds| from the WindowSizer.
-// |source| specifies which type of data gets set for the test: Either the
-// last active window, the persisted value which was stored earlier, both or
-// none. For all these states the |bounds| and |work_area| get used, for the
-// show states either |show_state_persisted| or |show_state_last| will be used.
-void GetWindowBounds(const gfx::Rect& monitor1_bounds,
-                     const gfx::Rect& monitor1_work_area,
-                     const gfx::Rect& monitor2_bounds,
-                     const gfx::Rect& bounds,
-                     const gfx::Rect& work_area,
-                     Source source,
-                     const Browser* browser,
-                     const gfx::Rect& passed_in,
-                     gfx::Rect* out_bounds);
+  // Sets up the window bounds, monitor bounds, and work area to get the
+  // resulting |out_bounds| from the WindowSizer.
+  // |source| specifies which type of data gets set for the test: Either the
+  // last active window, the persisted value which was stored earlier, both or
+  // none. For all these states the |bounds| and |work_area| get used, for the
+  // show states either |show_state_persisted| or |show_state_last| will be
+  // used.
+  static void GetWindowBounds(const gfx::Rect& monitor1_bounds,
+                              const gfx::Rect& monitor1_work_area,
+                              const gfx::Rect& monitor2_bounds,
+                              const gfx::Rect& bounds,
+                              const gfx::Rect& work_area,
+                              Source source,
+                              const Browser* browser,
+                              const gfx::Rect& passed_in,
+                              gfx::Rect* out_bounds);
 
-// Sets up the window |bounds| and various system states which have an influence
-// on the WindowSizer and then determines the resulting show state from it.
-// |bounds| specifies the |browser| last or persistent bounds depending on
-// |source|. The |display_config| is the primary display configuration used.
-ui::WindowShowState GetWindowShowState(
-    ui::WindowShowState show_state_persisted,
-    ui::WindowShowState show_state_last,
-    Source source,
-    const Browser* browser,
-    const gfx::Rect& bounds,
-    const gfx::Rect& display_config);
+  // Sets up the window |bounds| and various system states which have an
+  // influence on the WindowSizer and then determines the resulting show state
+  // from it. |bounds| specifies the |browser| last or persistent bounds
+  // depending on |source|. The |display_config| is the primary display
+  // configuration used.
+  static ui::WindowShowState GetWindowShowState(
+      ui::WindowShowState show_state_persisted,
+      ui::WindowShowState show_state_last,
+      Source source,
+      const Browser* browser,
+      const gfx::Rect& bounds,
+      const gfx::Rect& display_config);
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(WindowSizerTestUtil);
+};
 
 #endif  // CHROME_BROWSER_UI_WINDOW_SIZER_WINDOW_SIZER_COMMON_UNITTEST_H_
diff --git a/chrome/browser/ui/window_sizer/window_sizer_unittest.cc b/chrome/browser/ui/window_sizer/window_sizer_unittest.cc
index 8e7e296..6849f7bec9 100644
--- a/chrome/browser/ui/window_sizer/window_sizer_unittest.cc
+++ b/chrome/browser/ui/window_sizer/window_sizer_unittest.cc
@@ -8,13 +8,18 @@
 #include "build/build_config.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+namespace {
+using util = WindowSizerTestUtil;
+}
+
 // Test that the window is sized appropriately for the first run experience
 // where the default window bounds calculation is invoked.
 TEST(WindowSizerTest, DefaultSizeCase) {
   { // 4:3 monitor case, 1024x768, no taskbar
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(), gfx::Rect(),
-                    gfx::Rect(), DEFAULT, NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, gfx::Rect(), gfx::Rect(),
+                          gfx::Rect(), DEFAULT, NULL, gfx::Rect(),
+                          &window_bounds);
     EXPECT_EQ(gfx::Rect(kWindowTilePixels, kWindowTilePixels,
                         1024 - kWindowTilePixels * 2,
                         768 - kWindowTilePixels * 2),
@@ -23,9 +28,9 @@
 
   { // 4:3 monitor case, 1024x768, taskbar on bottom
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, taskbar_bottom_work_area, gfx::Rect(),
-                    gfx::Rect(), gfx::Rect(), DEFAULT, NULL, gfx::Rect(),
-                    &window_bounds);
+    util::GetWindowBounds(p1024x768, taskbar_bottom_work_area, gfx::Rect(),
+                          gfx::Rect(), gfx::Rect(), DEFAULT, NULL, gfx::Rect(),
+                          &window_bounds);
     EXPECT_EQ(gfx::Rect(kWindowTilePixels, kWindowTilePixels,
                         1024 - kWindowTilePixels * 2,
                         (taskbar_bottom_work_area.height() -
@@ -35,9 +40,9 @@
 
   { // 4:3 monitor case, 1024x768, taskbar on right
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, taskbar_right_work_area, gfx::Rect(),
-                    gfx::Rect(), gfx::Rect(), DEFAULT, NULL, gfx::Rect(),
-                    &window_bounds);
+    util::GetWindowBounds(p1024x768, taskbar_right_work_area, gfx::Rect(),
+                          gfx::Rect(), gfx::Rect(), DEFAULT, NULL, gfx::Rect(),
+                          &window_bounds);
     EXPECT_EQ(gfx::Rect(kWindowTilePixels, kWindowTilePixels,
                         taskbar_right_work_area.width() - kWindowTilePixels*2,
                         768 - kWindowTilePixels * 2),
@@ -46,9 +51,9 @@
 
   { // 4:3 monitor case, 1024x768, taskbar on left
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, taskbar_left_work_area, gfx::Rect(),
-                    gfx::Rect(), gfx::Rect(), DEFAULT, NULL, gfx::Rect(),
-                    &window_bounds);
+    util::GetWindowBounds(p1024x768, taskbar_left_work_area, gfx::Rect(),
+                          gfx::Rect(), gfx::Rect(), DEFAULT, NULL, gfx::Rect(),
+                          &window_bounds);
     EXPECT_EQ(gfx::Rect(taskbar_left_work_area.x() + kWindowTilePixels,
                         kWindowTilePixels,
                         taskbar_left_work_area.width() - kWindowTilePixels * 2,
@@ -59,9 +64,9 @@
 
   { // 4:3 monitor case, 1024x768, taskbar on top
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, taskbar_top_work_area, gfx::Rect(),
-                    gfx::Rect(), gfx::Rect(), DEFAULT, NULL, gfx::Rect(),
-                    &window_bounds);
+    util::GetWindowBounds(p1024x768, taskbar_top_work_area, gfx::Rect(),
+                          gfx::Rect(), gfx::Rect(), DEFAULT, NULL, gfx::Rect(),
+                          &window_bounds);
     EXPECT_EQ(gfx::Rect(kWindowTilePixels,
                         taskbar_top_work_area.y() + kWindowTilePixels,
                         1024 - kWindowTilePixels * 2,
@@ -71,8 +76,9 @@
 
   { // 4:3 monitor case, 1280x1024
     gfx::Rect window_bounds;
-    GetWindowBounds(p1280x1024, p1280x1024, gfx::Rect(), gfx::Rect(),
-                    gfx::Rect(), DEFAULT, NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1280x1024, p1280x1024, gfx::Rect(), gfx::Rect(),
+                          gfx::Rect(), DEFAULT, NULL, gfx::Rect(),
+                          &window_bounds);
     EXPECT_EQ(gfx::Rect(kWindowTilePixels, kWindowTilePixels,
                         WindowSizer::kWindowMaxDefaultWidth,
                         1024 - kWindowTilePixels * 2),
@@ -81,8 +87,9 @@
 
   { // 4:3 monitor case, 1600x1200
     gfx::Rect window_bounds;
-    GetWindowBounds(p1600x1200, p1600x1200, gfx::Rect(), gfx::Rect(),
-                    gfx::Rect(), DEFAULT, NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1600x1200, p1600x1200, gfx::Rect(), gfx::Rect(),
+                          gfx::Rect(), DEFAULT, NULL, gfx::Rect(),
+                          &window_bounds);
     EXPECT_EQ(gfx::Rect(kWindowTilePixels, kWindowTilePixels,
                         WindowSizer::kWindowMaxDefaultWidth,
                         1200 - kWindowTilePixels * 2),
@@ -101,8 +108,9 @@
         window_width / 2 - static_cast<int>(kWindowTilePixels * 1.5);
 #endif  // defined(OS_MACOSX)
     gfx::Rect window_bounds;
-    GetWindowBounds(p1680x1050, p1680x1050, gfx::Rect(), gfx::Rect(),
-                    gfx::Rect(), DEFAULT, NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1680x1050, p1680x1050, gfx::Rect(), gfx::Rect(),
+                          gfx::Rect(), DEFAULT, NULL, gfx::Rect(),
+                          &window_bounds);
     EXPECT_EQ(gfx::Rect(kWindowTilePixels, kWindowTilePixels,
                         expected_window_width, 1050 - kWindowTilePixels * 2),
               window_bounds);
@@ -120,8 +128,9 @@
         window_width / 2 - static_cast<int>(kWindowTilePixels * 1.5);
 #endif  // defined(OS_MACOSX)
     gfx::Rect window_bounds;
-    GetWindowBounds(p1920x1200, p1920x1200, gfx::Rect(), gfx::Rect(),
-                    gfx::Rect(), DEFAULT, NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1920x1200, p1920x1200, gfx::Rect(), gfx::Rect(),
+                          gfx::Rect(), DEFAULT, NULL, gfx::Rect(),
+                          &window_bounds);
     EXPECT_EQ(gfx::Rect(kWindowTilePixels, kWindowTilePixels,
                         expected_window_width, 1200 - kWindowTilePixels * 2),
               window_bounds);
@@ -133,20 +142,20 @@
 TEST(WindowSizerTest, LastWindowBoundsCase) {
   { // normal, in the middle of the screen somewhere.
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
-                    gfx::Rect(kWindowTilePixels, kWindowTilePixels, 500, 400),
-                    gfx::Rect(), LAST_ACTIVE, NULL, gfx::Rect(),
-                    &window_bounds);
+    util::GetWindowBounds(
+        p1024x768, p1024x768, gfx::Rect(),
+        gfx::Rect(kWindowTilePixels, kWindowTilePixels, 500, 400), gfx::Rect(),
+        LAST_ACTIVE, NULL, gfx::Rect(), &window_bounds);
     EXPECT_EQ(gfx::Rect(kWindowTilePixels * 2,
                         kWindowTilePixels * 2, 500, 400), window_bounds);
   }
 
   { // taskbar on top.
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, taskbar_top_work_area, gfx::Rect(),
-                    gfx::Rect(kWindowTilePixels, kWindowTilePixels, 500, 400),
-                    gfx::Rect(), LAST_ACTIVE, NULL, gfx::Rect(),
-                    &window_bounds);
+    util::GetWindowBounds(
+        p1024x768, taskbar_top_work_area, gfx::Rect(),
+        gfx::Rect(kWindowTilePixels, kWindowTilePixels, 500, 400), gfx::Rect(),
+        LAST_ACTIVE, NULL, gfx::Rect(), &window_bounds);
     EXPECT_EQ(gfx::Rect(kWindowTilePixels * 2,
                         std::max(kWindowTilePixels * 2,
                                  34 /* toolbar height */),
@@ -155,10 +164,10 @@
 
   { // Too small to satisify the minimum visibility condition.
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
-                    gfx::Rect(kWindowTilePixels, kWindowTilePixels, 29, 29),
-                    gfx::Rect(), LAST_ACTIVE, NULL, gfx::Rect(),
-                    &window_bounds);
+    util::GetWindowBounds(
+        p1024x768, p1024x768, gfx::Rect(),
+        gfx::Rect(kWindowTilePixels, kWindowTilePixels, 29, 29), gfx::Rect(),
+        LAST_ACTIVE, NULL, gfx::Rect(), &window_bounds);
     EXPECT_EQ(gfx::Rect(kWindowTilePixels * 2,
                         kWindowTilePixels * 2,
                         30 /* not 29 */,
@@ -169,10 +178,10 @@
 
   { // Normal.
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
-                    gfx::Rect(kWindowTilePixels, kWindowTilePixels, 500, 400),
-                    gfx::Rect(), LAST_ACTIVE, NULL, gfx::Rect(),
-                    &window_bounds);
+    util::GetWindowBounds(
+        p1024x768, p1024x768, gfx::Rect(),
+        gfx::Rect(kWindowTilePixels, kWindowTilePixels, 500, 400), gfx::Rect(),
+        LAST_ACTIVE, NULL, gfx::Rect(), &window_bounds);
     EXPECT_EQ(gfx::Rect(kWindowTilePixels * 2,
                         kWindowTilePixels * 2, 500, 400), window_bounds);
   }
@@ -184,8 +193,9 @@
     gfx::Rect initial_bounds(kWindowTilePixels, kWindowTilePixels, 500, 400);
 
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(), initial_bounds,
-                    gfx::Rect(), PERSISTED, NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, gfx::Rect(), initial_bounds,
+                          gfx::Rect(), PERSISTED, NULL, gfx::Rect(),
+                          &window_bounds);
     EXPECT_EQ(initial_bounds.ToString(), window_bounds.ToString());
   }
 
@@ -193,8 +203,9 @@
     gfx::Rect initial_bounds(0, 0, 1024, 768);
 
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(), initial_bounds,
-                    gfx::Rect(), PERSISTED, NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, gfx::Rect(), initial_bounds,
+                          gfx::Rect(), PERSISTED, NULL, gfx::Rect(),
+                          &window_bounds);
     EXPECT_EQ(initial_bounds.ToString(), window_bounds.ToString());
   }
 
@@ -202,9 +213,9 @@
     gfx::Rect initial_bounds(-600, 10, 500, 400);
 
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, left_s1024x768,
-                    initial_bounds, gfx::Rect(), PERSISTED, NULL, gfx::Rect(),
-                    &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, left_s1024x768, initial_bounds,
+                          gfx::Rect(), PERSISTED, NULL, gfx::Rect(),
+                          &window_bounds);
     EXPECT_EQ(initial_bounds.ToString(), window_bounds.ToString());
   }
 
@@ -212,9 +223,9 @@
     gfx::Rect initial_bounds(-1024, 0, 1024, 768);
 
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, left_s1024x768,
-                    initial_bounds, gfx::Rect(), PERSISTED, NULL, gfx::Rect(),
-                    &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, left_s1024x768, initial_bounds,
+                          gfx::Rect(), PERSISTED, NULL, gfx::Rect(),
+                          &window_bounds);
     EXPECT_EQ(initial_bounds.ToString(), window_bounds.ToString());
   }
 
@@ -224,9 +235,9 @@
     gfx::Rect initial_bounds(1074, 50, 600, 500);
 
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(1024, 0, 800, 600),
-                    initial_bounds, right_s1024x768, PERSISTED, NULL,
-                    gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, gfx::Rect(1024, 0, 800, 600),
+                          initial_bounds, right_s1024x768, PERSISTED, NULL,
+                          gfx::Rect(), &window_bounds);
     EXPECT_EQ(initial_bounds.ToString(), window_bounds.ToString());
   }
 
@@ -236,9 +247,9 @@
     gfx::Rect initial_bounds(1274, 50, 600, 500);
 
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(1024, 0, 800, 600),
-                    initial_bounds, right_s1024x768, PERSISTED,
-                    NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, gfx::Rect(1024, 0, 800, 600),
+                          initial_bounds, right_s1024x768, PERSISTED, NULL,
+                          gfx::Rect(), &window_bounds);
     EXPECT_EQ("1224,50 600x500", window_bounds.ToString());
   }
 
@@ -248,17 +259,18 @@
     gfx::Rect initial_bounds(1274, 50, 900, 700);
 
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(1024, 0, 800, 600),
-                    initial_bounds, right_s1024x768, PERSISTED,
-                    NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, gfx::Rect(1024, 0, 800, 600),
+                          initial_bounds, right_s1024x768, PERSISTED, NULL,
+                          gfx::Rect(), &window_bounds);
     EXPECT_EQ("1024,0 800x600", window_bounds.ToString());
   }
 
   { // width and height too small
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
-                    gfx::Rect(kWindowTilePixels, kWindowTilePixels, 29, 29),
-                    gfx::Rect(), PERSISTED, NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(
+        p1024x768, p1024x768, gfx::Rect(),
+        gfx::Rect(kWindowTilePixels, kWindowTilePixels, 29, 29), gfx::Rect(),
+        PERSISTED, NULL, gfx::Rect(), &window_bounds);
     EXPECT_EQ(gfx::Rect(kWindowTilePixels, kWindowTilePixels,
                         30 /* not 29 */, 30 /* not 29 */),
               window_bounds);
@@ -270,9 +282,10 @@
     // be moved higher than the menubar.  (Perhaps the user changed
     // resolution to something smaller before relaunching Chrome?)
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
-                    gfx::Rect(kWindowTilePixels, kWindowTilePixels, 30, 5000),
-                    gfx::Rect(), PERSISTED, NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(
+        p1024x768, p1024x768, gfx::Rect(),
+        gfx::Rect(kWindowTilePixels, kWindowTilePixels, 30, 5000), gfx::Rect(),
+        PERSISTED, NULL, gfx::Rect(), &window_bounds);
     EXPECT_EQ(p1024x768.height(), window_bounds.height());
   }
 #endif  // defined(OS_MACOSX)
@@ -289,19 +302,19 @@
   { // taskbar on left.  The new window overlaps slightly with the taskbar, so
     // it is moved to be flush with the left edge of the work area.
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, taskbar_left_work_area, gfx::Rect(),
-                    gfx::Rect(kWindowTilePixels, kWindowTilePixels, 500, 400),
-                    gfx::Rect(), LAST_ACTIVE, NULL, gfx::Rect(),
-                    &window_bounds);
+    util::GetWindowBounds(
+        p1024x768, taskbar_left_work_area, gfx::Rect(),
+        gfx::Rect(kWindowTilePixels, kWindowTilePixels, 500, 400), gfx::Rect(),
+        LAST_ACTIVE, NULL, gfx::Rect(), &window_bounds);
     EXPECT_EQ(gfx::Rect(taskbar_left_work_area.x(),
                         kWindowTilePixels * 2, 500, 400), window_bounds);
   }
 
   { // offset would put the new window offscreen at the bottom
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
-                    gfx::Rect(10, 729, 500, 400), gfx::Rect(), LAST_ACTIVE,
-                    NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
+                          gfx::Rect(10, 729, 500, 400), gfx::Rect(),
+                          LAST_ACTIVE, NULL, gfx::Rect(), &window_bounds);
     EXPECT_EQ(gfx::Rect(10 + kWindowTilePixels,
                         0 /* not 729 + kWindowTilePixels */,
                         500, 400),
@@ -310,9 +323,9 @@
 
   { // offset would put the new window offscreen at the right
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
-                    gfx::Rect(985, 10, 500, 400), gfx::Rect(), LAST_ACTIVE,
-                    NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
+                          gfx::Rect(985, 10, 500, 400), gfx::Rect(),
+                          LAST_ACTIVE, NULL, gfx::Rect(), &window_bounds);
     EXPECT_EQ(gfx::Rect(0 /* not 985 + kWindowTilePixels*/,
                         10 + kWindowTilePixels,
                         500, 400),
@@ -321,9 +334,9 @@
 
   { // offset would put the new window offscreen at the bottom right
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
-                    gfx::Rect(985, 729, 500, 400), gfx::Rect(), LAST_ACTIVE,
-                    NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
+                          gfx::Rect(985, 729, 500, 400), gfx::Rect(),
+                          LAST_ACTIVE, NULL, gfx::Rect(), &window_bounds);
     EXPECT_EQ(gfx::Rect(0 /* not 985 + kWindowTilePixels*/,
                         0 /* not 729 + kWindowTilePixels*/,
                         500, 400),
@@ -334,141 +347,141 @@
 TEST(WindowSizerTest, PersistedWindowOffscreenWithAggressiveRepositioning) {
   { // off the left
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
-                    gfx::Rect(-471, 50, 500, 400), gfx::Rect(), PERSISTED,
-                    NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
+                          gfx::Rect(-471, 50, 500, 400), gfx::Rect(), PERSISTED,
+                          NULL, gfx::Rect(), &window_bounds);
     EXPECT_EQ(gfx::Rect(0 /* not -471 */, 50, 500, 400), window_bounds);
   }
 
   { // off the top
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
-                    gfx::Rect(50, -370, 500, 400), gfx::Rect(), PERSISTED,
-                    NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
+                          gfx::Rect(50, -370, 500, 400), gfx::Rect(), PERSISTED,
+                          NULL, gfx::Rect(), &window_bounds);
     EXPECT_EQ(gfx::Rect(50, 0, 500, 400), window_bounds);
   }
 
   { // off the right
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
-                    gfx::Rect(995, 50, 500, 400), gfx::Rect(), PERSISTED,
-                    NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
+                          gfx::Rect(995, 50, 500, 400), gfx::Rect(), PERSISTED,
+                          NULL, gfx::Rect(), &window_bounds);
     EXPECT_EQ(gfx::Rect(0 /* not 995 */, 50, 500, 400), window_bounds);
   }
 
   { // off the bottom
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
-                    gfx::Rect(50, 739, 500, 400), gfx::Rect(), PERSISTED,
-                    NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
+                          gfx::Rect(50, 739, 500, 400), gfx::Rect(), PERSISTED,
+                          NULL, gfx::Rect(), &window_bounds);
     EXPECT_EQ(gfx::Rect(50, 0 /* not 739 */, 500, 400), window_bounds);
   }
 
   { // off the topleft
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
-                    gfx::Rect(-471, -371, 500, 400), gfx::Rect(), PERSISTED,
-                    NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
+                          gfx::Rect(-471, -371, 500, 400), gfx::Rect(),
+                          PERSISTED, NULL, gfx::Rect(), &window_bounds);
     EXPECT_EQ(gfx::Rect(0 /* not -471 */, 0 /* not -371 */, 500, 400),
               window_bounds);
   }
 
   { // off the topright
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
-                    gfx::Rect(995, -371, 500, 400), gfx::Rect(), PERSISTED,
-                    NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
+                          gfx::Rect(995, -371, 500, 400), gfx::Rect(),
+                          PERSISTED, NULL, gfx::Rect(), &window_bounds);
     EXPECT_EQ(gfx::Rect(0 /* not 995 */, 0 /* not -371 */, 500, 400),
                         window_bounds);
   }
 
   { // off the bottomleft
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
-                    gfx::Rect(-471, 739, 500, 400), gfx::Rect(), PERSISTED,
-                    NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
+                          gfx::Rect(-471, 739, 500, 400), gfx::Rect(),
+                          PERSISTED, NULL, gfx::Rect(), &window_bounds);
     EXPECT_EQ(gfx::Rect(0 /* not -471 */, 0 /* not 739 */, 500, 400),
                         window_bounds);
   }
 
   { // off the bottomright
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
-                    gfx::Rect(995, 739, 500, 400), gfx::Rect(), PERSISTED,
-                    NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
+                          gfx::Rect(995, 739, 500, 400), gfx::Rect(), PERSISTED,
+                          NULL, gfx::Rect(), &window_bounds);
     EXPECT_EQ(gfx::Rect(0 /* not 995 */, 0 /* not 739 */, 500, 400),
                         window_bounds);
   }
 
   { // entirely off left
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
-                    gfx::Rect(-700, 50, 500, 400), gfx::Rect(), PERSISTED,
-                    NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
+                          gfx::Rect(-700, 50, 500, 400), gfx::Rect(), PERSISTED,
+                          NULL, gfx::Rect(), &window_bounds);
     EXPECT_EQ(gfx::Rect(0 /* not -700 */, 50, 500, 400), window_bounds);
   }
 
   { // entirely off left (monitor was detached since last run)
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
-                    gfx::Rect(-700, 50, 500, 400), left_s1024x768,
-                    PERSISTED, NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
+                          gfx::Rect(-700, 50, 500, 400), left_s1024x768,
+                          PERSISTED, NULL, gfx::Rect(), &window_bounds);
     EXPECT_EQ(gfx::Rect(0, 50, 500, 400), window_bounds);
   }
 
   { // entirely off top
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
-                    gfx::Rect(50, -500, 500, 400), gfx::Rect(), PERSISTED,
-                    NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
+                          gfx::Rect(50, -500, 500, 400), gfx::Rect(), PERSISTED,
+                          NULL, gfx::Rect(), &window_bounds);
     EXPECT_EQ(gfx::Rect(50, 0, 500, 400), window_bounds);
   }
 
   { // entirely off top (monitor was detached since last run)
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
-                    gfx::Rect(50, -500, 500, 400), top_s1024x768, PERSISTED,
-                    NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
+                          gfx::Rect(50, -500, 500, 400), top_s1024x768,
+                          PERSISTED, NULL, gfx::Rect(), &window_bounds);
     EXPECT_EQ(gfx::Rect(50, 0, 500, 400), window_bounds);
   }
 
   { // entirely off right
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
-                    gfx::Rect(1200, 50, 500, 400), gfx::Rect(), PERSISTED,
-                    NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
+                          gfx::Rect(1200, 50, 500, 400), gfx::Rect(), PERSISTED,
+                          NULL, gfx::Rect(), &window_bounds);
     EXPECT_EQ(gfx::Rect(0 /* not 1200 */, 50, 500, 400), window_bounds);
   }
 
   { // entirely off right (monitor was detached since last run)
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
-                    gfx::Rect(1200, 50, 500, 400), right_s1024x768, PERSISTED,
-                    NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
+                          gfx::Rect(1200, 50, 500, 400), right_s1024x768,
+                          PERSISTED, NULL, gfx::Rect(), &window_bounds);
     EXPECT_EQ(gfx::Rect(524 /* not 1200 */, 50, 500, 400), window_bounds);
   }
 
   { // entirely off bottom
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
-                    gfx::Rect(50, 800, 500, 400), gfx::Rect(), PERSISTED,
-                    NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
+                          gfx::Rect(50, 800, 500, 400), gfx::Rect(), PERSISTED,
+                          NULL, gfx::Rect(), &window_bounds);
     EXPECT_EQ(gfx::Rect(50, 0 /* not 800 */, 500, 400), window_bounds);
   }
 
   { // entirely off bottom (monitor was detached since last run)
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
-                    gfx::Rect(50, 800, 500, 400), bottom_s1024x768,
-                    PERSISTED, NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
+                          gfx::Rect(50, 800, 500, 400), bottom_s1024x768,
+                          PERSISTED, NULL, gfx::Rect(), &window_bounds);
     EXPECT_EQ(gfx::Rect(50, 368 /* not 800 */, 500, 400), window_bounds);
   }
 
   { // wider than the screen. off both the left and right
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
-                    gfx::Rect(-100, 50, 2000, 400), gfx::Rect(), PERSISTED,
-                    NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
+                          gfx::Rect(-100, 50, 2000, 400), gfx::Rect(),
+                          PERSISTED, NULL, gfx::Rect(), &window_bounds);
     EXPECT_EQ(gfx::Rect(0 /* not -100 */, 50, 2000, 400), window_bounds);
   }
 }
@@ -476,10 +489,10 @@
 TEST(WindowSizerTest, LastWindowOffscreenWithNonAggressiveRepositioning) {
   { // taskbar on left.
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, taskbar_left_work_area, gfx::Rect(),
-                    gfx::Rect(kWindowTilePixels, kWindowTilePixels, 500, 400),
-                    gfx::Rect(), LAST_ACTIVE, NULL, gfx::Rect(),
-                    &window_bounds);
+    util::GetWindowBounds(
+        p1024x768, taskbar_left_work_area, gfx::Rect(),
+        gfx::Rect(kWindowTilePixels, kWindowTilePixels, 500, 400), gfx::Rect(),
+        LAST_ACTIVE, NULL, gfx::Rect(), &window_bounds);
     EXPECT_EQ(gfx::Rect(kWindowTilePixels * 2,
                         kWindowTilePixels * 2, 500, 400), window_bounds);
   }
@@ -489,9 +502,9 @@
   { // offset would put the new window offscreen at the bottom but the minimum
     // visibility condition is barely satisfied without relocation.
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
-                    gfx::Rect(10, 728, 500, 400), gfx::Rect(), LAST_ACTIVE,
-                    NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
+                          gfx::Rect(10, 728, 500, 400), gfx::Rect(),
+                          LAST_ACTIVE, NULL, gfx::Rect(), &window_bounds);
     EXPECT_EQ(gfx::Rect(10 + kWindowTilePixels, 738,
                         500, 400), window_bounds);
   }
@@ -499,9 +512,9 @@
   { // offset would put the new window offscreen at the bottom and the minimum
     // visibility condition is satisified by relocation.
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
-                    gfx::Rect(10, 729, 500, 400), gfx::Rect(), LAST_ACTIVE,
-                    NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
+                          gfx::Rect(10, 729, 500, 400), gfx::Rect(),
+                          LAST_ACTIVE, NULL, gfx::Rect(), &window_bounds);
     EXPECT_EQ(gfx::Rect(10 + kWindowTilePixels, 738 /* not 739 */, 500, 400),
               window_bounds);
   }
@@ -509,18 +522,18 @@
   { // offset would put the new window offscreen at the right but the minimum
     // visibility condition is barely satisfied without relocation.
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
-                    gfx::Rect(984, 10, 500, 400), gfx::Rect(), LAST_ACTIVE,
-                    NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
+                          gfx::Rect(984, 10, 500, 400), gfx::Rect(),
+                          LAST_ACTIVE, NULL, gfx::Rect(), &window_bounds);
     EXPECT_EQ(gfx::Rect(994, 10 + kWindowTilePixels, 500, 400), window_bounds);
   }
 
   { // offset would put the new window offscreen at the right and the minimum
     // visibility condition is satisified by relocation.
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
-                    gfx::Rect(985, 10, 500, 400), gfx::Rect(), LAST_ACTIVE,
-                    NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
+                          gfx::Rect(985, 10, 500, 400), gfx::Rect(),
+                          LAST_ACTIVE, NULL, gfx::Rect(), &window_bounds);
     EXPECT_EQ(gfx::Rect(994 /* not 995 */, 10 + kWindowTilePixels,
                         500, 400), window_bounds);
   }
@@ -528,9 +541,9 @@
   { // offset would put the new window offscreen at the bottom right and the
     // minimum visibility condition is satisified by relocation.
     gfx::Rect window_bounds;
-    GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
-                    gfx::Rect(985, 729, 500, 400), gfx::Rect(), LAST_ACTIVE,
-                    NULL, gfx::Rect(), &window_bounds);
+    util::GetWindowBounds(p1024x768, p1024x768, gfx::Rect(),
+                          gfx::Rect(985, 729, 500, 400), gfx::Rect(),
+                          LAST_ACTIVE, NULL, gfx::Rect(), &window_bounds);
     EXPECT_EQ(gfx::Rect(994 /* not 995 */, 738 /* not 739 */, 500, 400),
               window_bounds);
   }
diff --git a/chrome/browser/vr/BUILD.gn b/chrome/browser/vr/BUILD.gn
index d10c09a..ed0b63c 100644
--- a/chrome/browser/vr/BUILD.gn
+++ b/chrome/browser/vr/BUILD.gn
@@ -2,6 +2,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//build/buildflag_header.gni")
+import("//chrome/browser/vr/features.gni")
 import("//chrome/common/features.gni")
 import("//device/vr/features/features.gni")
 import("//testing/test.gni")
@@ -13,6 +15,11 @@
 
 assert(enable_vr)
 
+buildflag_header("vr_build_features") {
+  header = "vr_features.h"
+  flags = [ "USE_VR_ASSETS_COMPONENT=$use_vr_assets_component" ]
+}
+
 static_library("vr_common") {
   sources = [
     "animation.cc",
@@ -202,6 +209,7 @@
     "ui_scene_creator.cc",
     "ui_scene_creator.h",
     "ui_unsupported_mode.h",
+    "vr_features.h",
     "vr_gl_util.cc",
     "vr_gl_util.h",
   ]
@@ -211,6 +219,7 @@
   ]
 
   deps = [
+    ":vr_build_features",
     "//base",
     "//cc/animation",
     "//cc/paint",
diff --git a/chrome/browser/vr/assets_loader.cc b/chrome/browser/vr/assets_loader.cc
index 9e3f3d8..5926379 100644
--- a/chrome/browser/vr/assets_loader.cc
+++ b/chrome/browser/vr/assets_loader.cc
@@ -12,6 +12,7 @@
 #include "base/values.h"
 #include "chrome/browser/vr/metrics_helper.h"
 #include "chrome/browser/vr/model/assets.h"
+#include "chrome/browser/vr/vr_features.h"
 #include "content/public/browser/browser_thread.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/gfx/codec/jpeg_codec.h"
@@ -54,6 +55,15 @@
   return base::Version(kMinVersionWithGradients);
 }
 
+// static
+bool AssetsLoader::AssetsSupported() {
+#if BUILDFLAG(USE_VR_ASSETS_COMPONENT)
+  return true;
+#else   // BUILDFLAG(USE_VR_ASSETS_COMPONENT)
+  return false;
+#endif  // BUILDFLAG(USE_VR_ASSETS_COMPONENT)
+}
+
 void AssetsLoader::OnComponentReady(
     const base::Version& version,
     const base::FilePath& install_dir,
diff --git a/chrome/browser/vr/assets_loader.h b/chrome/browser/vr/assets_loader.h
index 9949d4d..eba61390 100644
--- a/chrome/browser/vr/assets_loader.h
+++ b/chrome/browser/vr/assets_loader.h
@@ -47,6 +47,7 @@
   static AssetsLoader* GetInstance();
 
   static base::Version MinVersionWithGradients();
+  static bool AssetsSupported();
 
   // Tells VR assets that a new VR assets component version is ready for use.
   void OnComponentReady(const base::Version& version,
diff --git a/chrome/browser/vr/browser_ui_interface.h b/chrome/browser/vr/browser_ui_interface.h
index 0da4d6d7..a2283c1 100644
--- a/chrome/browser/vr/browser_ui_interface.h
+++ b/chrome/browser/vr/browser_ui_interface.h
@@ -44,7 +44,6 @@
   virtual void OnSpeechRecognitionStateChanged(int new_state) = 0;
   virtual void SetOmniboxSuggestions(
       std::unique_ptr<OmniboxSuggestions> suggestions) = 0;
-  virtual void OnAssetsComponentReady() = 0;
   virtual void OnAssetsLoaded(AssetsLoadStatus status,
                               std::unique_ptr<Assets> assets,
                               const base::Version& component_version) = 0;
diff --git a/chrome/browser/vr/content_input_delegate.cc b/chrome/browser/vr/content_input_delegate.cc
index 5ed1aea..d7f465e 100644
--- a/chrome/browser/vr/content_input_delegate.cc
+++ b/chrome/browser/vr/content_input_delegate.cc
@@ -59,6 +59,14 @@
       MakeMouseEvent(blink::WebInputEvent::kMouseUp, normalized_hit_point));
 }
 
+void ContentInputDelegate::OnFocusChanged(bool focused) {
+  // The call below tells the renderer to clear the focused element. Note that
+  // we don't need to do anything when focused is true because the renderer
+  // already knows about the focused element.
+  if (!focused)
+    content_->ClearFocusedElement();
+}
+
 void ContentInputDelegate::OnWebInputEdited(const EditedText& info,
                                             bool commit) {
   if (!content_)
diff --git a/chrome/browser/vr/content_input_delegate.h b/chrome/browser/vr/content_input_delegate.h
index 1ee8fe2..39a115f 100644
--- a/chrome/browser/vr/content_input_delegate.h
+++ b/chrome/browser/vr/content_input_delegate.h
@@ -38,6 +38,7 @@
       std::unique_ptr<blink::WebInputEvent> event) = 0;
 
   // Text input specific.
+  virtual void ClearFocusedElement() = 0;
   virtual void OnWebInputEdited(const TextEdits& edits) = 0;
   virtual void SubmitWebInput() = 0;
   virtual void RequestWebInputText(TextStateUpdateCallback callback) = 0;
@@ -59,6 +60,7 @@
   virtual void OnContentUp(const gfx::PointF& normalized_hit_point);
 
   // Text Input specific.
+  void OnFocusChanged(bool focused);
   void OnWebInputEdited(const EditedText& info, bool commit);
 
   // The following functions are virtual so that they may be overridden in the
diff --git a/chrome/browser/vr/elements/content_element.cc b/chrome/browser/vr/elements/content_element.cc
index 6800f44..9d0b8b8 100644
--- a/chrome/browser/vr/elements/content_element.cc
+++ b/chrome/browser/vr/elements/content_element.cc
@@ -63,6 +63,9 @@
 }
 
 void ContentElement::OnFocusChanged(bool focused) {
+  if (delegate_)
+    delegate_->OnFocusChanged(focused);
+
   focused_ = focused;
   if (event_handlers_.focus_change)
     event_handlers_.focus_change.Run(focused);
diff --git a/chrome/browser/vr/elements/content_element_unittest.cc b/chrome/browser/vr/elements/content_element_unittest.cc
index bb1fcf33..821fc38 100644
--- a/chrome/browser/vr/elements/content_element_unittest.cc
+++ b/chrome/browser/vr/elements/content_element_unittest.cc
@@ -48,6 +48,39 @@
   TextInputInfo info_;
 };
 
+class TestContentInputForwarder : public ContentInputForwarder {
+ public:
+  TestContentInputForwarder() {}
+  ~TestContentInputForwarder() override {}
+
+  void ForwardEvent(std::unique_ptr<blink::WebInputEvent>, int) override {}
+  void ForwardDialogEvent(std::unique_ptr<blink::WebInputEvent>) override {}
+
+  void ClearFocusedElement() override { clear_focus_called_ = true; }
+  void OnWebInputEdited(const TextEdits& edits) override { edits_ = edits; }
+  void SubmitWebInput() override {}
+  void RequestWebInputText(TextStateUpdateCallback) override {
+    text_state_requested_ = true;
+  }
+
+  TextEdits edits() { return edits_; }
+  bool text_state_requested() { return text_state_requested_; }
+  bool clear_focus_called() { return clear_focus_called_; }
+
+  void Reset() {
+    edits_.clear();
+    text_state_requested_ = false;
+    clear_focus_called_ = false;
+  }
+
+ private:
+  TextEdits edits_;
+  bool text_state_requested_ = false;
+  bool clear_focus_called_ = false;
+
+  DISALLOW_COPY_AND_ASSIGN(TestContentInputForwarder);
+};
+
 class ContentElementSceneTest : public UiTest {
  public:
   void SetUp() override {
@@ -64,6 +97,10 @@
     text_input_delegate_ =
         std::make_unique<StrictMock<MockTextInputDelegate>>();
 
+    input_forwarder_ = std::make_unique<TestContentInputForwarder>();
+    ui_->GetContentInputDelegateForTest()->SetContentInputForwarderForTest(
+        input_forwarder_.get());
+
     auto* content =
         static_cast<ContentElement*>(scene_->GetUiElementByName(kContentQuad));
     content->SetTextInputDelegate(text_input_delegate_.get());
@@ -72,6 +109,7 @@
 
  protected:
   std::unique_ptr<StrictMock<MockTextInputDelegate>> text_input_delegate_;
+  std::unique_ptr<TestContentInputForwarder> input_forwarder_;
   testing::Sequence in_sequence_;
 };
 
@@ -120,37 +158,16 @@
   EXPECT_CALL(*kb_delegate, SetTransform(_)).InSequence(in_sequence_);
   ui_->ShowSoftInput(false);
   EXPECT_TRUE(OnBeginFrame());
+
+  // Taking focus away from content should clear the delegate state.
+  EXPECT_CALL(*kb_delegate, OnBeginFrame()).InSequence(in_sequence_);
+  EXPECT_CALL(*kb_delegate, SetTransform(_)).InSequence(in_sequence_);
+  EXPECT_FALSE(input_forwarder_->clear_focus_called());
+  content->OnFocusChanged(false);
+  EXPECT_TRUE(input_forwarder_->clear_focus_called());
+  EXPECT_TRUE(OnBeginFrame());
 }
 
-class TestContentInputForwarder : public ContentInputForwarder {
- public:
-  TestContentInputForwarder() {}
-  ~TestContentInputForwarder() override {}
-
-  void ForwardEvent(std::unique_ptr<blink::WebInputEvent>, int) override {}
-  void ForwardDialogEvent(std::unique_ptr<blink::WebInputEvent>) override {}
-
-  void OnWebInputEdited(const TextEdits& edits) override { edits_ = edits; }
-  void SubmitWebInput() override {}
-  void RequestWebInputText(TextStateUpdateCallback) override {
-    text_state_requested_ = true;
-  }
-
-  TextEdits edits() { return edits_; }
-  bool text_state_requested() { return text_state_requested_; }
-
-  void Reset() {
-    edits_.clear();
-    text_state_requested_ = false;
-  }
-
- private:
-  TextEdits edits_;
-  bool text_state_requested_ = false;
-
-  DISALLOW_COPY_AND_ASSIGN(TestContentInputForwarder);
-};
-
 class ContentElementInputEditingTest : public UiTest {
  public:
   void SetUp() override {
diff --git a/chrome/browser/vr/elements/shadow.cc b/chrome/browser/vr/elements/shadow.cc
index c9f25162..20232f4 100644
--- a/chrome/browser/vr/elements/shadow.cc
+++ b/chrome/browser/vr/elements/shadow.cc
@@ -115,7 +115,7 @@
 // This value adjust how the shadow translates due to depth changes. Increasing
 // this number effectively makes the faked light sounce appear higher (the
 // shadow descends more quickly).
-static constexpr float kYShadowOffset = 0.06f;
+static constexpr float kYShadowOffset = 0.03f;
 
 }  // namespace
 
diff --git a/chrome/browser/vr/model/model.h b/chrome/browser/vr/model/model.h
index 6f33dd3..45733d6 100644
--- a/chrome/browser/vr/model/model.h
+++ b/chrome/browser/vr/model/model.h
@@ -45,8 +45,7 @@
   UiElementRenderer::TextureLocation content_overlay_location =
       UiElementRenderer::kTextureLocationLocal;
   bool update_ready_snackbar_enabled = false;
-  bool waiting_for_background = true;
-  bool can_apply_new_background = false;
+  bool waiting_for_background = false;
   bool background_loaded = false;
   bool supports_selection = true;
   bool needs_keyboard_update = false;
diff --git a/chrome/browser/vr/model/text_input_info.cc b/chrome/browser/vr/model/text_input_info.cc
index c7383fb..7f0354fa 100644
--- a/chrome/browser/vr/model/text_input_info.cc
+++ b/chrome/browser/vr/model/text_input_info.cc
@@ -143,7 +143,13 @@
                          previous.CommittedTextBeforeCursor());
   bool had_composition =
       previous.CompositionSize() > 0 && current.CompositionSize() == 0;
-  if (had_composition) {
+  // If the composition changes while there was a composition previously, we
+  // first finish the previous composition by clearing then commiting it, then
+  // we set the new composition.
+  bool new_composition =
+      previous.composition_start != current.composition_start &&
+      previous.CompositionSize() > 0;
+  if (had_composition || new_composition) {
     edits.push_back(TextEditAction(TextEditActionType::CLEAR_COMPOSING_TEXT));
   }
 
@@ -151,7 +157,9 @@
   // We only want to delete text if the was no selection previously. In the case
   // where there was a selection, its the editor's responsibility to ensure that
   // the selected text gets modified when a new edit occurs.
-  if (previous.SelectionSize() == 0) {
+  bool had_selection =
+      previous.SelectionSize() > 0 && current.SelectionSize() == 0;
+  if (!had_selection) {
     to_delete =
         previous.CommittedTextBeforeCursor().size() - common_prefix_length;
     if (to_delete > 0) {
@@ -163,7 +171,7 @@
 
   int to_commit =
       current.CommittedTextBeforeCursor().size() - common_prefix_length;
-  if (to_commit > 0) {
+  if (to_commit > 0 || had_selection) {
     DCHECK(to_delete == 0);
     edits.push_back(TextEditAction(TextEditActionType::COMMIT_TEXT,
                                    current.CommittedTextBeforeCursor().substr(
@@ -171,10 +179,10 @@
                                    to_commit));
   }
   if (current.CompositionSize() > 0) {
-    DCHECK(to_commit <= 0);
-    int cursor = previous.CompositionSize() > 0
-                     ? current.CompositionSize() - previous.CompositionSize()
-                     : current.CompositionSize();
+    int cursor = current.CompositionSize();
+    if (!new_composition) {
+      cursor = current.CompositionSize() - previous.CompositionSize();
+    }
     edits.push_back(TextEditAction(TextEditActionType::SET_COMPOSING_TEXT,
                                    current.ComposingText(), cursor));
   }
diff --git a/chrome/browser/vr/model/text_input_info_unittest.cc b/chrome/browser/vr/model/text_input_info_unittest.cc
index 47162c1..d1222fa 100644
--- a/chrome/browser/vr/model/text_input_info_unittest.cc
+++ b/chrome/browser/vr/model/text_input_info_unittest.cc
@@ -92,6 +92,12 @@
   EXPECT_EQ(edits.size(), 1u);
   EXPECT_EQ(edits[0], TextEditAction(TextEditActionType::COMMIT_TEXT,
                                      base::UTF8ToUTF16("ha"), 2));
+
+  // There was a selection and backspace was pressed.
+  edits = EditedText(Text(" text", 0, 0), Text("short text", 0, 5)).GetDiff();
+  EXPECT_EQ(edits.size(), 1u);
+  EXPECT_EQ(edits[0], TextEditAction(TextEditActionType::COMMIT_TEXT,
+                                     base::UTF8ToUTF16(""), 0));
 }
 
 TEST_F(TextInputInfoTest, CompositionDiff) {
@@ -142,6 +148,32 @@
   EXPECT_EQ(edits[0], TextEditAction(TextEditActionType::CLEAR_COMPOSING_TEXT));
   EXPECT_EQ(edits[1], TextEditAction(TextEditActionType::COMMIT_TEXT,
                                      base::UTF8ToUTF16("hi"), 2));
+
+  // A new composition without finishing the previous composition. This could
+  // happen when we get coalesced events from the keyboard. For example, when
+  // the user presses the spacebar and a key right after while there is already
+  // an ongoing composition, the keyboard may give us a new composition without
+  // finishing the previous composition.
+  edits =
+      EditedText(Text("hii hello", 3, 3, 2, 3), Text("hi hello", 2, 2, 0, 2))
+          .GetDiff();
+  EXPECT_EQ(edits.size(), 3u);
+  EXPECT_EQ(edits[0], TextEditAction(TextEditActionType::CLEAR_COMPOSING_TEXT));
+  EXPECT_EQ(edits[1], TextEditAction(TextEditActionType::COMMIT_TEXT,
+                                     base::UTF8ToUTF16("hi"), 2));
+  EXPECT_EQ(edits[2], TextEditAction(TextEditActionType::SET_COMPOSING_TEXT,
+                                     base::UTF8ToUTF16("i"), 1));
+  // Same as above, but the new composition happens by deleting the current
+  // composition.
+  edits =
+      EditedText(Text("hi hello", 2, 2, 0, 2), Text("hii hello", 3, 3, 2, 3))
+          .GetDiff();
+  EXPECT_EQ(edits.size(), 3u);
+  EXPECT_EQ(edits[0], TextEditAction(TextEditActionType::CLEAR_COMPOSING_TEXT));
+  EXPECT_EQ(edits[1], TextEditAction(TextEditActionType::DELETE_TEXT,
+                                     base::UTF8ToUTF16(""), -2));
+  EXPECT_EQ(edits[2], TextEditAction(TextEditActionType::SET_COMPOSING_TEXT,
+                                     base::UTF8ToUTF16("hi"), 2));
 }
 
 }  // namespace vr
diff --git a/chrome/browser/vr/test/mock_browser_ui_interface.h b/chrome/browser/vr/test/mock_browser_ui_interface.h
index 120a7d7..f440ca75 100644
--- a/chrome/browser/vr/test/mock_browser_ui_interface.h
+++ b/chrome/browser/vr/test/mock_browser_ui_interface.h
@@ -38,7 +38,6 @@
   MOCK_METHOD1(SetRecognitionResult, void(const base::string16& result));
   MOCK_METHOD1(OnSpeechRecognitionStateChanged, void(int new_state));
   void SetOmniboxSuggestions(std::unique_ptr<OmniboxSuggestions> suggestions) {}
-  MOCK_METHOD0(OnAssetsComponentReady, void());
   void OnAssetsLoaded(AssetsLoadStatus status,
                       std::unique_ptr<Assets> assets,
                       const base::Version& component_version) {}
diff --git a/chrome/browser/vr/testapp/vr_test_context.cc b/chrome/browser/vr/testapp/vr_test_context.cc
index 59b908f2..1a9e124 100644
--- a/chrome/browser/vr/testapp/vr_test_context.cc
+++ b/chrome/browser/vr/testapp/vr_test_context.cc
@@ -195,9 +195,6 @@
         CycleOrigin();
         model_->can_navigate_back = !model_->can_navigate_back;
         break;
-      case ui::DomCode::US_C:
-        model_->can_apply_new_background = true;
-        break;
       case ui::DomCode::US_P:
         model_->toggle_mode(kModeRepositionWindow);
         break;
@@ -581,22 +578,6 @@
   state = (state + 1) % states.size();
 }
 
-void VrTestContext::LoadAssets() {
-  base::Version assets_component_version(VR_ASSETS_COMPONENT_VERSION);
-  auto assets = std::make_unique<Assets>();
-  if (!(LoadPng(IDR_VR_BACKGROUND_IMAGE, &assets->background) &&
-        LoadPng(IDR_VR_NORMAL_GRADIENT_IMAGE, &assets->normal_gradient) &&
-        LoadPng(IDR_VR_INCOGNITO_GRADIENT_IMAGE, &assets->incognito_gradient) &&
-        LoadPng(IDR_VR_FULLSCREEN_GRADIENT_IMAGE,
-                &assets->fullscreen_gradient))) {
-    ui_->OnAssetsLoaded(AssetsLoadStatus::kInvalidContent, nullptr,
-                        assets_component_version);
-    return;
-  }
-  ui_->OnAssetsLoaded(AssetsLoadStatus::kSuccess, std::move(assets),
-                      assets_component_version);
-}
-
 RenderInfo VrTestContext::GetRenderInfo() const {
   RenderInfo render_info;
   render_info.head_pose = head_pose_;
@@ -617,4 +598,20 @@
   return origin;
 }
 
+void VrTestContext::LoadAssets() {
+  base::Version assets_component_version(VR_ASSETS_COMPONENT_VERSION);
+  auto assets = std::make_unique<Assets>();
+  if (!(LoadPng(IDR_VR_BACKGROUND_IMAGE, &assets->background) &&
+        LoadPng(IDR_VR_NORMAL_GRADIENT_IMAGE, &assets->normal_gradient) &&
+        LoadPng(IDR_VR_INCOGNITO_GRADIENT_IMAGE, &assets->incognito_gradient) &&
+        LoadPng(IDR_VR_FULLSCREEN_GRADIENT_IMAGE,
+                &assets->fullscreen_gradient))) {
+    ui_->OnAssetsLoaded(AssetsLoadStatus::kInvalidContent, nullptr,
+                        assets_component_version);
+    return;
+  }
+  ui_->OnAssetsLoaded(AssetsLoadStatus::kSuccess, std::move(assets),
+                      assets_component_version);
+}
+
 }  // namespace vr
diff --git a/chrome/browser/vr/testapp/vr_test_context.h b/chrome/browser/vr/testapp/vr_test_context.h
index bbee184..5ee4ae5a 100644
--- a/chrome/browser/vr/testapp/vr_test_context.h
+++ b/chrome/browser/vr/testapp/vr_test_context.h
@@ -54,7 +54,6 @@
   void StartAutocomplete(const AutocompleteRequest& request) override;
   void StopAutocomplete() override;
   void Navigate(GURL gurl) override;
-  void LoadAssets() override;
 
   void set_window_size(const gfx::Size& size) { window_size_ = size; }
 
@@ -69,6 +68,7 @@
   gfx::Transform ViewProjectionMatrix() const;
   ControllerModel UpdateController(const RenderInfo& render_info);
   gfx::Point3F LaserOrigin() const;
+  void LoadAssets();
 
   std::unique_ptr<Ui> ui_;
   gfx::Size window_size_;
diff --git a/chrome/browser/vr/ui.cc b/chrome/browser/vr/ui.cc
index 4e27170..ea703bf 100644
--- a/chrome/browser/vr/ui.cc
+++ b/chrome/browser/vr/ui.cc
@@ -201,10 +201,6 @@
   model_->omnibox_suggestions = suggestions->suggestions;
 }
 
-void Ui::OnAssetsComponentReady() {
-  model_->can_apply_new_background = true;
-}
-
 bool Ui::CanSendWebVrVSync() {
   return model_->web_vr_enabled() &&
          !model_->web_vr.awaiting_min_splash_screen_duration();
@@ -294,21 +290,21 @@
 }
 
 void Ui::OnAppButtonClicked() {
-  // App button clicks should be a no-op when auto-presenting WebVR.
-  if (model_->web_vr_autopresentation_enabled()) {
+  // App button clicks should be a no-op when auto-presenting WebVR or if
+  // browsing mode is disabled.
+  if (model_->web_vr_autopresentation_enabled() || model_->browsing_disabled)
     return;
-  }
-
-  // If browsing mode is disabled, the app button should no-op.
-  if (model_->browsing_disabled) {
-    return;
-  }
 
   if (model_->reposition_window_enabled()) {
     model_->pop_mode(kModeRepositionWindow);
     return;
   }
 
+  if (model_->editing_web_input) {
+    ShowSoftInput(false);
+    return;
+  }
+
   // App button click exits the WebVR presentation and fullscreen.
   browser_->ExitPresent();
   browser_->ExitFullscreen();
@@ -389,10 +385,6 @@
 #endif
 }
 
-void Ui::OnAssetsLoading() {
-  model_->can_apply_new_background = false;
-}
-
 void Ui::OnAssetsLoaded(AssetsLoadStatus status,
                         std::unique_ptr<Assets> assets,
                         const base::Version& component_version) {
@@ -444,7 +436,7 @@
   model_->browsing_disabled = ui_initial_state.browsing_disabled;
   model_->skips_redraw_when_not_dirty =
       ui_initial_state.skips_redraw_when_not_dirty;
-  model_->waiting_for_background = ui_initial_state.assets_available;
+  model_->waiting_for_background = ui_initial_state.assets_supported;
   model_->supports_selection = ui_initial_state.supports_selection;
   model_->needs_keyboard_update = ui_initial_state.needs_keyboard_update;
 }
diff --git a/chrome/browser/vr/ui.h b/chrome/browser/vr/ui.h
index 41ab75fc..ee25e69 100644
--- a/chrome/browser/vr/ui.h
+++ b/chrome/browser/vr/ui.h
@@ -40,8 +40,7 @@
   bool browsing_disabled = false;
   bool has_or_can_request_audio_permission = true;
   bool skips_redraw_when_not_dirty = false;
-  // TODO(tiborg): Remove this flag.
-  bool assets_available = false;
+  bool assets_supported = false;
   bool supports_selection = true;
   bool needs_keyboard_update = false;
 };
@@ -94,13 +93,11 @@
   void OnSpeechRecognitionStateChanged(int new_state) override;
   void SetOmniboxSuggestions(
       std::unique_ptr<OmniboxSuggestions> suggestions) override;
-  void OnAssetsComponentReady() override;
   void OnAssetsLoaded(AssetsLoadStatus status,
                       std::unique_ptr<Assets> assets,
                       const base::Version& component_version) override;
   void OnAssetsUnavailable() override;
 
-  void OnAssetsLoading();
   // TODO(ymalik): We expose this to stop sending VSync to the WebVR page until
   // the splash screen has been visible for its minimum duration. The visibility
   // logic currently lives in the UI, and it'd be much cleaner if the UI didn't
diff --git a/chrome/browser/vr/ui_browser_interface.h b/chrome/browser/vr/ui_browser_interface.h
index 990cfb1..ad0ec29 100644
--- a/chrome/browser/vr/ui_browser_interface.h
+++ b/chrome/browser/vr/ui_browser_interface.h
@@ -32,7 +32,6 @@
   virtual void SetVoiceSearchActive(bool active) = 0;
   virtual void StartAutocomplete(const AutocompleteRequest& request) = 0;
   virtual void StopAutocomplete() = 0;
-  virtual void LoadAssets() = 0;
 };
 
 }  // namespace vr
diff --git a/chrome/browser/vr/ui_element_renderer.cc b/chrome/browser/vr/ui_element_renderer.cc
index e03af1e..fbb98d7e 100644
--- a/chrome/browser/vr/ui_element_renderer.cc
+++ b/chrome/browser/vr/ui_element_renderer.cc
@@ -9,6 +9,7 @@
 #include <string>
 
 #include "base/macros.h"
+#include "base/trace_event/trace_event.h"
 #include "chrome/browser/vr/renderers/base_quad_renderer.h"
 #include "chrome/browser/vr/renderers/base_renderer.h"
 #include "chrome/browser/vr/renderers/external_textured_quad_renderer.h"
@@ -58,6 +59,7 @@
     float opacity,
     const gfx::SizeF& element_size,
     float corner_radius) {
+  TRACE_EVENT0("gpu", "UiElementRenderer::DrawTexturedQuad");
   // TODO(vollick): handle drawing this degenerate situation crbug.com/768922
   if (corner_radius * 2.0 > element_size.width() ||
       corner_radius * 2.0 > element_size.height()) {
@@ -78,6 +80,7 @@
     float opacity,
     const gfx::SizeF& element_size,
     const CornerRadii& radii) {
+  TRACE_EVENT0("gpu", "UiElementRenderer::DrawGradientQuad");
   FlushIfNecessary(gradient_quad_renderer_.get());
   gradient_quad_renderer_->Draw(model_view_proj_matrix, edge_color,
                                 center_color, opacity, element_size, radii);
@@ -90,6 +93,7 @@
     const SkColor grid_color,
     int gridline_count,
     float opacity) {
+  TRACE_EVENT0("gpu", "UiElementRenderer::DrawGradientGridQuad");
   FlushIfNecessary(gradient_grid_renderer_.get());
   gradient_grid_renderer_->Draw(model_view_proj_matrix, edge_color,
                                 center_color, grid_color, gridline_count,
@@ -99,6 +103,7 @@
 void UiElementRenderer::DrawController(
     float opacity,
     const gfx::Transform& model_view_proj_matrix) {
+  TRACE_EVENT0("gpu", "UiElementRenderer::DrawController");
   FlushIfNecessary(controller_renderer_.get());
   controller_renderer_->Draw(opacity, model_view_proj_matrix);
 }
@@ -106,6 +111,7 @@
 void UiElementRenderer::DrawLaser(
     float opacity,
     const gfx::Transform& model_view_proj_matrix) {
+  TRACE_EVENT0("gpu", "UiElementRenderer::DrawLaser");
   FlushIfNecessary(laser_renderer_.get());
   laser_renderer_->Draw(opacity, model_view_proj_matrix);
 }
@@ -113,6 +119,7 @@
 void UiElementRenderer::DrawReticle(
     float opacity,
     const gfx::Transform& model_view_proj_matrix) {
+  TRACE_EVENT0("gpu", "UiElementRenderer::DrawReticle");
   FlushIfNecessary(reticle_renderer_.get());
   reticle_renderer_->Draw(opacity, model_view_proj_matrix);
 }
@@ -130,6 +137,7 @@
                                    SkColor color,
                                    float opacity,
                                    float corner_radius) {
+  TRACE_EVENT0("gpu", "UiElementRenderer::DrawShadow");
   FlushIfNecessary(shadow_renderer_.get());
   shadow_renderer_->Draw(model_view_proj_matrix, element_size, x_padding,
                          y_padding, y_offset, color, opacity, corner_radius);
@@ -138,6 +146,7 @@
 void UiElementRenderer::DrawStars(
     float t,
     const gfx::Transform& model_view_proj_matrix) {
+  TRACE_EVENT0("gpu", "UiElementRenderer::DrawStars");
   FlushIfNecessary(stars_renderer_.get());
   stars_renderer_->Draw(t, model_view_proj_matrix);
 }
@@ -151,6 +160,7 @@
     float normal_factor,
     float incognito_factor,
     float fullscreen_factor) {
+  TRACE_EVENT0("gpu", "UiElementRenderer::DrawBackground");
   FlushIfNecessary(background_renderer_.get());
   background_renderer_->Draw(model_view_proj_matrix, texture_data_handle,
                              normal_gradient_texture_data_handle,
@@ -162,6 +172,7 @@
 
 void UiElementRenderer::DrawKeyboard(const CameraModel& camera_model,
                                      KeyboardDelegate* delegate) {
+  TRACE_EVENT0("gpu", "UiElementRenderer::DrawKeyboard");
   FlushIfNecessary(keyboard_renderer_.get());
   keyboard_renderer_->Draw(camera_model, delegate);
 }
diff --git a/chrome/browser/vr/ui_scene_constants.h b/chrome/browser/vr/ui_scene_constants.h
index 1effdbec..a38e736f 100644
--- a/chrome/browser/vr/ui_scene_constants.h
+++ b/chrome/browser/vr/ui_scene_constants.h
@@ -34,7 +34,7 @@
     kContentVerticalOffsetDMM * kContentDistance;
 static constexpr float kContentCornerRadius = 0.005f * kContentWidth;
 static constexpr float kContentShadowOffset = 0.09f;
-static constexpr float kContentShadowIntesity = 0.3f;
+static constexpr float kContentShadowIntesity = 0.4f;
 static constexpr float kBackplaneSize = 1000.0f;
 static constexpr float kBackgroundDistanceMultiplier = 1.414f;
 
@@ -209,7 +209,7 @@
 static constexpr float kOmniboxCloseButtonVerticalOffsetDMM = -0.75f;
 static constexpr float kOmniboxCornerRadiusDMM = 0.006f;
 static constexpr float kOmniboxCloseButtonDepthOffset = -0.35f;
-static constexpr float kOmniboxShadowOffset = 0.015f;
+static constexpr float kOmniboxShadowOffset = 0.07f;
 static constexpr float kOmniboxShadowIntensity = 0.4f;
 static constexpr int kOmniboxTransitionMs = 300;
 
diff --git a/chrome/browser/vr/ui_scene_creator.cc b/chrome/browser/vr/ui_scene_creator.cc
index 6623271..52d6e09 100644
--- a/chrome/browser/vr/ui_scene_creator.cc
+++ b/chrome/browser/vr/ui_scene_creator.cc
@@ -906,6 +906,7 @@
   auto shadow = Create<Shadow>(kContentQuadShadow, kPhaseForeground);
   shadow->set_intensity(kContentShadowIntesity);
   shadow->SetTranslate(0, 0, -kContentShadowOffset);
+  shadow->set_corner_radius(kContentCornerRadius);
 
   auto main_content = std::make_unique<ContentElement>(
       content_input_delegate_,
@@ -917,7 +918,6 @@
         if (focused) {
           e->UpdateInput(model->web_input_text_field_info);
         } else {
-          model->editing_web_input = false;
           e->UpdateInput(EditedText());
         }
       },
@@ -1508,7 +1508,7 @@
       float, Model, model_,
       model->reposition_window_enabled() ? kRepositionContentOpacity : 1.0f,
       UiElement, content_toggle.get(), SetOpacity));
-  scene_->AddParentUiElement(kContentQuad, std::move(content_toggle));
+  scene_->AddParentUiElement(kContentQuadShadow, std::move(content_toggle));
 
   auto hit_plane =
       Create<InvisibleHitTarget>(kContentRepositionHitPlane, kPhaseForeground);
@@ -1803,21 +1803,7 @@
       kDownloadedSnackbar, model_, kFileDownloadDoneIcon,
       l10n_util::GetStringUTF16(IDS_VR_COMPONENT_UPDATE_READY),
       base::i18n::ToUpper(l10n_util::GetStringUTF16(IDS_VR_COMPONENT_APPLY)),
-      base::BindRepeating(
-          [](UiBrowserInterface* browser, Ui* ui) {
-            ui->OnAssetsLoading();
-            browser->LoadAssets();
-          },
-          base::Unretained(browser_), base::Unretained(ui_)));
-  snackbar->AddBinding(std::make_unique<Binding<bool>>(
-      VR_BIND_LAMBDA([](Model* m) { return m->can_apply_new_background; },
-                     base::Unretained(model_)),
-      VR_BIND_LAMBDA(
-          [](UiElement* s, const bool& value) {
-            s->SetVisible(value);
-            s->SetRotate(1, 0, 0, value ? 0 : kSnackbarMoveInAngle);
-          },
-          base::Unretained(snackbar.get()))));
+      base::DoNothing());
   snackbar->SetVisible(false);
   snackbar->SetRotate(1, 0, 0, kSnackbarMoveInAngle);
   snackbar->SetTransitionedProperties({OPACITY, TRANSFORM});
diff --git a/chrome/browser/vr/ui_unittest.cc b/chrome/browser/vr/ui_unittest.cc
index da1ded3..a3b91be2 100644
--- a/chrome/browser/vr/ui_unittest.cc
+++ b/chrome/browser/vr/ui_unittest.cc
@@ -556,6 +556,18 @@
   EXPECT_TRUE(scene_->GetUiElementByName(kUpdateKeyboardPrompt)->IsVisible());
 }
 
+TEST_F(UiTest, ExitWebInputEditingOnAppButtonClick) {
+  CreateScene(kNotInCct, kNotInWebVr);
+  EXPECT_FALSE(scene_->GetUiElementByName(kKeyboard)->IsVisible());
+  ui_->ShowSoftInput(true);
+  OnBeginFrame();
+  EXPECT_TRUE(scene_->GetUiElementByName(kKeyboard)->IsVisible());
+  ui_->OnAppButtonClicked();
+  OnBeginFrame();
+  // Clicking app button should hide the keyboard.
+  EXPECT_FALSE(scene_->GetUiElementByName(kKeyboard)->IsVisible());
+}
+
 TEST_F(UiTest, UiUpdatesForShowingExitPrompt) {
   CreateScene(kNotInCct, kNotInWebVr);
 
@@ -1091,7 +1103,7 @@
 
 TEST_F(UiTest, DefaultBackgroundWhenNoAssetAvailable) {
   UiInitialState state;
-  state.assets_available = false;
+  state.assets_supported = false;
   CreateScene(state);
 
   EXPECT_FALSE(IsVisible(k2dBrowsingTexturedBackground));
@@ -1101,7 +1113,7 @@
 
 TEST_F(UiTest, TextureBackgroundAfterAssetLoaded) {
   UiInitialState state;
-  state.assets_available = true;
+  state.assets_supported = true;
   CreateScene(state);
 
   EXPECT_FALSE(IsVisible(k2dBrowsingTexturedBackground));
diff --git a/chrome/browser/vr/vr_gl_util.cc b/chrome/browser/vr/vr_gl_util.cc
index 9096f26..67586cc 100644
--- a/chrome/browser/vr/vr_gl_util.cc
+++ b/chrome/browser/vr/vr_gl_util.cc
@@ -51,6 +51,8 @@
       glDeleteShader(shader_handle);
       shader_handle = 0;
     }
+  } else {
+    error = "Could not create a shader handle (did not attempt compilation).";
   }
 
   return shader_handle;
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index b204e28f..2a3abe3 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -37,13 +37,6 @@
 const base::Feature kFullscreenToolbarReveal{"FullscreenToolbarReveal",
                                              base::FEATURE_ENABLED_BY_DEFAULT};
 
-#if BUILDFLAG(MAC_VIEWS_BROWSER)
-// Causes Views browser builds to use Views browser windows by default rather
-// than Cocoa browser windows.
-const base::Feature kViewsBrowserWindows{"ViewsBrowserWindows",
-                                         base::FEATURE_DISABLED_BY_DEFAULT};
-#endif
-
 // Use toolkit-views for profile chooser menu.
 const base::Feature kViewsProfileChooser{"ViewsProfileChooser",
                                          base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h
index 8080b07..f9646bc 100644
--- a/chrome/common/chrome_features.h
+++ b/chrome/common/chrome_features.h
@@ -32,9 +32,6 @@
 #if defined(OS_MACOSX)
 extern const base::Feature kAppleScriptExecuteJavaScriptMenuItem;
 extern const base::Feature kShow10_9ObsoleteInfobar;
-#if BUILDFLAG(MAC_VIEWS_BROWSER)
-extern const base::Feature kViewsBrowserWindows;
-#endif
 extern const base::Feature kViewsProfileChooser;
 extern const base::Feature kViewsTaskManager;
 #endif  // defined(OS_MACOSX)
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 40c9ea1c..20af8e3b 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -347,12 +347,12 @@
     ":test_support",
     "//base",
     "//chrome/browser/profiling_host:profiling_browsertests",
-    "//components/grpc_support/test:quic_test_server",
     "//components/nacl/common:buildflags",
     "//components/spellcheck:buildflags",
     "//components/sync:test_support_model",
     "//extensions/features",
     "//media:media_features",
+    "//net:test_support",
     "//ppapi/features",
     "//printing/features",
     "//rlz/features",
@@ -422,7 +422,6 @@
     deps += [
       "//chrome/android:app_hooks_java",
       "//chrome/android:chrome_java",
-      "//chrome/android:class_register_java",
       "//v8:v8_external_startup_data_assets",
     ]
 
@@ -931,7 +930,7 @@
       "//components/strings",
       "//components/sync",
       "//components/translate/core/common",
-      "//content/public/common:features",
+      "//content/public/common:buildflags",
       "//content/test:test_support",
       "//crypto:platform",
       "//crypto:test_support",
@@ -2807,7 +2806,6 @@
       "//base:base_java",
       "//chrome/android:app_hooks_java",
       "//chrome/android:chrome_java",
-      "//chrome/android:class_register_java",
       "//components/gcm_driver/instance_id/android:instance_id_driver_java",
       "//components/gcm_driver/instance_id/android:instance_id_driver_test_support_java",
       "//content/public/android:content_java",
diff --git a/chrome/test/chromedriver/test/test_expectations b/chrome/test/chromedriver/test/test_expectations
index 6f1c719..f863f3a5 100644
--- a/chrome/test/chromedriver/test/test_expectations
+++ b/chrome/test/chromedriver/test/test_expectations
@@ -293,6 +293,7 @@
         'ElementAttributeTest.testCanRetrieveTheCurrentValueOfATextFormField_emailInput',
         'ElementAttributeTest.testShouldReturnTrueForPresentBooleanAttributes',
         'ElementAttributeTest.testShouldReturnValueOfOnClickAttribute',
+        'ElementAttributeTest.testCanRetrieveTheCurrentValueOfATextFormField_textInput',
         'JavascriptEnabledDriverTest.testShouldBeAbleToFindElementAfterJavascriptCausesANewPageToLoad',
         'JavascriptEnabledDriverTest.testShouldBeAbleToSwitchToFocusedElement',
         'JavascriptEnabledDriverTest.testShouldBeAbleToDetermineTheLocationOfAnElement',
diff --git a/chrome/test/data/extensions/api_test/mime_handler_view/index.js b/chrome/test/data/extensions/api_test/mime_handler_view/index.js
index 747554a3..6eaac5a 100644
--- a/chrome/test/data/extensions/api_test/mime_handler_view/index.js
+++ b/chrome/test/data/extensions/api_test/mime_handler_view/index.js
@@ -38,12 +38,10 @@
 }
 
 function expectSuccessfulRead(response) {
-  chrome.test.assertEq(200, response.status);
   chrome.test.assertEq('content to read\n', response.data);
 }
 
 function expectSuccessfulReadLong(response) {
-  chrome.test.assertEq(200, response.status);
   chrome.test.assertTrue(response.data.startsWith('content to read\n'));
 }
 
diff --git a/chrome/test/data/password/recurring_dynamic_form.html b/chrome/test/data/password/recurring_dynamic_form.html
new file mode 100644
index 0000000..935c2f0
--- /dev/null
+++ b/chrome/test/data/password/recurring_dynamic_form.html
@@ -0,0 +1,31 @@
+<html>
+<script>
+
+function addForm() {
+  var dynamicForm = document.createElement('form');
+  dynamicForm.setAttribute('method', 'post');
+  dynamicForm.setAttribute('action', 'done.html');
+  dynamicForm.setAttribute('onsubmit', 'return true;');
+
+  var inputUsername = document.createElement('input');
+  inputUsername.setAttribute('type', 'text');
+
+  var inputPassword = document.createElement('input');
+  inputPassword.setAttribute('type', 'password');
+
+  var submitButton = document.createElement('input');
+  submitButton.setAttribute('type', 'submit');
+  submitButton.setAttribute('value', 'Submit');
+
+  dynamicForm.appendChild(inputUsername);
+  dynamicForm.appendChild(inputPassword);
+  dynamicForm.appendChild(submitButton);
+
+  document.body.appendChild(dynamicForm);
+}
+
+</script>
+
+<body>
+</body>
+</html>
diff --git a/chrome/test/data/webrtc/peerconnection_getstats.js b/chrome/test/data/webrtc/peerconnection_getstats.js
index e63909bb..ac43e9a 100644
--- a/chrome/test/data/webrtc/peerconnection_getstats.js
+++ b/chrome/test/data/webrtc/peerconnection_getstats.js
@@ -129,6 +129,7 @@
   framesPerSecond: 'number',
   framesCaptured: 'number',
   framesSent: 'number',
+  hugeFramesSent: 'number',
   framesReceived: 'number',
   framesDecoded: 'number',
   framesDropped: 'number',
diff --git a/chromecast/base/BUILD.gn b/chromecast/base/BUILD.gn
index 6c37621..7a1f923 100644
--- a/chromecast/base/BUILD.gn
+++ b/chromecast/base/BUILD.gn
@@ -279,6 +279,8 @@
   android_library("base_java") {
     java_src_dir = "//chromecast/base/java/src"
     java_files = [
+      "$java_src_dir/org/chromium/chromecast/base/BiConsumer.java",
+      "$java_src_dir/org/chromium/chromecast/base/BiFunction.java",
       "$java_src_dir/org/chromium/chromecast/base/Both.java",
       "$java_src_dir/org/chromium/chromecast/base/CircularBuffer.java",
       "$java_src_dir/org/chromium/chromecast/base/Controller.java",
@@ -286,7 +288,6 @@
       "$java_src_dir/org/chromium/chromecast/base/Function.java",
       "$java_src_dir/org/chromium/chromecast/base/Itertools.java",
       "$java_src_dir/org/chromium/chromecast/base/Observable.java",
-      "$java_src_dir/org/chromium/chromecast/base/ReactiveUtils.java",
       "$java_src_dir/org/chromium/chromecast/base/ScopeFactories.java",
       "$java_src_dir/org/chromium/chromecast/base/ScopeFactory.java",
       "$java_src_dir/org/chromium/chromecast/base/Unit.java",
@@ -312,7 +313,6 @@
       "$java_test_dir/org/chromium/chromecast/base/CircularBufferTest.java",
       "$java_test_dir/org/chromium/chromecast/base/ItertoolsTest.java",
       "$java_test_dir/org/chromium/chromecast/base/ObservableAndControllerTest.java",
-      "$java_test_dir/org/chromium/chromecast/base/ReactiveUtilsTest.java",
       "$java_test_dir/org/chromium/chromecast/base/ScopeFactoriesTest.java",
       "$java_test_dir/org/chromium/chromecast/base/TestUtils.java",
       "$java_test_dir/org/chromium/chromecast/base/UnitTest.java",
diff --git a/chromecast/base/java/src/org/chromium/chromecast/base/BiConsumer.java b/chromecast/base/java/src/org/chromium/chromecast/base/BiConsumer.java
new file mode 100644
index 0000000..06bd183
--- /dev/null
+++ b/chromecast/base/java/src/org/chromium/chromecast/base/BiConsumer.java
@@ -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.
+
+package org.chromium.chromecast.base;
+
+/**
+ * A function that takes two arguments and returns void.
+ *
+ * TODO(sanfin): replace with Java 8 library if we're ever able to use the Java 8 library.
+ *
+ * @param <A> The first argument type.
+ * @param <B> The second argument type.
+ */
+public interface BiConsumer<A, B> { public void accept(A first, B second); }
diff --git a/chromecast/base/java/src/org/chromium/chromecast/base/BiFunction.java b/chromecast/base/java/src/org/chromium/chromecast/base/BiFunction.java
new file mode 100644
index 0000000..62320157
--- /dev/null
+++ b/chromecast/base/java/src/org/chromium/chromecast/base/BiFunction.java
@@ -0,0 +1,16 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chromecast.base;
+
+/**
+ * A function that takes two arguments and returns a value.
+ *
+ * TODO(sanfin): replace with Java 8 library if we're ever able to use the Java 8 library.
+ *
+ * @param <A> The first argument type.
+ * @param <B> The second argument type.
+ * @param <R> The return type.
+ */
+public interface BiFunction<A, B, R> { public R apply(A first, B second); }
diff --git a/chromecast/base/java/src/org/chromium/chromecast/base/Both.java b/chromecast/base/java/src/org/chromium/chromecast/base/Both.java
index 174cb70..0ea3847 100644
--- a/chromecast/base/java/src/org/chromium/chromecast/base/Both.java
+++ b/chromecast/base/java/src/org/chromium/chromecast/base/Both.java
@@ -53,4 +53,18 @@
         assert b != null;
         return new Both<>(a, b);
     }
+
+    /**
+     * Turns a function of two arguments into a function of a single Both argument.
+     */
+    public static <A, B, R> Function<Both<A, B>, R> adapt(BiFunction<A, B, R> function) {
+        return (Both<A, B> data) -> function.apply(data.first, data.second);
+    }
+
+    /**
+     * Turns a consumer of two arguments into a consumer of a single Both argument.
+     */
+    public static <A, B> Consumer<Both<A, B>> adapt(BiConsumer<A, B> consumer) {
+        return (Both<A, B> data) -> consumer.accept(data.first, data.second);
+    }
 }
diff --git a/chromecast/base/java/src/org/chromium/chromecast/base/ReactiveUtils.java b/chromecast/base/java/src/org/chromium/chromecast/base/ReactiveUtils.java
deleted file mode 100644
index 4a9c64288..0000000
--- a/chromecast/base/java/src/org/chromium/chromecast/base/ReactiveUtils.java
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chromecast.base;
-
-/**
- * Helper functions for working with Observables.
- */
-public final class ReactiveUtils {
-    // Uninstantiable.
-    private ReactiveUtils() {}
-
-    /**
-     * Interface representing actions to perform when activating and deactivating a state whose type
-     * is a Both structure. The arguments to the create() function are the fields of the Both value.
-     *
-     * @param <A> The type of the first argument to create().
-     * @param <B> The type of the second argument to create().
-     */
-    public interface BothScopeFactory<A, B> { public AutoCloseable create(A first, B second); }
-
-    /**
-     * A helper to make reacting to combinations of two Observables more readable.
-     *
-     * This disassembles the Both value observed by the `.and()`-conjunction of Observables and
-     * injects the constituent fields in the BothScopeFactory's create() function.
-     *
-     * This allows you to rewrite this:
-     *
-     *     observableA.and(observableB).watch((Both<A, B> data) -> {
-     *         A a = data.first;
-     *         B b = data.second;
-     *         ...
-     *     });
-     *
-     * as this:
-     *
-     *     watchBoth(observableA.and(observableB), (A a, B b) -> ...);
-     *
-     * This is not as composable as chained `.and()` calls, which can be extended to an arbitrary
-     * number of parameters. But it is more readable for the case where you are observing two
-     * Observables.
-     *
-     * @param <A> The first type in the Both structure.
-     * @param <B> The second type in the Both structure.
-     */
-    public static <A, B> Observable<Both<A, B>> watchBoth(Observable<Both<A, B>> observable,
-            BothScopeFactory<? super A, ? super B> scopeFactory) {
-        return observable.watch((Both<A, B> data) -> scopeFactory.create(data.first, data.second));
-    }
-}
diff --git a/chromecast/base/java/src/org/chromium/chromecast/base/ScopeFactories.java b/chromecast/base/java/src/org/chromium/chromecast/base/ScopeFactories.java
index 24057e0..2f19dada 100644
--- a/chromecast/base/java/src/org/chromium/chromecast/base/ScopeFactories.java
+++ b/chromecast/base/java/src/org/chromium/chromecast/base/ScopeFactories.java
@@ -34,6 +34,30 @@
     }
 
     /**
+     * Shorthand for making a ScopeFactory that only has side effects on activation, and has a Both
+     * object for activation data.
+     *
+     * For example, one can refactor the following:
+     *
+     *     observableA.and(observableB).watch((Both<A, B> data) -> {
+     *         A a = data.first;
+     *         B b = data.second;
+     *         ... // side effects on activation
+     *         return () -> {}; // no side effects on deactivation.
+     *     });
+     *
+     * ... into this:
+     *
+     *    observableA.and(observableB).watch(ScopeFactories.onEnter((A a, B b) -> ...));
+     *
+     * @param <A> The first argument of the consumer (and the first item in the Both).
+     * @param <B> The second argument of the consumer (and the second item in the Both).
+     */
+    public static <A, B> ScopeFactory<Both<A, B>> onEnter(BiConsumer<A, B> consumer) {
+        return onEnter(Both.adapt(consumer));
+    }
+
+    /**
      * Shorthand for making a ScopeFactory that only has side effects on deactivation.
      *
      * @param <T> The type of the activation data.
@@ -51,4 +75,53 @@
     public static <T> ScopeFactory<T> onExit(Runnable runnable) {
         return onExit((T value) -> runnable.run());
     }
+
+    /**
+     * Shorthand for making a ScopeFactory that only has side effects on deactivation, and has a
+     * Both object for activation data.
+     *
+     * For example, one can refactor the following:
+     *
+     *     observableA.and(observableB).watch((Both<A, B> data) -> {
+     *         A a = data.first;
+     *         B b = data.second;
+     *         return () -> {
+     *             // side effects on deactivation.
+     *         };
+     *     });
+     *
+     * ... into this:
+     *
+     *    observableA.and(observableB).watch(ScopeFactories.onExit((A a, B b) -> ...));
+     *
+     * @param <A> The first argument of the consumer (and the first item in the Both).
+     * @param <B> The second argument of the consumer (and the second item in the Both).
+     */
+    public static <A, B> ScopeFactory<Both<A, B>> onExit(BiConsumer<A, B> consumer) {
+        return onExit(Both.adapt(consumer));
+    }
+
+    /**
+     * Adapts a ScopeFactory-like function that takes two arguments into a true ScopeFactory that
+     * takes a Both object.
+     *
+     * @param <A> The type of the first argument (and the first item in the Both).
+     * @param <B> The type of the second argument (and the second item in the Both).
+     *
+     * For example, one can refactor the following:
+     *
+     *     observableA.and(observableB).watch((Both<A, B> data) -> {
+     *         A a = data.first;
+     *         B b = data.second;
+     *         ...
+     *     });
+     *
+     * ... into this:
+     *
+     *     observableA.and(observableB).watch(ScopeFactories.both((A a, B b) -> ...));
+     */
+    public static <A, B> ScopeFactory<Both<A, B>> both(
+            BiFunction<? super A, ? super B, AutoCloseable> function) {
+        return (Both<A, B> data) -> function.apply(data.first, data.second);
+    }
 }
diff --git a/chromecast/base/java/test/org/chromium/chromecast/base/BothTest.java b/chromecast/base/java/test/org/chromium/chromecast/base/BothTest.java
index 8717d56..fff1c80 100644
--- a/chromecast/base/java/test/org/chromium/chromecast/base/BothTest.java
+++ b/chromecast/base/java/test/org/chromium/chromecast/base/BothTest.java
@@ -4,12 +4,17 @@
 
 package org.chromium.chromecast.base;
 
+import static org.hamcrest.Matchers.contains;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.BlockJUnit4ClassRunner;
 
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * Tests for Both.
  */
@@ -52,4 +57,17 @@
         Function<Both<Integer, String>, String> getSecond = Both::getSecond;
         assertEquals(getSecond.apply(x), "two");
     }
+
+    @Test
+    public void testAdaptBiFunction() {
+        String result = Both.adapt((String a, String b) -> a + b).apply(Both.both("a", "b"));
+        assertEquals(result, "ab");
+    }
+
+    @Test
+    public void testAdaptBiConsumer() {
+        List<String> result = new ArrayList<>();
+        Both.adapt((String a, String b) -> result.add(a + b)).apply(Both.both("A", "B"));
+        assertThat(result, contains("AB"));
+    }
 }
diff --git a/chromecast/base/java/test/org/chromium/chromecast/base/ReactiveUtilsTest.java b/chromecast/base/java/test/org/chromium/chromecast/base/ReactiveUtilsTest.java
deleted file mode 100644
index e57b5afb..0000000
--- a/chromecast/base/java/test/org/chromium/chromecast/base/ReactiveUtilsTest.java
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chromecast.base;
-
-import static org.hamcrest.Matchers.contains;
-import static org.junit.Assert.assertThat;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.BlockJUnit4ClassRunner;
-
-import org.chromium.chromecast.base.TestUtils.Base;
-import org.chromium.chromecast.base.TestUtils.Derived;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Tests for helper methods used to work with Observables.
- */
-@RunWith(BlockJUnit4ClassRunner.class)
-public class ReactiveUtilsTest {
-    @Test
-    public void testWatchBothWithStrings() {
-        Controller<String> controllerA = new Controller<>();
-        Controller<String> controllerB = new Controller<>();
-        List<String> result = new ArrayList<>();
-        ReactiveUtils.watchBoth(controllerA.and(controllerB), (String a, String b) -> {
-            result.add("enter: " + a + ", " + b);
-            return () -> result.add("exit: " + a + ", " + b);
-        });
-        controllerA.set("A");
-        controllerB.set("B");
-        controllerA.set("AA");
-        controllerB.set("BB");
-        assertThat(result,
-                contains("enter: A, B", "exit: A, B", "enter: AA, B", "exit: AA, B",
-                        "enter: AA, BB"));
-    }
-
-    @Test
-    public void testWatchBothWithSuperclassAsScopeFactoryParameters() {
-        Controller<Derived> controllerA = new Controller<>();
-        Controller<Derived> controllerB = new Controller<>();
-        List<String> result = new ArrayList<>();
-        // Compile error if generics are wrong.
-        ReactiveUtils.watchBoth(controllerA.and(controllerB), (Base a, Base b) -> {
-            result.add("enter: " + a + ", " + b);
-            return () -> result.add("exit: " + a + ", " + b);
-        });
-        controllerA.set(new Derived());
-        controllerB.set(new Derived());
-        assertThat(result, contains("enter: Derived, Derived"));
-    }
-}
diff --git a/chromecast/base/java/test/org/chromium/chromecast/base/ScopeFactoriesTest.java b/chromecast/base/java/test/org/chromium/chromecast/base/ScopeFactoriesTest.java
index c79b3fa..8028dec 100644
--- a/chromecast/base/java/test/org/chromium/chromecast/base/ScopeFactoriesTest.java
+++ b/chromecast/base/java/test/org/chromium/chromecast/base/ScopeFactoriesTest.java
@@ -134,4 +134,67 @@
                 contains("enter Derived", "enter and ignore data", "exit and ignore data",
                         "exit Derived"));
     }
+
+    @Test
+    public void testWatchBothWithStrings() {
+        Controller<String> controllerA = new Controller<>();
+        Controller<String> controllerB = new Controller<>();
+        List<String> result = new ArrayList<>();
+        controllerA.and(controllerB).watch(ScopeFactories.both((String a, String b) -> {
+            result.add("enter: " + a + ", " + b);
+            return () -> result.add("exit: " + a + ", " + b);
+        }));
+        controllerA.set("A");
+        controllerB.set("B");
+        controllerA.set("AA");
+        controllerB.set("BB");
+        assertThat(result,
+                contains("enter: A, B", "exit: A, B", "enter: AA, B", "exit: AA, B",
+                        "enter: AA, BB"));
+    }
+
+    @Test
+    public void testWatchBothWithSuperclassAsScopeFactoryParameters() {
+        Controller<Derived> controllerA = new Controller<>();
+        Controller<Derived> controllerB = new Controller<>();
+        List<String> result = new ArrayList<>();
+        // Compile error if generics are wrong.
+        controllerA.and(controllerB).watch(ScopeFactories.both((Base a, Base b) -> {
+            result.add("enter: " + a + ", " + b);
+            return () -> result.add("exit: " + a + ", " + b);
+        }));
+        controllerA.set(new Derived());
+        controllerB.set(new Derived());
+        assertThat(result, contains("enter: Derived, Derived"));
+    }
+
+    @Test
+    public void testWatchBothOnEnter() {
+        Controller<String> controllerA = new Controller<>();
+        Controller<String> controllerB = new Controller<>();
+        List<String> result = new ArrayList<>();
+        controllerA.and(controllerB).watch(ScopeFactories.onEnter((String a, String b) -> {
+            result.add("enter: " + a + ", " + b);
+        }));
+        controllerA.set("A");
+        controllerB.set("B");
+        controllerA.set("AA");
+        controllerB.set("BB");
+        assertThat(result, contains("enter: A, B", "enter: AA, B", "enter: AA, BB"));
+    }
+
+    @Test
+    public void testWatchBothOnExit() {
+        Controller<String> controllerA = new Controller<>();
+        Controller<String> controllerB = new Controller<>();
+        List<String> result = new ArrayList<>();
+        controllerA.and(controllerB).watch(ScopeFactories.onExit((String a, String b) -> {
+            result.add("exit: " + a + ", " + b);
+        }));
+        controllerA.set("A");
+        controllerB.set("B");
+        controllerA.set("AA");
+        controllerB.set("BB");
+        assertThat(result, contains("exit: A, B", "exit: AA, B"));
+    }
 }
diff --git a/chromecast/browser/extensions/cast_extension_web_contents_observer.cc b/chromecast/browser/extensions/cast_extension_web_contents_observer.cc
index 6edada3..55ba563 100644
--- a/chromecast/browser/extensions/cast_extension_web_contents_observer.cc
+++ b/chromecast/browser/extensions/cast_extension_web_contents_observer.cc
@@ -14,4 +14,13 @@
 
 CastExtensionWebContentsObserver::~CastExtensionWebContentsObserver() {}
 
+void CastExtensionWebContentsObserver::CreateForWebContents(
+    content::WebContents* web_contents) {
+  content::WebContentsUserData<
+      CastExtensionWebContentsObserver>::CreateForWebContents(web_contents);
+
+  // Initialize this instance if necessary.
+  FromWebContents(web_contents)->Initialize();
+}
+
 }  // namespace extensions
diff --git a/chromecast/browser/extensions/cast_extension_web_contents_observer.h b/chromecast/browser/extensions/cast_extension_web_contents_observer.h
index 8d548350..e3acfc2 100644
--- a/chromecast/browser/extensions/cast_extension_web_contents_observer.h
+++ b/chromecast/browser/extensions/cast_extension_web_contents_observer.h
@@ -18,6 +18,10 @@
  public:
   ~CastExtensionWebContentsObserver() override;
 
+  // Creates and initializes an instance of this class for the given
+  // |web_contents|, if it doesn't already exist.
+  static void CreateForWebContents(content::WebContents* web_contents);
+
  private:
   friend class content::WebContentsUserData<CastExtensionWebContentsObserver>;
 
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index d8db4a6..7cb4bc3 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-10448.0.0
\ No newline at end of file
+10460.0.0
\ No newline at end of file
diff --git a/components/autofill/core/browser/BUILD.gn b/components/autofill/core/browser/BUILD.gn
index cfdd295..af9350b 100644
--- a/components/autofill/core/browser/BUILD.gn
+++ b/components/autofill/core/browser/BUILD.gn
@@ -151,8 +151,6 @@
     "validation.h",
     "webdata/autocomplete_sync_bridge.cc",
     "webdata/autocomplete_sync_bridge.h",
-    "webdata/autocomplete_syncable_service.cc",
-    "webdata/autocomplete_syncable_service.h",
     "webdata/autofill_change.cc",
     "webdata/autofill_change.h",
     "webdata/autofill_data_type_controller.cc",
diff --git a/components/autofill/core/browser/webdata/autocomplete_syncable_service.cc b/components/autofill/core/browser/webdata/autocomplete_syncable_service.cc
deleted file mode 100644
index 6053afa..0000000
--- a/components/autofill/core/browser/webdata/autocomplete_syncable_service.cc
+++ /dev/null
@@ -1,430 +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 "components/autofill/core/browser/webdata/autocomplete_syncable_service.h"
-
-#include <stdint.h>
-
-#include <utility>
-
-#include "base/location.h"
-#include "base/logging.h"
-#include "base/memory/ptr_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "components/autofill/core/browser/webdata/autofill_table.h"
-#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
-#include "components/sync/model/sync_error.h"
-#include "components/sync/model/sync_error_factory.h"
-#include "components/sync/protocol/autofill_specifics.pb.h"
-#include "components/sync/protocol/sync.pb.h"
-#include "components/webdata/common/web_database.h"
-#include "net/base/escape.h"
-
-namespace autofill {
-namespace {
-
-const char kAutofillEntryNamespaceTag[] = "autofill_entry|";
-
-// Merges timestamps from the |sync_timestamps| and the |local_entry|.
-// Returns true if they were different, false if they were the same.  If the
-// timestamps were different, fills |date_created| and |date_last_used| with the
-// merged timestamps.  The |sync_timestamps| vector is assumed to be sorted.
-bool MergeTimestamps(
-    const google::protobuf::RepeatedField<int64_t>& sync_timestamps,
-    const AutofillEntry& local_entry,
-    base::Time* date_created,
-    base::Time* date_last_used) {
-  if (sync_timestamps.size() == 0) {
-    *date_created = local_entry.date_created();
-    *date_last_used = local_entry.date_last_used();
-    return true;
-  }
-
-  base::Time sync_date_created =
-      base::Time::FromInternalValue(*sync_timestamps.begin());
-  base::Time sync_date_last_used =
-      base::Time::FromInternalValue(*sync_timestamps.rbegin());
-
-  if (sync_date_created == local_entry.date_created() &&
-      sync_date_last_used == local_entry.date_last_used())
-    return false;
-
-  *date_created = std::min(local_entry.date_created(), sync_date_created);
-  *date_last_used = std::max(local_entry.date_last_used(), sync_date_last_used);
-  return true;
-}
-
-void* UserDataKey() {
-  // Use the address of a static that COMDAT folding won't ever fold
-  // with something else.
-  static int user_data_key = 0;
-  return reinterpret_cast<void*>(&user_data_key);
-}
-
-}  // namespace
-
-AutocompleteSyncableService::AutocompleteSyncableService(
-    AutofillWebDataBackend* web_data_backend)
-    : web_data_backend_(web_data_backend), scoped_observer_(this) {
-  DCHECK(web_data_backend_);
-
-  scoped_observer_.Add(web_data_backend_);
-}
-
-AutocompleteSyncableService::~AutocompleteSyncableService() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-}
-
-// static
-void AutocompleteSyncableService::CreateForWebDataServiceAndBackend(
-    AutofillWebDataService* web_data_service,
-    AutofillWebDataBackend* web_data_backend) {
-  web_data_service->GetDBUserData()->SetUserData(
-      UserDataKey(),
-      base::WrapUnique(new AutocompleteSyncableService(web_data_backend)));
-}
-
-// static
-AutocompleteSyncableService* AutocompleteSyncableService::FromWebDataService(
-    AutofillWebDataService* web_data_service) {
-  return static_cast<AutocompleteSyncableService*>(
-      web_data_service->GetDBUserData()->GetUserData(UserDataKey()));
-}
-
-AutocompleteSyncableService::AutocompleteSyncableService()
-    : web_data_backend_(nullptr), scoped_observer_(this) {
-}
-
-void AutocompleteSyncableService::InjectStartSyncFlare(
-    const syncer::SyncableService::StartSyncFlare& flare) {
-  flare_ = flare;
-}
-
-syncer::SyncMergeResult AutocompleteSyncableService::MergeDataAndStartSyncing(
-    syncer::ModelType type,
-    const syncer::SyncDataList& initial_sync_data,
-    std::unique_ptr<syncer::SyncChangeProcessor> sync_processor,
-    std::unique_ptr<syncer::SyncErrorFactory> error_handler) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  DCHECK(!sync_processor_);
-  DCHECK(sync_processor);
-  DCHECK(error_handler);
-
-  syncer::SyncMergeResult merge_result(type);
-  error_handler_ = std::move(error_handler);
-  std::vector<AutofillEntry> entries;
-  if (!LoadAutofillData(&entries)) {
-    merge_result.set_error(error_handler_->CreateAndUploadError(
-        FROM_HERE,
-        "Could not load autocomplete data from the WebDatabase."));
-    return merge_result;
-  }
-
-  AutocompleteEntryMap new_db_entries;
-  for (auto it = entries.begin(); it != entries.end(); ++it) {
-    new_db_entries[it->key()] =
-        std::make_pair(syncer::SyncChange::ACTION_ADD, it);
-  }
-
-  sync_processor_ = std::move(sync_processor);
-
-  std::vector<AutofillEntry> new_synced_entries;
-  // Go through and check for all the entries that sync already knows about.
-  // CreateOrUpdateEntry() will remove entries that are same with the synced
-  // ones from |new_db_entries|.
-  for (const auto& it : initial_sync_data)
-    CreateOrUpdateEntry(it, &new_db_entries, &new_synced_entries);
-
-  if (!SaveChangesToWebData(new_synced_entries)) {
-    merge_result.set_error(error_handler_->CreateAndUploadError(
-        FROM_HERE,
-        "Failed to update webdata."));
-    return merge_result;
-  }
-
-  syncer::SyncChangeList new_changes;
-  for (const auto& it : new_db_entries) {
-    new_changes.push_back(
-        syncer::SyncChange(FROM_HERE,
-                           it.second.first,
-                           CreateSyncData(*(it.second.second))));
-  }
-
-  merge_result.set_error(
-      sync_processor_->ProcessSyncChanges(FROM_HERE, new_changes));
-
-  // This will schedule a deletion operation on the DB thread, which will
-  // trigger a notification to propagate the deletion to Sync.
-  // NOTE: This must be called *after* the ProcessSyncChanges call above.
-  // Otherwise, an item that Sync is not yet aware of might expire, causing a
-  // Sync error when that item's deletion is propagated to Sync.
-  web_data_backend_->RemoveExpiredFormElements();
-
-  web_data_backend_->NotifyThatSyncHasStarted(type);
-
-  return merge_result;
-}
-
-void AutocompleteSyncableService::StopSyncing(syncer::ModelType type) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  DCHECK_EQ(syncer::AUTOFILL, type);
-
-  sync_processor_.reset();
-  error_handler_.reset();
-}
-
-syncer::SyncDataList AutocompleteSyncableService::GetAllSyncData(
-    syncer::ModelType type) const {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  DCHECK(sync_processor_);
-  DCHECK_EQ(type, syncer::AUTOFILL);
-
-  syncer::SyncDataList current_data;
-
-  std::vector<AutofillEntry> entries;
-  if (!LoadAutofillData(&entries))
-    return current_data;
-
-  for (const AutofillEntry& it : entries)
-    current_data.push_back(CreateSyncData(it));
-
-  return current_data;
-}
-
-syncer::SyncError AutocompleteSyncableService::ProcessSyncChanges(
-    const base::Location& from_here,
-    const syncer::SyncChangeList& change_list) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  DCHECK(sync_processor_);
-
-  if (!sync_processor_) {
-    syncer::SyncError error(FROM_HERE,
-                            syncer::SyncError::DATATYPE_ERROR,
-                            "Models not yet associated.",
-                            syncer::AUTOFILL);
-    return error;
-  }
-
-  // Data is loaded only if we get new ADD/UPDATE change.
-  std::vector<AutofillEntry> entries;
-  std::unique_ptr<AutocompleteEntryMap> db_entries;
-  std::vector<AutofillEntry> new_entries;
-
-  syncer::SyncError list_processing_error;
-
-  for (const auto& i : change_list) {
-    DCHECK(i.IsValid());
-    switch (i.change_type()) {
-      case syncer::SyncChange::ACTION_ADD:
-      case syncer::SyncChange::ACTION_UPDATE:
-        if (!db_entries) {
-          if (!LoadAutofillData(&entries)) {
-            return error_handler_->CreateAndUploadError(
-                FROM_HERE,
-                "Could not get the autocomplete data from WebDatabase.");
-          }
-          db_entries.reset(new AutocompleteEntryMap);
-          for (std::vector<AutofillEntry>::iterator it = entries.begin();
-               it != entries.end(); ++it) {
-            (*db_entries)[it->key()] =
-                std::make_pair(syncer::SyncChange::ACTION_ADD, it);
-          }
-        }
-        CreateOrUpdateEntry(i.sync_data(), db_entries.get(), &new_entries);
-        break;
-
-      case syncer::SyncChange::ACTION_DELETE: {
-        DCHECK(i.sync_data().GetSpecifics().has_autofill())
-            << "Autofill specifics data not present on delete!";
-        const sync_pb::AutofillSpecifics& autofill =
-            i.sync_data().GetSpecifics().autofill();
-        if (autofill.has_value())
-          list_processing_error = AutofillEntryDelete(autofill);
-        else
-          DVLOG(1) << "Delete for old-style autofill profile being dropped!";
-        break;
-      }
-
-      case syncer::SyncChange::ACTION_INVALID:
-        NOTREACHED();
-        return error_handler_->CreateAndUploadError(
-            FROM_HERE,
-            "ProcessSyncChanges failed on ChangeType " +
-                 syncer::SyncChange::ChangeTypeToString(i.change_type()));
-    }
-  }
-
-  if (!SaveChangesToWebData(new_entries)) {
-    return error_handler_->CreateAndUploadError(
-        FROM_HERE,
-        "Failed to update webdata.");
-  }
-
-  // This will schedule a deletion operation on the DB thread, which will
-  // trigger a notification to propagate the deletion to Sync.
-  web_data_backend_->RemoveExpiredFormElements();
-
-  return list_processing_error;
-}
-
-void AutocompleteSyncableService::AutofillEntriesChanged(
-    const AutofillChangeList& changes) {
-  // Check if sync is on. If we receive this notification prior to sync being
-  // started, we'll notify sync to start as soon as it can and later process all
-  // entries when MergeDataAndStartSyncing() is called. If we receive this
-  // notification after sync has exited, it will be synced the next time Chrome
-  // starts.
-  if (sync_processor_) {
-    ActOnChanges(changes);
-  } else if (!flare_.is_null()) {
-    flare_.Run(syncer::AUTOFILL);
-    flare_.Reset();
-  }
-}
-
-bool AutocompleteSyncableService::LoadAutofillData(
-    std::vector<AutofillEntry>* entries) const {
-  return GetAutofillTable()->GetAllAutofillEntries(entries);
-}
-
-bool AutocompleteSyncableService::SaveChangesToWebData(
-    const std::vector<AutofillEntry>& new_entries) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  if (!GetAutofillTable()->UpdateAutofillEntries(new_entries))
-    return false;
-
-  web_data_backend_->NotifyOfMultipleAutofillChanges();
-  return true;
-}
-
-// Creates or updates an autocomplete entry based on |data|.
-void AutocompleteSyncableService::CreateOrUpdateEntry(
-    const syncer::SyncData& data,
-    AutocompleteEntryMap* loaded_data,
-    std::vector<AutofillEntry>* new_entries) {
-  const sync_pb::EntitySpecifics& specifics = data.GetSpecifics();
-  const sync_pb::AutofillSpecifics& autofill_specifics(specifics.autofill());
-
-  if (!autofill_specifics.has_value()) {
-    DVLOG(1) << "Add/Update for old-style autofill profile being dropped!";
-    return;
-  }
-
-  AutofillKey key(autofill_specifics.name(), autofill_specifics.value());
-  AutocompleteEntryMap::iterator it = loaded_data->find(key);
-  const google::protobuf::RepeatedField<int64_t>& timestamps =
-      autofill_specifics.usage_timestamp();
-  if (it == loaded_data->end()) {
-    // New entry.
-    base::Time date_created, date_last_used;
-    if (!timestamps.empty()) {
-      date_created = base::Time::FromInternalValue(*timestamps.begin());
-      date_last_used = base::Time::FromInternalValue(*timestamps.rbegin());
-    }
-    new_entries->push_back(AutofillEntry(key, date_created, date_last_used));
-  } else {
-    // Entry already present - merge if necessary.
-    base::Time date_created, date_last_used;
-    bool different = MergeTimestamps(timestamps, *it->second.second,
-                                     &date_created, &date_last_used);
-    if (different) {
-      AutofillEntry new_entry(
-          it->second.second->key(), date_created, date_last_used);
-      new_entries->push_back(new_entry);
-      // Update the sync db since the timestamps have changed.
-      *(it->second.second) = new_entry;
-      it->second.first = syncer::SyncChange::ACTION_UPDATE;
-    } else {
-      loaded_data->erase(it);
-    }
-  }
-}
-
-// static
-void AutocompleteSyncableService::WriteAutofillEntry(
-    const AutofillEntry& entry, sync_pb::EntitySpecifics* autofill_specifics) {
-  sync_pb::AutofillSpecifics* autofill =
-      autofill_specifics->mutable_autofill();
-  autofill->set_name(base::UTF16ToUTF8(entry.key().name()));
-  autofill->set_value(base::UTF16ToUTF8(entry.key().value()));
-  autofill->add_usage_timestamp(entry.date_created().ToInternalValue());
-  if (entry.date_created() != entry.date_last_used())
-    autofill->add_usage_timestamp(entry.date_last_used().ToInternalValue());
-}
-
-syncer::SyncError AutocompleteSyncableService::AutofillEntryDelete(
-    const sync_pb::AutofillSpecifics& autofill) {
-  if (!GetAutofillTable()->RemoveFormElement(
-          base::UTF8ToUTF16(autofill.name()),
-          base::UTF8ToUTF16(autofill.value()))) {
-    return error_handler_->CreateAndUploadError(
-        FROM_HERE,
-        "Could not remove autocomplete entry from WebDatabase.");
-  }
-  return syncer::SyncError();
-}
-
-void AutocompleteSyncableService::ActOnChanges(
-    const AutofillChangeList& changes) {
-  DCHECK(sync_processor_);
-  syncer::SyncChangeList new_changes;
-  for (const auto& change : changes) {
-    switch (change.type()) {
-      case AutofillChange::ADD:
-      case AutofillChange::UPDATE: {
-        base::Time date_created, date_last_used;
-        bool success = GetAutofillTable()->GetAutofillTimestamps(
-            change.key().name(), change.key().value(),
-            &date_created, &date_last_used);
-        DCHECK(success);
-        AutofillEntry entry(change.key(), date_created, date_last_used);
-        syncer::SyncChange::SyncChangeType change_type =
-           (change.type() == AutofillChange::ADD) ?
-            syncer::SyncChange::ACTION_ADD :
-            syncer::SyncChange::ACTION_UPDATE;
-        new_changes.push_back(syncer::SyncChange(FROM_HERE,
-                                                 change_type,
-                                                 CreateSyncData(entry)));
-        break;
-      }
-
-      case AutofillChange::REMOVE: {
-        AutofillEntry entry(change.key(), base::Time(), base::Time());
-        new_changes.push_back(
-            syncer::SyncChange(FROM_HERE,
-                               syncer::SyncChange::ACTION_DELETE,
-                               CreateSyncData(entry)));
-        break;
-      }
-    }
-  }
-  syncer::SyncError error =
-      sync_processor_->ProcessSyncChanges(FROM_HERE, new_changes);
-  if (error.IsSet()) {
-    DVLOG(1) << "[AUTOCOMPLETE SYNC] Failed processing change.  Error: "
-             << error.message();
-  }
-}
-
-syncer::SyncData AutocompleteSyncableService::CreateSyncData(
-    const AutofillEntry& entry) const {
-  sync_pb::EntitySpecifics autofill_specifics;
-  WriteAutofillEntry(entry, &autofill_specifics);
-  std::string tag(KeyToTag(base::UTF16ToUTF8(entry.key().name()),
-                           base::UTF16ToUTF8(entry.key().value())));
-  return syncer::SyncData::CreateLocalData(tag, tag, autofill_specifics);
-}
-
-AutofillTable* AutocompleteSyncableService::GetAutofillTable() const {
-  return AutofillTable::FromWebDatabase(web_data_backend_->GetDatabase());
-}
-
-// static
-std::string AutocompleteSyncableService::KeyToTag(const std::string& name,
-                                                  const std::string& value) {
-  std::string prefix(kAutofillEntryNamespaceTag);
-  return prefix + net::EscapePath(name) + "|" + net::EscapePath(value);
-}
-
-}  // namespace autofill
diff --git a/components/autofill/core/browser/webdata/autocomplete_syncable_service.h b/components/autofill/core/browser/webdata/autocomplete_syncable_service.h
deleted file mode 100644
index 72a22f7..0000000
--- a/components/autofill/core/browser/webdata/autocomplete_syncable_service.h
+++ /dev/null
@@ -1,171 +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 COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_AUTOCOMPLETE_SYNCABLE_SERVICE_H_
-#define COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_AUTOCOMPLETE_SYNCABLE_SERVICE_H_
-
-#include <map>
-#include <memory>
-#include <set>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "base/macros.h"
-#include "base/scoped_observer.h"
-#include "base/sequence_checker.h"
-#include "base/supports_user_data.h"
-#include "components/autofill/core/browser/webdata/autofill_change.h"
-#include "components/autofill/core/browser/webdata/autofill_entry.h"
-#include "components/autofill/core/browser/webdata/autofill_webdata_backend.h"
-#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
-#include "components/autofill/core/browser/webdata/autofill_webdata_service_observer.h"
-#include "components/sync/model/sync_change.h"
-#include "components/sync/model/sync_data.h"
-#include "components/sync/model/sync_error.h"
-#include "components/sync/model/syncable_service.h"
-
-namespace browser_sync {
-class FakeServerUpdater;
-class ProfileSyncServiceAutofillTest;
-}  // namespace browser_sync
-
-namespace syncer {
-class SyncErrorFactory;
-}  // namespace syncer
-
-namespace sync_pb {
-class AutofillSpecifics;
-}  // namespace sync_pb
-
-namespace autofill {
-
-class AutofillTable;
-
-// The sync implementation for autocomplete.
-// MergeDataAndStartSyncing() called first, it does cloud->local and
-// local->cloud syncs. Then for each cloud change we receive
-// ProcessSyncChanges() and for each local change Observe() is called.
-class AutocompleteSyncableService
-    : public base::SupportsUserData::Data,
-      public syncer::SyncableService,
-      public AutofillWebDataServiceObserverOnDBSequence {
- public:
-  ~AutocompleteSyncableService() override;
-
-  // Creates a new AutocompleteSyncableService and hangs it off of
-  // |web_data_service|, which takes ownership.
-  static void CreateForWebDataServiceAndBackend(
-      AutofillWebDataService* web_data_service,
-      AutofillWebDataBackend* web_data_backend);
-
-  // Retrieves the AutocompleteSyncableService stored on |web_data_service|.
-  static AutocompleteSyncableService* FromWebDataService(
-      AutofillWebDataService* web_data_service);
-
-  static syncer::ModelType model_type() { return syncer::AUTOFILL; }
-
-  // syncer::SyncableService:
-  syncer::SyncMergeResult MergeDataAndStartSyncing(
-      syncer::ModelType type,
-      const syncer::SyncDataList& initial_sync_data,
-      std::unique_ptr<syncer::SyncChangeProcessor> sync_processor,
-      std::unique_ptr<syncer::SyncErrorFactory> error_handler) override;
-  void StopSyncing(syncer::ModelType type) override;
-  syncer::SyncDataList GetAllSyncData(syncer::ModelType type) const override;
-  syncer::SyncError ProcessSyncChanges(
-      const base::Location& from_here,
-      const syncer::SyncChangeList& change_list) override;
-
-  // AutofillWebDataServiceObserverOnDBSequence:
-  void AutofillEntriesChanged(const AutofillChangeList& changes) override;
-
-  // Provides a StartSyncFlare to the SyncableService. See sync_start_util for
-  // more.
-  void InjectStartSyncFlare(
-      const syncer::SyncableService::StartSyncFlare& flare);
-
- protected:
-  explicit AutocompleteSyncableService(
-      AutofillWebDataBackend* web_data_backend);
-
-  // Helper to query WebDatabase for the current autocomplete state.
-  // Made virtual for ease of mocking in the unit-test.
-  virtual bool LoadAutofillData(std::vector<AutofillEntry>* entries) const;
-
-  // Helper to persist any changes that occured during model association to
-  // the WebDatabase. |entries| will be either added or updated.
-  // Made virtual for ease of mocking in the unit-test.
-  virtual bool SaveChangesToWebData(const std::vector<AutofillEntry>& entries);
-
- private:
-  friend class browser_sync::FakeServerUpdater;
-  friend class browser_sync::ProfileSyncServiceAutofillTest;
-
-  // This is a helper map used only in Merge/Process* functions. The lifetime
-  // of the iterator is longer than the map object. The bool in the pair is used
-  // to indicate if the item needs to be added (true) or updated (false).
-  typedef std::map<AutofillKey,
-                   std::pair<syncer::SyncChange::SyncChangeType,
-                             std::vector<AutofillEntry>::iterator>>
-      AutocompleteEntryMap;
-
-  // Creates or updates an autocomplete entry based on |data|.
-  // |data| - an entry for sync.
-  // |loaded_data| - entries that were loaded from local storage.
-  // |new_entries| - entries that came from the sync.
-  // |ignored_entries| - entries that came from the sync, but too old to be
-  // stored and immediately discarded.
-  void CreateOrUpdateEntry(const syncer::SyncData& data,
-                           AutocompleteEntryMap* loaded_data,
-                           std::vector<AutofillEntry>* new_entries);
-
-  // Writes |entry| data into supplied |autofill_specifics|.
-  static void WriteAutofillEntry(const AutofillEntry& entry,
-                                 sync_pb::EntitySpecifics* autofill_specifics);
-
-  // Deletes the database entry corresponding to the |autofill| specifics.
-  syncer::SyncError AutofillEntryDelete(
-      const sync_pb::AutofillSpecifics& autofill);
-
-  syncer::SyncData CreateSyncData(const AutofillEntry& entry) const;
-
-  // Syncs |changes| to the cloud.
-  void ActOnChanges(const AutofillChangeList& changes);
-
-  // Returns the table associated with the |web_data_backend_|.
-  AutofillTable* GetAutofillTable() const;
-
-  static std::string KeyToTag(const std::string& name,
-                              const std::string& value);
-
-  // For unit-tests.
-  AutocompleteSyncableService();
-  void set_sync_processor(syncer::SyncChangeProcessor* sync_processor) {
-    sync_processor_.reset(sync_processor);
-  }
-
-  // The |web_data_backend_| is expected to outlive |this|.
-  AutofillWebDataBackend* const web_data_backend_;
-
-  ScopedObserver<AutofillWebDataBackend, AutocompleteSyncableService>
-      scoped_observer_;
-
-  // We receive ownership of |sync_processor_| in MergeDataAndStartSyncing() and
-  // destroy it in StopSyncing().
-  std::unique_ptr<syncer::SyncChangeProcessor> sync_processor_;
-
-  // We receive ownership of |error_handler_| in MergeDataAndStartSyncing() and
-  // destroy it in StopSyncing().
-  std::unique_ptr<syncer::SyncErrorFactory> error_handler_;
-
-  syncer::SyncableService::StartSyncFlare flare_;
-
-  SEQUENCE_CHECKER(sequence_checker_);
-
-  DISALLOW_COPY_AND_ASSIGN(AutocompleteSyncableService);
-};
-
-}  // namespace autofill
-
-#endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_AUTOCOMPLETE_SYNCABLE_SERVICE_H_
diff --git a/components/autofill/core/browser/webdata/autofill_data_type_controller.cc b/components/autofill/core/browser/webdata/autofill_data_type_controller.cc
index 922d2325..1308021 100644
--- a/components/autofill/core/browser/webdata/autofill_data_type_controller.cc
+++ b/components/autofill/core/browser/webdata/autofill_data_type_controller.cc
@@ -9,7 +9,6 @@
 #include "base/bind.h"
 #include "base/metrics/histogram.h"
 #include "components/autofill/core/browser/personal_data_manager.h"
-#include "components/autofill/core/browser/webdata/autocomplete_syncable_service.h"
 #include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
 #include "components/autofill/core/common/autofill_pref_names.h"
 #include "components/prefs/pref_service.h"
diff --git a/components/autofill/core/browser/webdata/autofill_profile_data_type_controller.cc b/components/autofill/core/browser/webdata/autofill_profile_data_type_controller.cc
index 677b806..5f88eac4 100644
--- a/components/autofill/core/browser/webdata/autofill_profile_data_type_controller.cc
+++ b/components/autofill/core/browser/webdata/autofill_profile_data_type_controller.cc
@@ -9,7 +9,6 @@
 #include "base/bind.h"
 #include "base/metrics/histogram.h"
 #include "components/autofill/core/browser/personal_data_manager.h"
-#include "components/autofill/core/browser/webdata/autocomplete_syncable_service.h"
 #include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
 #include "components/autofill/core/common/autofill_pref_names.h"
 #include "components/prefs/pref_service.h"
diff --git a/components/browser_sync/abstract_profile_sync_service_test.cc b/components/browser_sync/abstract_profile_sync_service_test.cc
index cb706fa..a331fb14 100644
--- a/components/browser_sync/abstract_profile_sync_service_test.cc
+++ b/components/browser_sync/abstract_profile_sync_service_test.cc
@@ -43,7 +43,7 @@
       syncer::SyncClient* sync_client,
       invalidation::InvalidationService* invalidator,
       const base::WeakPtr<syncer::SyncPrefs>& sync_prefs,
-      const base::Closure& callback);
+      base::OnceClosure callback);
   ~SyncEngineForProfileSyncTest() override;
 
   void Initialize(InitParams params) override;
@@ -54,7 +54,7 @@
   // Invoked at the start of HandleSyncManagerInitializationOnFrontendLoop.
   // Allows extra initialization work to be performed before the engine comes
   // up.
-  base::Closure callback_;
+  base::OnceClosure callback_;
 
   DISALLOW_COPY_AND_ASSIGN(SyncEngineForProfileSyncTest);
 };
@@ -64,21 +64,22 @@
     syncer::SyncClient* sync_client,
     invalidation::InvalidationService* invalidator,
     const base::WeakPtr<syncer::SyncPrefs>& sync_prefs,
-    const base::Closure& callback)
+    base::OnceClosure callback)
     : SyncBackendHostImpl(
           "dummy_debug_name",
           sync_client,
           invalidator,
           sync_prefs,
           temp_dir.Append(base::FilePath(FILE_PATH_LITERAL("test")))),
-      callback_(callback) {}
+      callback_(std::move(callback)) {}
 
 SyncEngineForProfileSyncTest::~SyncEngineForProfileSyncTest() {}
 
 void SyncEngineForProfileSyncTest::Initialize(InitParams params) {
   params.http_factory_getter = base::Bind(&GetHttpPostProviderFactory);
   params.sync_manager_factory =
-      std::make_unique<syncer::SyncManagerFactoryForProfileSyncTest>(callback_);
+      std::make_unique<syncer::SyncManagerFactoryForProfileSyncTest>(
+          std::move(callback_));
   params.credentials.email = "testuser@gmail.com";
   params.credentials.sync_token = "token";
   params.credentials.scope_set.insert(GaiaConstants::kChromeSyncOAuth2Scope);
@@ -160,7 +161,7 @@
 
 void AbstractProfileSyncServiceTest::CreateSyncService(
     std::unique_ptr<syncer::SyncClient> sync_client,
-    const base::Closure& initialization_success_callback) {
+    base::OnceClosure initialization_success_callback) {
   ASSERT_TRUE(sync_client);
   ProfileSyncService::InitParams init_params =
       profile_sync_service_bundle_.CreateBasicInitParams(
@@ -175,7 +176,7 @@
           temp_dir_.GetPath(), sync_service_->GetSyncClient(),
           profile_sync_service_bundle_.fake_invalidation_service(),
           sync_service_->sync_prefs()->AsWeakPtr(),
-          initialization_success_callback)));
+          std::move(initialization_success_callback))));
 
   sync_service_->SetFirstSetupComplete();
 }
diff --git a/components/browser_sync/abstract_profile_sync_service_test.h b/components/browser_sync/abstract_profile_sync_service_test.h
index 2171b68..05d355b3 100644
--- a/components/browser_sync/abstract_profile_sync_service_test.h
+++ b/components/browser_sync/abstract_profile_sync_service_test.h
@@ -53,7 +53,7 @@
   // NotifyInitializationSuccess. |sync_client| is passed to the service. The
   // created service is stored in |sync_service_|.
   void CreateSyncService(std::unique_ptr<syncer::SyncClient> sync_client,
-                         const base::Closure& initialization_success_callback);
+                         base::OnceClosure initialization_success_callback);
 
   base::Thread* data_type_thread() { return &data_type_thread_; }
 
diff --git a/components/browser_sync/profile_sync_service_autofill_unittest.cc b/components/browser_sync/profile_sync_service_autofill_unittest.cc
index 54dd4a7..921fddc 100644
--- a/components/browser_sync/profile_sync_service_autofill_unittest.cc
+++ b/components/browser_sync/profile_sync_service_autofill_unittest.cc
@@ -29,10 +29,8 @@
 #include "components/autofill/core/browser/country_names.h"
 #include "components/autofill/core/browser/field_types.h"
 #include "components/autofill/core/browser/personal_data_manager.h"
-#include "components/autofill/core/browser/webdata/autocomplete_syncable_service.h"
 #include "components/autofill/core/browser/webdata/autofill_change.h"
 #include "components/autofill/core/browser/webdata/autofill_data_type_controller.h"
-#include "components/autofill/core/browser/webdata/autofill_entry.h"
 #include "components/autofill/core/browser/webdata/autofill_profile_data_type_controller.h"
 #include "components/autofill/core/browser/webdata/autofill_profile_syncable_service.h"
 #include "components/autofill/core/browser/webdata/autofill_table.h"
@@ -60,10 +58,8 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-using autofill::AutocompleteSyncableService;
 using autofill::AutofillChange;
 using autofill::AutofillChangeList;
-using autofill::AutofillEntry;
 using autofill::AutofillKey;
 using autofill::AutofillProfile;
 using autofill::AutofillProfileChange;
@@ -77,7 +73,6 @@
 using base::Time;
 using base::TimeDelta;
 using base::WaitableEvent;
-using syncer::AUTOFILL;
 using syncer::AUTOFILL_PROFILE;
 using syncer::BaseNode;
 using syncer::syncable::CREATE;
@@ -111,33 +106,11 @@
                                0.0);
 }
 
-void RunAndSignal(const base::Closure& cb, WaitableEvent* event) {
-  cb.Run();
+void RunAndSignal(base::OnceClosure cb, WaitableEvent* event) {
+  std::move(cb).Run();
   event->Signal();
 }
 
-AutofillEntry MakeAutofillEntry(const std::string& name,
-                                const std::string& value,
-                                int time_shift0,
-                                int time_shift1) {
-  // Time deep in the past would cause Autocomplete sync to discard the
-  // entries.
-  static Time base_time = Time::Now().LocalMidnight();
-
-  Time date_created = base_time + TimeDelta::FromSeconds(time_shift0);
-  Time date_last_used = date_created;
-  if (time_shift1 >= 0)
-    date_last_used = base_time + TimeDelta::FromSeconds(time_shift1);
-  return AutofillEntry(AutofillKey(ASCIIToUTF16(name), ASCIIToUTF16(value)),
-                       date_created, date_last_used);
-}
-
-AutofillEntry MakeAutofillEntry(const std::string& name,
-                                const std::string& value,
-                                int time_shift) {
-  return MakeAutofillEntry(name, value, time_shift, -1);
-}
-
 }  // namespace
 
 class AutofillTableMock : public AutofillTable {
@@ -146,15 +119,11 @@
   MOCK_METHOD2(RemoveFormElement,
                bool(const base::string16& name,
                     const base::string16& value));  // NOLINT
-  MOCK_METHOD1(GetAllAutofillEntries,
-               bool(std::vector<AutofillEntry>* entries));  // NOLINT
   MOCK_METHOD4(GetAutofillTimestamps,
                bool(const base::string16& name,  // NOLINT
                     const base::string16& value,
                     Time* date_created,
                     Time* date_last_used));
-  MOCK_METHOD1(UpdateAutofillEntries,
-               bool(const std::vector<AutofillEntry>&));  // NOLINT
   MOCK_METHOD1(GetAutofillProfiles,
                bool(std::vector<std::unique_ptr<AutofillProfile>>*));  // NOLINT
   MOCK_METHOD1(UpdateAutofillProfile, bool(const AutofillProfile&));  // NOLINT
@@ -183,8 +152,8 @@
  public:
   MockAutofillBackend(
       WebDatabase* web_database,
-      const base::Closure& on_changed,
-      const base::Callback<void(syncer::ModelType)>& on_sync_started,
+      const base::RepeatingClosure& on_changed,
+      const base::RepeatingCallback<void(syncer::ModelType)>& on_sync_started,
       const scoped_refptr<base::SequencedTaskRunner>& ui_task_runner)
       : web_database_(web_database),
         on_changed_(on_changed),
@@ -212,28 +181,13 @@
 
  private:
   WebDatabase* web_database_;
-  base::Closure on_changed_;
-  base::Callback<void(syncer::ModelType)> on_sync_started_;
+  base::RepeatingClosure on_changed_;
+  base::RepeatingCallback<void(syncer::ModelType)> on_sync_started_;
   const scoped_refptr<base::SequencedTaskRunner> ui_task_runner_;
 };
 
 class ProfileSyncServiceAutofillTest;
 
-template <class AutofillProfile>
-syncer::ModelType GetModelType() {
-  return syncer::UNSPECIFIED;
-}
-
-template <>
-syncer::ModelType GetModelType<AutofillEntry>() {
-  return AUTOFILL;
-}
-
-template <>
-syncer::ModelType GetModelType<AutofillProfile>() {
-  return AUTOFILL_PROFILE;
-}
-
 class TokenWebDataServiceFake : public TokenWebData {
  public:
   TokenWebDataServiceFake(
@@ -268,7 +222,6 @@
       const scoped_refptr<base::SingleThreadTaskRunner>& db_task_runner)
       : AutofillWebDataService(ui_task_runner, db_task_runner),
         web_database_(nullptr),
-        autocomplete_syncable_service_(nullptr),
         autofill_profile_syncable_service_(nullptr),
         syncable_service_created_or_destroyed_(
             base::WaitableEvent::ResetPolicy::AUTOMATIC,
@@ -281,17 +234,17 @@
   void StartSyncableService() {
     // The |autofill_profile_syncable_service_| must be constructed on the DB
     // sequence.
-    const base::Closure& on_changed_callback = base::Bind(
+    const base::RepeatingClosure& on_changed_callback = base::BindRepeating(
         &WebDataServiceFake::NotifyAutofillMultipleChangedOnUISequence,
         AsWeakPtr());
-    const base::Callback<void(syncer::ModelType)> on_sync_started_callback =
-        base::Bind(&WebDataServiceFake::NotifySyncStartedOnUISequence,
-                   AsWeakPtr());
+    const base::RepeatingCallback<void(syncer::ModelType)>&
+        on_sync_started_callback = base::BindRepeating(
+            &WebDataServiceFake::NotifySyncStartedOnUISequence, AsWeakPtr());
 
     db_task_runner_->PostTask(
         FROM_HERE, base::Bind(&WebDataServiceFake::CreateSyncableService,
                               base::Unretained(this), on_changed_callback,
-                              on_sync_started_callback));
+                              std::move(on_sync_started_callback)));
     syncable_service_created_or_destroyed_.Wait();
   }
 
@@ -308,27 +261,15 @@
 
   WebDatabase* GetDatabase() override { return web_database_; }
 
-  void OnAutofillEntriesChanged(const AutofillChangeList& changes) {
-    WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
-                        base::WaitableEvent::InitialState::NOT_SIGNALED);
-
-    base::Closure notify_cb =
-        base::Bind(&AutocompleteSyncableService::AutofillEntriesChanged,
-                   base::Unretained(autocomplete_syncable_service_), changes);
-    db_task_runner_->PostTask(FROM_HERE,
-                              base::Bind(&RunAndSignal, notify_cb, &event));
-    event.Wait();
-  }
-
   void OnAutofillProfileChanged(const AutofillProfileChange& changes) {
     WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
                         base::WaitableEvent::InitialState::NOT_SIGNALED);
 
-    base::Closure notify_cb = base::Bind(
-        &AutocompleteSyncableService::AutofillProfileChanged,
+    base::OnceClosure notify_cb = base::BindOnce(
+        &AutofillProfileSyncableService::AutofillProfileChanged,
         base::Unretained(autofill_profile_syncable_service_), changes);
-    db_task_runner_->PostTask(FROM_HERE,
-                              base::Bind(&RunAndSignal, notify_cb, &event));
+    db_task_runner_->PostTask(
+        FROM_HERE, base::BindOnce(&RunAndSignal, std::move(notify_cb), &event));
     event.Wait();
   }
 
@@ -336,20 +277,16 @@
   ~WebDataServiceFake() override {}
 
   void CreateSyncableService(
-      const base::Closure& on_changed_callback,
-      const base::Callback<void(syncer::ModelType)>& on_sync_started) {
+      const base::RepeatingClosure& on_changed_callback,
+      const base::RepeatingCallback<void(syncer::ModelType)>& on_sync_started) {
     ASSERT_TRUE(db_task_runner_->RunsTasksInCurrentSequence());
     // These services are deleted in DestroySyncableService().
     backend_ = std::make_unique<MockAutofillBackend>(
         GetDatabase(), on_changed_callback, on_sync_started,
         ui_task_runner_.get());
-    AutocompleteSyncableService::CreateForWebDataServiceAndBackend(
-        this, backend_.get());
     AutofillProfileSyncableService::CreateForWebDataServiceAndBackend(
         this, backend_.get(), "en-US");
 
-    autocomplete_syncable_service_ =
-        AutocompleteSyncableService::FromWebDataService(this);
     autofill_profile_syncable_service_ =
         AutofillProfileSyncableService::FromWebDataService(this);
 
@@ -358,14 +295,12 @@
 
   void DestroySyncableService() {
     ASSERT_TRUE(db_task_runner_->RunsTasksInCurrentSequence());
-    autocomplete_syncable_service_ = nullptr;
     autofill_profile_syncable_service_ = nullptr;
     backend_.reset();
     syncable_service_created_or_destroyed_.Signal();
   }
 
   WebDatabase* web_database_;
-  AutocompleteSyncableService* autocomplete_syncable_service_;
   AutofillProfileSyncableService* autofill_profile_syncable_service_;
   std::unique_ptr<autofill::AutofillWebDataBackend> backend_;
 
@@ -393,8 +328,7 @@
   MOCK_METHOD0(Refresh, void());
 };
 
-template <class T>
-class AddAutofillHelper;
+class AddAutofillProfileHelper;
 
 class ProfileSyncServiceAutofillTest
     : public AbstractProfileSyncServiceTest,
@@ -449,12 +383,6 @@
     builder.set_activate_model_creation();
     sync_client_owned_ = builder.Build();
     sync_client_ = sync_client_owned_.get();
-
-    // When UpdateAutofillEntries() is called with an empty list, the return
-    // value should be |true|, rather than the default of |false|.
-    std::vector<AutofillEntry> empty;
-    EXPECT_CALL(autofill_table_, UpdateAutofillEntries(empty))
-        .WillRepeatedly(Return(true));
   }
 
   ~ProfileSyncServiceAutofillTest() override {
@@ -469,20 +397,18 @@
     sync_service()->Shutdown();
   }
 
-  int GetSyncCount(syncer::ModelType type) {
+  int GetSyncCount() {
     syncer::ReadTransaction trans(FROM_HERE, sync_service()->GetUserShare());
     syncer::ReadNode node(&trans);
-    if (node.InitTypeRoot(type) != BaseNode::INIT_OK)
+    if (node.InitTypeRoot(AUTOFILL_PROFILE) != BaseNode::INIT_OK)
       return 0;
     return node.GetTotalNodeCount() - 1;
   }
 
-  void StartSyncService(const base::Closure& callback,
-                        bool will_fail_association,
-                        syncer::ModelType type) {
+  void StartAutofillProfileSyncService(base::OnceClosure callback) {
     SigninManagerBase* signin = profile_sync_service_bundle()->signin_manager();
     signin->SetAuthenticatedAccountInfo("12345", "test_user@gmail.com");
-    CreateSyncService(std::move(sync_client_owned_), callback);
+    CreateSyncService(std::move(sync_client_owned_), std::move(callback));
 
     EXPECT_CALL(*profile_sync_service_bundle()->component_factory(),
                 CreateDataTypeManager(_, _, _, _, _, _))
@@ -497,14 +423,17 @@
     profile_sync_service_bundle()->auth_service()->UpdateCredentials(
         signin->GetAuthenticatedAccountId(), "oauth2_login_token");
 
-    sync_service()->RegisterDataTypeController(CreateDataTypeController(type));
+    sync_service()->RegisterDataTypeController(
+        std::make_unique<AutofillProfileDataTypeController>(
+            data_type_thread()->task_runner(), base::DoNothing(), sync_client_,
+            web_data_service_));
     sync_service()->Initialize();
     base::RunLoop().Run();
 
     // It's possible this test triggered an unrecoverable error, in which case
     // we can't get the sync count.
     if (sync_service()->IsSyncActive()) {
-      EXPECT_EQ(GetSyncCount(type),
+      EXPECT_EQ(GetSyncCount(),
                 association_stats_.num_sync_items_after_association);
     }
     EXPECT_EQ(association_stats_.num_sync_items_after_association,
@@ -513,23 +442,6 @@
                   association_stats_.num_sync_items_deleted);
   }
 
-  bool AddAutofillSyncNode(const AutofillEntry& entry) {
-    syncer::WriteTransaction trans(FROM_HERE, sync_service()->GetUserShare());
-    syncer::WriteNode node(&trans);
-    std::string tag = AutocompleteSyncableService::KeyToTag(
-        base::UTF16ToUTF8(entry.key().name()),
-        base::UTF16ToUTF8(entry.key().value()));
-    syncer::WriteNode::InitUniqueByCreationResult result =
-        node.InitUniqueByCreation(AUTOFILL, tag);
-    if (result != syncer::WriteNode::INIT_SUCCESS)
-      return false;
-
-    sync_pb::EntitySpecifics specifics;
-    AutocompleteSyncableService::WriteAutofillEntry(entry, &specifics);
-    node.SetEntitySpecifics(specifics);
-    return true;
-  }
-
   bool AddAutofillSyncNode(const AutofillProfile& profile) {
     syncer::WriteTransaction trans(FROM_HERE, sync_service()->GetUserShare());
     syncer::WriteNode node(&trans);
@@ -545,45 +457,6 @@
     return true;
   }
 
-  bool GetAutofillEntriesFromSyncDB(std::vector<AutofillEntry>* entries,
-                                    std::vector<AutofillProfile>* profiles) {
-    syncer::ReadTransaction trans(FROM_HERE, sync_service()->GetUserShare());
-    syncer::ReadNode autofill_root(&trans);
-    if (autofill_root.InitTypeRoot(AUTOFILL) != BaseNode::INIT_OK) {
-      return false;
-    }
-
-    int64_t child_id = autofill_root.GetFirstChildId();
-    while (child_id != syncer::kInvalidId) {
-      syncer::ReadNode child_node(&trans);
-      if (child_node.InitByIdLookup(child_id) != BaseNode::INIT_OK)
-        return false;
-
-      const sync_pb::AutofillSpecifics& autofill(
-          child_node.GetEntitySpecifics().autofill());
-      if (autofill.has_value()) {
-        AutofillKey key(base::UTF8ToUTF16(autofill.name()),
-                        base::UTF8ToUTF16(autofill.value()));
-        std::vector<Time> timestamps;
-        int timestamps_count = autofill.usage_timestamp_size();
-        for (int i = 0; i < timestamps_count; ++i) {
-          timestamps.push_back(
-              Time::FromInternalValue(autofill.usage_timestamp(i)));
-        }
-        entries->push_back(
-            AutofillEntry(key, timestamps.front(), timestamps.back()));
-      } else if (autofill.has_profile()) {
-        AutofillProfile p;
-        p.set_guid(autofill.profile().guid());
-        AutofillProfileSyncableService::OverwriteProfileWithServerData(
-            autofill.profile(), &p);
-        profiles->push_back(p);
-      }
-      child_id = child_node.GetSuccessorId();
-    }
-    return true;
-  }
-
   bool GetAutofillProfilesFromSyncDBUnderProfileNode(
       std::vector<AutofillProfile>* profiles) {
     syncer::ReadTransaction trans(FROM_HERE, sync_service()->GetUserShare());
@@ -613,24 +486,6 @@
   void SetIdleChangeProcessorExpectations() {
     EXPECT_CALL(autofill_table_, RemoveFormElement(_, _)).Times(0);
     EXPECT_CALL(autofill_table_, GetAutofillTimestamps(_, _, _, _)).Times(0);
-
-    // Only permit UpdateAutofillEntries() to be called with an empty list.
-    std::vector<AutofillEntry> empty;
-    EXPECT_CALL(autofill_table_, UpdateAutofillEntries(Not(empty))).Times(0);
-  }
-
-  std::unique_ptr<syncer::DataTypeController> CreateDataTypeController(
-      syncer::ModelType type) {
-    DCHECK(type == AUTOFILL || type == AUTOFILL_PROFILE);
-    if (type == AUTOFILL) {
-      return std::make_unique<AutofillDataTypeController>(
-          data_type_thread()->task_runner(), base::DoNothing(), sync_client_,
-          web_data_service_);
-    } else {
-      return std::make_unique<AutofillProfileDataTypeController>(
-          data_type_thread()->task_runner(), base::DoNothing(), sync_client_,
-          web_data_service_);
-    }
   }
 
   AutofillTableMock& autofill_table() { return autofill_table_; }
@@ -642,21 +497,14 @@
   WebDataServiceFake* web_data_service() { return web_data_service_.get(); }
 
  private:
-  friend class AddAutofillHelper<AutofillEntry>;
-  friend class AddAutofillHelper<AutofillProfile>;
+  friend class AddAutofillProfileHelper;
 
   base::WeakPtr<syncer::SyncableService> GetSyncableServiceForType(
       syncer::ModelType type) {
-    DCHECK(type == AUTOFILL || type == AUTOFILL_PROFILE);
-    if (type == AUTOFILL) {
-      return AutocompleteSyncableService::FromWebDataService(
-                 web_data_service_.get())
-          ->AsWeakPtr();
-    } else {
-      return AutofillProfileSyncableService::FromWebDataService(
-                 web_data_service_.get())
-          ->AsWeakPtr();
-    }
+    DCHECK(type == AUTOFILL_PROFILE);
+    return AutofillProfileSyncableService::FromWebDataService(
+               web_data_service_.get())
+        ->AsWeakPtr();
   }
 
   AutofillTableMock autofill_table_;
@@ -675,24 +523,23 @@
   DISALLOW_COPY_AND_ASSIGN(ProfileSyncServiceAutofillTest);
 };
 
-template <class T>
-class AddAutofillHelper {
+class AddAutofillProfileHelper {
  public:
-  AddAutofillHelper(ProfileSyncServiceAutofillTest* test,
-                    const std::vector<T>& entries)
-      : callback_(base::Bind(&AddAutofillHelper::AddAutofillCallback,
-                             base::Unretained(this),
-                             test,
-                             entries)),
+  AddAutofillProfileHelper(ProfileSyncServiceAutofillTest* test,
+                           const std::vector<AutofillProfile>& entries)
+      : callback_(base::BindOnce(&AddAutofillProfileHelper::AddAutofillCallback,
+                                 base::Unretained(this),
+                                 test,
+                                 entries)),
         success_(false) {}
 
-  const base::Closure& callback() const { return callback_; }
+  base::OnceClosure callback() { return std::move(callback_); }
   bool success() { return success_; }
 
  private:
   void AddAutofillCallback(ProfileSyncServiceAutofillTest* test,
-                           const std::vector<T>& entries) {
-    if (!test->CreateRoot(GetModelType<T>()))
+                           const std::vector<AutofillProfile>& entries) {
+    if (!test->CreateRoot(AUTOFILL_PROFILE))
       return;
 
     for (size_t i = 0; i < entries.size(); ++i) {
@@ -702,167 +549,10 @@
     success_ = true;
   }
 
-  base::Closure callback_;
+  base::OnceClosure callback_;
   bool success_;
 };
 
-// Overload write transaction to use custom NotifyTransactionComplete
-class WriteTransactionTest : public WriteTransaction {
- public:
-  WriteTransactionTest(const base::Location& from_here,
-                       WriterTag writer,
-                       syncer::syncable::Directory* directory,
-                       WaitableEvent* wait_for_syncapi)
-      : WriteTransaction(from_here, writer, directory),
-        wait_for_syncapi_(wait_for_syncapi) {}
-
-  void NotifyTransactionComplete(syncer::ModelTypeSet types) override {
-    // This is where we differ. Force a thread change here, giving another
-    // thread a chance to create a WriteTransaction
-    wait_for_syncapi_->Wait();
-
-    WriteTransaction::NotifyTransactionComplete(types);
-  }
-
- private:
-  WaitableEvent* const wait_for_syncapi_;
-};
-
-// Our fake server updater. Needs the RefCountedThreadSafe inheritance so we can
-// post tasks with it.
-class FakeServerUpdater : public base::RefCountedThreadSafe<FakeServerUpdater> {
- public:
-  FakeServerUpdater(TestProfileSyncService* service,
-                    WaitableEvent* wait_for_start,
-                    WaitableEvent* wait_for_syncapi,
-                    scoped_refptr<base::SequencedTaskRunner> db_task_runner)
-      : entry_(MakeAutofillEntry("0", "0", 0)),
-        service_(service),
-        wait_for_start_(wait_for_start),
-        wait_for_syncapi_(wait_for_syncapi),
-        is_finished_(base::WaitableEvent::ResetPolicy::AUTOMATIC,
-                     base::WaitableEvent::InitialState::NOT_SIGNALED),
-        db_task_runner_(db_task_runner) {}
-
-  void Update() {
-    // This gets called in a modelsafeworker thread.
-    ASSERT_TRUE(db_task_runner_->RunsTasksInCurrentSequence());
-
-    syncer::UserShare* user_share = service_->GetUserShare();
-    syncer::syncable::Directory* directory = user_share->directory.get();
-
-    // Create autofill protobuf.
-    std::string tag = AutocompleteSyncableService::KeyToTag(
-        base::UTF16ToUTF8(entry_.key().name()),
-        base::UTF16ToUTF8(entry_.key().value()));
-    sync_pb::AutofillSpecifics new_autofill;
-    new_autofill.set_name(base::UTF16ToUTF8(entry_.key().name()));
-    new_autofill.set_value(base::UTF16ToUTF8(entry_.key().value()));
-    new_autofill.add_usage_timestamp(entry_.date_created().ToInternalValue());
-    if (entry_.date_created() != entry_.date_last_used()) {
-      new_autofill.add_usage_timestamp(
-          entry_.date_last_used().ToInternalValue());
-    }
-
-    sync_pb::EntitySpecifics entity_specifics;
-    entity_specifics.mutable_autofill()->CopyFrom(new_autofill);
-
-    {
-      // Tell main thread we've started
-      wait_for_start_->Signal();
-
-      // Create write transaction.
-      WriteTransactionTest trans(FROM_HERE, UNITTEST, directory,
-                                 wait_for_syncapi_);
-
-      // Create actual entry based on autofill protobuf information.
-      // Simulates effects of UpdateLocalDataFromServerData
-      MutableEntry parent(&trans, GET_TYPE_ROOT, AUTOFILL);
-      MutableEntry item(&trans, CREATE, AUTOFILL, parent.GetId(), tag);
-      ASSERT_TRUE(item.good());
-      item.PutSpecifics(entity_specifics);
-      item.PutServerSpecifics(entity_specifics);
-      item.PutBaseVersion(1);
-      syncer::syncable::Id server_item_id =
-          service_->id_factory()->NewServerId();
-      item.PutId(server_item_id);
-      syncer::syncable::Id new_predecessor;
-      ASSERT_TRUE(item.PutPredecessor(new_predecessor));
-    }
-    DVLOG(1) << "FakeServerUpdater finishing.";
-    is_finished_.Signal();
-  }
-
-  void CreateNewEntry(const AutofillEntry& entry) {
-    entry_ = entry;
-    ASSERT_FALSE(db_task_runner_->RunsTasksInCurrentSequence());
-    if (!db_task_runner_->PostTask(
-            FROM_HERE, base::Bind(&FakeServerUpdater::Update, this))) {
-      NOTREACHED() << "Failed to post task to the db sequence.";
-      return;
-    }
-  }
-
-  void WaitForUpdateCompletion() { is_finished_.Wait(); }
-
- private:
-  friend class base::RefCountedThreadSafe<FakeServerUpdater>;
-  ~FakeServerUpdater() {}
-
-  AutofillEntry entry_;
-  TestProfileSyncService* service_;
-  WaitableEvent* const wait_for_start_;
-  WaitableEvent* const wait_for_syncapi_;
-  WaitableEvent is_finished_;
-  syncer::syncable::Id parent_id_;
-  scoped_refptr<base::SequencedTaskRunner> db_task_runner_;
-
-  DISALLOW_COPY_AND_ASSIGN(FakeServerUpdater);
-};
-
-// TODO(skrul): Test abort startup.
-// TODO(skrul): Test processing of cloud changes.
-// TODO(tim): Add autofill data type controller test, and a case to cover
-//            waiting for the PersonalDataManager.
-TEST_F(ProfileSyncServiceAutofillTest, FailModelAssociation) {
-  // Don't create the root autofill node so startup fails.
-  StartSyncService(base::Closure(), true, AUTOFILL);
-  EXPECT_TRUE(sync_service()->HasUnrecoverableError());
-}
-
-TEST_F(ProfileSyncServiceAutofillTest, EmptyNativeEmptySync) {
-  EXPECT_CALL(autofill_table(), GetAllAutofillEntries(_))
-      .WillOnce(Return(true));
-  SetIdleChangeProcessorExpectations();
-  CreateRootHelper create_root(this, AUTOFILL);
-  EXPECT_CALL(personal_data_manager(), Refresh());
-  StartSyncService(create_root.callback(), false, AUTOFILL);
-  EXPECT_TRUE(create_root.success());
-  std::vector<AutofillEntry> sync_entries;
-  std::vector<AutofillProfile> sync_profiles;
-  ASSERT_TRUE(GetAutofillEntriesFromSyncDB(&sync_entries, &sync_profiles));
-  EXPECT_EQ(0U, sync_entries.size());
-  EXPECT_EQ(0U, sync_profiles.size());
-}
-
-TEST_F(ProfileSyncServiceAutofillTest, HasNativeEntriesEmptySync) {
-  std::vector<AutofillEntry> entries;
-  entries.push_back(MakeAutofillEntry("foo", "bar", 1));
-  EXPECT_CALL(autofill_table(), GetAllAutofillEntries(_))
-      .WillOnce(DoAll(SetArgPointee<0>(entries), Return(true)));
-  SetIdleChangeProcessorExpectations();
-  CreateRootHelper create_root(this, AUTOFILL);
-  EXPECT_CALL(personal_data_manager(), Refresh());
-  StartSyncService(create_root.callback(), false, AUTOFILL);
-  ASSERT_TRUE(create_root.success());
-  std::vector<AutofillEntry> sync_entries;
-  std::vector<AutofillProfile> sync_profiles;
-  ASSERT_TRUE(GetAutofillEntriesFromSyncDB(&sync_entries, &sync_profiles));
-  ASSERT_EQ(1U, sync_entries.size());
-  EXPECT_EQ(entries[0], sync_entries[0]);
-  EXPECT_EQ(0U, sync_profiles.size());
-}
-
 TEST_F(ProfileSyncServiceAutofillTest, HasProfileEmptySync) {
   std::vector<std::unique_ptr<AutofillProfile>> profiles;
   std::vector<AutofillProfile> expected_profiles;
@@ -880,7 +570,7 @@
   EXPECT_CALL(personal_data_manager(), Refresh());
   SetIdleChangeProcessorExpectations();
   CreateRootHelper create_root(this, AUTOFILL_PROFILE);
-  StartSyncService(create_root.callback(), false, AUTOFILL_PROFILE);
+  StartAutofillProfileSyncService(create_root.callback());
   ASSERT_TRUE(create_root.success());
   std::vector<AutofillProfile> sync_profiles;
   ASSERT_TRUE(GetAutofillProfilesFromSyncDBUnderProfileNode(&sync_profiles));
@@ -888,140 +578,6 @@
   EXPECT_EQ(0, expected_profiles[0].Compare(sync_profiles[0]));
 }
 
-TEST_F(ProfileSyncServiceAutofillTest, HasNativeWithDuplicatesEmptySync) {
-  // There is buggy autofill code that allows duplicate name/value
-  // pairs to exist in the database with separate pair_ids.
-  std::vector<AutofillEntry> entries;
-  entries.push_back(MakeAutofillEntry("foo", "bar", 1));
-  entries.push_back(MakeAutofillEntry("dup", "", 2));
-  entries.push_back(MakeAutofillEntry("dup", "", 3));
-  EXPECT_CALL(autofill_table(), GetAllAutofillEntries(_))
-      .WillOnce(DoAll(SetArgPointee<0>(entries), Return(true)));
-  SetIdleChangeProcessorExpectations();
-  CreateRootHelper create_root(this, AUTOFILL);
-  EXPECT_CALL(personal_data_manager(), Refresh());
-  StartSyncService(create_root.callback(), false, AUTOFILL);
-  ASSERT_TRUE(create_root.success());
-  std::vector<AutofillEntry> sync_entries;
-  std::vector<AutofillProfile> sync_profiles;
-  ASSERT_TRUE(GetAutofillEntriesFromSyncDB(&sync_entries, &sync_profiles));
-  EXPECT_EQ(2U, sync_entries.size());
-}
-
-TEST_F(ProfileSyncServiceAutofillTest, HasNativeHasSyncNoMerge) {
-  AutofillEntry native_entry(MakeAutofillEntry("native", "entry", 1));
-  AutofillEntry sync_entry(MakeAutofillEntry("sync", "entry", 2));
-
-  std::vector<AutofillEntry> native_entries;
-  native_entries.push_back(native_entry);
-
-  EXPECT_CALL(autofill_table(), GetAllAutofillEntries(_))
-      .WillOnce(DoAll(SetArgPointee<0>(native_entries), Return(true)));
-
-  std::vector<AutofillEntry> sync_entries;
-  sync_entries.push_back(sync_entry);
-
-  AddAutofillHelper<AutofillEntry> add_autofill(this, sync_entries);
-
-  EXPECT_CALL(autofill_table(), UpdateAutofillEntries(ElementsAre(sync_entry)))
-      .WillOnce(Return(true));
-
-  EXPECT_CALL(personal_data_manager(), Refresh());
-  StartSyncService(add_autofill.callback(), false, AUTOFILL);
-  ASSERT_TRUE(add_autofill.success());
-
-  std::set<AutofillEntry> expected_entries;
-  expected_entries.insert(native_entry);
-  expected_entries.insert(sync_entry);
-
-  std::vector<AutofillEntry> new_sync_entries;
-  std::vector<AutofillProfile> new_sync_profiles;
-  ASSERT_TRUE(
-      GetAutofillEntriesFromSyncDB(&new_sync_entries, &new_sync_profiles));
-  std::set<AutofillEntry> new_sync_entries_set(new_sync_entries.begin(),
-                                               new_sync_entries.end());
-
-  EXPECT_EQ(expected_entries, new_sync_entries_set);
-}
-
-TEST_F(ProfileSyncServiceAutofillTest, HasNativeHasSyncNoMerge_NullTerminated) {
-  const char kEntry[] = "entry";
-  // A value which contains null terminating symbol.
-  std::string entry(kEntry, arraysize(kEntry));
-  AutofillEntry native_entry0(MakeAutofillEntry("native", kEntry, 1));
-  AutofillEntry native_entry1(MakeAutofillEntry("native", entry, 1));
-  AutofillEntry sync_entry0(MakeAutofillEntry("sync", kEntry, 2));
-  AutofillEntry sync_entry1(MakeAutofillEntry("sync", entry, 2));
-
-  std::vector<AutofillEntry> native_entries;
-  native_entries.push_back(native_entry0);
-  native_entries.push_back(native_entry1);
-
-  EXPECT_CALL(autofill_table(), GetAllAutofillEntries(_))
-      .WillOnce(DoAll(SetArgPointee<0>(native_entries), Return(true)));
-
-  std::vector<AutofillEntry> sync_entries;
-  sync_entries.push_back(sync_entry0);
-  sync_entries.push_back(sync_entry1);
-
-  AddAutofillHelper<AutofillEntry> add_autofill(this, sync_entries);
-
-  // Expecting that sync_entry0 and sync_entry1 will be written in an autofill
-  // table and a value in sync_entry1 won't lose null terminating symbol.
-  EXPECT_CALL(autofill_table(),
-              UpdateAutofillEntries(ElementsAre(sync_entry0, sync_entry1)))
-      .WillOnce(Return(true));
-
-  EXPECT_CALL(personal_data_manager(), Refresh());
-  StartSyncService(add_autofill.callback(), false, AUTOFILL);
-  ASSERT_TRUE(add_autofill.success());
-
-  // Expecting that native_entry0 and native_entry1 won't merge into one entry.
-  std::set<AutofillEntry> expected_entries;
-  expected_entries.insert(native_entry0);
-  expected_entries.insert(native_entry1);
-  expected_entries.insert(sync_entry0);
-  expected_entries.insert(sync_entry1);
-
-  std::vector<AutofillEntry> new_sync_entries;
-  std::vector<AutofillProfile> new_sync_profiles;
-  ASSERT_TRUE(
-      GetAutofillEntriesFromSyncDB(&new_sync_entries, &new_sync_profiles));
-  std::set<AutofillEntry> new_sync_entries_set(new_sync_entries.begin(),
-                                               new_sync_entries.end());
-
-  EXPECT_EQ(expected_entries, new_sync_entries_set);
-}
-
-TEST_F(ProfileSyncServiceAutofillTest, HasNativeHasSyncMergeEntry) {
-  AutofillEntry native_entry(MakeAutofillEntry("merge", "entry", 1));
-  AutofillEntry sync_entry(MakeAutofillEntry("merge", "entry", 2));
-  AutofillEntry merged_entry(MakeAutofillEntry("merge", "entry", 1, 2));
-
-  std::vector<AutofillEntry> native_entries;
-  native_entries.push_back(native_entry);
-  EXPECT_CALL(autofill_table(), GetAllAutofillEntries(_))
-      .WillOnce(DoAll(SetArgPointee<0>(native_entries), Return(true)));
-
-  std::vector<AutofillEntry> sync_entries;
-  sync_entries.push_back(sync_entry);
-  AddAutofillHelper<AutofillEntry> add_autofill(this, sync_entries);
-
-  EXPECT_CALL(autofill_table(),
-              UpdateAutofillEntries(ElementsAre(merged_entry)))
-      .WillOnce(Return(true));
-  EXPECT_CALL(personal_data_manager(), Refresh());
-  StartSyncService(add_autofill.callback(), false, AUTOFILL);
-  ASSERT_TRUE(add_autofill.success());
-
-  std::vector<AutofillEntry> new_sync_entries;
-  std::vector<AutofillProfile> new_sync_profiles;
-  ASSERT_TRUE(
-      GetAutofillEntriesFromSyncDB(&new_sync_entries, &new_sync_profiles));
-  ASSERT_EQ(1U, new_sync_entries.size());
-  EXPECT_EQ(merged_entry, new_sync_entries[0]);
-}
-
 TEST_F(ProfileSyncServiceAutofillTest, HasNativeHasSyncMergeProfile) {
   AutofillProfile sync_profile;
   autofill::test::SetProfileInfoWithGuid(
@@ -1046,13 +602,13 @@
 
   std::vector<AutofillProfile> sync_profiles;
   sync_profiles.push_back(sync_profile);
-  AddAutofillHelper<AutofillProfile> add_autofill(this, sync_profiles);
+  AddAutofillProfileHelper add_autofill(this, sync_profiles);
 
   EXPECT_CALL(autofill_table(),
               UpdateAutofillProfile(MatchProfiles(sync_profile)))
       .WillOnce(Return(true));
   EXPECT_CALL(personal_data_manager(), Refresh());
-  StartSyncService(add_autofill.callback(), false, AUTOFILL_PROFILE);
+  StartAutofillProfileSyncService(add_autofill.callback());
   ASSERT_TRUE(add_autofill.success());
 
   std::vector<AutofillProfile> new_sync_profiles;
@@ -1105,11 +661,11 @@
       .WillOnce(Return(true));
   std::vector<AutofillProfile> sync_profiles;
   sync_profiles.push_back(sync_profile);
-  AddAutofillHelper<AutofillProfile> add_autofill(this, sync_profiles);
+  AddAutofillProfileHelper add_autofill(this, sync_profiles);
 
   EXPECT_CALL(personal_data_manager(), Refresh());
   // Adds all entries in |sync_profiles| to sync.
-  StartSyncService(add_autofill.callback(), false, AUTOFILL_PROFILE);
+  StartAutofillProfileSyncService(add_autofill.callback());
   ASSERT_TRUE(add_autofill.success());
 
   std::vector<AutofillProfile> new_sync_profiles;
@@ -1170,11 +726,11 @@
       .WillOnce(Return(true));
   std::vector<AutofillProfile> sync_profiles;
   sync_profiles.push_back(sync_profile);
-  AddAutofillHelper<AutofillProfile> add_autofill(this, sync_profiles);
+  AddAutofillProfileHelper add_autofill(this, sync_profiles);
 
   EXPECT_CALL(personal_data_manager(), Refresh());
   // Adds all entries in |sync_profiles| to sync.
-  StartSyncService(add_autofill.callback(), false, AUTOFILL_PROFILE);
+  StartAutofillProfileSyncService(add_autofill.callback());
   ASSERT_TRUE(add_autofill.success());
 
   std::vector<AutofillProfile> new_sync_profiles;
@@ -1237,11 +793,11 @@
       .WillOnce(Return(true));
   std::vector<AutofillProfile> sync_profiles;
   sync_profiles.push_back(sync_profile);
-  AddAutofillHelper<AutofillProfile> add_autofill(this, sync_profiles);
+  AddAutofillProfileHelper add_autofill(this, sync_profiles);
 
   EXPECT_CALL(personal_data_manager(), Refresh());
   // Adds all entries in |sync_profiles| to sync.
-  StartSyncService(add_autofill.callback(), false, AUTOFILL_PROFILE);
+  StartAutofillProfileSyncService(add_autofill.callback());
   ASSERT_TRUE(add_autofill.success());
 
   std::vector<AutofillProfile> new_sync_profiles;
@@ -1289,11 +845,11 @@
       .WillOnce(Return(true));
   std::vector<AutofillProfile> sync_profiles;
   sync_profiles.push_back(sync_profile);
-  AddAutofillHelper<AutofillProfile> add_autofill(this, sync_profiles);
+  AddAutofillProfileHelper add_autofill(this, sync_profiles);
 
   EXPECT_CALL(personal_data_manager(), Refresh());
   // Adds all entries in |sync_profiles| to sync.
-  StartSyncService(add_autofill.callback(), false, AUTOFILL_PROFILE);
+  StartAutofillProfileSyncService(add_autofill.callback());
   ASSERT_TRUE(add_autofill.success());
 
   std::vector<AutofillProfile> new_sync_profiles;
@@ -1336,13 +892,13 @@
 
   std::vector<AutofillProfile> sync_profiles;
   sync_profiles.push_back(sync_profile);
-  AddAutofillHelper<AutofillProfile> add_autofill(this, sync_profiles);
+  AddAutofillProfileHelper add_autofill(this, sync_profiles);
 
   EXPECT_CALL(autofill_table(), AddAutofillProfile(_)).WillOnce(Return(true));
   EXPECT_CALL(autofill_table(), RemoveAutofillProfile(native_guid))
       .WillOnce(Return(true));
   EXPECT_CALL(personal_data_manager(), Refresh());
-  StartSyncService(add_autofill.callback(), false, AUTOFILL_PROFILE);
+  StartAutofillProfileSyncService(add_autofill.callback());
   ASSERT_TRUE(add_autofill.success());
 
   std::vector<AutofillProfile> new_sync_profiles;
@@ -1359,41 +915,13 @@
   EXPECT_EQ(base::Time::FromTimeT(1234), new_sync_profiles[0].use_date());
 }
 
-TEST_F(ProfileSyncServiceAutofillTest, ProcessUserChangeAddEntry) {
-  EXPECT_CALL(autofill_table(), GetAllAutofillEntries(_))
-      .WillOnce(Return(true));
-  EXPECT_CALL(personal_data_manager(), Refresh());
-  SetIdleChangeProcessorExpectations();
-  CreateRootHelper create_root(this, AUTOFILL);
-  StartSyncService(create_root.callback(), false, AUTOFILL);
-  ASSERT_TRUE(create_root.success());
-
-  AutofillEntry added_entry(MakeAutofillEntry("added", "entry", 1));
-
-  EXPECT_CALL(autofill_table(), GetAutofillTimestamps(_, _, _, _))
-      .WillOnce(DoAll(SetArgPointee<2>(added_entry.date_created()),
-                      SetArgPointee<3>(added_entry.date_last_used()),
-                      Return(true)));
-
-  AutofillChangeList changes;
-  changes.push_back(AutofillChange(AutofillChange::ADD, added_entry.key()));
-
-  web_data_service()->OnAutofillEntriesChanged(changes);
-
-  std::vector<AutofillEntry> new_sync_entries;
-  std::vector<AutofillProfile> new_sync_profiles;
-  ASSERT_TRUE(
-      GetAutofillEntriesFromSyncDB(&new_sync_entries, &new_sync_profiles));
-  ASSERT_EQ(1U, new_sync_entries.size());
-  EXPECT_EQ(added_entry, new_sync_entries[0]);
-}
 
 TEST_F(ProfileSyncServiceAutofillTest, ProcessUserChangeAddProfile) {
   EXPECT_CALL(autofill_table(), GetAutofillProfiles(_)).WillOnce(Return(true));
   EXPECT_CALL(personal_data_manager(), Refresh());
   SetIdleChangeProcessorExpectations();
   CreateRootHelper create_root(this, AUTOFILL_PROFILE);
-  StartSyncService(create_root.callback(), false, AUTOFILL_PROFILE);
+  StartAutofillProfileSyncService(create_root.callback());
   ASSERT_TRUE(create_root.success());
 
   AutofillProfile added_profile;
@@ -1413,62 +941,6 @@
   EXPECT_EQ(0, added_profile.Compare(new_sync_profiles[0]));
 }
 
-TEST_F(ProfileSyncServiceAutofillTest, ProcessUserChangeUpdateEntry) {
-  AutofillEntry original_entry(MakeAutofillEntry("my", "entry", 1));
-  std::vector<AutofillEntry> original_entries;
-  original_entries.push_back(original_entry);
-
-  EXPECT_CALL(autofill_table(), GetAllAutofillEntries(_))
-      .WillOnce(DoAll(SetArgPointee<0>(original_entries), Return(true)));
-  EXPECT_CALL(personal_data_manager(), Refresh());
-  CreateRootHelper create_root(this, AUTOFILL);
-  StartSyncService(create_root.callback(), false, AUTOFILL);
-  ASSERT_TRUE(create_root.success());
-
-  AutofillEntry updated_entry(MakeAutofillEntry("my", "entry", 1, 2));
-
-  EXPECT_CALL(autofill_table(), GetAutofillTimestamps(_, _, _, _))
-      .WillOnce(DoAll(SetArgPointee<2>(updated_entry.date_created()),
-                      SetArgPointee<3>(updated_entry.date_last_used()),
-                      Return(true)));
-
-  AutofillChangeList changes;
-  changes.push_back(
-      AutofillChange(AutofillChange::UPDATE, updated_entry.key()));
-  web_data_service()->OnAutofillEntriesChanged(changes);
-
-  std::vector<AutofillEntry> new_sync_entries;
-  std::vector<AutofillProfile> new_sync_profiles;
-  ASSERT_TRUE(
-      GetAutofillEntriesFromSyncDB(&new_sync_entries, &new_sync_profiles));
-  ASSERT_EQ(1U, new_sync_entries.size());
-  EXPECT_EQ(updated_entry, new_sync_entries[0]);
-}
-
-TEST_F(ProfileSyncServiceAutofillTest, ProcessUserChangeRemoveEntry) {
-  AutofillEntry original_entry(MakeAutofillEntry("my", "entry", 1));
-  std::vector<AutofillEntry> original_entries;
-  original_entries.push_back(original_entry);
-
-  EXPECT_CALL(autofill_table(), GetAllAutofillEntries(_))
-      .WillOnce(DoAll(SetArgPointee<0>(original_entries), Return(true)));
-  EXPECT_CALL(personal_data_manager(), Refresh());
-  CreateRootHelper create_root(this, AUTOFILL);
-  StartSyncService(create_root.callback(), false, AUTOFILL);
-  ASSERT_TRUE(create_root.success());
-
-  AutofillChangeList changes;
-  changes.push_back(
-      AutofillChange(AutofillChange::REMOVE, original_entry.key()));
-  web_data_service()->OnAutofillEntriesChanged(changes);
-
-  std::vector<AutofillEntry> new_sync_entries;
-  std::vector<AutofillProfile> new_sync_profiles;
-  ASSERT_TRUE(
-      GetAutofillEntriesFromSyncDB(&new_sync_entries, &new_sync_profiles));
-  ASSERT_EQ(0U, new_sync_entries.size());
-}
-
 TEST_F(ProfileSyncServiceAutofillTest, ProcessUserChangeRemoveProfile) {
   AutofillProfile sync_profile;
   autofill::test::SetProfileInfoWithGuid(
@@ -1492,9 +964,9 @@
 
   std::vector<AutofillProfile> sync_profiles;
   sync_profiles.push_back(sync_profile);
-  AddAutofillHelper<AutofillProfile> add_autofill(this, sync_profiles);
+  AddAutofillProfileHelper add_autofill(this, sync_profiles);
   EXPECT_CALL(personal_data_manager(), Refresh());
-  StartSyncService(add_autofill.callback(), false, AUTOFILL_PROFILE);
+  StartAutofillProfileSyncService(add_autofill.callback());
   ASSERT_TRUE(add_autofill.success());
 
   AutofillProfileChange change(AutofillProfileChange::REMOVE,
@@ -1507,62 +979,4 @@
   ASSERT_EQ(0U, new_sync_profiles.size());
 }
 
-TEST_F(ProfileSyncServiceAutofillTest, ServerChangeRace) {
-  // Once for MergeDataAndStartSyncing() and twice for ProcessSyncChanges(), via
-  // LoadAutofillData().
-  EXPECT_CALL(autofill_table(), GetAllAutofillEntries(_))
-      .Times(3)
-      .WillRepeatedly(Return(true));
-  // On the other hand Autofill and Autocomplete are separated now, so
-  // GetAutofillProfiles() should not be called.
-  EXPECT_CALL(autofill_table(), GetAutofillProfiles(_)).Times(0);
-  EXPECT_CALL(autofill_table(), UpdateAutofillEntries(_))
-      .WillRepeatedly(Return(true));
-  EXPECT_CALL(personal_data_manager(), Refresh()).Times(3);
-  CreateRootHelper create_root(this, AUTOFILL);
-  StartSyncService(create_root.callback(), false, AUTOFILL);
-  ASSERT_TRUE(create_root.success());
-
-  std::unique_ptr<WaitableEvent> wait_for_start(
-      new WaitableEvent(base::WaitableEvent::ResetPolicy::MANUAL,
-                        base::WaitableEvent::InitialState::NOT_SIGNALED));
-  std::unique_ptr<WaitableEvent> wait_for_syncapi(
-      new WaitableEvent(base::WaitableEvent::ResetPolicy::MANUAL,
-                        base::WaitableEvent::InitialState::NOT_SIGNALED));
-  scoped_refptr<FakeServerUpdater> updater(new FakeServerUpdater(
-      sync_service(), wait_for_start.get(), wait_for_syncapi.get(),
-      data_type_thread()->task_runner()));
-
-  // This server side update will stall waiting for CommitWaiter.
-  updater->CreateNewEntry(MakeAutofillEntry("server", "entry", 1));
-  wait_for_start->Wait();
-
-  AutofillEntry syncapi_entry(MakeAutofillEntry("syncapi", "entry", 2));
-  ASSERT_TRUE(AddAutofillSyncNode(syncapi_entry));
-  DVLOG(1) << "Syncapi update finished.";
-
-  // If we reach here, it means syncapi succeeded and we didn't deadlock. Yay!
-  // Signal FakeServerUpdater that it can complete.
-  wait_for_syncapi->Signal();
-
-  // Make another entry to ensure nothing broke afterwards and wait for finish
-  // to clean up.
-  updater->WaitForUpdateCompletion();
-  updater->CreateNewEntry(MakeAutofillEntry("server2", "entry2", 3));
-  updater->WaitForUpdateCompletion();
-
-  // Let callbacks posted on UI sequence execute.
-  base::RunLoop().RunUntilIdle();
-
-  std::vector<AutofillEntry> sync_entries;
-  std::vector<AutofillProfile> sync_profiles;
-  ASSERT_TRUE(GetAutofillEntriesFromSyncDB(&sync_entries, &sync_profiles));
-  EXPECT_EQ(3U, sync_entries.size());
-  EXPECT_EQ(0U, sync_profiles.size());
-  for (size_t i = 0; i < sync_entries.size(); i++) {
-    DVLOG(1) << "Entry " << i << ": " << sync_entries[i].key().name() << ", "
-             << sync_entries[i].key().value();
-  }
-}
-
 }  // namespace browser_sync
diff --git a/components/cronet/ios/test/BUILD.gn b/components/cronet/ios/test/BUILD.gn
index 7a074f5..a8da143d 100644
--- a/components/cronet/ios/test/BUILD.gn
+++ b/components/cronet/ios/test/BUILD.gn
@@ -30,7 +30,6 @@
     "//components/cronet/native/test:cronet_native_tests",
     "//components/cronet/test:test_support",
     "//components/grpc_support:bidirectional_stream_unittest",
-    "//components/grpc_support/test:quic_test_server",
     "//net",
     "//net:simple_quic_tools",
     "//net:test_support",
diff --git a/components/cronet/ios/test/cronet_http_test.mm b/components/cronet/ios/test/cronet_http_test.mm
index dafe20a..fb95316 100644
--- a/components/cronet/ios/test/cronet_http_test.mm
+++ b/components/cronet/ios/test/cronet_http_test.mm
@@ -16,10 +16,10 @@
 #include "components/cronet/ios/test/cronet_test_base.h"
 #include "components/cronet/ios/test/start_cronet.h"
 #include "components/cronet/test/test_server.h"
-#include "components/grpc_support/test/quic_test_server.h"
 #include "net/base/mac/url_conversions.h"
 #include "net/base/net_errors.h"
 #include "net/cert/mock_cert_verifier.h"
+#include "net/test/quic_simple_test_server.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/gtest_mac.h"
 
@@ -112,7 +112,7 @@
     [Cronet setRequestFilterBlock:^(NSURLRequest* request) {
       return YES;
     }];
-    StartCronet(grpc_support::GetQuicTestServerPort());
+    StartCronet(net::QuicSimpleTestServer::GetPort());
     [Cronet registerHttpProtocolHandler];
     NSURLSessionConfiguration* config =
         [NSURLSessionConfiguration ephemeralSessionConfiguration];
@@ -151,7 +151,7 @@
               [NSString stringWithFormat:@"{\"ssl_key_log_file\":\"%@\"}",
                                          ssl_key_log_file]];
 
-  StartCronet(grpc_support::GetQuicTestServerPort());
+  StartCronet(net::QuicSimpleTestServer::GetPort());
 
   bool ssl_file_created =
       [[NSFileManager defaultManager] fileExistsAtPath:ssl_key_log_file];
@@ -165,7 +165,7 @@
 }
 
 TEST_F(HttpTest, NSURLSessionReceivesData) {
-  NSURL* url = net::NSURLWithGURL(GURL(grpc_support::kTestServerSimpleUrl));
+  NSURL* url = net::NSURLWithGURL(net::QuicSimpleTestServer::GetSimpleURL());
   __block BOOL block_used = NO;
   NSURLSessionDataTask* task = [session_ dataTaskWithURL:url];
   [Cronet setRequestFilterBlock:^(NSURLRequest* request) {
@@ -176,19 +176,18 @@
   StartDataTaskAndWaitForCompletion(task);
   EXPECT_TRUE(block_used);
   EXPECT_EQ(nil, [delegate_ error]);
-  EXPECT_STREQ(grpc_support::kSimpleBodyValue,
-               base::SysNSStringToUTF8([delegate_ responseBody]).c_str());
+  EXPECT_EQ(net::QuicSimpleTestServer::GetSimpleBodyValue(),
+            base::SysNSStringToUTF8([delegate_ responseBody]));
 }
 
 TEST_F(HttpTest, GetGlobalMetricsDeltas) {
   NSData* delta1 = [Cronet getGlobalMetricsDeltas];
-
-  NSURL* url = net::NSURLWithGURL(GURL(grpc_support::kTestServerSimpleUrl));
+  NSURL* url = net::NSURLWithGURL(net::QuicSimpleTestServer::GetSimpleURL());
   NSURLSessionDataTask* task = [session_ dataTaskWithURL:url];
   StartDataTaskAndWaitForCompletion(task);
   EXPECT_EQ(nil, [delegate_ error]);
-  EXPECT_STREQ(grpc_support::kSimpleBodyValue,
-               base::SysNSStringToUTF8([delegate_ responseBody]).c_str());
+  EXPECT_EQ(net::QuicSimpleTestServer::GetSimpleBodyValue(),
+            base::SysNSStringToUTF8([delegate_ responseBody]));
 
   NSData* delta2 = [Cronet getGlobalMetricsDeltas];
   EXPECT_FALSE([delta2 isEqualToData:delta1]);
@@ -423,7 +422,7 @@
 
   [Cronet setBrotliEnabled:YES];
 
-  StartCronet(grpc_support::GetQuicTestServerPort());
+  StartCronet(net::QuicSimpleTestServer::GetPort());
 
   NSURL* url =
       net::NSURLWithGURL(GURL(TestServer::GetEchoHeaderURL("Accept-Encoding")));
@@ -438,7 +437,7 @@
 
   [Cronet setBrotliEnabled:NO];
 
-  StartCronet(grpc_support::GetQuicTestServerPort());
+  StartCronet(net::QuicSimpleTestServer::GetPort());
 
   NSURL* url =
       net::NSURLWithGURL(GURL(TestServer::GetEchoHeaderURL("Accept-Encoding")));
@@ -453,7 +452,7 @@
 
   [Cronet setBrotliEnabled:YES];
 
-  StartCronet(grpc_support::GetQuicTestServerPort());
+  StartCronet(net::QuicSimpleTestServer::GetPort());
 
   NSURL* url =
       net::NSURLWithGURL(GURL(TestServer::GetUseEncodingURL("brotli")));
@@ -679,7 +678,7 @@
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
 TEST_F(HttpTest, LegacyApi) {
-  NSURL* url = net::NSURLWithGURL(GURL(grpc_support::kTestServerSimpleUrl));
+  NSURL* url = net::NSURLWithGURL(net::QuicSimpleTestServer::GetSimpleURL());
 
   __block BOOL block_used = NO;
   [Cronet setRequestFilterBlock:^(NSURLRequest* request) {
diff --git a/components/cronet/ios/test/cronet_metrics_test.mm b/components/cronet/ios/test/cronet_metrics_test.mm
index f4032bd..d5849ab 100644
--- a/components/cronet/ios/test/cronet_metrics_test.mm
+++ b/components/cronet/ios/test/cronet_metrics_test.mm
@@ -8,8 +8,8 @@
 #include "components/cronet/ios/test/cronet_test_base.h"
 #include "components/cronet/ios/test/start_cronet.h"
 #include "components/cronet/test/test_server.h"
-#include "components/grpc_support/test/quic_test_server.h"
 #import "net/base/mac/url_conversions.h"
+#include "net/test/quic_simple_test_server.h"
 #include "testing/gtest_mac.h"
 #include "url/gurl.h"
 
@@ -26,7 +26,7 @@
     TestServer::Start();
 
     [Cronet setMetricsEnabled:metrics_enabled];
-    StartCronet(grpc_support::GetQuicTestServerPort());
+    StartCronet(net::QuicSimpleTestServer::GetPort());
 
     [Cronet registerHttpProtocolHandler];
     NSURLSessionConfiguration* config =
@@ -67,7 +67,7 @@
 // Tests that metrics data is sane for a QUIC request.
 TEST_F(CronetEnabledMetricsTest, ProtocolIsQuic) {
   if (@available(iOS 10, *)) {
-    NSURL* url = net::NSURLWithGURL(GURL(grpc_support::kTestServerSimpleUrl));
+    NSURL* url = net::NSURLWithGURL(net::QuicSimpleTestServer::GetSimpleURL());
 
     __block BOOL block_used = NO;
     NSURLSessionDataTask* task = [session_ dataTaskWithURL:url];
@@ -79,8 +79,8 @@
     StartDataTaskAndWaitForCompletion(task);
     EXPECT_TRUE(block_used);
     EXPECT_EQ(nil, [delegate_ error]);
-    EXPECT_STREQ(grpc_support::kSimpleBodyValue,
-                 base::SysNSStringToUTF8([delegate_ responseBody]).c_str());
+    EXPECT_EQ(net::QuicSimpleTestServer::GetSimpleBodyValue(),
+              base::SysNSStringToUTF8([delegate_ responseBody]));
 
     NSURLSessionTaskMetrics* task_metrics = delegate_.taskMetrics;
     ASSERT_TRUE(task_metrics);
@@ -246,7 +246,7 @@
 // Tests that the metrics API behaves sanely when the request is canceled.
 TEST_F(CronetEnabledMetricsTest, CanceledRequest) {
   if (@available(iOS 10, *)) {
-    NSURL* url = net::NSURLWithGURL(GURL(grpc_support::kTestServerSimpleUrl));
+    NSURL* url = net::NSURLWithGURL(net::QuicSimpleTestServer::GetSimpleURL());
 
     __block BOOL block_used = NO;
     NSURLSessionDataTask* task = [session_ dataTaskWithURL:url];
@@ -267,7 +267,7 @@
 // Tests the metrics data for a reused connection is correct.
 TEST_F(CronetEnabledMetricsTest, ReusedConnection) {
   if (@available(iOS 10, *)) {
-    NSURL* url = net::NSURLWithGURL(GURL(grpc_support::kTestServerSimpleUrl));
+    NSURL* url = net::NSURLWithGURL(net::QuicSimpleTestServer::GetSimpleURL());
 
     __block BOOL block_used = NO;
     NSURLSessionDataTask* task = [session_ dataTaskWithURL:url];
@@ -279,8 +279,8 @@
     StartDataTaskAndWaitForCompletion(task);
     EXPECT_TRUE(block_used);
     EXPECT_EQ(nil, [delegate_ error]);
-    EXPECT_STREQ(grpc_support::kSimpleBodyValue,
-                 base::SysNSStringToUTF8([delegate_ responseBody]).c_str());
+    EXPECT_EQ(net::QuicSimpleTestServer::GetSimpleBodyValue(),
+              base::SysNSStringToUTF8([delegate_ responseBody]));
 
     NSURLSessionTaskMetrics* task_metrics = [delegate_ taskMetrics];
     ASSERT_TRUE(task_metrics);
@@ -301,8 +301,8 @@
     StartDataTaskAndWaitForCompletion(task);
     EXPECT_TRUE(block_used);
     EXPECT_EQ(nil, [delegate_ error]);
-    EXPECT_STREQ(grpc_support::kSimpleBodyValue,
-                 base::SysNSStringToUTF8([delegate_ responseBody]).c_str());
+    EXPECT_EQ(net::QuicSimpleTestServer::GetSimpleBodyValue(),
+              base::SysNSStringToUTF8([delegate_ responseBody]));
 
     task_metrics = delegate_.taskMetrics;
     ASSERT_TRUE(task_metrics);
@@ -322,7 +322,7 @@
 // Tests that the metrics disable switch works.
 TEST_F(CronetDisabledMetricsTest, MetricsDisabled) {
   if (@available(iOS 10, *)) {
-    NSURL* url = net::NSURLWithGURL(GURL(grpc_support::kTestServerSimpleUrl));
+    NSURL* url = net::NSURLWithGURL(net::QuicSimpleTestServer::GetSimpleURL());
 
     __block BOOL block_used = NO;
     NSURLSessionDataTask* task = [session_ dataTaskWithURL:url];
@@ -334,8 +334,8 @@
     StartDataTaskAndWaitForCompletion(task);
     EXPECT_TRUE(block_used);
     EXPECT_EQ(nil, [delegate_ error]);
-    EXPECT_STREQ(grpc_support::kSimpleBodyValue,
-                 base::SysNSStringToUTF8([delegate_ responseBody]).c_str());
+    EXPECT_EQ(net::QuicSimpleTestServer::GetSimpleBodyValue(),
+              base::SysNSStringToUTF8([delegate_ responseBody]));
 
     NSURLSessionTaskMetrics* task_metrics = [delegate_ taskMetrics];
     ASSERT_TRUE(task_metrics);
@@ -362,7 +362,7 @@
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
 TEST_F(CronetEnabledMetricsTest, LegacyApi) {
-  NSURL* url = net::NSURLWithGURL(GURL(grpc_support::kTestServerSimpleUrl));
+  NSURL* url = net::NSURLWithGURL(net::QuicSimpleTestServer::GetSimpleURL());
 
   __block BOOL block_used = NO;
   [Cronet setRequestFilterBlock:^(NSURLRequest* request) {
diff --git a/components/cronet/ios/test/cronet_netlog_test.mm b/components/cronet/ios/test/cronet_netlog_test.mm
index f2e7f81..3eabe0e 100644
--- a/components/cronet/ios/test/cronet_netlog_test.mm
+++ b/components/cronet/ios/test/cronet_netlog_test.mm
@@ -7,7 +7,7 @@
 
 #include "components/cronet/ios/test/cronet_test_base.h"
 #include "components/cronet/ios/test/start_cronet.h"
-#include "components/grpc_support/test/quic_test_server.h"
+#include "net/test/quic_simple_test_server.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace cronet {
@@ -17,7 +17,7 @@
   NetLogTest() {}
   ~NetLogTest() override {}
 
-  void SetUp() override { StartCronet(grpc_support::GetQuicTestServerPort()); }
+  void SetUp() override { StartCronet(net::QuicSimpleTestServer::GetPort()); }
 
   void TearDown() override {
     [Cronet stopNetLog];
@@ -112,7 +112,7 @@
       setExperimentalOptions:
           @"{ \"QUIC\" : {\"max_server_configs_stored_in_properties\" : 8} }"];
 
-  StartCronet(grpc_support::GetQuicTestServerPort());
+  StartCronet(net::QuicSimpleTestServer::GetPort());
   bool netlog_started =
       [Cronet startNetLogToFile:@"cronet_netlog.json" logBytes:NO];
   ASSERT_TRUE(netlog_started);
diff --git a/components/cronet/ios/test/cronet_performance_test.mm b/components/cronet/ios/test/cronet_performance_test.mm
index a4bf39e..4d53f42 100644
--- a/components/cronet/ios/test/cronet_performance_test.mm
+++ b/components/cronet/ios/test/cronet_performance_test.mm
@@ -13,10 +13,10 @@
 #include "base/strings/sys_string_conversions.h"
 #include "components/cronet/ios/test/cronet_test_base.h"
 #include "components/cronet/test/test_server.h"
-#include "components/grpc_support/test/quic_test_server.h"
 #include "net/base/mac/url_conversions.h"
 #include "net/base/net_errors.h"
 #include "net/cert/mock_cert_verifier.h"
+#include "net/test/quic_simple_test_server.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/gtest_mac.h"
 #include "url/gurl.h"
@@ -138,7 +138,7 @@
     NSString* rules = base::SysUTF8ToNSString(
         base::StringPrintf("MAP test.example.com 127.0.0.1:%d,"
                            "MAP notfound.example.com ~NOTFOUND",
-                           grpc_support::GetQuicTestServerPort()));
+                           net::QuicSimpleTestServer::GetPort()));
     [Cronet setHostResolverRulesForTesting:rules];
     // This is the end of the behavior normally performed by StartCronet()
 
diff --git a/components/cronet/ios/test/cronet_pkp_test.mm b/components/cronet/ios/test/cronet_pkp_test.mm
index 4535515..e9defa60 100644
--- a/components/cronet/ios/test/cronet_pkp_test.mm
+++ b/components/cronet/ios/test/cronet_pkp_test.mm
@@ -4,15 +4,16 @@
 
 #import <Cronet/Cronet.h>
 
+#include "base/strings/sys_string_conversions.h"
 #include "components/cronet/ios/test/cronet_test_base.h"
 #include "components/cronet/ios/test/start_cronet.h"
-#include "components/grpc_support/test/quic_test_server.h"
 #include "net/base/mac/url_conversions.h"
 #include "net/cert/mock_cert_verifier.h"
 #include "net/test/cert_test_util.h"
+#include "net/test/quic_simple_test_server.h"
 #include "net/test/test_data_directory.h"
-
 #include "testing/gtest_mac.h"
+#include "url/gurl.h"
 
 namespace {
 const bool kIncludeSubdomains = true;
@@ -29,15 +30,13 @@
  protected:
   void SetUp() override {
     CronetTestBase::SetUp();
-    server_host_ = [NSString stringWithCString:grpc_support::kTestServerHost
-                                      encoding:NSUTF8StringEncoding];
-    server_domain_ = [NSString stringWithCString:grpc_support::kTestServerDomain
-                                        encoding:NSUTF8StringEncoding];
 
-    NSString* request_url_str =
-        [NSString stringWithCString:grpc_support::kTestServerSimpleUrl
-                           encoding:NSUTF8StringEncoding];
-    request_url_ = [NSURL URLWithString:request_url_str];
+    server_host_ =
+        base::SysUTF8ToNSString(net::QuicSimpleTestServer::GetHost());
+    server_domain_ =
+        base::SysUTF8ToNSString(net::QuicSimpleTestServer::GetDomain());
+    request_url_ =
+        net::NSURLWithGURL(net::QuicSimpleTestServer::GetSimpleURL());
 
     // Create a Cronet enabled NSURLSession.
     NSURLSessionConfiguration* sessionConfig =
@@ -89,7 +88,7 @@
                                              error:&error];
     CHECK(success);
     CHECK(!error);
-    StartCronet(grpc_support::GetQuicTestServerPort());
+    StartCronet(net::QuicSimpleTestServer::GetPort());
   }
 
   // Returns an arbitrary public key hash that doesn't match with any test
@@ -205,7 +204,7 @@
 
   // Restart Cronet engine and try the same request again. Since the pins are
   // not persisted, a successful response is expected.
-  StartCronet(grpc_support::GetQuicTestServerPort());
+  StartCronet(net::QuicSimpleTestServer::GetPort());
   ASSERT_NO_FATAL_FAILURE(sendRequestAndAssertResult(request_url_, kSuccess));
 }
 
diff --git a/components/cronet/ios/test/cronet_prefs_test.mm b/components/cronet/ios/test/cronet_prefs_test.mm
index 5104f5ac..12d7546 100644
--- a/components/cronet/ios/test/cronet_prefs_test.mm
+++ b/components/cronet/ios/test/cronet_prefs_test.mm
@@ -9,12 +9,13 @@
 #include "components/cronet/ios/test/cronet_test_base.h"
 #include "components/cronet/ios/test/start_cronet.h"
 #include "components/cronet/test/test_server.h"
-#include "components/grpc_support/test/quic_test_server.h"
 #include "net/base/mac/url_conversions.h"
+#include "net/test/quic_simple_test_server.h"
 #include "testing/gtest_mac.h"
 #include "url/gurl.h"
 
 namespace cronet {
+
 class PrefsTest : public CronetTestBase {
  protected:
   void SetUp() override {
@@ -97,10 +98,10 @@
   [Cronet setExperimentalOptions:options];
 
   // Start Cronet Engine
-  StartCronet(grpc_support::GetQuicTestServerPort());
+  StartCronet(net::QuicSimpleTestServer::GetPort());
 
   // Start the request
-  NSURL* url = net::NSURLWithGURL(GURL(grpc_support::kTestServerSimpleUrl));
+  NSURL* url = net::NSURLWithGURL(net::QuicSimpleTestServer::GetSimpleURL());
   NSURLSessionDataTask* task = [session_ dataTaskWithURL:url];
   StartDataTaskAndWaitForCompletion(task);
 
diff --git a/components/cronet/ios/test/cronet_quic_test.mm b/components/cronet/ios/test/cronet_quic_test.mm
index a29a6385..feae7918 100644
--- a/components/cronet/ios/test/cronet_quic_test.mm
+++ b/components/cronet/ios/test/cronet_quic_test.mm
@@ -7,9 +7,9 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/sys_string_conversions.h"
 #include "components/cronet/ios/test/cronet_test_base.h"
-#include "components/grpc_support/test/quic_test_server.h"
 #include "net/base/mac/url_conversions.h"
 #include "net/cert/mock_cert_verifier.h"
+#include "net/test/quic_simple_test_server.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/gtest_mac.h"
 #include "url/gurl.h"
@@ -38,7 +38,7 @@
     }];
 
     // QUIC Server simple URL.
-    simple_url_ = net::NSURLWithGURL(GURL(grpc_support::kTestServerSimpleUrl));
+    simple_url_ = net::NSURLWithGURL(net::QuicSimpleTestServer::GetSimpleURL());
   }
 
   void TearDown() override {
@@ -54,7 +54,7 @@
     NSString* rules = base::SysUTF8ToNSString(
         base::StringPrintf("MAP test.example.com 127.0.0.1:%d,"
                            "MAP notfound.example.com ~NOTFOUND",
-                           grpc_support::GetQuicTestServerPort()));
+                           net::QuicSimpleTestServer::GetPort()));
     [Cronet setHostResolverRulesForTesting:rules];
 
     // Prepare a session.
@@ -98,7 +98,7 @@
 
   // Check that a successful response was received using QUIC.
   EXPECT_EQ(nil, [delegate_ error]);
-  EXPECT_EQ(grpc_support::kSimpleBodyValue,
+  EXPECT_EQ(net::QuicSimpleTestServer::GetSimpleBodyValue(),
             base::SysNSStringToUTF8(delegate_.responseBody));
   if (@available(iOS 10, *)) {
     NSURLSessionTaskTransactionMetrics* metrics =
diff --git a/components/cronet/ios/test/cronet_test_base.mm b/components/cronet/ios/test/cronet_test_base.mm
index 712567a0..36e3562 100644
--- a/components/cronet/ios/test/cronet_test_base.mm
+++ b/components/cronet/ios/test/cronet_test_base.mm
@@ -6,13 +6,13 @@
 
 #include "base/location.h"
 #include "base/threading/thread.h"
-#include "components/grpc_support/test/quic_test_server.h"
 #include "crypto/sha2.h"
 #include "net/base/net_errors.h"
 #include "net/cert/asn1_util.h"
 #include "net/cert/mock_cert_verifier.h"
 #include "net/cert/x509_util.h"
 #include "net/test/cert_test_util.h"
+#include "net/test/quic_simple_test_server.h"
 #include "net/test/test_data_directory.h"
 
 #pragma mark
@@ -200,12 +200,12 @@
 
 void CronetTestBase::SetUp() {
   ::testing::Test::SetUp();
-  grpc_support::StartQuicTestServer();
+  net::QuicSimpleTestServer::Start();
   delegate_ = [[TestDelegate alloc] init];
 }
 
 void CronetTestBase::TearDown() {
-  grpc_support::ShutdownQuicTestServer();
+  net::QuicSimpleTestServer::Shutdown();
   ::testing::Test::TearDown();
 }
 
diff --git a/components/grpc_support/BUILD.gn b/components/grpc_support/BUILD.gn
index 95ada09..515aeba5 100644
--- a/components/grpc_support/BUILD.gn
+++ b/components/grpc_support/BUILD.gn
@@ -22,7 +22,6 @@
   deps = [
     ":grpc_support",
     "//base",
-    "//components/grpc_support/test:quic_test_server",
     "//net",
     "//net:test_support",
   ]
diff --git a/components/grpc_support/bidirectional_stream_unittest.cc b/components/grpc_support/bidirectional_stream_unittest.cc
index e0bea67..ed57fb64f 100644
--- a/components/grpc_support/bidirectional_stream_unittest.cc
+++ b/components/grpc_support/bidirectional_stream_unittest.cc
@@ -15,8 +15,8 @@
 #include "base/synchronization/waitable_event.h"
 #include "components/grpc_support/include/bidirectional_stream_c.h"
 #include "components/grpc_support/test/get_stream_engine.h"
-#include "components/grpc_support/test/quic_test_server.h"
 #include "net/base/net_errors.h"
+#include "net/test/quic_simple_test_server.h"
 #include "net/test/test_data_directory.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
@@ -36,23 +36,28 @@
 class BidirectionalStreamTest : public ::testing::TestWithParam<bool> {
  protected:
   void SetUp() override {
-    StartQuicTestServer();
-    StartTestStreamEngine(GetQuicTestServerPort());
+    net::QuicSimpleTestServer::Start();
+    StartTestStreamEngine(net::QuicSimpleTestServer::GetPort());
+    quic_server_hello_url_ = net::QuicSimpleTestServer::GetHelloURL().spec();
   }
 
   void TearDown() override {
     ShutdownTestStreamEngine();
-    ShutdownQuicTestServer();
+    net::QuicSimpleTestServer::Shutdown();
   }
 
   BidirectionalStreamTest() {}
   ~BidirectionalStreamTest() override {}
 
   stream_engine* engine() {
-    return GetTestStreamEngine(GetQuicTestServerPort());
+    return GetTestStreamEngine(net::QuicSimpleTestServer::GetPort());
   }
 
+  const char* test_hello_url() const { return quic_server_hello_url_.c_str(); }
+
  private:
+  std::string quic_server_hello_url_;
+
   DISALLOW_COPY_AND_ASSIGN(BidirectionalStreamTest);
 };
 
@@ -268,29 +273,40 @@
 TestBidirectionalStreamCallback::WriteData::~WriteData() {}
 
 TEST_P(BidirectionalStreamTest, StartExampleBidiStream) {
-  TestBidirectionalStreamCallback test;
-  test.AddWriteData("Hello, ");
-  test.AddWriteData("world!");
+  TestBidirectionalStreamCallback test_callback;
+  test_callback.AddWriteData("Hello, ");
+  test_callback.AddWriteData("world!");
   // Use small read buffer size to test that response is split properly.
-  test.read_buffer_size = 2;
-  test.stream = bidirectional_stream_create(engine(), &test, test.callback());
-  DCHECK(test.stream);
-  bidirectional_stream_delay_request_headers_until_flush(test.stream,
+  test_callback.read_buffer_size = 2;
+  test_callback.stream = bidirectional_stream_create(engine(), &test_callback,
+                                                     test_callback.callback());
+  DCHECK(test_callback.stream);
+  bidirectional_stream_delay_request_headers_until_flush(test_callback.stream,
                                                          GetParam());
-  bidirectional_stream_start(test.stream, kTestServerUrl, 0,
-                             "POST", &kTestHeadersArray, false);
-  test.BlockForDone();
-  ASSERT_EQ(std::string(kHelloStatus), test.response_headers[kStatusHeader]);
-  ASSERT_EQ(std::string(kHelloHeaderValue),
-            test.response_headers[kHelloHeaderName]);
-  ASSERT_EQ(TestBidirectionalStreamCallback::ON_SUCCEEDED, test.response_step);
-  ASSERT_EQ(std::string(kHelloBodyValue, 2), test.read_data.front());
+  bidirectional_stream_start(test_callback.stream, test_hello_url(), 0, "POST",
+                             &kTestHeadersArray, false);
+  test_callback.BlockForDone();
+  ASSERT_EQ(
+      net::QuicSimpleTestServer::GetHelloStatus(),
+      test_callback
+          .response_headers[net::QuicSimpleTestServer::GetStatusHeaderName()]);
+  ASSERT_EQ(
+      net::QuicSimpleTestServer::GetHelloHeaderValue(),
+      test_callback
+          .response_headers[net::QuicSimpleTestServer::GetHelloHeaderName()]);
+  ASSERT_EQ(TestBidirectionalStreamCallback::ON_SUCCEEDED,
+            test_callback.response_step);
+  ASSERT_EQ(std::string(net::QuicSimpleTestServer::GetHelloBodyValue(), 0, 2),
+            test_callback.read_data.front());
   // Verify that individual read data joined using empty separator match
   // expected body.
-  ASSERT_EQ(std::string(kHelloBodyValue), base::StrCat(test.read_data));
-  ASSERT_EQ(std::string(kHelloTrailerValue),
-            test.response_trailers[kHelloTrailerName]);
-  bidirectional_stream_destroy(test.stream);
+  ASSERT_EQ(net::QuicSimpleTestServer::GetHelloBodyValue(),
+            base::StrCat(test_callback.read_data));
+  ASSERT_EQ(
+      net::QuicSimpleTestServer::GetHelloTrailerValue(),
+      test_callback
+          .response_trailers[net::QuicSimpleTestServer::GetHelloTrailerName()]);
+  bidirectional_stream_destroy(test_callback.stream);
 }
 
 TEST_P(BidirectionalStreamTest, SimplePutWithEmptyWriteDataAtTheEnd) {
@@ -302,16 +318,21 @@
   DCHECK(test.stream);
   bidirectional_stream_delay_request_headers_until_flush(test.stream,
                                                          GetParam());
-  bidirectional_stream_start(test.stream, kTestServerUrl, 0,
-                             "PUT", &kTestHeadersArray, false);
+  bidirectional_stream_start(test.stream, test_hello_url(), 0, "PUT",
+                             &kTestHeadersArray, false);
   test.BlockForDone();
-  ASSERT_EQ(std::string(kHelloStatus), test.response_headers[kStatusHeader]);
-  ASSERT_EQ(std::string(kHelloHeaderValue),
-            test.response_headers[kHelloHeaderName]);
+  ASSERT_EQ(
+      net::QuicSimpleTestServer::GetHelloStatus(),
+      test.response_headers[net::QuicSimpleTestServer::GetStatusHeaderName()]);
+  ASSERT_EQ(
+      net::QuicSimpleTestServer::GetHelloHeaderValue(),
+      test.response_headers[net::QuicSimpleTestServer::GetHelloHeaderName()]);
   ASSERT_EQ(TestBidirectionalStreamCallback::ON_SUCCEEDED, test.response_step);
-  ASSERT_EQ(std::string(kHelloBodyValue), test.read_data.front());
-  ASSERT_EQ(std::string(kHelloTrailerValue),
-            test.response_trailers[kHelloTrailerName]);
+  ASSERT_EQ(net::QuicSimpleTestServer::GetHelloBodyValue(),
+            test.read_data.front());
+  ASSERT_EQ(
+      net::QuicSimpleTestServer::GetHelloTrailerValue(),
+      test.response_trailers[net::QuicSimpleTestServer::GetHelloTrailerName()]);
   bidirectional_stream_destroy(test.stream);
 }
 
@@ -324,16 +345,21 @@
                                                          GetParam());
   // Flush before start is ignored.
   bidirectional_stream_flush(test.stream);
-  bidirectional_stream_start(test.stream, kTestServerUrl, 0,
-                             "GET", &kTestHeadersArray, true);
+  bidirectional_stream_start(test.stream, test_hello_url(), 0, "GET",
+                             &kTestHeadersArray, true);
   test.BlockForDone();
-  ASSERT_EQ(std::string(kHelloStatus), test.response_headers[kStatusHeader]);
-  ASSERT_EQ(std::string(kHelloHeaderValue),
-            test.response_headers[kHelloHeaderName]);
+  ASSERT_EQ(
+      net::QuicSimpleTestServer::GetHelloStatus(),
+      test.response_headers[net::QuicSimpleTestServer::GetStatusHeaderName()]);
+  ASSERT_EQ(
+      net::QuicSimpleTestServer::GetHelloHeaderValue(),
+      test.response_headers[net::QuicSimpleTestServer::GetHelloHeaderName()]);
   ASSERT_EQ(TestBidirectionalStreamCallback::ON_SUCCEEDED, test.response_step);
-  ASSERT_EQ(std::string(kHelloBodyValue), base::StrCat(test.read_data));
-  ASSERT_EQ(std::string(kHelloTrailerValue),
-            test.response_trailers[kHelloTrailerName]);
+  ASSERT_EQ(net::QuicSimpleTestServer::GetHelloBodyValue(),
+            test.read_data.front());
+  ASSERT_EQ(
+      net::QuicSimpleTestServer::GetHelloTrailerValue(),
+      test.response_trailers[net::QuicSimpleTestServer::GetHelloTrailerName()]);
   // Flush after done is ignored.
   bidirectional_stream_flush(test.stream);
   bidirectional_stream_destroy(test.stream);
@@ -351,16 +377,21 @@
                                                          GetParam());
   // Flush before start is ignored.
   bidirectional_stream_flush(test.stream);
-  bidirectional_stream_start(test.stream, kTestServerUrl, 0,
-                             "POST", &kTestHeadersArray, false);
+  bidirectional_stream_start(test.stream, test_hello_url(), 0, "POST",
+                             &kTestHeadersArray, false);
   test.BlockForDone();
-  ASSERT_EQ(std::string(kHelloStatus), test.response_headers[kStatusHeader]);
-  ASSERT_EQ(std::string(kHelloHeaderValue),
-            test.response_headers[kHelloHeaderName]);
+  ASSERT_EQ(
+      net::QuicSimpleTestServer::GetHelloStatus(),
+      test.response_headers[net::QuicSimpleTestServer::GetStatusHeaderName()]);
+  ASSERT_EQ(
+      net::QuicSimpleTestServer::GetHelloHeaderValue(),
+      test.response_headers[net::QuicSimpleTestServer::GetHelloHeaderName()]);
   ASSERT_EQ(TestBidirectionalStreamCallback::ON_SUCCEEDED, test.response_step);
-  ASSERT_EQ(std::string(kHelloBodyValue), base::StrCat(test.read_data));
-  ASSERT_EQ(std::string(kHelloTrailerValue),
-            test.response_trailers[kHelloTrailerName]);
+  ASSERT_EQ(net::QuicSimpleTestServer::GetHelloBodyValue(),
+            base::StrCat(test.read_data));
+  ASSERT_EQ(
+      net::QuicSimpleTestServer::GetHelloTrailerValue(),
+      test.response_trailers[net::QuicSimpleTestServer::GetHelloTrailerName()]);
   // Flush after done is ignored.
   bidirectional_stream_flush(test.stream);
   bidirectional_stream_destroy(test.stream);
@@ -381,16 +412,21 @@
                                                          GetParam());
   // Flush before start is ignored.
   bidirectional_stream_flush(test.stream);
-  bidirectional_stream_start(test.stream, kTestServerUrl, 0,
-                             "POST", &kTestHeadersArray, false);
+  bidirectional_stream_start(test.stream, test_hello_url(), 0, "POST",
+                             &kTestHeadersArray, false);
   test.BlockForDone();
-  ASSERT_EQ(std::string(kHelloStatus), test.response_headers[kStatusHeader]);
-  ASSERT_EQ(std::string(kHelloHeaderValue),
-            test.response_headers[kHelloHeaderName]);
+  ASSERT_EQ(
+      net::QuicSimpleTestServer::GetHelloStatus(),
+      test.response_headers[net::QuicSimpleTestServer::GetStatusHeaderName()]);
+  ASSERT_EQ(
+      net::QuicSimpleTestServer::GetHelloHeaderValue(),
+      test.response_headers[net::QuicSimpleTestServer::GetHelloHeaderName()]);
   ASSERT_EQ(TestBidirectionalStreamCallback::ON_SUCCEEDED, test.response_step);
-  ASSERT_EQ(std::string(kHelloBodyValue), base::StrCat(test.read_data));
-  ASSERT_EQ(std::string(kHelloTrailerValue),
-            test.response_trailers[kHelloTrailerName]);
+  ASSERT_EQ(net::QuicSimpleTestServer::GetHelloBodyValue(),
+            base::StrCat(test.read_data));
+  ASSERT_EQ(
+      net::QuicSimpleTestServer::GetHelloTrailerValue(),
+      test.response_trailers[net::QuicSimpleTestServer::GetHelloTrailerName()]);
   // Flush after done is ignored.
   bidirectional_stream_flush(test.stream);
   bidirectional_stream_destroy(test.stream);
@@ -408,16 +444,21 @@
                                                          GetParam());
   // Flush before start is ignored.
   bidirectional_stream_flush(test.stream);
-  bidirectional_stream_start(test.stream, kTestServerUrl, 0,
-                             "POST", &kTestHeadersArray, false);
+  bidirectional_stream_start(test.stream, test_hello_url(), 0, "POST",
+                             &kTestHeadersArray, false);
   test.BlockForDone();
-  ASSERT_EQ(std::string(kHelloStatus), test.response_headers[kStatusHeader]);
-  ASSERT_EQ(std::string(kHelloHeaderValue),
-            test.response_headers[kHelloHeaderName]);
+  ASSERT_EQ(
+      net::QuicSimpleTestServer::GetHelloStatus(),
+      test.response_headers[net::QuicSimpleTestServer::GetStatusHeaderName()]);
+  ASSERT_EQ(
+      net::QuicSimpleTestServer::GetHelloHeaderValue(),
+      test.response_headers[net::QuicSimpleTestServer::GetHelloHeaderName()]);
   ASSERT_EQ(TestBidirectionalStreamCallback::ON_SUCCEEDED, test.response_step);
-  ASSERT_EQ(std::string(kHelloBodyValue), base::StrCat(test.read_data));
-  ASSERT_EQ(std::string(kHelloTrailerValue),
-            test.response_trailers[kHelloTrailerName]);
+  ASSERT_EQ(net::QuicSimpleTestServer::GetHelloBodyValue(),
+            base::StrCat(test.read_data));
+  ASSERT_EQ(
+      net::QuicSimpleTestServer::GetHelloTrailerValue(),
+      test.response_trailers[net::QuicSimpleTestServer::GetHelloTrailerName()]);
   // Flush after done is ignored.
   bidirectional_stream_flush(test.stream);
   bidirectional_stream_destroy(test.stream);
@@ -463,8 +504,8 @@
                                                          GetParam());
   // Flush before start is ignored.
   bidirectional_stream_flush(test.stream);
-  bidirectional_stream_start(test.stream, kTestServerUrl, 0,
-                             "POST", &kTestHeadersArray, false);
+  bidirectional_stream_start(test.stream, test_hello_url(), 0, "POST",
+                             &kTestHeadersArray, false);
   test.BlockForDone();
   // Flush after done is ignored.
   bidirectional_stream_flush(test.stream);
@@ -478,11 +519,14 @@
   bidirectional_stream_delay_request_headers_until_flush(test.stream,
                                                          GetParam());
   test.cancel_from_step = TestBidirectionalStreamCallback::ON_READ_COMPLETED;
-  bidirectional_stream_start(test.stream, kTestServerUrl, 0,
-                             "POST", &kTestHeadersArray, true);
+  bidirectional_stream_start(test.stream, test_hello_url(), 0, "POST",
+                             &kTestHeadersArray, true);
   test.BlockForDone();
-  ASSERT_EQ(std::string(kHelloStatus), test.response_headers[kStatusHeader]);
-  ASSERT_EQ(std::string(kHelloBodyValue), test.read_data.front());
+  ASSERT_EQ(
+      net::QuicSimpleTestServer::GetHelloStatus(),
+      test.response_headers[net::QuicSimpleTestServer::GetStatusHeaderName()]);
+  ASSERT_EQ(net::QuicSimpleTestServer::GetHelloBodyValue(),
+            test.read_data.front());
   ASSERT_EQ(TestBidirectionalStreamCallback::ON_CANCELED, test.response_step);
   bidirectional_stream_destroy(test.stream);
 }
@@ -494,10 +538,12 @@
   bidirectional_stream_delay_request_headers_until_flush(test.stream,
                                                          GetParam());
   test.cancel_from_step = TestBidirectionalStreamCallback::ON_RESPONSE_STARTED;
-  bidirectional_stream_start(test.stream, kTestServerUrl, 0,
-                             "POST", &kTestHeadersArray, true);
+  bidirectional_stream_start(test.stream, test_hello_url(), 0, "POST",
+                             &kTestHeadersArray, true);
   test.BlockForDone();
-  ASSERT_EQ(std::string(kHelloStatus), test.response_headers[kStatusHeader]);
+  ASSERT_EQ(
+      net::QuicSimpleTestServer::GetHelloStatus(),
+      test.response_headers[net::QuicSimpleTestServer::GetStatusHeaderName()]);
   ASSERT_TRUE(test.read_data.empty());
   ASSERT_EQ(TestBidirectionalStreamCallback::ON_CANCELED, test.response_step);
   bidirectional_stream_destroy(test.stream);
@@ -510,11 +556,14 @@
   bidirectional_stream_delay_request_headers_until_flush(test.stream,
                                                          GetParam());
   test.cancel_from_step = TestBidirectionalStreamCallback::ON_SUCCEEDED;
-  bidirectional_stream_start(test.stream, kTestServerUrl, 0,
-                             "POST", &kTestHeadersArray, true);
+  bidirectional_stream_start(test.stream, test_hello_url(), 0, "POST",
+                             &kTestHeadersArray, true);
   test.BlockForDone();
-  ASSERT_EQ(std::string(kHelloStatus), test.response_headers[kStatusHeader]);
-  ASSERT_EQ(std::string(kHelloBodyValue), test.read_data.front());
+  ASSERT_EQ(
+      net::QuicSimpleTestServer::GetHelloStatus(),
+      test.response_headers[net::QuicSimpleTestServer::GetStatusHeaderName()]);
+  ASSERT_EQ(net::QuicSimpleTestServer::GetHelloBodyValue(),
+            test.read_data.front());
   ASSERT_EQ(TestBidirectionalStreamCallback::ON_SUCCEEDED, test.response_step);
   bidirectional_stream_destroy(test.stream);
 }
@@ -540,7 +589,7 @@
     bool MaybeCancel(bidirectional_stream* stream, ResponseStep step) override {
       if (step == ResponseStep::ON_READ_COMPLETED) {
         // Shut down the server dispatcher, and the stream should error out.
-        ShutdownQuicTestServerDispatcher();
+        net::QuicSimpleTestServer::ShutdownDispatcherForTesting();
       }
       return TestBidirectionalStreamCallback::MaybeCancel(stream, step);
     }
@@ -554,8 +603,8 @@
   DCHECK(test.stream);
   bidirectional_stream_delay_request_headers_until_flush(test.stream,
                                                          GetParam());
-  bidirectional_stream_start(test.stream, kTestServerUrl, 0,
-                             "POST", &kTestHeadersArray, false);
+  bidirectional_stream_start(test.stream, test_hello_url(), 0, "POST",
+                             &kTestHeadersArray, false);
   test.BlockForDone();
   ASSERT_EQ(TestBidirectionalStreamCallback::ON_FAILED, test.response_step);
   ASSERT_TRUE(test.net_error == net::ERR_QUIC_PROTOCOL_ERROR ||
@@ -583,7 +632,7 @@
     bool MaybeCancel(bidirectional_stream* stream, ResponseStep step) override {
       if (step == ResponseStep::ON_STREAM_READY) {
         // Shut down the server dispatcher, and the stream should error out.
-        ShutdownQuicTestServerDispatcher();
+        net::QuicSimpleTestServer::ShutdownDispatcherForTesting();
       }
       return TestBidirectionalStreamCallback::MaybeCancel(stream, step);
     }
@@ -595,8 +644,8 @@
   DCHECK(test.stream);
   bidirectional_stream_delay_request_headers_until_flush(test.stream,
                                                          GetParam());
-  bidirectional_stream_start(test.stream, kTestServerUrl, 0,
-                             "POST", &kTestHeadersArray, false);
+  bidirectional_stream_start(test.stream, test_hello_url(), 0, "POST",
+                             &kTestHeadersArray, false);
   test.BlockForDone();
   ASSERT_EQ(TestBidirectionalStreamCallback::ON_FAILED, test.response_step);
   ASSERT_TRUE(test.net_error == net::ERR_QUIC_PROTOCOL_ERROR ||
@@ -612,7 +661,7 @@
     bool MaybeCancel(bidirectional_stream* stream, ResponseStep step) override {
       if (step == ResponseStep::ON_WRITE_COMPLETED) {
         // Shut down the server dispatcher, and the stream should error out.
-        ShutdownQuicTestServerDispatcher();
+        net::QuicSimpleTestServer::ShutdownDispatcherForTesting();
       }
       return TestBidirectionalStreamCallback::MaybeCancel(stream, step);
     }
@@ -626,8 +675,8 @@
   DCHECK(test.stream);
   bidirectional_stream_delay_request_headers_until_flush(test.stream,
                                                          GetParam());
-  bidirectional_stream_start(test.stream, kTestServerUrl, 0,
-                             "POST", &kTestHeadersArray, false);
+  bidirectional_stream_start(test.stream, test_hello_url(), 0, "POST",
+                             &kTestHeadersArray, false);
   test.BlockForDone();
   ASSERT_EQ(TestBidirectionalStreamCallback::ON_FAILED, test.response_step);
   ASSERT_TRUE(test.net_error == net::ERR_QUIC_PROTOCOL_ERROR ||
diff --git a/components/grpc_support/test/BUILD.gn b/components/grpc_support/test/BUILD.gn
index 6f3b7f0d..d0b39f6 100644
--- a/components/grpc_support/test/BUILD.gn
+++ b/components/grpc_support/test/BUILD.gn
@@ -5,7 +5,6 @@
   ]
 
   deps = [
-    ":quic_test_server",
     "//base",
     "//components/grpc_support",
     "//components/grpc_support:bidirectional_stream_unittest",
@@ -14,21 +13,6 @@
   ]
 }
 
-source_set("quic_test_server") {
-  testonly = true
-  sources = [
-    "quic_test_server.cc",
-    "quic_test_server.h",
-  ]
-
-  deps = [
-    "//base",
-    "//net",
-    "//net:simple_quic_tools",
-    "//net:test_support",
-  ]
-}
-
 source_set("get_stream_engine_header") {
   testonly = true
   sources = [
diff --git a/components/grpc_support/test/get_stream_engine.cc b/components/grpc_support/test/get_stream_engine.cc
index 02c4d1e7..dd9d851 100644
--- a/components/grpc_support/test/get_stream_engine.cc
+++ b/components/grpc_support/test/get_stream_engine.cc
@@ -3,6 +3,9 @@
 // found in the LICENSE file.
 
 #include <memory>
+#include <utility>
+
+#include "components/grpc_support/test/get_stream_engine.h"
 
 #include "base/lazy_instance.h"
 #include "base/macros.h"
@@ -13,12 +16,12 @@
 #include "base/strings/stringprintf.h"
 #include "base/threading/thread.h"
 #include "components/grpc_support/include/bidirectional_stream_c.h"
-#include "components/grpc_support/test/quic_test_server.h"
 #include "net/base/host_port_pair.h"
 #include "net/cert/mock_cert_verifier.h"
 #include "net/dns/mapped_host_resolver.h"
 #include "net/dns/mock_host_resolver.h"
 #include "net/http/http_server_properties_impl.h"
+#include "net/test/quic_simple_test_server.h"
 #include "net/url_request/url_request_test_util.h"
 
 namespace grpc_support {
@@ -53,7 +56,8 @@
       params->enable_quic = true;
       params->enable_http2 = true;
       net::AlternativeService alternative_service(net::kProtoQUIC, "", 443);
-      url::SchemeHostPort quic_hint_server("https", kTestServerHost, 443);
+      url::SchemeHostPort quic_hint_server(
+          "https", net::QuicSimpleTestServer::GetHost(), 443);
       server_properties_->SetQuicAlternativeService(
           quic_hint_server, alternative_service, base::Time::Max(),
           net::QuicTransportVersionVector());
diff --git a/components/grpc_support/test/quic_test_server.h b/components/grpc_support/test/quic_test_server.h
deleted file mode 100644
index 6bc25da0..0000000
--- a/components/grpc_support/test/quic_test_server.h
+++ /dev/null
@@ -1,47 +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 COMPONENTS_GRPC_SUPPORT_TEST_QUIC_TEST_SERVER_H_
-#define COMPONENTS_GRPC_SUPPORT_TEST_QUIC_TEST_SERVER_H_
-
-#include <string>
-
-namespace grpc_support {
-
-bool StartQuicTestServer();
-
-void ShutdownQuicTestServer();
-
-// Shuts down the server dispatcher, which results in sending ConnectionClose
-// frames to all connected clients.
-void ShutdownQuicTestServerDispatcher();
-
-int GetQuicTestServerPort();
-
-extern const char kTestServerDomain[];
-extern const char kTestServerHost[];
-extern const char kTestServerUrl[];
-
-extern const char kStatusHeader[];
-
-extern const char kHelloPath[];
-extern const char kHelloBodyValue[];
-extern const char kHelloStatus[];
-
-extern const char kHelloHeaderName[];
-extern const char kHelloHeaderValue[];
-
-extern const char kHelloTrailerName[];
-extern const char kHelloTrailerValue[];
-
-// Simple Url returns response without HTTP/2 trailers.
-extern const char kTestServerSimpleUrl[];
-extern const char kSimpleBodyValue[];
-extern const char kSimpleStatus[];
-extern const char kSimpleHeaderName[];
-extern const char kSimpleHeaderValue[];
-
-}  // namespace grpc_support
-
-#endif  // COMPONENTS_GRPC_SUPPORT_TEST_QUIC_TEST_SERVER_H_
diff --git a/components/nacl/broker/BUILD.gn b/components/nacl/broker/BUILD.gn
index 0e9b9d9..07ffe2a 100644
--- a/components/nacl/broker/BUILD.gn
+++ b/components/nacl/broker/BUILD.gn
@@ -49,6 +49,13 @@
     "//content/public/common/sandbox_init.h",
     "//content/public/common/sandboxed_process_launcher_delegate.h",
   ]
+
+  deps = [
+    # sandboxed_process_launcher_delegate.h includes headers generated from
+    # //content/public/common:zygote_buildflags, so this target needs to have a
+    # dep on it as well.
+    "//content/public/common:zygote_buildflags",
+  ]
 }
 
 if (current_cpu == "x86") {
@@ -144,7 +151,7 @@
     deps = [
       "//base",
       "//content/public/common:static_switches",
-      "//content/public/common:zygote_features",
+      "//content/public/common:zygote_buildflags",
       "//sandbox",
       "//services/service_manager/sandbox",
     ]
diff --git a/components/nacl/browser/BUILD.gn b/components/nacl/browser/BUILD.gn
index 5a1b541..467443a 100644
--- a/components/nacl/browser/BUILD.gn
+++ b/components/nacl/browser/BUILD.gn
@@ -39,7 +39,7 @@
     "//components/url_formatter",
     "//content/public/browser",
     "//content/public/common",
-    "//content/public/common:zygote_features",
+    "//content/public/common:zygote_buildflags",
     "//mojo/edk/system",
     "//native_client/src/trusted/service_runtime:sel_main_chrome",
     "//net",
diff --git a/components/nacl/browser/nacl_process_host.cc b/components/nacl/browser/nacl_process_host.cc
index b69582b..47524845 100644
--- a/components/nacl/browser/nacl_process_host.cc
+++ b/components/nacl/browser/nacl_process_host.cc
@@ -54,7 +54,7 @@
 #include "content/public/common/mojo_channel_switches.h"
 #include "content/public/common/process_type.h"
 #include "content/public/common/sandboxed_process_launcher_delegate.h"
-#include "content/public/common/zygote_features.h"
+#include "content/public/common/zygote_buildflags.h"
 #include "ipc/ipc_channel.h"
 #include "mojo/edk/embedder/embedder.h"
 #include "net/socket/socket_descriptor.h"
diff --git a/components/ntp_snippets/remote/remote_suggestions_status_service_impl.cc b/components/ntp_snippets/remote/remote_suggestions_status_service_impl.cc
index 80fb6ee3..fa2af3d 100644
--- a/components/ntp_snippets/remote/remote_suggestions_status_service_impl.cc
+++ b/components/ntp_snippets/remote/remote_suggestions_status_service_impl.cc
@@ -6,6 +6,7 @@
 
 #include <string>
 
+#include "base/feature_list.h"
 #include "components/ntp_snippets/content_suggestions_metrics.h"
 #include "components/ntp_snippets/features.h"
 #include "components/ntp_snippets/pref_names.h"
@@ -111,7 +112,9 @@
     return true;
   }
 
-  if (!list_visible_during_session_) {
+  if (base::FeatureList::IsEnabled(
+          ntp_snippets::kArticleSuggestionsExpandableHeader) &&
+      !list_visible_during_session_) {
     DVLOG(1) << "[GetStatusFromDeps] Disabled because articles list hidden.";
     return true;
   }
diff --git a/components/ntp_snippets/remote/remote_suggestions_status_service_impl_unittest.cc b/components/ntp_snippets/remote/remote_suggestions_status_service_impl_unittest.cc
index 9294376..829b2c0 100644
--- a/components/ntp_snippets/remote/remote_suggestions_status_service_impl_unittest.cc
+++ b/components/ntp_snippets/remote/remote_suggestions_status_service_impl_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 
+#include "base/test/scoped_feature_list.h"
 #include "build/build_config.h"
 #include "components/ntp_snippets/features.h"
 #include "components/ntp_snippets/ntp_snippets_constants.h"
@@ -40,6 +41,15 @@
   // is enabled.
   std::unique_ptr<RemoteSuggestionsStatusServiceImpl> MakeService(
       bool list_hiding_enabled) {
+    // Enabling/disabling the feature.
+    if (list_hiding_enabled) {
+      feature_list_.InitAndEnableFeature(
+          ntp_snippets::kArticleSuggestionsExpandableHeader);
+    } else {
+      feature_list_.InitAndDisableFeature(
+          ntp_snippets::kArticleSuggestionsExpandableHeader);
+    }
+
     auto service = std::make_unique<RemoteSuggestionsStatusServiceImpl>(
         false, utils_.pref_service(),
         list_hiding_enabled ? std::string() : kTestPrefName);
@@ -57,6 +67,7 @@
     last_status_ = new_status;
   }
 
+  base::test::ScopedFeatureList feature_list_;
   RemoteSuggestionsStatus last_status_;
   test::RemoteSuggestionsTestUtils utils_;
   variations::testing::VariationParamsManager params_manager_;
@@ -165,4 +176,17 @@
   EXPECT_EQ(RemoteSuggestionsStatus::ENABLED_AND_SIGNED_IN, last_status());
 }
 
+TEST_F(RemoteSuggestionsStatusServiceImplTest,
+       DisablingHidingFeatureWhenFolder) {
+  utils_.pref_service()->SetBoolean(prefs::kArticlesListVisible, false);
+  auto service = MakeService(/*list_hiding_enabled="*/ false);
+
+  // The state should be enabled when hiding is disabled.
+  EXPECT_EQ(RemoteSuggestionsStatus::ENABLED_AND_SIGNED_OUT, last_status());
+
+  // Signin should cause a state change.
+  service->OnSignInStateChanged(/*has_signed_in=*/true);
+  EXPECT_EQ(RemoteSuggestionsStatus::ENABLED_AND_SIGNED_IN, last_status());
+}
+
 }  // namespace ntp_snippets
diff --git a/components/password_manager/core/browser/password_form_manager.cc b/components/password_manager/core/browser/password_form_manager.cc
index 17194ee7..a215665 100644
--- a/components/password_manager/core/browser/password_form_manager.cc
+++ b/components/password_manager/core/browser/password_form_manager.cc
@@ -337,14 +337,13 @@
   if (CalculateFormSignature(form.form_data) == observed_form_signature_)
     result |= RESULT_SIGNATURE_MATCH;
 
-  if (!form.form_data.name.empty() &&
-      form.form_data.name == observed_form_.form_data.name)
+  if (form.form_data.name == observed_form_.form_data.name)
     result |= RESULT_FORM_NAME_MATCH;
 
   // Note: although saved password forms might actually have an empty action
   // URL if they were imported (see bug 1107719), the |form| we see here comes
   // never from the password store, and should have an exactly matching action.
-  if (!form.action.is_empty() && form.action == observed_form_.action)
+  if (form.action == observed_form_.action)
     result |= RESULT_ACTION_MATCH;
 
   return result;
diff --git a/components/password_manager/core/browser/password_form_manager_unittest.cc b/components/password_manager/core/browser/password_form_manager_unittest.cc
index 011dfad..6a4e6d2c 100644
--- a/components/password_manager/core/browser/password_form_manager_unittest.cc
+++ b/components/password_manager/core/browser/password_form_manager_unittest.cc
@@ -1893,24 +1893,18 @@
                 PasswordFormManager::RESULT_SIGNATURE_MATCH);
 }
 
-TEST_F(PasswordFormManagerTest, NoMatchForEmptyNames) {
-  // If two forms have no name, it's not evidence for a match.
+TEST_F(PasswordFormManagerTest, FormWithEmptyActionAndNameMatchesItself) {
+  observed_form()->form_data.name.clear();
+  observed_form()->action = GURL::EmptyGURL();
+  PasswordFormManager form_manager(
+      password_manager(), client(), client()->driver(), *observed_form(),
+      std::make_unique<NiceMock<MockFormSaver>>(), fake_form_fetcher());
+  form_manager.Init(nullptr);
+  // Any form should match itself regardless of missing properties. Otherwise,
+  // a PasswordFormManager instance is created for the same form multiple times.
   PasswordForm other_form(*observed_form());
-  const_cast<PasswordForm&>(form_manager()->observed_form())
-      .form_data.name.clear();
-  other_form.form_data.name.clear();
-  EXPECT_EQ(0, form_manager()->DoesManage(other_form, nullptr) &
-                   PasswordFormManager::RESULT_FORM_NAME_MATCH);
-}
-
-TEST_F(PasswordFormManagerTest, NoMatchForEmtpyActions) {
-  // If two forms have no actions, it's not evidence for a match.
-  PasswordForm other_form(*observed_form());
-  const_cast<PasswordForm&>(form_manager()->observed_form()).form_data.action =
-      GURL::EmptyGURL();
-  other_form.action = GURL::EmptyGURL();
-  EXPECT_EQ(0, form_manager()->DoesManage(other_form, nullptr) &
-                   PasswordFormManager::RESULT_ACTION_MATCH);
+  EXPECT_EQ(PasswordFormManager::RESULT_COMPLETE_MATCH,
+            form_manager.DoesManage(other_form, nullptr));
 }
 
 // Test that if multiple credentials with the same username are stored, and the
diff --git a/components/password_manager/core/browser/password_manager_unittest.cc b/components/password_manager/core/browser/password_manager_unittest.cc
index 5d498c0c..593519f2 100644
--- a/components/password_manager/core/browser/password_manager_unittest.cc
+++ b/components/password_manager/core/browser/password_manager_unittest.cc
@@ -2257,6 +2257,8 @@
   };
 
   const std::vector<PasswordForm> observed = {PasswordForm()};
+  // PasswordStore requested only once for the same form.
+  EXPECT_CALL(*store_, GetLogins(_, _));
 
   for (const auto& test_case : kCases) {
     SCOPED_TRACE(testing::Message("index of test_case = ")
@@ -2264,7 +2266,6 @@
     EXPECT_CALL(client_, GetMainFrameCertStatus())
         .WillRepeatedly(Return(test_case.cert_status));
     base::HistogramTester histogram_tester;
-    EXPECT_CALL(*store_, GetLogins(_, _));
     manager()->OnPasswordFormsParsed(&driver_, observed);
     histogram_tester.ExpectUniqueSample(
         "PasswordManager.CertificateErrorsWhileSeeingForms",
diff --git a/components/patch_service/public/cpp/patch.cc b/components/patch_service/public/cpp/patch.cc
index 14d3b05..837fb25 100644
--- a/components/patch_service/public/cpp/patch.cc
+++ b/components/patch_service/public/cpp/patch.cc
@@ -49,6 +49,7 @@
 };
 
 void PatchDone(scoped_refptr<PatchParams> params, int result) {
+  params->file_patcher()->reset();
   PatchCallback cb = params->TakeCallback();
   if (!cb.is_null())
     std::move(cb).Run(result);
diff --git a/components/safe_browsing/common/BUILD.gn b/components/safe_browsing/common/BUILD.gn
index 7e01e18..b003b51 100644
--- a/components/safe_browsing/common/BUILD.gn
+++ b/components/safe_browsing/common/BUILD.gn
@@ -52,6 +52,7 @@
     "//base:base",
     "//base/test:test_support",
     "//components/prefs:test_support",
+    "//content/test:test_support",
     "//testing/gtest",
     "//url:url",
   ]
diff --git a/components/safe_browsing/common/DEPS b/components/safe_browsing/common/DEPS
index 60d09aae..0e7f7e1 100644
--- a/components/safe_browsing/common/DEPS
+++ b/components/safe_browsing/common/DEPS
@@ -1,6 +1,7 @@
 include_rules = [
   "+components/pref_registry",
   "+components/prefs",
+  "+content/public/test",
   "+crypto/sha2.h",
   "+ipc",
   "+url"
diff --git a/components/safe_browsing/common/safe_browsing_prefs.cc b/components/safe_browsing/common/safe_browsing_prefs.cc
index 3fcc848..0ca4bb2 100644
--- a/components/safe_browsing/common/safe_browsing_prefs.cc
+++ b/components/safe_browsing/common/safe_browsing_prefs.cc
@@ -526,6 +526,8 @@
 bool IsURLWhitelistedByPolicy(const GURL& url,
                               StringListPrefMember* pref_member) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+  if (!pref_member)
+    return false;
   std::vector<std::string> sb_whitelist_domains = pref_member->GetValue();
   return std::find_if(sb_whitelist_domains.begin(), sb_whitelist_domains.end(),
                       [&url](const std::string& domain) {
diff --git a/components/safe_browsing/common/safe_browsing_prefs_unittest.cc b/components/safe_browsing/common/safe_browsing_prefs_unittest.cc
index 34882c6..08ccaa9 100644
--- a/components/safe_browsing/common/safe_browsing_prefs_unittest.cc
+++ b/components/safe_browsing/common/safe_browsing_prefs_unittest.cc
@@ -12,6 +12,7 @@
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/testing_pref_service.h"
 #include "components/safe_browsing/common/safe_browsing_prefs.h"
+#include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
 
@@ -35,6 +36,8 @@
     prefs_.registry()->RegisterListPref(prefs::kPasswordProtectionLoginURLs);
     prefs_.registry()->RegisterBooleanPref(
         prefs::kSafeBrowsingExtendedReportingOptInAllowed, true);
+    prefs_.registry()->RegisterListPref(prefs::kSafeBrowsingWhitelistDomains);
+
     ResetExperiments(/*can_show_scout=*/false);
   }
 
@@ -112,6 +115,7 @@
 
  private:
   std::unique_ptr<base::test::ScopedFeatureList> feature_list_;
+  content::TestBrowserThreadBundle thread_bundle_;
 };
 
 // This test ensures that we correctly select between SBER and Scout as the
@@ -422,4 +426,23 @@
   EXPECT_TRUE(IsExtendedReportingOptInAllowed(prefs_));
 }
 
+TEST_F(SafeBrowsingPrefsTest, VerifyIsURLWhitelistedByPolicy) {
+  GURL target_url("https://www.foo.com");
+  // When PrefMember is null, URL is not whitelisted.
+  EXPECT_FALSE(IsURLWhitelistedByPolicy(target_url, nullptr));
+
+  EXPECT_FALSE(prefs_.HasPrefPath(prefs::kSafeBrowsingWhitelistDomains));
+  base::ListValue whitelisted_domains;
+  whitelisted_domains.AppendString("foo.com");
+  prefs_.Set(prefs::kSafeBrowsingWhitelistDomains, whitelisted_domains);
+  StringListPrefMember string_list_pref;
+  string_list_pref.Init(prefs::kSafeBrowsingWhitelistDomains, &prefs_);
+  EXPECT_TRUE(IsURLWhitelistedByPolicy(target_url, prefs_));
+  EXPECT_TRUE(IsURLWhitelistedByPolicy(target_url, &string_list_pref));
+
+  GURL not_whitelisted_url("https://www.bar.com");
+  EXPECT_FALSE(IsURLWhitelistedByPolicy(not_whitelisted_url, prefs_));
+  EXPECT_FALSE(
+      IsURLWhitelistedByPolicy(not_whitelisted_url, &string_list_pref));
+}
 }  // namespace safe_browsing
diff --git a/components/sync/driver/about_sync_util.cc b/components/sync/driver/about_sync_util.cc
index 18d80bd..f848f68 100644
--- a/components/sync/driver/about_sync_util.cc
+++ b/components/sync/driver/about_sync_util.cc
@@ -527,10 +527,8 @@
   }
 
   if (snapshot.is_initialized()) {
-    if (snapshot.legacy_updates_source() !=
-        sync_pb::GetUpdatesCallerInfo::UNKNOWN) {
-      session_source.SetValue(
-          ProtoEnumToString(snapshot.legacy_updates_source()));
+    if (snapshot.get_updates_origin() != sync_pb::SyncEnums::UNKNOWN_ORIGIN) {
+      session_source.SetValue(ProtoEnumToString(snapshot.get_updates_origin()));
     }
     get_key_result.SetValue(GetSyncerErrorString(
         snapshot.model_neutral_state().last_get_key_result));
diff --git a/components/sync/engine/cycle/sync_cycle_snapshot.cc b/components/sync/engine/cycle/sync_cycle_snapshot.cc
index fab6c65..20823b51 100644
--- a/components/sync/engine/cycle/sync_cycle_snapshot.cc
+++ b/components/sync/engine/cycle/sync_cycle_snapshot.cc
@@ -36,7 +36,7 @@
     base::Time poll_finish_time,
     const std::vector<int>& num_entries_by_type,
     const std::vector<int>& num_to_delete_entries_by_type,
-    sync_pb::GetUpdatesCallerInfo::GetUpdatesSource legacy_updates_source)
+    sync_pb::SyncEnums::GetUpdatesOrigin get_updates_origin)
     : model_neutral_state_(model_neutral_state),
       download_progress_markers_(download_progress_markers),
       is_silenced_(is_silenced),
@@ -49,7 +49,7 @@
       poll_finish_time_(poll_finish_time),
       num_entries_by_type_(num_entries_by_type),
       num_to_delete_entries_by_type_(num_to_delete_entries_by_type),
-      legacy_updates_source_(legacy_updates_source),
+      get_updates_origin_(get_updates_origin),
       is_initialized_(true) {}
 
 SyncCycleSnapshot::SyncCycleSnapshot(const SyncCycleSnapshot& other) = default;
@@ -82,7 +82,7 @@
   value->SetInteger("numHierarchyConflicts", num_hierarchy_conflicts_);
   value->SetInteger("numServerConflicts", num_server_conflicts_);
   value->SetInteger("numEntries", num_entries_);
-  value->SetString("legacySource", ProtoEnumToString(legacy_updates_source_));
+  value->SetString("getUpdatesOrigin", ProtoEnumToString(get_updates_origin_));
   value->SetBoolean("notificationsEnabled", notifications_enabled_);
 
   std::unique_ptr<base::DictionaryValue> counter_entries(
@@ -157,9 +157,9 @@
   return num_to_delete_entries_by_type_;
 }
 
-sync_pb::GetUpdatesCallerInfo::GetUpdatesSource
-SyncCycleSnapshot::legacy_updates_source() const {
-  return legacy_updates_source_;
+sync_pb::SyncEnums::GetUpdatesOrigin SyncCycleSnapshot::get_updates_origin()
+    const {
+  return get_updates_origin_;
 }
 
 }  // namespace syncer
diff --git a/components/sync/engine/cycle/sync_cycle_snapshot.h b/components/sync/engine/cycle/sync_cycle_snapshot.h
index 1897af2..62aee7e 100644
--- a/components/sync/engine/cycle/sync_cycle_snapshot.h
+++ b/components/sync/engine/cycle/sync_cycle_snapshot.h
@@ -30,20 +30,19 @@
 class SyncCycleSnapshot {
  public:
   SyncCycleSnapshot();
-  SyncCycleSnapshot(
-      const ModelNeutralState& model_neutral_state,
-      const ProgressMarkerMap& download_progress_markers,
-      bool is_silenced,
-      int num_encryption_conflicts,
-      int num_hierarchy_conflicts,
-      int num_server_conflicts,
-      bool notifications_enabled,
-      size_t num_entries,
-      base::Time sync_start_time,
-      base::Time poll_finish_time,
-      const std::vector<int>& num_entries_by_type,
-      const std::vector<int>& num_to_delete_entries_by_type,
-      sync_pb::GetUpdatesCallerInfo::GetUpdatesSource legacy_updates_source);
+  SyncCycleSnapshot(const ModelNeutralState& model_neutral_state,
+                    const ProgressMarkerMap& download_progress_markers,
+                    bool is_silenced,
+                    int num_encryption_conflicts,
+                    int num_hierarchy_conflicts,
+                    int num_server_conflicts,
+                    bool notifications_enabled,
+                    size_t num_entries,
+                    base::Time sync_start_time,
+                    base::Time poll_finish_time,
+                    const std::vector<int>& num_entries_by_type,
+                    const std::vector<int>& num_to_delete_entries_by_type,
+                    sync_pb::SyncEnums::GetUpdatesOrigin get_updates_origin);
   SyncCycleSnapshot(const SyncCycleSnapshot& other);
   ~SyncCycleSnapshot();
 
@@ -63,7 +62,7 @@
   base::Time poll_finish_time() const;
   const std::vector<int>& num_entries_by_type() const;
   const std::vector<int>& num_to_delete_entries_by_type() const;
-  sync_pb::GetUpdatesCallerInfo::GetUpdatesSource legacy_updates_source() const;
+  sync_pb::SyncEnums::GetUpdatesOrigin get_updates_origin() const;
 
   // Set iff this snapshot was not built using the default constructor.
   bool is_initialized() const;
@@ -83,10 +82,7 @@
   std::vector<int> num_entries_by_type_;
   std::vector<int> num_to_delete_entries_by_type_;
 
-  // This enum value used to be an important part of the sync protocol, but is
-  // now deprecated.  We continue to use it in the snapshot because there is
-  // still some value in displaying it on the about:sync page.
-  sync_pb::GetUpdatesCallerInfo::GetUpdatesSource legacy_updates_source_;
+  sync_pb::SyncEnums::GetUpdatesOrigin get_updates_origin_;
 
   bool is_initialized_;
 };
diff --git a/components/sync/engine/cycle/sync_cycle_snapshot_unittest.cc b/components/sync/engine/cycle/sync_cycle_snapshot_unittest.cc
index 2e7c2b9..ca0f243 100644
--- a/components/sync/engine/cycle/sync_cycle_snapshot_unittest.cc
+++ b/components/sync/engine/cycle/sync_cycle_snapshot_unittest.cc
@@ -47,7 +47,7 @@
                              0, base::Time::Now(), base::Time::Now(),
                              std::vector<int>(MODEL_TYPE_COUNT, 0),
                              std::vector<int>(MODEL_TYPE_COUNT, 0),
-                             sync_pb::GetUpdatesCallerInfo::UNKNOWN);
+                             sync_pb::SyncEnums::UNKNOWN_ORIGIN);
   std::unique_ptr<base::DictionaryValue> value(snapshot.ToValue());
   EXPECT_EQ(16u, value->size());
   ExpectDictIntegerValue(model_neutral.num_successful_commits, *value,
diff --git a/components/sync/engine/sync_manager_factory_for_profile_sync_test.cc b/components/sync/engine/sync_manager_factory_for_profile_sync_test.cc
index 1911dfb..949d3c02 100644
--- a/components/sync/engine/sync_manager_factory_for_profile_sync_test.cc
+++ b/components/sync/engine/sync_manager_factory_for_profile_sync_test.cc
@@ -9,8 +9,8 @@
 namespace syncer {
 
 SyncManagerFactoryForProfileSyncTest::SyncManagerFactoryForProfileSyncTest(
-    base::Closure init_callback)
-    : SyncManagerFactory(), init_callback_(init_callback) {}
+    base::OnceClosure init_callback)
+    : SyncManagerFactory(), init_callback_(std::move(init_callback)) {}
 
 SyncManagerFactoryForProfileSyncTest::~SyncManagerFactoryForProfileSyncTest() {}
 
@@ -18,7 +18,7 @@
 SyncManagerFactoryForProfileSyncTest::CreateSyncManager(
     const std::string& name) {
   return std::unique_ptr<SyncManager>(
-      new SyncManagerForProfileSyncTest(name, init_callback_));
+      new SyncManagerForProfileSyncTest(name, std::move(init_callback_)));
 }
 
 }  // namespace syncer
diff --git a/components/sync/engine/sync_manager_factory_for_profile_sync_test.h b/components/sync/engine/sync_manager_factory_for_profile_sync_test.h
index 2956cb3..c3eee0a 100644
--- a/components/sync/engine/sync_manager_factory_for_profile_sync_test.h
+++ b/components/sync/engine/sync_manager_factory_for_profile_sync_test.h
@@ -15,13 +15,14 @@
 
 class SyncManagerFactoryForProfileSyncTest : public SyncManagerFactory {
  public:
-  explicit SyncManagerFactoryForProfileSyncTest(base::Closure init_callback);
+  explicit SyncManagerFactoryForProfileSyncTest(
+      base::OnceClosure init_callback);
   ~SyncManagerFactoryForProfileSyncTest() override;
   std::unique_ptr<SyncManager> CreateSyncManager(
       const std::string& name) override;
 
  private:
-  base::Closure init_callback_;
+  base::OnceClosure init_callback_;
 };
 
 }  // namespace syncer
diff --git a/components/sync/engine_impl/conflict_resolver.cc b/components/sync/engine_impl/conflict_resolver.cc
index 53236cf..fabcbcc 100644
--- a/components/sync/engine_impl/conflict_resolver.cc
+++ b/components/sync/engine_impl/conflict_resolver.cc
@@ -4,7 +4,6 @@
 
 #include "components/sync/engine_impl/conflict_resolver.h"
 
-#include <list>
 #include <string>
 
 #include "base/metrics/histogram_macros.h"
@@ -17,7 +16,6 @@
 #include "components/sync/syncable/mutable_entry.h"
 #include "components/sync/syncable/syncable_write_transaction.h"
 
-using std::list;
 using std::set;
 
 namespace syncer {
@@ -27,39 +25,6 @@
 using syncable::Id;
 using syncable::MutableEntry;
 
-namespace {
-
-// Returns true iff the set of attachment ids contained in attachment_metadata
-// matches the set of ids contained in server_attachment_metadata.
-bool AttachmentMetadataMatches(const MutableEntry& entity) {
-  const sync_pb::AttachmentMetadata& local = entity.GetAttachmentMetadata();
-  const sync_pb::AttachmentMetadata& server =
-      entity.GetServerAttachmentMetadata();
-  if (local.record_size() != server.record_size()) {
-    return false;
-  }
-
-  // The order of records in local and server may be different so use a std::set
-  // to determine if they are equivalent.
-  std::set<std::string> local_ids;
-  for (int i = 0; i < local.record_size(); ++i) {
-    const sync_pb::AttachmentMetadataRecord& record = local.record(i);
-    DCHECK(record.is_on_server());
-    local_ids.insert(record.id().SerializeAsString());
-  }
-  for (int i = 0; i < server.record_size(); ++i) {
-    const sync_pb::AttachmentMetadataRecord& record = server.record(i);
-    DCHECK(record.is_on_server());
-    if (local_ids.find(record.id().SerializeAsString()) == local_ids.end()) {
-      return false;
-    }
-  }
-
-  return true;
-}
-
-}  // namespace
-
 ConflictResolver::ConflictResolver() {}
 
 ConflictResolver::~ConflictResolver() {}
@@ -181,9 +146,8 @@
         base_server_specifics_match = true;
     }
 
-    bool attachment_metadata_matches = AttachmentMetadataMatches(entry);
     if (!entry_deleted && name_matches && parent_matches && specifics_match &&
-        position_matches && attachment_metadata_matches) {
+        position_matches) {
       DVLOG(1) << "Resolving simple conflict, everything matches, ignoring "
                << "changes for: " << entry;
       conflict_util::IgnoreConflict(&entry);
diff --git a/components/sync/engine_impl/cycle/nudge_tracker.cc b/components/sync/engine_impl/cycle/nudge_tracker.cc
index 40d26e5..8b327e6 100644
--- a/components/sync/engine_impl/cycle/nudge_tracker.cc
+++ b/components/sync/engine_impl/cycle/nudge_tracker.cc
@@ -299,53 +299,22 @@
   type_trackers_.find(type)->second->SetLegacyNotificationHint(progress);
 }
 
-sync_pb::GetUpdatesCallerInfo::GetUpdatesSource NudgeTracker::GetLegacySource()
-    const {
-  // There's an order to these sources: NOTIFICATION, DATATYPE_REFRESH, LOCAL,
-  // RETRY.  The server makes optimization decisions based on this field, so
-  // it's important to get this right.  Setting it wrong could lead to missed
-  // updates.
-  //
-  // This complexity is part of the reason why we're deprecating 'source' in
-  // favor of 'origin'.
-  bool has_invalidation_pending = false;
-  bool has_refresh_request_pending = false;
-  bool has_commit_pending = false;
-  bool is_initial_sync_required = false;
-  bool has_retry = IsRetryRequired();
-
-  for (TypeTrackerMap::const_iterator it = type_trackers_.begin();
-       it != type_trackers_.end(); ++it) {
-    const DataTypeTracker& tracker = *it->second;
-    if (!tracker.IsBlocked() && tracker.HasPendingInvalidation()) {
-      has_invalidation_pending = true;
-    }
-    if (!tracker.IsBlocked() && tracker.HasRefreshRequestPending()) {
-      has_refresh_request_pending = true;
-    }
-    if (!tracker.IsBlocked() && tracker.HasLocalChangePending()) {
-      has_commit_pending = true;
-    }
-    if (!tracker.IsBlocked() && tracker.IsInitialSyncRequired()) {
-      is_initial_sync_required = true;
+sync_pb::SyncEnums::GetUpdatesOrigin NudgeTracker::GetOrigin() const {
+  for (const auto& type_and_tracker : type_trackers_) {
+    const DataTypeTracker& tracker = *type_and_tracker.second;
+    if (!tracker.IsBlocked() &&
+        (tracker.HasPendingInvalidation() ||
+         tracker.HasRefreshRequestPending() ||
+         tracker.HasLocalChangePending() || tracker.IsInitialSyncRequired())) {
+      return sync_pb::SyncEnums::GU_TRIGGER;
     }
   }
 
-  if (has_invalidation_pending) {
-    return sync_pb::GetUpdatesCallerInfo::NOTIFICATION;
-  } else if (has_refresh_request_pending) {
-    return sync_pb::GetUpdatesCallerInfo::DATATYPE_REFRESH;
-  } else if (is_initial_sync_required) {
-    // Not quite accurate, but good enough for our purposes.  This setting of
-    // SOURCE is just a backward-compatibility hack anyway.
-    return sync_pb::GetUpdatesCallerInfo::DATATYPE_REFRESH;
-  } else if (has_commit_pending) {
-    return sync_pb::GetUpdatesCallerInfo::LOCAL;
-  } else if (has_retry) {
-    return sync_pb::GetUpdatesCallerInfo::RETRY;
-  } else {
-    return sync_pb::GetUpdatesCallerInfo::UNKNOWN;
+  if (IsRetryRequired()) {
+    return sync_pb::SyncEnums::RETRY;
   }
+
+  return sync_pb::SyncEnums::UNKNOWN_ORIGIN;
 }
 
 void NudgeTracker::FillProtoMessage(ModelType type,
diff --git a/components/sync/engine_impl/cycle/nudge_tracker.h b/components/sync/engine_impl/cycle/nudge_tracker.h
index f63923e..57fd37c 100644
--- a/components/sync/engine_impl/cycle/nudge_tracker.h
+++ b/components/sync/engine_impl/cycle/nudge_tracker.h
@@ -117,15 +117,8 @@
   // Returns the set of types that have pending refresh requests.
   ModelTypeSet GetRefreshRequestedTypes() const;
 
-  // Returns the 'source' of the GetUpdate request.
-  //
-  // This flag is deprecated, but still used by the server.  There can be more
-  // than one reason to perform a particular sync cycle.  The GetUpdatesTrigger
-  // message will contain more reliable information about the reasons for
-  // performing a sync.
-  //
-  // See the implementation for important information about the coalesce logic.
-  sync_pb::GetUpdatesCallerInfo::GetUpdatesSource GetLegacySource() const;
+  // Returns the 'origin' of the GetUpdate request.
+  sync_pb::SyncEnums::GetUpdatesOrigin GetOrigin() const;
 
   // Fills a GetUpdatesTrigger message for the next GetUpdates request.  This is
   // used by the DownloadUpdatesCommand to dump lots of useful per-type state
diff --git a/components/sync/engine_impl/cycle/nudge_tracker_unittest.cc b/components/sync/engine_impl/cycle/nudge_tracker_unittest.cc
index f3dbf35..cab1d19 100644
--- a/components/sync/engine_impl/cycle/nudge_tracker_unittest.cc
+++ b/components/sync/engine_impl/cycle/nudge_tracker_unittest.cc
@@ -97,76 +97,43 @@
   // Now we're at the normal, "idle" state.
   EXPECT_FALSE(nudge_tracker_.IsSyncRequired());
   EXPECT_FALSE(nudge_tracker_.IsGetUpdatesRequired());
-  EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::UNKNOWN,
-            nudge_tracker_.GetLegacySource());
 
   sync_pb::GetUpdateTriggers gu_trigger;
   nudge_tracker_.FillProtoMessage(BOOKMARKS, &gu_trigger);
-
-  EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::UNKNOWN,
-            nudge_tracker_.GetLegacySource());
 }
 
 // Verify that nudges override each other based on a priority order.
-// RETRY < LOCAL < DATATYPE_REFRESH < NOTIFICATION
+// RETRY < all variants of GU_TRIGGER
 TEST_F(NudgeTrackerTest, SourcePriorities) {
   // Start with a retry request.
   const base::TimeTicks t0 = base::TimeTicks::FromInternalValue(1234);
   const base::TimeTicks t1 = t0 + base::TimeDelta::FromSeconds(10);
   nudge_tracker_.SetNextRetryTime(t0);
   nudge_tracker_.SetSyncCycleStartTime(t1);
-  EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::RETRY,
-            nudge_tracker_.GetLegacySource());
+  EXPECT_EQ(sync_pb::SyncEnums::RETRY, nudge_tracker_.GetOrigin());
 
   // Track a local nudge.
   nudge_tracker_.RecordLocalChange(ModelTypeSet(BOOKMARKS));
-  EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::LOCAL,
-            nudge_tracker_.GetLegacySource());
+  EXPECT_EQ(sync_pb::SyncEnums::GU_TRIGGER, nudge_tracker_.GetOrigin());
 
   // A refresh request will override it.
   nudge_tracker_.RecordLocalRefreshRequest(ModelTypeSet(TYPED_URLS));
-  EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::DATATYPE_REFRESH,
-            nudge_tracker_.GetLegacySource());
+  EXPECT_EQ(sync_pb::SyncEnums::GU_TRIGGER, nudge_tracker_.GetOrigin());
 
   // Another local nudge will not be enough to change it.
   nudge_tracker_.RecordLocalChange(ModelTypeSet(BOOKMARKS));
-  EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::DATATYPE_REFRESH,
-            nudge_tracker_.GetLegacySource());
+  EXPECT_EQ(sync_pb::SyncEnums::GU_TRIGGER, nudge_tracker_.GetOrigin());
 
   // An invalidation will override the refresh request source.
   nudge_tracker_.RecordRemoteInvalidation(PREFERENCES,
                                           BuildInvalidation(1, "hint"));
-  EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::NOTIFICATION,
-            nudge_tracker_.GetLegacySource());
+  EXPECT_EQ(sync_pb::SyncEnums::GU_TRIGGER, nudge_tracker_.GetOrigin());
 
   // Neither local nudges nor refresh requests will override it.
   nudge_tracker_.RecordLocalChange(ModelTypeSet(BOOKMARKS));
-  EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::NOTIFICATION,
-            nudge_tracker_.GetLegacySource());
+  EXPECT_EQ(sync_pb::SyncEnums::GU_TRIGGER, nudge_tracker_.GetOrigin());
   nudge_tracker_.RecordLocalRefreshRequest(ModelTypeSet(TYPED_URLS));
-  EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::NOTIFICATION,
-            nudge_tracker_.GetLegacySource());
-}
-
-TEST_F(NudgeTrackerTest, SourcePriority_InitialSyncRequest) {
-  nudge_tracker_.RecordInitialSyncRequired(BOOKMARKS);
-
-  // For lack of a better source, we describe an initial sync request as having
-  // source DATATYPE_REFRESH.
-  EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::DATATYPE_REFRESH,
-            nudge_tracker_.GetLegacySource());
-
-  // This should never happen in practice.  But, if it did, we'd want the
-  // initial sync required to keep the source set to DATATYPE_REFRESH.
-  nudge_tracker_.RecordLocalChange(ModelTypeSet(BOOKMARKS));
-  EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::DATATYPE_REFRESH,
-            nudge_tracker_.GetLegacySource());
-
-  // It should be safe to let NOTIFICATIONs override it.
-  nudge_tracker_.RecordRemoteInvalidation(BOOKMARKS,
-                                          BuildInvalidation(1, "hint"));
-  EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::NOTIFICATION,
-            nudge_tracker_.GetLegacySource());
+  EXPECT_EQ(sync_pb::SyncEnums::GU_TRIGGER, nudge_tracker_.GetOrigin());
 }
 
 // Verifies the management of invalidation hints and GU trigger fields.
diff --git a/components/sync/engine_impl/cycle/sync_cycle.cc b/components/sync/engine_impl/cycle/sync_cycle.cc
index fd30097..7127f036 100644
--- a/components/sync/engine_impl/cycle/sync_cycle.cc
+++ b/components/sync/engine_impl/cycle/sync_cycle.cc
@@ -20,12 +20,11 @@
 SyncCycle::~SyncCycle() {}
 
 SyncCycleSnapshot SyncCycle::TakeSnapshot() const {
-  return TakeSnapshotWithSource(sync_pb::GetUpdatesCallerInfo::UNKNOWN);
+  return TakeSnapshotWithOrigin(sync_pb::SyncEnums::UNKNOWN_ORIGIN);
 }
 
-SyncCycleSnapshot SyncCycle::TakeSnapshotWithSource(
-    sync_pb::GetUpdatesCallerInfo::GetUpdatesSource legacy_updates_source)
-    const {
+SyncCycleSnapshot SyncCycle::TakeSnapshotWithOrigin(
+    sync_pb::SyncEnums::GetUpdatesOrigin get_updates_origin) const {
   syncable::Directory* dir = context_->directory();
 
   ProgressMarkerMap download_progress_markers;
@@ -48,15 +47,15 @@
       context_->notifications_enabled(), dir->GetEntriesCount(),
       status_controller_->sync_start_time(),
       status_controller_->poll_finish_time(), num_entries_by_type,
-      num_to_delete_entries_by_type, legacy_updates_source);
+      num_to_delete_entries_by_type, get_updates_origin);
 
   return snapshot;
 }
 
 void SyncCycle::SendSyncCycleEndEventNotification(
-    sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source) {
+    sync_pb::SyncEnums::GetUpdatesOrigin get_updates_origin) {
   SyncCycleEvent event(SyncCycleEvent::SYNC_CYCLE_ENDED);
-  event.snapshot = TakeSnapshotWithSource(source);
+  event.snapshot = TakeSnapshotWithOrigin(get_updates_origin);
 
   DVLOG(1) << "Sending cycle end event with snapshot: "
            << event.snapshot.ToString();
diff --git a/components/sync/engine_impl/cycle/sync_cycle.h b/components/sync/engine_impl/cycle/sync_cycle.h
index 11201dd..b41478d 100644
--- a/components/sync/engine_impl/cycle/sync_cycle.h
+++ b/components/sync/engine_impl/cycle/sync_cycle.h
@@ -93,13 +93,12 @@
 
   // Builds a thread-safe and read-only copy of the current cycle state.
   SyncCycleSnapshot TakeSnapshot() const;
-  SyncCycleSnapshot TakeSnapshotWithSource(
-      sync_pb::GetUpdatesCallerInfo::GetUpdatesSource legacy_updates_source)
-      const;
+  SyncCycleSnapshot TakeSnapshotWithOrigin(
+      sync_pb::SyncEnums::GetUpdatesOrigin get_updates_origin) const;
 
   // Builds and sends a snapshot to the cycle context's listeners.
   void SendSyncCycleEndEventNotification(
-      sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source);
+      sync_pb::SyncEnums::GetUpdatesOrigin get_updates_origin);
   void SendEventNotification(SyncCycleEvent::EventCause cause);
 
   void SendProtocolEvent(const ProtocolEvent& event);
diff --git a/components/sync/engine_impl/cycle/test_util.cc b/components/sync/engine_impl/cycle/test_util.cc
index 92947fde3..5c8939b 100644
--- a/components/sync/engine_impl/cycle/test_util.cc
+++ b/components/sync/engine_impl/cycle/test_util.cc
@@ -7,29 +7,26 @@
 namespace syncer {
 namespace test_util {
 
-void SimulateGetEncryptionKeyFailed(
-    ModelTypeSet requsted_types,
-    sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source,
-    SyncCycle* cycle) {
+void SimulateGetEncryptionKeyFailed(ModelTypeSet requsted_types,
+                                    sync_pb::SyncEnums::GetUpdatesOrigin origin,
+                                    SyncCycle* cycle) {
   cycle->mutable_status_controller()->set_last_get_key_result(
       SERVER_RESPONSE_VALIDATION_FAILED);
   cycle->mutable_status_controller()->set_last_download_updates_result(
       SYNCER_OK);
 }
 
-void SimulateConfigureSuccess(
-    ModelTypeSet requsted_types,
-    sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source,
-    SyncCycle* cycle) {
+void SimulateConfigureSuccess(ModelTypeSet requsted_types,
+                              sync_pb::SyncEnums::GetUpdatesOrigin origin,
+                              SyncCycle* cycle) {
   cycle->mutable_status_controller()->set_last_get_key_result(SYNCER_OK);
   cycle->mutable_status_controller()->set_last_download_updates_result(
       SYNCER_OK);
 }
 
-void SimulateConfigureFailed(
-    ModelTypeSet requsted_types,
-    sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source,
-    SyncCycle* cycle) {
+void SimulateConfigureFailed(ModelTypeSet requsted_types,
+                             sync_pb::SyncEnums::GetUpdatesOrigin origin,
+                             SyncCycle* cycle) {
   cycle->mutable_status_controller()->set_last_get_key_result(SYNCER_OK);
   cycle->mutable_status_controller()->set_last_download_updates_result(
       SERVER_RETURN_TRANSIENT_ERROR);
@@ -37,7 +34,7 @@
 
 void SimulateConfigureConnectionFailure(
     ModelTypeSet requsted_types,
-    sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source,
+    sync_pb::SyncEnums::GetUpdatesOrigin origin,
     SyncCycle* cycle) {
   cycle->mutable_status_controller()->set_last_get_key_result(SYNCER_OK);
   cycle->mutable_status_controller()->set_last_download_updates_result(
diff --git a/components/sync/engine_impl/cycle/test_util.h b/components/sync/engine_impl/cycle/test_util.h
index 77b111d..2f17712b 100644
--- a/components/sync/engine_impl/cycle/test_util.h
+++ b/components/sync/engine_impl/cycle/test_util.h
@@ -16,21 +16,18 @@
 // Utils to simulate various outcomes of a sync cycle.
 
 // Configure sync cycle successes and failures.
-void SimulateGetEncryptionKeyFailed(
-    ModelTypeSet requested_types,
-    sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source,
-    SyncCycle* cycle);
-void SimulateConfigureSuccess(
-    ModelTypeSet requested_types,
-    sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source,
-    SyncCycle* cycle);
-void SimulateConfigureFailed(
-    ModelTypeSet requested_types,
-    sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source,
-    SyncCycle* cycle);
+void SimulateGetEncryptionKeyFailed(ModelTypeSet requested_types,
+                                    sync_pb::SyncEnums::GetUpdatesOrigin origin,
+                                    SyncCycle* cycle);
+void SimulateConfigureSuccess(ModelTypeSet requested_types,
+                              sync_pb::SyncEnums::GetUpdatesOrigin origin,
+                              SyncCycle* cycle);
+void SimulateConfigureFailed(ModelTypeSet requested_types,
+                             sync_pb::SyncEnums::GetUpdatesOrigin origin,
+                             SyncCycle* cycle);
 void SimulateConfigureConnectionFailure(
     ModelTypeSet requested_types,
-    sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source,
+    sync_pb::SyncEnums::GetUpdatesOrigin origin,
     SyncCycle* cycle);
 
 // Normal mode sync cycle successes and failures.
diff --git a/components/sync/engine_impl/debug_info_event_listener.cc b/components/sync/engine_impl/debug_info_event_listener.cc
index 511e584..820f08b 100644
--- a/components/sync/engine_impl/debug_info_event_listener.cc
+++ b/components/sync/engine_impl/debug_info_event_listener.cc
@@ -36,11 +36,16 @@
       snapshot.model_neutral_state().num_updates_downloaded_total);
   sync_completed_event_info->set_num_reflected_updates_downloaded(
       snapshot.model_neutral_state().num_reflected_updates_downloaded_total);
-  sync_completed_event_info->mutable_caller_info()->set_source(
-      snapshot.legacy_updates_source());
+  sync_completed_event_info->set_get_updates_origin(
+      snapshot.get_updates_origin());
   sync_completed_event_info->mutable_caller_info()->set_notifications_enabled(
       snapshot.notifications_enabled());
 
+  // Fill the legacy GetUpdatesSource field. This is not used anymore, but it's
+  // a required field so we still have to fill it with something.
+  sync_completed_event_info->mutable_caller_info()->set_source(
+      sync_pb::GetUpdatesCallerInfo::UNKNOWN);
+
   AddEventToQueue(event_info);
 }
 
diff --git a/components/sync/engine_impl/get_commit_ids.cc b/components/sync/engine_impl/get_commit_ids.cc
index 1835cf5..f8a9557 100644
--- a/components/sync/engine_impl/get_commit_ids.cc
+++ b/components/sync/engine_impl/get_commit_ids.cc
@@ -34,18 +34,6 @@
   return false;
 }
 
-// Return true if this entry has any attachments that haven't yet been uploaded
-// to the server.
-bool HasAttachmentNotOnServer(const Entry& entry) {
-  const sync_pb::AttachmentMetadata& metadata = entry.GetAttachmentMetadata();
-  for (int i = 0; i < metadata.record_size(); ++i) {
-    if (!metadata.record(i).is_on_server()) {
-      return true;
-    }
-  }
-  return false;
-}
-
 // An entry may not commit if any are true:
 // 1. It requires encryption (either the type is encrypted but a passphrase
 //    is missing from the cryptographer, or the entry itself wasn't properly
@@ -99,13 +87,6 @@
     return false;
   }
 
-  if (HasAttachmentNotOnServer(entry)) {
-    // This entry is not ready to be sent to the server because it has one or
-    // more attachments that have not yet been uploaded to the server. The idea
-    // here is avoid propagating an entry with dangling attachment references.
-    return false;
-  }
-
   DVLOG(2) << "Entry is ready for commit: " << entry;
   return true;
 }
@@ -463,9 +444,7 @@
     Entry entry(trans, syncable::GET_BY_HANDLE, handle);
     // TODO(maniscalco): While we check if entry is ready to be committed, we
     // also need to check that all of its ancestors (parents, transitive) are
-    // ready to be committed. Once attachments can prevent an entry from being
-    // committable, this method must ensure all ancestors are ready for commit
-    // (crbug.com/356273).
+    // ready to be committed.
     if (MayEntryCommit(requested_types, encrypted_types, passphrase_missing,
                        entry)) {
       if (IsEntryInConflict(entry)) {
diff --git a/components/sync/engine_impl/get_updates_delegate.cc b/components/sync/engine_impl/get_updates_delegate.cc
index 2e54b54..c5d493be 100644
--- a/components/sync/engine_impl/get_updates_delegate.cc
+++ b/components/sync/engine_impl/get_updates_delegate.cc
@@ -49,17 +49,18 @@
 // This function assumes the progress markers have already been populated.
 void NormalGetUpdatesDelegate::HelpPopulateGuMessage(
     sync_pb::GetUpdatesMessage* get_updates) const {
-  // Set legacy GetUpdatesMessage.GetUpdatesCallerInfo information.
+  // Fill the legacy GetUpdatesSource field. This is not used anymore, but it's
+  // a required field so we still have to fill it with something.
   get_updates->mutable_caller_info()->set_source(
-      nudge_tracker_.GetLegacySource());
+      sync_pb::GetUpdatesCallerInfo::UNKNOWN);
 
-  // Set the new and improved version of source, too.
+  // Set the origin.
   get_updates->set_get_updates_origin(sync_pb::SyncEnums::GU_TRIGGER);
   get_updates->set_is_retry(nudge_tracker_.IsRetryRequired());
 
   // Special case: A GU performed for no other reason than retry will have its
   // origin set to RETRY.
-  if (nudge_tracker_.GetLegacySource() == sync_pb::GetUpdatesCallerInfo::RETRY)
+  if (nudge_tracker_.GetOrigin() == sync_pb::SyncEnums::RETRY)
     get_updates->set_get_updates_origin(sync_pb::SyncEnums::RETRY);
 
   // Fill in the notification hints.
@@ -93,15 +94,19 @@
 }
 
 ConfigureGetUpdatesDelegate::ConfigureGetUpdatesDelegate(
-    sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source)
-    : source_(source) {}
+    sync_pb::SyncEnums::GetUpdatesOrigin origin)
+    : origin_(origin) {}
 
 ConfigureGetUpdatesDelegate::~ConfigureGetUpdatesDelegate() {}
 
 void ConfigureGetUpdatesDelegate::HelpPopulateGuMessage(
     sync_pb::GetUpdatesMessage* get_updates) const {
-  get_updates->mutable_caller_info()->set_source(source_);
-  get_updates->set_get_updates_origin(ConvertConfigureSourceToOrigin(source_));
+  // Fill the legacy GetUpdatesSource field. This is not used anymore, but it's
+  // a required field so we still have to fill it with something.
+  get_updates->mutable_caller_info()->set_source(
+      sync_pb::GetUpdatesCallerInfo::UNKNOWN);
+
+  get_updates->set_get_updates_origin(origin_);
 }
 
 void ConfigureGetUpdatesDelegate::ApplyUpdates(
@@ -115,29 +120,8 @@
 ConfigureGetUpdatesDelegate::GetNetworkRequestEvent(
     base::Time timestamp,
     const sync_pb::ClientToServerMessage& request) const {
-  return std::unique_ptr<ProtocolEvent>(new ConfigureGetUpdatesRequestEvent(
-      timestamp, ConvertConfigureSourceToOrigin(source_), request));
-}
-
-sync_pb::SyncEnums::GetUpdatesOrigin
-ConfigureGetUpdatesDelegate::ConvertConfigureSourceToOrigin(
-    sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source) {
-  switch (source) {
-    // Configurations:
-    case sync_pb::GetUpdatesCallerInfo::NEWLY_SUPPORTED_DATATYPE:
-      return sync_pb::SyncEnums::NEWLY_SUPPORTED_DATATYPE;
-    case sync_pb::GetUpdatesCallerInfo::MIGRATION:
-      return sync_pb::SyncEnums::MIGRATION;
-    case sync_pb::GetUpdatesCallerInfo::RECONFIGURATION:
-      return sync_pb::SyncEnums::RECONFIGURATION;
-    case sync_pb::GetUpdatesCallerInfo::NEW_CLIENT:
-      return sync_pb::SyncEnums::NEW_CLIENT;
-    case sync_pb::GetUpdatesCallerInfo::PROGRAMMATIC:
-      return sync_pb::SyncEnums::PROGRAMMATIC;
-    default:
-      NOTREACHED();
-      return sync_pb::SyncEnums::UNKNOWN_ORIGIN;
-  }
+  return std::unique_ptr<ProtocolEvent>(
+      new ConfigureGetUpdatesRequestEvent(timestamp, origin_, request));
 }
 
 PollGetUpdatesDelegate::PollGetUpdatesDelegate() {}
@@ -146,11 +130,11 @@
 
 void PollGetUpdatesDelegate::HelpPopulateGuMessage(
     sync_pb::GetUpdatesMessage* get_updates) const {
-  // Set legacy GetUpdatesMessage.GetUpdatesCallerInfo information.
+  // Fill the legacy GetUpdatesSource field. This is not used anymore, but it's
+  // a required field so we still have to fill it with something.
   get_updates->mutable_caller_info()->set_source(
-      sync_pb::GetUpdatesCallerInfo::PERIODIC);
+      sync_pb::GetUpdatesCallerInfo::UNKNOWN);
 
-  // Set the new and improved version of source, too.
   get_updates->set_get_updates_origin(sync_pb::SyncEnums::PERIODIC);
 }
 
diff --git a/components/sync/engine_impl/get_updates_delegate.h b/components/sync/engine_impl/get_updates_delegate.h
index f02829e..88e3d601 100644
--- a/components/sync/engine_impl/get_updates_delegate.h
+++ b/components/sync/engine_impl/get_updates_delegate.h
@@ -69,8 +69,8 @@
 // Functionality specific to the configure GetUpdate request.
 class ConfigureGetUpdatesDelegate : public GetUpdatesDelegate {
  public:
-  ConfigureGetUpdatesDelegate(
-      sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source);
+  explicit ConfigureGetUpdatesDelegate(
+      sync_pb::SyncEnums::GetUpdatesOrigin origin);
   ~ConfigureGetUpdatesDelegate() override;
 
   // Sets the 'source' and 'origin' fields for this request.
@@ -90,10 +90,7 @@
       const sync_pb::ClientToServerMessage& request) const override;
 
  private:
-  static sync_pb::SyncEnums::GetUpdatesOrigin ConvertConfigureSourceToOrigin(
-      sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source);
-
-  const sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source_;
+  const sync_pb::SyncEnums::GetUpdatesOrigin origin_;
 
   DISALLOW_COPY_AND_ASSIGN(ConfigureGetUpdatesDelegate);
 };
diff --git a/components/sync/engine_impl/get_updates_processor.cc b/components/sync/engine_impl/get_updates_processor.cc
index 85e4542..5ac5d88 100644
--- a/components/sync/engine_impl/get_updates_processor.cc
+++ b/components/sync/engine_impl/get_updates_processor.cc
@@ -152,7 +152,6 @@
   bool need_encryption_key = ShouldRequestEncryptionKey(cycle->context());
   get_updates->set_need_encryption_key(need_encryption_key);
 
-  // Set legacy GetUpdatesMessage.GetUpdatesCallerInfo information.
   get_updates->mutable_caller_info()->set_notifications_enabled(
       cycle->context()->notifications_enabled());
 }
diff --git a/components/sync/engine_impl/get_updates_processor_unittest.cc b/components/sync/engine_impl/get_updates_processor_unittest.cc
index e45eb3f..34fe0b4 100644
--- a/components/sync/engine_impl/get_updates_processor_unittest.cc
+++ b/components/sync/engine_impl/get_updates_processor_unittest.cc
@@ -108,8 +108,6 @@
   processor->PrepareGetUpdates(enabled_types(), &message);
 
   const sync_pb::GetUpdatesMessage& gu_msg = message.get_updates();
-  EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::LOCAL,
-            gu_msg.caller_info().source());
   EXPECT_EQ(sync_pb::SyncEnums::GU_TRIGGER, gu_msg.get_updates_origin());
   for (int i = 0; i < gu_msg.from_progress_marker_size(); ++i) {
     ModelType type = GetModelTypeFromSpecificsFieldNumber(
@@ -156,8 +154,6 @@
   processor->PrepareGetUpdates(enabled_types(), &message);
 
   const sync_pb::GetUpdatesMessage& gu_msg = message.get_updates();
-  EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::NOTIFICATION,
-            gu_msg.caller_info().source());
   EXPECT_EQ(sync_pb::SyncEnums::GU_TRIGGER, gu_msg.get_updates_origin());
   for (int i = 0; i < gu_msg.from_progress_marker_size(); ++i) {
     ModelType type = GetModelTypeFromSpecificsFieldNumber(
@@ -196,8 +192,6 @@
   processor->PrepareGetUpdates(enabled_types(), &message);
 
   const sync_pb::GetUpdatesMessage& gu_msg = message.get_updates();
-  EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::DATATYPE_REFRESH,
-            gu_msg.caller_info().source());
   EXPECT_EQ(sync_pb::SyncEnums::GU_TRIGGER, gu_msg.get_updates_origin());
   for (int i = 0; i < gu_msg.from_progress_marker_size(); ++i) {
     ModelType type = GetModelTypeFromSpecificsFieldNumber(
@@ -222,15 +216,13 @@
 TEST_F(GetUpdatesProcessorTest, ConfigureTest) {
   sync_pb::ClientToServerMessage message;
   ConfigureGetUpdatesDelegate configure_delegate(
-      sync_pb::GetUpdatesCallerInfo::RECONFIGURATION);
+      sync_pb::SyncEnums::RECONFIGURATION);
   std::unique_ptr<GetUpdatesProcessor> processor(
       BuildGetUpdatesProcessor(configure_delegate));
   processor->PrepareGetUpdates(enabled_types(), &message);
 
   const sync_pb::GetUpdatesMessage& gu_msg = message.get_updates();
   EXPECT_EQ(sync_pb::SyncEnums::RECONFIGURATION, gu_msg.get_updates_origin());
-  EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::RECONFIGURATION,
-            gu_msg.caller_info().source());
 
   ModelTypeSet progress_types;
   for (int i = 0; i < gu_msg.from_progress_marker_size(); ++i) {
@@ -250,8 +242,6 @@
 
   const sync_pb::GetUpdatesMessage& gu_msg = message.get_updates();
   EXPECT_EQ(sync_pb::SyncEnums::PERIODIC, gu_msg.get_updates_origin());
-  EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::PERIODIC,
-            gu_msg.caller_info().source());
 
   ModelTypeSet progress_types;
   for (int i = 0; i < gu_msg.from_progress_marker_size(); ++i) {
@@ -280,8 +270,6 @@
 
   const sync_pb::GetUpdatesMessage& gu_msg = message.get_updates();
   EXPECT_EQ(sync_pb::SyncEnums::RETRY, gu_msg.get_updates_origin());
-  EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::RETRY,
-            gu_msg.caller_info().source());
   EXPECT_TRUE(gu_msg.is_retry());
 
   ModelTypeSet progress_types;
@@ -314,8 +302,6 @@
 
   const sync_pb::GetUpdatesMessage& gu_msg = message.get_updates();
   EXPECT_NE(sync_pb::SyncEnums::RETRY, gu_msg.get_updates_origin());
-  EXPECT_NE(sync_pb::GetUpdatesCallerInfo::RETRY,
-            gu_msg.caller_info().source());
 
   EXPECT_TRUE(gu_msg.is_retry());
 }
@@ -423,7 +409,7 @@
 // types.
 TEST_F(GetUpdatesProcessorApplyUpdatesTest, Configure) {
   ConfigureGetUpdatesDelegate configure_delegate(
-      sync_pb::GetUpdatesCallerInfo::RECONFIGURATION);
+      sync_pb::SyncEnums::RECONFIGURATION);
   std::unique_ptr<GetUpdatesProcessor> processor(
       BuildGetUpdatesProcessor(configure_delegate));
 
diff --git a/components/sync/engine_impl/js_sync_manager_observer_unittest.cc b/components/sync/engine_impl/js_sync_manager_observer_unittest.cc
index 52774eeb..8dc6370f 100644
--- a/components/sync/engine_impl/js_sync_manager_observer_unittest.cc
+++ b/components/sync/engine_impl/js_sync_manager_observer_unittest.cc
@@ -66,7 +66,7 @@
                              base::Time::Now(),
                              std::vector<int>(MODEL_TYPE_COUNT, 0),
                              std::vector<int>(MODEL_TYPE_COUNT, 0),
-                             sync_pb::GetUpdatesCallerInfo::UNKNOWN);
+                             sync_pb::SyncEnums::UNKNOWN_ORIGIN);
   base::DictionaryValue expected_details;
   expected_details.Set("snapshot", snapshot.ToValue());
 
diff --git a/components/sync/engine_impl/sync_manager_for_profile_sync_test.cc b/components/sync/engine_impl/sync_manager_for_profile_sync_test.cc
index 2d946e3e..3af98e71 100644
--- a/components/sync/engine_impl/sync_manager_for_profile_sync_test.cc
+++ b/components/sync/engine_impl/sync_manager_for_profile_sync_test.cc
@@ -12,8 +12,8 @@
 
 SyncManagerForProfileSyncTest::SyncManagerForProfileSyncTest(
     std::string name,
-    base::Closure init_callback)
-    : SyncManagerImpl(name), init_callback_(init_callback) {}
+    base::OnceClosure init_callback)
+    : SyncManagerImpl(name), init_callback_(std::move(init_callback)) {}
 
 SyncManagerForProfileSyncTest::~SyncManagerForProfileSyncTest() {}
 
@@ -22,7 +22,7 @@
   syncable::Directory* directory = user_share->directory.get();
 
   if (!init_callback_.is_null())
-    init_callback_.Run();
+    std::move(init_callback_).Run();
 
   ModelTypeSet early_download_types;
   early_download_types.PutAll(ControlTypes());
diff --git a/components/sync/engine_impl/sync_manager_for_profile_sync_test.h b/components/sync/engine_impl/sync_manager_for_profile_sync_test.h
index 3292d87..f1399f8 100644
--- a/components/sync/engine_impl/sync_manager_for_profile_sync_test.h
+++ b/components/sync/engine_impl/sync_manager_for_profile_sync_test.h
@@ -17,12 +17,13 @@
 // Those tests try to test sync without instantiating a real backend.
 class SyncManagerForProfileSyncTest : public SyncManagerImpl {
  public:
-  SyncManagerForProfileSyncTest(std::string name, base::Closure init_callback);
+  SyncManagerForProfileSyncTest(std::string name,
+                                base::OnceClosure init_callback);
   ~SyncManagerForProfileSyncTest() override;
   void NotifyInitializationSuccess() override;
 
  private:
-  base::Closure init_callback_;
+  base::OnceClosure init_callback_;
 };
 
 }  // namespace syncer
diff --git a/components/sync/engine_impl/sync_manager_impl.cc b/components/sync/engine_impl/sync_manager_impl.cc
index 80ad5e1..2f3a289 100644
--- a/components/sync/engine_impl/sync_manager_impl.cc
+++ b/components/sync/engine_impl/sync_manager_impl.cc
@@ -49,7 +49,6 @@
 
 
 using base::TimeDelta;
-using sync_pb::GetUpdatesCallerInfo;
 
 class GURL;
 
@@ -61,25 +60,25 @@
 
 namespace {
 
-GetUpdatesCallerInfo::GetUpdatesSource GetSourceFromReason(
+sync_pb::SyncEnums::GetUpdatesOrigin GetOriginFromReason(
     ConfigureReason reason) {
   switch (reason) {
     case CONFIGURE_REASON_RECONFIGURATION:
-      return GetUpdatesCallerInfo::RECONFIGURATION;
+      return sync_pb::SyncEnums::RECONFIGURATION;
     case CONFIGURE_REASON_MIGRATION:
-      return GetUpdatesCallerInfo::MIGRATION;
+      return sync_pb::SyncEnums::MIGRATION;
     case CONFIGURE_REASON_NEW_CLIENT:
-      return GetUpdatesCallerInfo::NEW_CLIENT;
+      return sync_pb::SyncEnums::NEW_CLIENT;
     case CONFIGURE_REASON_NEWLY_ENABLED_DATA_TYPE:
     case CONFIGURE_REASON_CRYPTO:
     case CONFIGURE_REASON_CATCH_UP:
-      return GetUpdatesCallerInfo::NEWLY_SUPPORTED_DATATYPE;
+      return sync_pb::SyncEnums::NEWLY_SUPPORTED_DATATYPE;
     case CONFIGURE_REASON_PROGRAMMATIC:
-      return GetUpdatesCallerInfo::PROGRAMMATIC;
+      return sync_pb::SyncEnums::PROGRAMMATIC;
     case CONFIGURE_REASON_UNKNOWN:
       NOTREACHED();
   }
-  return GetUpdatesCallerInfo::UNKNOWN;
+  return sync_pb::SyncEnums::UNKNOWN_ORIGIN;
 }
 
 }  // namespace
@@ -190,7 +189,7 @@
   DVLOG(1) << "Configuring -"
            << "\n\t"
            << "types to download: " << ModelTypeSetToString(to_download);
-  ConfigurationParams params(GetSourceFromReason(reason), to_download,
+  ConfigurationParams params(GetOriginFromReason(reason), to_download,
                              ready_task, retry_task);
 
   scheduler_->Start(SyncScheduler::CONFIGURATION_MODE, base::Time());
diff --git a/components/sync/engine_impl/sync_manager_impl_unittest.cc b/components/sync/engine_impl/sync_manager_impl_unittest.cc
index d349dd9..ef1a524 100644
--- a/components/sync/engine_impl/sync_manager_impl_unittest.cc
+++ b/components/sync/engine_impl/sync_manager_impl_unittest.cc
@@ -2710,7 +2710,7 @@
                  base::Unretained(&retry_task_counter)));
   EXPECT_EQ(0, ready_task_counter.times_called());
   EXPECT_EQ(0, retry_task_counter.times_called());
-  EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::RECONFIGURATION, params.source);
+  EXPECT_EQ(sync_pb::SyncEnums::RECONFIGURATION, params.origin);
   EXPECT_EQ(types_to_download, params.types_to_download);
 }
 
diff --git a/components/sync/engine_impl/sync_scheduler.h b/components/sync/engine_impl/sync_scheduler.h
index d3229e1..423bec9 100644
--- a/components/sync/engine_impl/sync_scheduler.h
+++ b/components/sync/engine_impl/sync_scheduler.h
@@ -24,16 +24,15 @@
 
 struct ConfigurationParams {
   ConfigurationParams();
-  ConfigurationParams(
-      const sync_pb::GetUpdatesCallerInfo::GetUpdatesSource& source,
-      ModelTypeSet types_to_download,
-      const base::Closure& ready_task,
-      const base::Closure& retry_task);
+  ConfigurationParams(sync_pb::SyncEnums::GetUpdatesOrigin origin,
+                      ModelTypeSet types_to_download,
+                      const base::Closure& ready_task,
+                      const base::Closure& retry_task);
   ConfigurationParams(const ConfigurationParams& other);
   ~ConfigurationParams();
 
-  // Source for the configuration.
-  sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source;
+  // Origin for the configuration.
+  sync_pb::SyncEnums::GetUpdatesOrigin origin;
   // The types that should be downloaded.
   ModelTypeSet types_to_download;
   // Callback to invoke on configuration completion.
diff --git a/components/sync/engine_impl/sync_scheduler_impl.cc b/components/sync/engine_impl/sync_scheduler_impl.cc
index 935fc8ac..e5e45d47 100644
--- a/components/sync/engine_impl/sync_scheduler_impl.cc
+++ b/components/sync/engine_impl/sync_scheduler_impl.cc
@@ -23,20 +23,19 @@
 
 using base::TimeDelta;
 using base::TimeTicks;
-using sync_pb::GetUpdatesCallerInfo;
 
 namespace syncer {
 
 namespace {
 
-bool IsConfigRelatedUpdateSourceValue(
-    GetUpdatesCallerInfo::GetUpdatesSource source) {
-  switch (source) {
-    case GetUpdatesCallerInfo::RECONFIGURATION:
-    case GetUpdatesCallerInfo::MIGRATION:
-    case GetUpdatesCallerInfo::NEW_CLIENT:
-    case GetUpdatesCallerInfo::NEWLY_SUPPORTED_DATATYPE:
-    case GetUpdatesCallerInfo::PROGRAMMATIC:
+bool IsConfigRelatedUpdateOriginValue(
+    sync_pb::SyncEnums::GetUpdatesOrigin origin) {
+  switch (origin) {
+    case sync_pb::SyncEnums::RECONFIGURATION:
+    case sync_pb::SyncEnums::MIGRATION:
+    case sync_pb::SyncEnums::NEW_CLIENT:
+    case sync_pb::SyncEnums::NEWLY_SUPPORTED_DATATYPE:
+    case sync_pb::SyncEnums::PROGRAMMATIC:
       return true;
     default:
       return false;
@@ -94,13 +93,13 @@
 }  // namespace
 
 ConfigurationParams::ConfigurationParams()
-    : source(GetUpdatesCallerInfo::UNKNOWN) {}
+    : origin(sync_pb::SyncEnums::UNKNOWN_ORIGIN) {}
 ConfigurationParams::ConfigurationParams(
-    const sync_pb::GetUpdatesCallerInfo::GetUpdatesSource& source,
+    sync_pb::SyncEnums::GetUpdatesOrigin origin,
     ModelTypeSet types_to_download,
     const base::Closure& ready_task,
     const base::Closure& retry_task)
-    : source(source),
+    : origin(origin),
       types_to_download(types_to_download),
       ready_task(ready_task),
       retry_task(retry_task) {
@@ -254,7 +253,7 @@
 void SyncSchedulerImpl::ScheduleConfiguration(
     const ConfigurationParams& params) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  DCHECK(IsConfigRelatedUpdateSourceValue(params.source));
+  DCHECK(IsConfigRelatedUpdateOriginValue(params.origin));
   DCHECK_EQ(CONFIGURATION_MODE, mode_);
   DCHECK(!params.ready_task.is_null());
   DCHECK(started_) << "Scheduler must be running to configure.";
@@ -473,7 +472,7 @@
   SyncCycle cycle(cycle_context_, this);
   bool success =
       syncer_->ConfigureSyncShare(pending_configure_params_->types_to_download,
-                                  pending_configure_params_->source, &cycle);
+                                  pending_configure_params_->origin, &cycle);
 
   if (success) {
     SDVLOG(2) << "Configure succeeded.";
diff --git a/components/sync/engine_impl/sync_scheduler_impl_unittest.cc b/components/sync/engine_impl/sync_scheduler_impl_unittest.cc
index 3c9bbc4..d309241 100644
--- a/components/sync/engine_impl/sync_scheduler_impl_unittest.cc
+++ b/components/sync/engine_impl/sync_scheduler_impl_unittest.cc
@@ -44,15 +44,13 @@
 
 namespace syncer {
 
-using sync_pb::GetUpdatesCallerInfo;
-
 class MockSyncer : public Syncer {
  public:
   MockSyncer();
   MOCK_METHOD3(NormalSyncShare, bool(ModelTypeSet, NudgeTracker*, SyncCycle*));
   MOCK_METHOD3(ConfigureSyncShare,
                bool(const ModelTypeSet&,
-                    sync_pb::GetUpdatesCallerInfo::GetUpdatesSource,
+                    sync_pb::SyncEnums::GetUpdatesOrigin,
                     SyncCycle*));
   MOCK_METHOD2(PollSyncShare, bool(ModelTypeSet, SyncCycle*));
 };
@@ -388,7 +386,7 @@
   CallbackCounter ready_counter;
   CallbackCounter retry_counter;
   ConfigurationParams params(
-      GetUpdatesCallerInfo::RECONFIGURATION, model_types,
+      sync_pb::SyncEnums::RECONFIGURATION, model_types,
       base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
       base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
   scheduler()->ScheduleConfiguration(params);
@@ -416,7 +414,7 @@
   CallbackCounter ready_counter;
   CallbackCounter retry_counter;
   ConfigurationParams params(
-      GetUpdatesCallerInfo::RECONFIGURATION, model_types,
+      sync_pb::SyncEnums::RECONFIGURATION, model_types,
       base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
       base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
   scheduler()->ScheduleConfiguration(params);
@@ -461,7 +459,7 @@
   CallbackCounter ready_counter;
   CallbackCounter retry_counter;
   ConfigurationParams params(
-      GetUpdatesCallerInfo::RECONFIGURATION, model_types,
+      sync_pb::SyncEnums::RECONFIGURATION, model_types,
       base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
       base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
   scheduler()->ScheduleConfiguration(params);
@@ -482,7 +480,7 @@
   CallbackCounter ready_counter;
   CallbackCounter retry_counter;
   ConfigurationParams params(
-      GetUpdatesCallerInfo::RECONFIGURATION, model_types,
+      sync_pb::SyncEnums::RECONFIGURATION, model_types,
       base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
       base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
   scheduler()->ScheduleConfiguration(params);
@@ -509,7 +507,7 @@
   CallbackCounter ready_counter;
   CallbackCounter retry_counter;
   ConfigurationParams params(
-      GetUpdatesCallerInfo::RECONFIGURATION, model_types,
+      sync_pb::SyncEnums::RECONFIGURATION, model_types,
       base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
       base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
   scheduler()->ScheduleConfiguration(params);
@@ -536,7 +534,7 @@
   CallbackCounter ready_counter;
   CallbackCounter retry_counter;
   ConfigurationParams params(
-      GetUpdatesCallerInfo::RECONFIGURATION, model_types,
+      sync_pb::SyncEnums::RECONFIGURATION, model_types,
       base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
       base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
   scheduler()->ScheduleConfiguration(params);
@@ -797,7 +795,7 @@
   CallbackCounter ready_counter;
   CallbackCounter retry_counter;
   ConfigurationParams params(
-      GetUpdatesCallerInfo::RECONFIGURATION, types,
+      sync_pb::SyncEnums::RECONFIGURATION, types,
       base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
       base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
   scheduler()->ScheduleConfiguration(params);
@@ -881,7 +879,7 @@
   CallbackCounter ready_counter;
   CallbackCounter retry_counter;
   ConfigurationParams params(
-      GetUpdatesCallerInfo::RECONFIGURATION, types,
+      sync_pb::SyncEnums::RECONFIGURATION, types,
       base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
       base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
   scheduler()->ScheduleConfiguration(params);
@@ -1214,7 +1212,7 @@
   CallbackCounter ready_counter;
   CallbackCounter retry_counter;
   ConfigurationParams params(
-      GetUpdatesCallerInfo::RECONFIGURATION, config_types,
+      sync_pb::SyncEnums::RECONFIGURATION, config_types,
       base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
       base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
   scheduler()->ScheduleConfiguration(params);
@@ -1306,7 +1304,7 @@
   CallbackCounter ready_counter;
   CallbackCounter retry_counter;
   ConfigurationParams params(
-      GetUpdatesCallerInfo::RECONFIGURATION, types,
+      sync_pb::SyncEnums::RECONFIGURATION, types,
       base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
       base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
   scheduler()->ScheduleConfiguration(params);
@@ -1355,7 +1353,7 @@
   CallbackCounter ready_counter;
   CallbackCounter retry_counter;
   ConfigurationParams params(
-      GetUpdatesCallerInfo::RECONFIGURATION, types,
+      sync_pb::SyncEnums::RECONFIGURATION, types,
       base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
       base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
   scheduler()->ScheduleConfiguration(params);
@@ -1614,7 +1612,7 @@
   CallbackCounter ready_counter;
   CallbackCounter retry_counter;
   ConfigurationParams params(
-      GetUpdatesCallerInfo::RECONFIGURATION, model_types,
+      sync_pb::SyncEnums::RECONFIGURATION, model_types,
       base::Bind(&CallbackCounter::Callback, base::Unretained(&ready_counter)),
       base::Bind(&CallbackCounter::Callback, base::Unretained(&retry_counter)));
   scheduler()->ScheduleConfiguration(params);
diff --git a/components/sync/engine_impl/syncer.cc b/components/sync/engine_impl/syncer.cc
index 158652ce..6a81698 100644
--- a/components/sync/engine_impl/syncer.cc
+++ b/components/sync/engine_impl/syncer.cc
@@ -60,7 +60,7 @@
     if (!DownloadAndApplyUpdates(&request_types, cycle,
                                  NormalGetUpdatesDelegate(*nudge_tracker),
                                  kCreateMobileBookmarksFolder)) {
-      return HandleCycleEnd(cycle, nudge_tracker->GetLegacySource());
+      return HandleCycleEnd(cycle, nudge_tracker->GetOrigin());
     }
   }
 
@@ -70,13 +70,12 @@
                                                   cycle, &commit_processor);
   cycle->mutable_status_controller()->set_commit_result(commit_result);
 
-  return HandleCycleEnd(cycle, nudge_tracker->GetLegacySource());
+  return HandleCycleEnd(cycle, nudge_tracker->GetOrigin());
 }
 
-bool Syncer::ConfigureSyncShare(
-    const ModelTypeSet& request_types,
-    sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source,
-    SyncCycle* cycle) {
+bool Syncer::ConfigureSyncShare(const ModelTypeSet& request_types,
+                                sync_pb::SyncEnums::GetUpdatesOrigin origin,
+                                SyncCycle* cycle) {
   base::AutoReset<bool> is_syncing(&is_syncing_, true);
 
   // It is possible during configuration that datatypes get unregistered from
@@ -90,9 +89,9 @@
   VLOG(1) << "Configuring types " << ModelTypeSetToString(still_enabled_types);
   HandleCycleBegin(cycle);
   DownloadAndApplyUpdates(&still_enabled_types, cycle,
-                          ConfigureGetUpdatesDelegate(source),
+                          ConfigureGetUpdatesDelegate(origin),
                           kCreateMobileBookmarksFolder);
-  return HandleCycleEnd(cycle, source);
+  return HandleCycleEnd(cycle, origin);
 }
 
 bool Syncer::PollSyncShare(ModelTypeSet request_types, SyncCycle* cycle) {
@@ -101,7 +100,7 @@
   HandleCycleBegin(cycle);
   DownloadAndApplyUpdates(&request_types, cycle, PollGetUpdatesDelegate(),
                           kCreateMobileBookmarksFolder);
-  return HandleCycleEnd(cycle, sync_pb::GetUpdatesCallerInfo::PERIODIC);
+  return HandleCycleEnd(cycle, sync_pb::SyncEnums::PERIODIC);
 }
 
 bool Syncer::PostClearServerData(SyncCycle* cycle) {
@@ -196,16 +195,15 @@
   return cancelation_signal_->IsSignalled();
 }
 
-bool Syncer::HandleCycleEnd(
-    SyncCycle* cycle,
-    sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source) {
+bool Syncer::HandleCycleEnd(SyncCycle* cycle,
+                            sync_pb::SyncEnums::GetUpdatesOrigin origin) {
   if (ExitRequested())
     return false;
 
-  cycle->SendSyncCycleEndEventNotification(source);
+  cycle->SendSyncCycleEndEventNotification(origin);
   bool success =
       !HasSyncerError(cycle->status_controller().model_neutral_state());
-  if (success && source == sync_pb::GetUpdatesCallerInfo::PERIODIC) {
+  if (success && origin == sync_pb::SyncEnums::PERIODIC) {
     cycle->mutable_status_controller()->UpdatePollTime();
   }
 
diff --git a/components/sync/engine_impl/syncer.h b/components/sync/engine_impl/syncer.h
index 455c7590..2aac6af 100644
--- a/components/sync/engine_impl/syncer.h
+++ b/components/sync/engine_impl/syncer.h
@@ -57,10 +57,9 @@
   // purposes.  It describes the reson for performing this initial download.
   // Returns: false if an error occurred and retries should backoff, true
   // otherwise.
-  virtual bool ConfigureSyncShare(
-      const ModelTypeSet& request_types,
-      sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source,
-      SyncCycle* cycle);
+  virtual bool ConfigureSyncShare(const ModelTypeSet& request_types,
+                                  sync_pb::SyncEnums::GetUpdatesOrigin origin,
+                                  SyncCycle* cycle);
 
   // Requests to download updates for the |request_types|.  For a well-behaved
   // client with a working connection to the invalidations server, this should
@@ -94,7 +93,7 @@
   bool ExitRequested();
 
   bool HandleCycleEnd(SyncCycle* cycle,
-                      sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source);
+                      sync_pb::SyncEnums::GetUpdatesOrigin origin);
 
   CancelationSignal* const cancelation_signal_;
 
diff --git a/components/sync/engine_impl/syncer_unittest.cc b/components/sync/engine_impl/syncer_unittest.cc
index 310abd7d..c95fb2c 100644
--- a/components/sync/engine_impl/syncer_unittest.cc
+++ b/components/sync/engine_impl/syncer_unittest.cc
@@ -259,7 +259,7 @@
   bool SyncShareConfigureTypes(ModelTypeSet types) {
     ResetCycle();
     return syncer_->ConfigureSyncShare(
-        types, sync_pb::GetUpdatesCallerInfo::RECONFIGURATION, cycle_.get());
+        types, sync_pb::SyncEnums::RECONFIGURATION, cycle_.get());
   }
 
   void SetUp() override {
diff --git a/components/sync/protocol/attachments.proto b/components/sync/protocol/attachments.proto
deleted file mode 100644
index 3f4846b..0000000
--- a/components/sync/protocol/attachments.proto
+++ /dev/null
@@ -1,39 +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.
-//
-// Sync protocol for attachments.
-
-// Update proto_{value,enum}_conversions{.h,.cc,_unittest.cc} if you change any
-// fields in this file.
-
-syntax = "proto2";
-
-option optimize_for = LITE_RUNTIME;
-
-package sync_pb;
-
-// Identifies an attachment.
-message AttachmentIdProto {
-  // Uniquely identifies the attachment. Two attachments with the same unique_id
-  // are considered equivalent.
-  optional string unique_id = 1;
-  // Size of the attachment data in bytes.
-  optional uint64 size_bytes = 2;
-  // Crc32c of the attachment data.
-  optional uint32 crc32c = 3;
-}
-
-// Metadata for a single attachment.
-message AttachmentMetadataRecord {
-  optional AttachmentIdProto id = 1;
-  // Indicates we know this attachment exists on the server.
-  optional bool is_on_server = 2;
-}
-
-// A collection of attachment metadata. This proto is part of EntryKernel's "on
-// disk" representation. Private to sync.
-message AttachmentMetadata {
-  // One record per attachment.
-  repeated AttachmentMetadataRecord record = 1;
-}
diff --git a/components/sync/protocol/client_debug_info.proto b/components/sync/protocol/client_debug_info.proto
index d2446e03..b10cb4e 100644
--- a/components/sync/protocol/client_debug_info.proto
+++ b/components/sync/protocol/client_debug_info.proto
@@ -22,14 +22,7 @@
   optional bool has_valid_hint = 2;
 }
 
-// Information about the source that triggered a sync.
-message SourceInfo {
-  // An enum indicating the reason for the nudge.
-  optional GetUpdatesCallerInfo.GetUpdatesSource source = 1;
-
-  // The per-type hint information associated with the nudge.
-  repeated TypeHint type_hint = 2;
-}
+message DeprecatedSourceInfo {}
 
 // The additional info here is from the StatusController. They get sent when
 // the event SYNC_CYCLE_COMPLETED  is sent.
@@ -55,13 +48,15 @@
   // Counts to track the effective usefulness of our GetUpdate requests.
   optional int32 num_updates_downloaded = 8;
   optional int32 num_reflected_updates_downloaded = 9;
+
+  // |caller_info| was mostly replaced by |get_updates_origin|; now it only
+  // contains the |notifications_enabled| flag.
   optional GetUpdatesCallerInfo caller_info = 10;
 
-  // A list of all the sources that were merged into this cycle.
-  //
-  // Some scenarios, notably mode switches and canary jobs, can spuriously add
-  // back-to-back duplicate sources to this list.
-  repeated SourceInfo source_info = 11;
+  // |source_info| was unused and marked deprecated in M66.
+  repeated DeprecatedSourceInfo source_info = 11 [deprecated = true];
+
+  optional SyncEnums.GetUpdatesOrigin get_updates_origin = 12;
 }
 
 // Datatype specifics statistics gathered at association time.
diff --git a/components/sync/protocol/get_updates_caller_info.proto b/components/sync/protocol/get_updates_caller_info.proto
index bfc092d..f035864 100644
--- a/components/sync/protocol/get_updates_caller_info.proto
+++ b/components/sync/protocol/get_updates_caller_info.proto
@@ -9,45 +9,15 @@
 package sync_pb;
 
 message GetUpdatesCallerInfo {
-  // This message was deprecated in M28.  The preferred represenation of this
+  // This enum was deprecated in M28.  The preferred represenation of this
   // information is now the GetUpdatesOrigin enum, which is defined in
-  // sync_enums.proto.
-  enum GetUpdatesSource {
-    UNKNOWN = 0;       // The source was not set by the caller.
-    FIRST_UPDATE = 1;  // First request after browser restart.  Not to
-                       // be confused with "NEW_CLIENT".
-    LOCAL = 2;         // The source of the update was a local change.
-    NOTIFICATION = 3;  // The source of the update was a p2p notification.
-    PERIODIC = 4;      // The source of the update was periodic polling.
-    SYNC_CYCLE_CONTINUATION = 5;  // The source of the update was a
-                                  // continuation of a previous sync cycle.
-                                  // No longer sent as of M24.
-
-    // This value is deprecated and was never used in production.
-    // CLEAR_PRIVATE_DATA = 6;
-
-    NEWLY_SUPPORTED_DATATYPE = 7;  // The client is in configuration mode
-                                   // because it's syncing all datatypes, and
-                                   // support for a new datatype was recently
-                                   // released via a software auto-update.
-    MIGRATION = 8;          // The client is in configuration mode because a
-                            // MIGRATION_DONE error previously returned by the
-                            // server necessitated resynchronization.
-    NEW_CLIENT = 9;         // The client is in configuration mode because the
-                            // user enabled sync for the first time.  Not to be
-                            // confused with FIRST_UPDATE.
-    RECONFIGURATION = 10;   // The client is in configuration mode because the
-                            // user opted to sync a different set of datatypes.
-    DATATYPE_REFRESH = 11;  // A datatype has requested a refresh. This is
-                            // typically used when datatype's have custom
-                            // sync UI, e.g. sessions.
-    RETRY = 13;  // A follow-up GU to pick up updates missed by previous GU.
-    PROGRAMMATIC = 14;  // The client is programmatically enabling/disabling
-                        // a type, typically for error handling purposes.
-  }
-
-  required GetUpdatesSource source = 1;
+  // sync_enums.proto.  However, since |source| is a required field, both the
+  // field and the enum have to be kept around.
+  enum GetUpdatesSource { UNKNOWN = 0; }
+  required GetUpdatesSource source = 1 [deprecated = true];
 
   // True only if notifications were enabled for this GetUpdateMessage.
+  // TODO(crbug.com/510165): Move this bool out of GetUpdatesCallerInfo so that
+  // GetUpdatesCallerInfo can be removed.
   optional bool notifications_enabled = 2;
 };
diff --git a/components/sync/protocol/proto_enum_conversions.cc b/components/sync/protocol/proto_enum_conversions.cc
index 24dc909..0de51225 100644
--- a/components/sync/protocol/proto_enum_conversions.cc
+++ b/components/sync/protocol/proto_enum_conversions.cc
@@ -75,24 +75,11 @@
 
 const char* ProtoEnumToString(
     sync_pb::GetUpdatesCallerInfo::GetUpdatesSource updates_source) {
-  ASSERT_ENUM_BOUNDS(sync_pb::GetUpdatesCallerInfo, GetUpdatesSource, UNKNOWN,
-                     PROGRAMMATIC);
   switch (updates_source) {
     ENUM_CASE(sync_pb::GetUpdatesCallerInfo, UNKNOWN);
-    ENUM_CASE(sync_pb::GetUpdatesCallerInfo, FIRST_UPDATE);
-    ENUM_CASE(sync_pb::GetUpdatesCallerInfo, LOCAL);
-    ENUM_CASE(sync_pb::GetUpdatesCallerInfo, NOTIFICATION);
-    ENUM_CASE(sync_pb::GetUpdatesCallerInfo, PERIODIC);
-    ENUM_CASE(sync_pb::GetUpdatesCallerInfo, SYNC_CYCLE_CONTINUATION);
-    ENUM_CASE(sync_pb::GetUpdatesCallerInfo, NEWLY_SUPPORTED_DATATYPE);
-    ENUM_CASE(sync_pb::GetUpdatesCallerInfo, MIGRATION);
-    ENUM_CASE(sync_pb::GetUpdatesCallerInfo, NEW_CLIENT);
-    ENUM_CASE(sync_pb::GetUpdatesCallerInfo, RECONFIGURATION);
-    ENUM_CASE(sync_pb::GetUpdatesCallerInfo, DATATYPE_REFRESH);
-    ENUM_CASE(sync_pb::GetUpdatesCallerInfo, RETRY);
-    ENUM_CASE(sync_pb::GetUpdatesCallerInfo, PROGRAMMATIC);
   }
-  NOTREACHED();
+  // Note: No "NOTREACHED()" here - this enum used to have more entries, but it
+  // has been deprecated so we don't need to handle them anymore.
   return "";
 }
 
diff --git a/components/sync/protocol/proto_enum_conversions_unittest.cc b/components/sync/protocol/proto_enum_conversions_unittest.cc
index 71370dc..5ce5fe7 100644
--- a/components/sync/protocol/proto_enum_conversions_unittest.cc
+++ b/components/sync/protocol/proto_enum_conversions_unittest.cc
@@ -49,11 +49,21 @@
 
 TEST_F(ProtoEnumConversionsTest, GetUpdatesSourceString) {
   TestEnumStringFunction(sync_pb::GetUpdatesCallerInfo::GetUpdatesSource_MIN,
-                         sync_pb::GetUpdatesCallerInfo::PERIODIC);
-  TestEnumStringFunction(sync_pb::GetUpdatesCallerInfo::RETRY,
                          sync_pb::GetUpdatesCallerInfo::GetUpdatesSource_MAX);
 }
 
+TEST_F(ProtoEnumConversionsTest, GetUpdatesOriginString) {
+  // This enum has rather scattered values, so we need multiple ranges.
+  TestEnumStringFunction(sync_pb::SyncEnums::GetUpdatesOrigin_MIN,
+                         sync_pb::SyncEnums::UNKNOWN_ORIGIN);
+  TestEnumStringFunction(sync_pb::SyncEnums::PERIODIC,
+                         sync_pb::SyncEnums::PERIODIC);
+  TestEnumStringFunction(sync_pb::SyncEnums::NEWLY_SUPPORTED_DATATYPE,
+                         sync_pb::SyncEnums::RECONFIGURATION);
+  TestEnumStringFunction(sync_pb::SyncEnums::GU_TRIGGER,
+                         sync_pb::SyncEnums::GetUpdatesOrigin_MAX);
+}
+
 TEST_F(ProtoEnumConversionsTest, GetResponseTypeString) {
   TestEnumStringFunction(sync_pb::CommitResponse::ResponseType_MIN,
                          sync_pb::CommitResponse::ResponseType_MAX);
diff --git a/components/sync/protocol/proto_memory_estimations.cc b/components/sync/protocol/proto_memory_estimations.cc
index a36c1478..0f66046 100644
--- a/components/sync/protocol/proto_memory_estimations.cc
+++ b/components/sync/protocol/proto_memory_estimations.cc
@@ -121,7 +121,6 @@
 #define INSTANTIATE(Proto) \
   template size_t EstimateMemoryUsage<Proto>(const Proto&);
 
-INSTANTIATE(AttachmentMetadata)
 INSTANTIATE(DataTypeContext)
 INSTANTIATE(DataTypeProgressMarker)
 INSTANTIATE(EntityMetadata)
diff --git a/components/sync/protocol/proto_visitors.h b/components/sync/protocol/proto_visitors.h
index ffe266d..97c28db4d 100644
--- a/components/sync/protocol/proto_visitors.h
+++ b/components/sync/protocol/proto_visitors.h
@@ -10,7 +10,6 @@
 #include "components/sync/protocol/app_setting_specifics.pb.h"
 #include "components/sync/protocol/app_specifics.pb.h"
 #include "components/sync/protocol/arc_package_specifics.pb.h"
-#include "components/sync/protocol/attachments.pb.h"
 #include "components/sync/protocol/autofill_specifics.pb.h"
 #include "components/sync/protocol/bookmark_specifics.pb.h"
 #include "components/sync/protocol/dictionary_specifics.pb.h"
@@ -146,19 +145,6 @@
   VISIT_REP(pages);
 }
 
-VISIT_PROTO_FIELDS(const sync_pb::AttachmentIdProto& proto) {
-  VISIT(unique_id);
-}
-
-VISIT_PROTO_FIELDS(const sync_pb::AttachmentMetadata& proto) {
-  VISIT_REP(record);
-}
-
-VISIT_PROTO_FIELDS(const sync_pb::AttachmentMetadataRecord& proto) {
-  VISIT(id);
-  VISIT(is_on_server);
-}
-
 VISIT_PROTO_FIELDS(const sync_pb::AutofillCullingFlags& proto) {
   VISIT(enabled);
 }
@@ -758,11 +744,6 @@
   VISIT_ENUM(browser_type);
 }
 
-VISIT_PROTO_FIELDS(const sync_pb::SourceInfo& proto) {
-  VISIT_ENUM(source);
-  VISIT_REP(type_hint);
-}
-
 VISIT_PROTO_FIELDS(const sync_pb::SyncCycleCompletedEventInfo& proto) {
   VISIT(num_encryption_conflicts);
   VISIT(num_hierarchy_conflicts);
@@ -770,7 +751,7 @@
   VISIT(num_updates_downloaded);
   VISIT(num_reflected_updates_downloaded);
   VISIT(caller_info);
-  VISIT_REP(source_info);
+  VISIT_ENUM(get_updates_origin);
 }
 
 VISIT_PROTO_FIELDS(const sync_pb::SyncEntity& proto) {
diff --git a/components/sync/protocol/protocol_sources.gni b/components/sync/protocol/protocol_sources.gni
index 5b58e1a..3212373 100644
--- a/components/sync/protocol/protocol_sources.gni
+++ b/components/sync/protocol/protocol_sources.gni
@@ -9,7 +9,6 @@
   "//components/sync/protocol/app_list_specifics.proto",
   "//components/sync/protocol/arc_package_specifics.proto",
   "//components/sync/protocol/article_specifics.proto",
-  "//components/sync/protocol/attachments.proto",
   "//components/sync/protocol/autofill_specifics.proto",
   "//components/sync/protocol/bookmark_specifics.proto",
   "//components/sync/protocol/client_commands.proto",
diff --git a/components/sync/protocol/sync.proto b/components/sync/protocol/sync.proto
index 4d3001a..0e0b7bd 100644
--- a/components/sync/protocol/sync.proto
+++ b/components/sync/protocol/sync.proto
@@ -618,8 +618,9 @@
   optional int64 from_timestamp = 1;
 
   // Indicates the reason for the GetUpdatesMessage.
-  // Deprecated in M29.  We should eventually rely on GetUpdatesOrigin instead.
-  // Newer clients will support both systems during the transition period.
+  // This was *mostly* deprecated in M29.  We now rely on GetUpdatesOrigin
+  // instead to encode the reason for the GetUpdates request.  Now this field
+  // only contains the "notifications_enabled" flag.
   optional GetUpdatesCallerInfo caller_info = 2;
 
   // Indicates whether related folders should be fetched.
diff --git a/components/sync/syncable/directory_backing_store.cc b/components/sync/syncable/directory_backing_store.cc
index 9bc512e..6b681c4b 100644
--- a/components/sync/syncable/directory_backing_store.cc
+++ b/components/sync/syncable/directory_backing_store.cc
@@ -82,19 +82,10 @@
     //////////////////////////////////////
     // Blobs (positions).
     {"server_unique_position", "blob"},
-    {"unique_position", "blob"},
-    //////////////////////////////////////
-    // AttachmentMetadata is a proto that contains all the metadata associated
-    // with an entry's attachments.  Each entry has only one AttachmentMetadata
-    // proto.  We store a single proto per entry (as opposed to one for each
-    // attachment) because it simplifies the database schema and implementation
-    // of
-    // DirectoryBackingStore.
-    {"attachment_metadata", "blob"},
-    {"server_attachment_metadata", "blob"}};
+    {"unique_position", "blob"}};
 
 // Increment this version whenever updating DB tables.
-const int32_t kCurrentDBVersion = 91;
+const int32_t kCurrentDBVersion = 92;
 
 // The current database page size in Kilobytes.
 const int32_t kCurrentPageSizeKB = 32768;
@@ -132,11 +123,6 @@
     entry.ref(static_cast<UniquePositionField>(i)).SerializeToString(&temp);
     statement->BindBlob(index++, temp.data(), temp.length());
   }
-  for (; i < ATTACHMENT_METADATA_FIELDS_END; ++i) {
-    std::string temp;
-    entry.ref(static_cast<AttachmentMetadataField>(i)).SerializeToString(&temp);
-    statement->BindBlob(index++, temp.data(), temp.length());
-  }
 }
 
 // Helper function that loads a number of shareable fields of the
@@ -220,10 +206,6 @@
     kernel->mutable_ref(static_cast<UniquePositionField>(i)) =
         UniquePosition::FromProto(proto);
   }
-  int attachemnt_specifics_counts = 0;
-  UnpackProtoFields<sync_pb::AttachmentMetadata, AttachmentMetadataField>(
-      statement, kernel.get(), &i, ATTACHMENT_METADATA_FIELDS_END,
-      &attachemnt_specifics_counts);
 
   // Sanity check on positions.  We risk strange and rare crashes if our
   // assumptions about unique position values are broken.
@@ -637,6 +619,12 @@
       version_on_disk = 91;
   }
 
+  // Version 92 migration removes attachment metadata from the metas table.
+  if (version_on_disk == 91) {
+    if (MigrateVersion91To92())
+      version_on_disk = 92;
+  }
+
   // If one of the migrations requested it, drop columns that aren't current.
   // It's only safe to do this after migrating all the way to the current
   // version.
@@ -1570,6 +1558,16 @@
   return true;
 }
 
+bool DirectoryBackingStore::MigrateVersion91To92() {
+  // This change removed 2 columns from metas:
+  //   attachment_metadata
+  //   server_attachment_metadata
+  // No data migration is necessary, but we should do a column refresh.
+  SetVersion(92);
+  needs_metas_column_refresh_ = true;
+  return true;
+}
+
 bool DirectoryBackingStore::CreateTables() {
   DVLOG(1) << "First run, creating tables";
 
diff --git a/components/sync/syncable/directory_backing_store.h b/components/sync/syncable/directory_backing_store.h
index 149a32f..20b4529 100644
--- a/components/sync/syncable/directory_backing_store.h
+++ b/components/sync/syncable/directory_backing_store.h
@@ -188,6 +188,7 @@
   bool MigrateVersion88To89();
   bool MigrateVersion89To90();
   bool MigrateVersion90To91();
+  bool MigrateVersion91To92();
 
   // Accessor for needs_column_refresh_.  Used in tests.
   bool needs_column_refresh() const;
diff --git a/components/sync/syncable/directory_backing_store_unittest.cc b/components/sync/syncable/directory_backing_store_unittest.cc
index 3093bf9..e9ccac8 100644
--- a/components/sync/syncable/directory_backing_store_unittest.cc
+++ b/components/sync/syncable/directory_backing_store_unittest.cc
@@ -98,9 +98,10 @@
   void SetUpVersion89Database(sql::Connection* connection);
   void SetUpVersion90Database(sql::Connection* connection);
   void SetUpVersion91Database(sql::Connection* connection);
+  void SetUpVersion92Database(sql::Connection* connection);
 
   void SetUpCurrentDatabaseAndCheckVersion(sql::Connection* connection) {
-    SetUpVersion91Database(connection);  // Prepopulates data.
+    SetUpVersion92Database(connection);  // Prepopulates data.
     std::unique_ptr<TestDirectoryBackingStore> dbs(
         new TestDirectoryBackingStore(GetUsername(), connection));
     ASSERT_EQ(kCurrentDBVersion, dbs->GetVersion());
@@ -3154,6 +3155,119 @@
   ASSERT_TRUE(connection->CommitTransaction());
 }
 
+void MigrationTest::SetUpVersion92Database(sql::Connection* connection) {
+  ASSERT_TRUE(connection->is_open());
+  ASSERT_TRUE(connection->BeginTransaction());
+  // clang-format mangles the below query by indenting each time the
+  // META_PROTO_TIMES_VALS macro is invoked, making it unreadable.
+  // clang-format off
+  ASSERT_TRUE(connection->Execute(
+    "CREATE TABLE share_version (id VARCHAR(128) primary key, data INT);"
+    "INSERT INTO 'share_version' VALUES('nick@chromium.org',92);"
+    "CREATE TABLE models (model_id BLOB primary key, progress_marker BLOB, tr"
+       "ansaction_version BIGINT default 0, context BLOB);"
+    "INSERT INTO 'models' VALUES(X'C2881000',X'0888810218B605',1,NULL);"
+    "CREATE TABLE 'metas'(metahandle bigint primary key ON CONFLICT FAIL,base"
+       "_version bigint default -1,server_version bigint default 0,local_exte"
+       "rnal_id bigint default 0,transaction_version bigint default 0,mtime b"
+       "igint default 0,server_mtime bigint default 0,ctime bigint default 0,"
+       "server_ctime bigint default 0,id varchar(255) default 'r',parent_id v"
+       "archar(255) default 'r',server_parent_id varchar(255) default 'r',is_"
+       "unsynced bit default 0,is_unapplied_update bit default 0,is_del bit d"
+       "efault 0,is_dir bit default 0,server_is_dir bit default 0,server_is_d"
+       "el bit default 0,non_unique_name varchar,server_non_unique_name varch"
+       "ar(255),unique_server_tag varchar,unique_client_tag varchar,unique_bo"
+       "okmark_tag varchar,specifics blob,server_specifics blob,base_server_s"
+       "pecifics blob,server_unique_position blob,unique_position blob);"
+    "INSERT INTO 'metas' VALUES(1,-1,0,0,0,"
+       META_PROTO_TIMES_VALS(1)
+       ",'r','r','r',0,0,0,1,0,0,NULL,NULL,NULL,NULL,X'',X'',X'',NULL,X'2200'"
+       ",X'2200');"
+    "INSERT INTO 'metas' VALUES(6,694,694,6,0,"
+       META_PROTO_TIMES_VALS(6)
+       ",'s_ID_6','s_ID_9','s_ID_9',0,0,0,1,1,0,'The Internet','The Internet'"
+       ",NULL,NULL,X'6754307476346749735A5734654D653273625336557753582F77673D"
+       "',X'C2881000',X'C2881000',NULL,X'22247FFFFFFFFFC000006754307476346749"
+       "735A5734654D653273625336557753582F77673D',X'22247FFFFFFFFFC0000067543"
+       "07476346749735A5734654D653273625336557753582F77673D');"
+    "INSERT INTO 'metas' VALUES(7,663,663,0,0,"
+       META_PROTO_TIMES_VALS(7)
+       ",'s_ID_7','r','r',0,0,0,1,1,0,'Google Chrome','Google Chrome','google"
+       "_chrome',NULL,X'',NULL,NULL,NULL,X'2200',X'2200');"
+    "INSERT INTO 'metas' VALUES(8,664,664,0,0,"
+       META_PROTO_TIMES_VALS(8)
+       ",'s_ID_8','s_ID_7','s_ID_7',0,0,0,1,1,0,'Bookmarks','Bookmarks','goog"
+       "le_chrome_bookmarks',NULL,X'',X'C2881000',X'C2881000',NULL,X'2200',X'"
+       "2200');"
+    "INSERT INTO 'metas' VALUES(9,665,665,1,0,"
+       META_PROTO_TIMES_VALS(9)
+       ",'s_ID_9','s_ID_8','s_ID_8',0,0,0,1,1,0,'Bookmark Bar','Bookmark Bar'"
+       ",'bookmark_bar',NULL,X'',X'C2881000',X'C2881000',NULL,X'2200',X'2200'"
+       ");"
+    "INSERT INTO 'metas' VALUES(10,666,666,2,0,"
+       META_PROTO_TIMES_VALS(10)
+       ",'s_ID_10','s_ID_8','s_ID_8',0,0,0,1,1,0,'Other Bookmarks','Other Boo"
+       "kmarks','other_bookmarks',NULL,X'',X'C2881000',X'C2881000',NULL,X'220"
+       "0',X'2200');"
+    "INSERT INTO 'metas' VALUES(11,683,683,8,0,"
+       META_PROTO_TIMES_VALS(11)
+       ",'s_ID_11','s_ID_6','s_ID_6',0,0,0,0,0,0,'Home (The Chromium Projects"
+       ")','Home (The Chromium Projects)',NULL,NULL,X'50514C784A456D623579366"
+       "267644237646A7A2B62314130346E493D',X'C28810220A18687474703A2F2F646576"
+       "2E6368726F6D69756D2E6F72672F1206414741545741',X'C28810290A1D687474703"
+       "A2F2F6465762E6368726F6D69756D2E6F72672F6F7468657212084146414756415346"
+       "',NULL,X'22247FFFFFFFFFF0000050514C784A456D623579366267644237646A7A2B"
+       "62314130346E493D',X'22247FFFFFFFFFF0000050514C784A456D623579366267644"
+       "237646A7A2B62314130346E493D');"
+    "INSERT INTO 'metas' VALUES(12,685,685,9,0,"
+       META_PROTO_TIMES_VALS(12)
+       ",'s_ID_12','s_ID_6','s_ID_6',0,0,0,1,1,0,'Extra Bookmarks','Extra Boo"
+       "kmarks',NULL,NULL,X'7867626A704A646134635A6F616C376A49513338734B46324"
+       "837773D',X'C2881000',X'C2881000',NULL,X'222480000000000000007867626A7"
+       "04A646134635A6F616C376A49513338734B46324837773D',X'222480000000000000"
+       "007867626A704A646134635A6F616C376A49513338734B46324837773D');"
+    "INSERT INTO 'metas' VALUES(13,687,687,10,0,"
+       META_PROTO_TIMES_VALS(13)
+       ",'s_ID_13','s_ID_6','s_ID_6',0,0,0,0,0,0,'ICANN | Internet Corporatio"
+       "n for Assigned Names and Numbers','ICANN | Internet Corporation for A"
+       "ssigned Names and Numbers',NULL,NULL,X'3142756B572F774176695650417967"
+       "2B304A614A514B3452384A413D',X'C28810240A15687474703A2F2F7777772E69636"
+       "16E6E2E636F6D2F120B504E474158463041414646',X'C28810200A15687474703A2F"
+       "2F7777772E6963616E6E2E636F6D2F120744414146415346',NULL,X'22247FFFFFFF"
+       "FFF200003142756B572F7741766956504179672B304A614A514B3452384A413D',X'2"
+       "2247FFFFFFFFFF200003142756B572F7741766956504179672B304A614A514B345238"
+       "4A413D');"
+    "INSERT INTO 'metas' VALUES(14,692,692,11,0,"
+       META_PROTO_TIMES_VALS(14)
+       ",'s_ID_14','s_ID_6','s_ID_6',0,0,0,0,0,0,'The WebKit Open Source Proj"
+       "ect','The WebKit Open Source Project',NULL,NULL,X'5A5678314E797636457"
+       "9524D3177494F7236563159552F6E644C553D',X'C288101A0A12687474703A2F2F77"
+       "65626B69742E6F72672F1204504E4758',X'C288101C0A13687474703A2F2F7765626"
+       "B69742E6F72672F781205504E473259',NULL,X'222480000000001000005A5678314"
+       "E7976364579524D3177494F7236563159552F6E644C553D',X'222480000000001000"
+       "005A5678314E7976364579524D3177494F7236563159552F6E644C553D');"
+    "CREATE TABLE deleted_metas (metahandle bigint primary key ON CONFLICT FA"
+       "IL,base_version bigint default -1,server_version bigint default 0,loc"
+       "al_external_id bigint default 0,transaction_version bigint default 0,"
+       "mtime bigint default 0,server_mtime bigint default 0,ctime bigint def"
+       "ault 0,server_ctime bigint default 0,id varchar(255) default 'r',pare"
+       "nt_id varchar(255) default 'r',server_parent_id varchar(255) default "
+       "'r',is_unsynced bit default 0,is_unapplied_update bit default 0,is_de"
+       "l bit default 0,is_dir bit default 0,server_is_dir bit default 0,serv"
+       "er_is_del bit default 0,non_unique_name varchar,server_non_unique_nam"
+       "e varchar(255),unique_server_tag varchar,unique_client_tag varchar,un"
+       "ique_bookmark_tag varchar,specifics blob,server_specifics blob,base_s"
+       "erver_specifics blob,server_unique_position blob,unique_position blob"
+       ");"
+    "CREATE TABLE 'share_info' (id TEXT primary key, name TEXT, store_birthda"
+       "y TEXT, cache_guid TEXT, bag_of_chips BLOB);"
+    "INSERT INTO 'share_info' VALUES('nick@chromium.org','nick@chromium.org',"
+       "'c27e9f59-08ca-46f8-b0cc-f16a2ed778bb','9010788312004066376x-66092343"
+       "93368420856x',NULL);"));
+  // clang-format on
+  ASSERT_TRUE(connection->CommitTransaction());
+}
+
 TEST_F(DirectoryBackingStoreTest, MigrateVersion67To68) {
   sql::Connection connection;
   ASSERT_TRUE(connection.OpenInMemory());
@@ -3682,6 +3796,28 @@
   ASSERT_FALSE(dbs->needs_column_refresh());
 }
 
+TEST_F(DirectoryBackingStoreTest, MigrateVersion91To92) {
+  sql::Connection connection;
+  ASSERT_TRUE(connection.OpenInMemory());
+  SetUpVersion91Database(&connection);
+  ASSERT_TRUE(connection.DoesColumnExist("metas", "attachment_metadata"));
+  ASSERT_TRUE(
+      connection.DoesColumnExist("metas", "server_attachment_metadata"));
+
+  std::unique_ptr<TestDirectoryBackingStore> dbs(
+      new TestDirectoryBackingStore(GetUsername(), &connection));
+  ASSERT_TRUE(dbs->MigrateVersion91To92());
+  ASSERT_EQ(92, dbs->GetVersion());
+  EXPECT_TRUE(dbs->needs_column_refresh());
+
+  ASSERT_TRUE(dbs->RefreshColumns());
+  EXPECT_FALSE(dbs->needs_column_refresh());
+
+  ASSERT_FALSE(connection.DoesColumnExist("metas", "attachment_metadata"));
+  ASSERT_FALSE(
+      connection.DoesColumnExist("metas", "server_attachment_metadata"));
+}
+
 // The purpose of this test case is to make it easier to get a dump of the
 // database so you can implement a SetUpVersionYDatabase method.  Here's what
 // you should do:
@@ -3703,13 +3839,13 @@
   {
     sql::Connection connection;
     ASSERT_TRUE(connection.Open(GetDatabasePath()));
-    SetUpVersion89Database(&connection);  // Update this.
+    SetUpVersion91Database(&connection);  // Update this.
 
     std::unique_ptr<TestDirectoryBackingStore> dbs(
         new TestDirectoryBackingStore(GetUsername(), &connection));
-    ASSERT_TRUE(dbs->MigrateVersion90To91());  // Update this.
+    ASSERT_TRUE(dbs->MigrateVersion91To92());  // Update this.
     ASSERT_TRUE(LoadAndIgnoreReturnedData(dbs.get()));
-    EXPECT_EQ(91, dbs->GetVersion());  // Update this.
+    EXPECT_EQ(92, dbs->GetVersion());  // Update this.
     ASSERT_FALSE(dbs->needs_column_refresh());
   }
   // Set breakpoint here.
@@ -3840,6 +3976,9 @@
     case 91:
       SetUpVersion91Database(&connection);
       break;
+    case 92:
+      SetUpVersion92Database(&connection);
+      break;
     default:
       // If you see this error, it may mean that you've increased the
       // database version number but you haven't finished adding unit tests
@@ -3933,22 +4072,20 @@
   ASSERT_FALSE(connection.DoesColumnExist("metas", "prev_id"));
   ASSERT_FALSE(connection.DoesColumnExist("metas", "server_ordinal_in_parent"));
 
-  // Column added in version 87.
-  ASSERT_TRUE(connection.DoesColumnExist("metas", "attachment_metadata"));
-
   // Column added in version 88.
   ASSERT_TRUE(connection.DoesColumnExist("models", "context"));
 
-  // Column added in version 89.
-  ASSERT_TRUE(
-      connection.DoesColumnExist("metas", "server_attachment_metadata"));
-
   // Columns removed in version 90.
   ASSERT_FALSE(connection.DoesColumnExist("share_info", "db_create_version"));
   ASSERT_FALSE(connection.DoesColumnExist("share_info", "db_create_time"));
   ASSERT_FALSE(connection.DoesColumnExist("share_info", "next_id"));
   ASSERT_FALSE(connection.DoesColumnExist("share_info", "notification_state"));
 
+  // Columns removed in version 92.
+  ASSERT_FALSE(connection.DoesColumnExist("metas", "attachment_metadata"));
+  ASSERT_FALSE(
+      connection.DoesColumnExist("metas", "server_attachment_metadata"));
+
   // Check download_progress state (v75 migration)
   ASSERT_EQ(694,
       dir_info.kernel_info.download_progress[BOOKMARKS]
@@ -3984,8 +4121,6 @@
   EXPECT_FALSE(it->second->ref(UNIQUE_POSITION).IsValid());
   EXPECT_FALSE(it->second->ref(SERVER_UNIQUE_POSITION).IsValid());
   EXPECT_TRUE(it->second->ref(UNIQUE_BOOKMARK_TAG).empty());
-  EXPECT_TRUE(it->second->ref(ATTACHMENT_METADATA).IsInitialized());
-  EXPECT_TRUE(it->second->ref(SERVER_ATTACHMENT_METADATA).IsInitialized());
 
   // Items 2, 4, and 5 were deleted.
   it = handles_map.find(2);
@@ -4007,8 +4142,6 @@
   EXPECT_TRUE(it->second->ref(SERVER_UNIQUE_POSITION).IsValid());
   EXPECT_EQ(UniquePosition::kSuffixLength,
             it->second->ref(UNIQUE_BOOKMARK_TAG).length());
-  EXPECT_TRUE(it->second->ref(ATTACHMENT_METADATA).IsInitialized());
-  EXPECT_TRUE(it->second->ref(SERVER_ATTACHMENT_METADATA).IsInitialized());
 
   it = handles_map.find(7);
   ASSERT_EQ(7, it->second->ref(META_HANDLE));
@@ -4019,8 +4152,6 @@
   EXPECT_FALSE(it->second->ref(UNIQUE_POSITION).IsValid());
   EXPECT_FALSE(it->second->ref(SERVER_UNIQUE_POSITION).IsValid());
   EXPECT_TRUE(it->second->ref(UNIQUE_BOOKMARK_TAG).empty());
-  EXPECT_TRUE(it->second->ref(ATTACHMENT_METADATA).IsInitialized());
-  EXPECT_TRUE(it->second->ref(SERVER_ATTACHMENT_METADATA).IsInitialized());
 
   it = handles_map.find(8);
   ASSERT_EQ(8, it->second->ref(META_HANDLE));
@@ -4032,8 +4163,6 @@
   EXPECT_FALSE(it->second->ref(UNIQUE_POSITION).IsValid());
   EXPECT_FALSE(it->second->ref(SERVER_UNIQUE_POSITION).IsValid());
   EXPECT_TRUE(it->second->ref(UNIQUE_BOOKMARK_TAG).empty());
-  EXPECT_TRUE(it->second->ref(ATTACHMENT_METADATA).IsInitialized());
-  EXPECT_TRUE(it->second->ref(SERVER_ATTACHMENT_METADATA).IsInitialized());
 
   it = handles_map.find(9);
   ASSERT_EQ(9, it->second->ref(META_HANDLE));
@@ -4044,8 +4173,6 @@
   EXPECT_FALSE(it->second->ref(UNIQUE_POSITION).IsValid());
   EXPECT_FALSE(it->second->ref(SERVER_UNIQUE_POSITION).IsValid());
   EXPECT_TRUE(it->second->ref(UNIQUE_BOOKMARK_TAG).empty());
-  EXPECT_TRUE(it->second->ref(ATTACHMENT_METADATA).IsInitialized());
-  EXPECT_TRUE(it->second->ref(SERVER_ATTACHMENT_METADATA).IsInitialized());
 
   it = handles_map.find(10);
   ASSERT_EQ(10, it->second->ref(META_HANDLE));
@@ -4060,14 +4187,10 @@
   EXPECT_EQ("Other Bookmarks", it->second->ref(NON_UNIQUE_NAME));
   EXPECT_EQ("Other Bookmarks", it->second->ref(SERVER_NON_UNIQUE_NAME));
   ASSERT_EQ(it->second->ref(ID).value(), "s_ID_10");
-  EXPECT_TRUE(it->second->ref(ATTACHMENT_METADATA).IsInitialized());
-  EXPECT_TRUE(it->second->ref(SERVER_ATTACHMENT_METADATA).IsInitialized());
   // Make sure we didn't assign positions to server-created folders, either.
   EXPECT_FALSE(it->second->ref(UNIQUE_POSITION).IsValid());
   EXPECT_FALSE(it->second->ref(SERVER_UNIQUE_POSITION).IsValid());
   EXPECT_TRUE(it->second->ref(UNIQUE_BOOKMARK_TAG).empty());
-  EXPECT_TRUE(it->second->ref(ATTACHMENT_METADATA).IsInitialized());
-  EXPECT_TRUE(it->second->ref(SERVER_ATTACHMENT_METADATA).IsInitialized());
 
   it = handles_map.find(11);
   ASSERT_EQ(11, it->second->ref(META_HANDLE));
@@ -4089,7 +4212,6 @@
   EXPECT_TRUE(it->second->ref(SERVER_UNIQUE_POSITION).IsValid());
   EXPECT_EQ(UniquePosition::kSuffixLength,
             it->second->ref(UNIQUE_BOOKMARK_TAG).length());
-  EXPECT_TRUE(it->second->ref(ATTACHMENT_METADATA).IsInitialized());
 
   it = handles_map.find(12);
   ASSERT_EQ(12, it->second->ref(META_HANDLE));
@@ -4107,8 +4229,6 @@
   EXPECT_TRUE(it->second->ref(SERVER_UNIQUE_POSITION).IsValid());
   EXPECT_EQ(UniquePosition::kSuffixLength,
             it->second->ref(UNIQUE_BOOKMARK_TAG).length());
-  EXPECT_TRUE(it->second->ref(ATTACHMENT_METADATA).IsInitialized());
-  EXPECT_TRUE(it->second->ref(SERVER_ATTACHMENT_METADATA).IsInitialized());
 
   it = handles_map.find(13);
   ASSERT_EQ(13, it->second->ref(META_HANDLE));
@@ -4116,8 +4236,6 @@
   EXPECT_TRUE(it->second->ref(SERVER_UNIQUE_POSITION).IsValid());
   EXPECT_EQ(UniquePosition::kSuffixLength,
             it->second->ref(UNIQUE_BOOKMARK_TAG).length());
-  EXPECT_TRUE(it->second->ref(ATTACHMENT_METADATA).IsInitialized());
-  EXPECT_TRUE(it->second->ref(SERVER_ATTACHMENT_METADATA).IsInitialized());
 
   it = handles_map.find(14);
   ASSERT_EQ(14, it->second->ref(META_HANDLE));
@@ -4125,8 +4243,6 @@
   EXPECT_TRUE(it->second->ref(SERVER_UNIQUE_POSITION).IsValid());
   EXPECT_EQ(UniquePosition::kSuffixLength,
             it->second->ref(UNIQUE_BOOKMARK_TAG).length());
-  EXPECT_TRUE(it->second->ref(ATTACHMENT_METADATA).IsInitialized());
-  EXPECT_TRUE(it->second->ref(SERVER_ATTACHMENT_METADATA).IsInitialized());
 
   ASSERT_EQ(static_cast<size_t>(10), handles_map.size());
 
diff --git a/components/sync/syncable/entry.h b/components/sync/syncable/entry.h
index 7669eba..352a06d 100644
--- a/components/sync/syncable/entry.h
+++ b/components/sync/syncable/entry.h
@@ -206,16 +206,6 @@
     return kernel_->ref(UNIQUE_POSITION);
   }
 
-  const sync_pb::AttachmentMetadata& GetAttachmentMetadata() const {
-    DCHECK(kernel_);
-    return kernel_->ref(ATTACHMENT_METADATA);
-  }
-
-  const sync_pb::AttachmentMetadata& GetServerAttachmentMetadata() const {
-    DCHECK(kernel_);
-    return kernel_->ref(SERVER_ATTACHMENT_METADATA);
-  }
-
   bool GetSyncing() const;
   bool GetDirtySync() const;
 
diff --git a/components/sync/syncable/entry_kernel.cc b/components/sync/syncable/entry_kernel.cc
index e984a48..938b5ac0 100644
--- a/components/sync/syncable/entry_kernel.cc
+++ b/components/sync/syncable/entry_kernel.cc
@@ -145,11 +145,6 @@
   return std::make_unique<base::Value>(pos.ToDebugString());
 }
 
-std::unique_ptr<base::Value> AttachmentMetadataToValue(
-    const sync_pb::AttachmentMetadata& a) {
-  return std::make_unique<base::Value>(a.SerializeAsString());
-}
-
 // Estimates memory usage of ProtoValuePtr<T> arrays where consecutive
 // elements can share the same value.
 template <class T, size_t N>
@@ -216,11 +211,6 @@
                  &UniquePositionToValue, UNIQUE_POSITION_FIELDS_BEGIN,
                  UNIQUE_POSITION_FIELDS_END - 1);
 
-  // AttachmentMetadata fields
-  SetFieldValues(*this, kernel_info.get(), &GetAttachmentMetadataFieldString,
-                 &AttachmentMetadataToValue, ATTACHMENT_METADATA_FIELDS_BEGIN,
-                 ATTACHMENT_METADATA_FIELDS_END - 1);
-
   // Bit temps.
   SetFieldValues(*this, kernel_info.get(), &GetBitTempString, &BooleanToValue,
                  BIT_TEMPS_BEGIN, BIT_TEMPS_END - 1);
@@ -234,8 +224,7 @@
     memory_usage_ = EstimateMemoryUsage(string_fields) +
                     EstimateSharedMemoryUsage(specifics_fields) +
                     EstimateMemoryUsage(id_fields) +
-                    EstimateMemoryUsage(unique_position_fields) +
-                    EstimateSharedMemoryUsage(attachment_metadata_fields);
+                    EstimateMemoryUsage(unique_position_fields);
   }
   return memory_usage_;
 }
@@ -292,13 +281,6 @@
        << kernel->ref(static_cast<UniquePositionField>(i)).ToDebugString()
        << ", ";
   }
-  for (; i < ATTACHMENT_METADATA_FIELDS_END; ++i) {
-    std::string escaped_str = base::EscapeBytesAsInvalidJSONString(
-        kernel->ref(static_cast<AttachmentMetadataField>(i))
-            .SerializeAsString(),
-        false);
-    os << g_metas_columns[i].name << ": " << escaped_str << ", ";
-  }
   os << "TempFlags: ";
   for (; i < BIT_TEMPS_END; ++i) {
     if (kernel->ref(static_cast<BitTemp>(i)))
diff --git a/components/sync/syncable/entry_kernel.h b/components/sync/syncable/entry_kernel.h
index fbaac41..97e89bb 100644
--- a/components/sync/syncable/entry_kernel.h
+++ b/components/sync/syncable/entry_kernel.h
@@ -20,7 +20,6 @@
 #include "components/sync/base/proto_value_ptr.h"
 #include "components/sync/base/time.h"
 #include "components/sync/base/unique_position.h"
-#include "components/sync/protocol/attachments.pb.h"
 #include "components/sync/protocol/sync.pb.h"
 #include "components/sync/syncable/metahandle_set.h"
 #include "components/sync/syncable/syncable_id.h"
@@ -161,23 +160,14 @@
 
 enum {
   UNIQUE_POSITION_FIELDS_COUNT =
-      UNIQUE_POSITION_FIELDS_END - UNIQUE_POSITION_FIELDS_BEGIN,
-  ATTACHMENT_METADATA_FIELDS_BEGIN = UNIQUE_POSITION_FIELDS_END
-};
-
-enum AttachmentMetadataField {
-  ATTACHMENT_METADATA = ATTACHMENT_METADATA_FIELDS_BEGIN,
-  SERVER_ATTACHMENT_METADATA,
-  ATTACHMENT_METADATA_FIELDS_END
+      UNIQUE_POSITION_FIELDS_END - UNIQUE_POSITION_FIELDS_BEGIN
 };
 
 enum {
-  ATTACHMENT_METADATA_FIELDS_COUNT =
-      ATTACHMENT_METADATA_FIELDS_END - ATTACHMENT_METADATA_FIELDS_BEGIN,
   // If FIELD_COUNT is changed then g_metas_columns must be updated.
-  FIELD_COUNT = ATTACHMENT_METADATA_FIELDS_END - BEGIN_FIELDS,
+  FIELD_COUNT = UNIQUE_POSITION_FIELDS_END - BEGIN_FIELDS,
   // Past this point we have temporaries, stored in memory only.
-  BEGIN_TEMPS = ATTACHMENT_METADATA_FIELDS_END,
+  BEGIN_TEMPS = UNIQUE_POSITION_FIELDS_END,
   BIT_TEMPS_BEGIN = BEGIN_TEMPS,
 };
 
@@ -197,7 +187,6 @@
 struct EntryKernel {
  private:
   using EntitySpecificsPtr = ProtoValuePtr<sync_pb::EntitySpecifics>;
-  using AttachmentMetadataPtr = ProtoValuePtr<sync_pb::AttachmentMetadata>;
 
   std::string string_fields[STRING_FIELDS_COUNT];
   EntitySpecificsPtr specifics_fields[PROTO_FIELDS_COUNT];
@@ -205,8 +194,6 @@
   base::Time time_fields[TIME_FIELDS_COUNT];
   Id id_fields[ID_FIELDS_COUNT];
   UniquePosition unique_position_fields[UNIQUE_POSITION_FIELDS_COUNT];
-  AttachmentMetadataPtr
-      attachment_metadata_fields[ATTACHMENT_METADATA_FIELDS_COUNT];
   std::bitset<BIT_FIELDS_COUNT> bit_fields;
   std::bitset<BIT_TEMPS_COUNT> bit_temps;
 
@@ -279,11 +266,6 @@
   inline void put(UniquePositionField field, const UniquePosition& value) {
     unique_position_fields[field - UNIQUE_POSITION_FIELDS_BEGIN] = value;
   }
-  inline void put(AttachmentMetadataField field,
-                  const sync_pb::AttachmentMetadata& value) {
-    attachment_metadata_fields[field - ATTACHMENT_METADATA_FIELDS_BEGIN]
-        .set_value(value);
-  }
   inline void put(BitTemp field, bool value) {
     bit_temps[field - BIT_TEMPS_BEGIN] = value;
   }
@@ -322,11 +304,6 @@
   inline const UniquePosition& ref(UniquePositionField field) const {
     return unique_position_fields[field - UNIQUE_POSITION_FIELDS_BEGIN];
   }
-  inline const sync_pb::AttachmentMetadata& ref(
-      AttachmentMetadataField field) const {
-    return attachment_metadata_fields[field - ATTACHMENT_METADATA_FIELDS_BEGIN]
-        .value();
-  }
   inline bool ref(BitTemp field) const {
     return bit_temps[field - BIT_TEMPS_BEGIN];
   }
@@ -347,13 +324,6 @@
     specifics_fields[field - PROTO_FIELDS_BEGIN].load(blob, length);
   }
 
-  inline void load(AttachmentMetadataField field,
-                   const void* blob,
-                   int length) {
-    attachment_metadata_fields[field - ATTACHMENT_METADATA_FIELDS_BEGIN].load(
-        blob, length);
-  }
-
   // Sharing data methods for ::google::protobuf::MessageLite derived types.
   inline void copy(ProtoField src, ProtoField dest) {
     DCHECK_NE(src, dest);
@@ -361,12 +331,6 @@
         specifics_fields[src - PROTO_FIELDS_BEGIN];
   }
 
-  inline void copy(AttachmentMetadataField src, AttachmentMetadataField dest) {
-    DCHECK_NE(src, dest);
-    attachment_metadata_fields[dest - ATTACHMENT_METADATA_FIELDS_BEGIN] =
-        attachment_metadata_fields[src - ATTACHMENT_METADATA_FIELDS_BEGIN];
-  }
-
   ModelType GetModelType() const;
   ModelType GetServerModelType() const;
   bool ShouldMaintainPosition() const;
diff --git a/components/sync/syncable/syncable_enum_conversions.cc b/components/sync/syncable/syncable_enum_conversions.cc
index db64a81..4bd65df 100644
--- a/components/sync/syncable/syncable_enum_conversions.cc
+++ b/components/sync/syncable/syncable_enum_conversions.cc
@@ -156,21 +156,6 @@
   return "";
 }
 
-const char* GetAttachmentMetadataFieldString(
-    AttachmentMetadataField attachment_metadata_field) {
-  ASSERT_ENUM_BOUNDS(ATTACHMENT_METADATA, SERVER_ATTACHMENT_METADATA,
-                     ATTACHMENT_METADATA_FIELDS_BEGIN,
-                     ATTACHMENT_METADATA_FIELDS_END - 1);
-  switch (attachment_metadata_field) {
-    ENUM_CASE(ATTACHMENT_METADATA);
-    ENUM_CASE(SERVER_ATTACHMENT_METADATA);
-    case ATTACHMENT_METADATA_FIELDS_END:
-      break;
-  }
-  NOTREACHED();
-  return "";
-}
-
 const char* GetBitTempString(BitTemp bit_temp) {
   ASSERT_ENUM_BOUNDS(SYNCING, DIRTY_SYNC, BIT_TEMPS_BEGIN, BIT_TEMPS_END - 1);
   switch (bit_temp) {
diff --git a/components/sync/syncable/syncable_enum_conversions.h b/components/sync/syncable/syncable_enum_conversions.h
index 49e288c1..365ab5f 100644
--- a/components/sync/syncable/syncable_enum_conversions.h
+++ b/components/sync/syncable/syncable_enum_conversions.h
@@ -40,9 +40,6 @@
 
 const char* GetUniquePositionFieldString(UniquePositionField position_field);
 
-const char* GetAttachmentMetadataFieldString(
-    AttachmentMetadataField attachment_metadata_field);
-
 const char* GetBitTempString(BitTemp bit_temp);
 
 }  // namespace syncable
diff --git a/components/sync/syncable/syncable_enum_conversions_unittest.cc b/components/sync/syncable/syncable_enum_conversions_unittest.cc
index 3711a13..f439197 100644
--- a/components/sync/syncable/syncable_enum_conversions_unittest.cc
+++ b/components/sync/syncable/syncable_enum_conversions_unittest.cc
@@ -78,12 +78,6 @@
                          UNIQUE_POSITION_FIELDS_END - 1);
 }
 
-TEST_F(SyncableEnumConversionsTest, GetAttachmentMetadataFieldString) {
-  TestEnumStringFunction(GetAttachmentMetadataFieldString,
-                         ATTACHMENT_METADATA_FIELDS_BEGIN,
-                         ATTACHMENT_METADATA_FIELDS_END - 1);
-}
-
 TEST_F(SyncableEnumConversionsTest, GetBitTempString) {
   TestEnumStringFunction(GetBitTempString, BIT_TEMPS_BEGIN, BIT_TEMPS_END - 1);
 }
diff --git a/components/sync/test/engine/mock_connection_manager.cc b/components/sync/test/engine/mock_connection_manager.cc
index 02e29ba..753f89b 100644
--- a/components/sync/test/engine/mock_connection_manager.cc
+++ b/components/sync/test/engine/mock_connection_manager.cc
@@ -547,8 +547,7 @@
   EXPECT_FALSE(gu.has_requested_types());
 
   if (fail_non_periodic_get_updates_) {
-    EXPECT_EQ(sync_pb::GetUpdatesCallerInfo::PERIODIC,
-              gu.caller_info().source());
+    EXPECT_EQ(sync_pb::SyncEnums::PERIODIC, gu.get_updates_origin());
   }
 
   // Verify that the items we're about to send back to the client are of
diff --git a/components/sync/test/test_directory_backing_store.h b/components/sync/test/test_directory_backing_store.h
index e275080..0cf23ec 100644
--- a/components/sync/test/test_directory_backing_store.h
+++ b/components/sync/test/test_directory_backing_store.h
@@ -56,6 +56,7 @@
   FRIEND_TEST_ALL_PREFIXES(DirectoryBackingStoreTest, MigrateVersion88To89);
   FRIEND_TEST_ALL_PREFIXES(DirectoryBackingStoreTest, MigrateVersion89To90);
   FRIEND_TEST_ALL_PREFIXES(DirectoryBackingStoreTest, MigrateVersion90To91);
+  FRIEND_TEST_ALL_PREFIXES(DirectoryBackingStoreTest, MigrateVersion91To92);
   FRIEND_TEST_ALL_PREFIXES(DirectoryBackingStoreTest, DetectInvalidPosition);
   FRIEND_TEST_ALL_PREFIXES(DirectoryBackingStoreTest, ModelTypeIds);
   FRIEND_TEST_ALL_PREFIXES(DirectoryBackingStoreTest, Corruption);
diff --git a/components/sync/tools/testserver/chromiumsync.py b/components/sync/tools/testserver/chromiumsync.py
index e6f1991..fe1c0ff 100644
--- a/components/sync/tools/testserver/chromiumsync.py
+++ b/components/sync/tools/testserver/chromiumsync.py
@@ -33,7 +33,6 @@
 import bookmark_specifics_pb2
 import client_commands_pb2
 import dictionary_specifics_pb2
-import get_updates_caller_info_pb2
 import extension_setting_specifics_pb2
 import extension_specifics_pb2
 import favicon_image_specifics_pb2
@@ -302,11 +301,10 @@
   return SYNC_TYPE_TO_DESCRIPTOR[data_type].name
 
 
-def CallerInfoToString(caller_info_source):
-  """Formats a GetUpdatesSource enum value to a readable string."""
-  return get_updates_caller_info_pb2.GetUpdatesCallerInfo \
-      .DESCRIPTOR.enum_types_by_name['GetUpdatesSource'] \
-      .values_by_number[caller_info_source].name
+def GetUpdatesOriginToString(origin):
+  """Formats a GetUpdatesOrigin enum value to a readable string."""
+  return sync_enums_pb2.SyncEnums.DESCRIPTOR \
+      .enum_types_by_name['GetUpdatesOrigin'].values_by_number[origin].name
 
 
 def ShortDatatypeListSummary(data_types):
@@ -1581,7 +1579,7 @@
     update_response.SetInParent()
     update_sieve = UpdateSieve(update_request, self.account.migration_history)
 
-    print CallerInfoToString(update_request.caller_info.source),
+    print GetUpdatesOriginToString(update_request.get_updates_origin),
     print update_sieve.SummarizeRequest()
 
     update_sieve.CheckMigrationState()
diff --git a/components/sync_sessions/local_session_event_handler_impl.cc b/components/sync_sessions/local_session_event_handler_impl.cc
index 01e5e84..cce4816 100644
--- a/components/sync_sessions/local_session_event_handler_impl.cc
+++ b/components/sync_sessions/local_session_event_handler_impl.cc
@@ -13,7 +13,6 @@
 #include "base/strings/stringprintf.h"
 #include "components/sync/model/sync_change.h"
 #include "components/sync/protocol/sync.pb.h"
-#include "components/sync_sessions/sessions_global_id_mapper.h"
 #include "components/sync_sessions/sync_sessions_client.h"
 #include "components/sync_sessions/synced_session_tracker.h"
 #include "components/sync_sessions/synced_tab_delegate.h"
@@ -105,36 +104,24 @@
 LocalSessionEventHandlerImpl::LocalSessionEventHandlerImpl(
     Delegate* delegate,
     SyncSessionsClient* sessions_client,
-    SyncedSessionTracker* session_tracker)
+    SyncedSessionTracker* session_tracker,
+    WriteBatch* initial_batch)
     : delegate_(delegate),
       sessions_client_(sessions_client),
       session_tracker_(session_tracker) {
   DCHECK(delegate);
   DCHECK(sessions_client);
   DCHECK(session_tracker);
+  DCHECK(initial_batch);
+
+  current_session_tag_ = session_tracker_->GetLocalSessionTag();
+  DCHECK(!current_session_tag_.empty());
+
+  AssociateWindows(RELOAD_TABS, ScanForTabbedWindow(), initial_batch);
 }
 
 LocalSessionEventHandlerImpl::~LocalSessionEventHandlerImpl() {}
 
-void LocalSessionEventHandlerImpl::AssociateWindowsAndTabs(
-    const std::string& session_tag,
-    const std::string& session_name,
-    sync_pb::SyncEnums::DeviceType device_type,
-    WriteBatch* change_output) {
-  SyncedSession* current_session = session_tracker_->GetSession(session_tag);
-  current_session->session_name = session_name;
-  current_session->device_type = device_type;
-  current_session->session_tag = session_tag;
-
-  current_session_tag_ = session_tag;
-
-  AssociateWindows(RELOAD_TABS, ScanForTabbedWindow(), change_output);
-}
-
-SessionsGlobalIdMapper* LocalSessionEventHandlerImpl::GetGlobalIdMapper() {
-  return &global_id_mapper_;
-}
-
 void LocalSessionEventHandlerImpl::SetSessionTabFromDelegateForTest(
     const SyncedTabDelegate& tab_delegate,
     base::Time mtime,
@@ -144,7 +131,7 @@
 
 void LocalSessionEventHandlerImpl::AssociateWindows(ReloadTabsOption option,
                                                     bool has_tabbed_window,
-                                                    WriteBatch* change_output) {
+                                                    WriteBatch* batch) {
   // Note that |current_session| is a pointer owned by |session_tracker_|.
   // |session_tracker_| will continue to update |current_session| under
   // the hood so care must be taken accessing it. In particular, invoking
@@ -190,7 +177,7 @@
         }
         DVLOG(1) << "Rewriting tab node " << sync_id << " with tab id "
                  << tab->tab_id.id();
-        AppendChangeForExistingTab(sync_id, *tab, change_output);
+        AppendChangeForExistingTab(sync_id, *tab, batch);
       }
     }
   }
@@ -253,12 +240,12 @@
         // as it could have changed after a session restore.
         if (synced_tab->GetSyncId() > TabNodePool::kInvalidTabNodeID) {
           AssociateRestoredPlaceholderTab(*synced_tab, tab_id, window_id,
-                                          change_output);
+                                          batch);
         } else {
           DVLOG(1) << "Placeholder tab " << tab_id << " has no sync id.";
         }
       } else if (RELOAD_TABS == option) {
-        AssociateTab(synced_tab, has_tabbed_window, change_output);
+        AssociateTab(synced_tab, has_tabbed_window, batch);
       }
 
       // If the tab was syncable, it would have been added to the tracker
@@ -302,7 +289,7 @@
   std::set<int> deleted_tab_node_ids;
   session_tracker_->CleanupLocalTabs(&deleted_tab_node_ids);
   for (int tab_node_id : deleted_tab_node_ids) {
-    change_output->Delete(tab_node_id);
+    batch->Delete(tab_node_id);
   }
 
   // Always update the header.  Sync takes care of dropping this update
@@ -311,13 +298,13 @@
   auto specifics = std::make_unique<sync_pb::SessionSpecifics>();
   specifics->set_session_tag(current_session_tag_);
   current_session->ToSessionHeaderProto().Swap(specifics->mutable_header());
-  change_output->Update(std::move(specifics));
+  batch->Update(std::move(specifics));
 }
 
 void LocalSessionEventHandlerImpl::AssociateTab(
     SyncedTabDelegate* const tab_delegate,
     bool has_tabbed_window,
-    WriteBatch* change_output) {
+    WriteBatch* batch) {
   DCHECK(!tab_delegate->IsPlaceholderTab());
 
   if (tab_delegate->IsBeingDestroyed()) {
@@ -379,9 +366,9 @@
       .Swap(specifics.get());
   WriteTasksIntoSpecifics(specifics->mutable_tab());
   if (existing_tab_node) {
-    change_output->Update(std::move(specifics));
+    batch->Update(std::move(specifics));
   } else {
-    change_output->Add(std::move(specifics));
+    batch->Add(std::move(specifics));
   }
 
   int current_index = tab_delegate->GetCurrentEntryIndex();
@@ -446,8 +433,7 @@
   sessions::SerializedNavigationEntry current;
   modified_tab->GetSerializedNavigationAtIndex(
       modified_tab->GetCurrentEntryIndex(), &current);
-  global_id_mapper_.TrackNavigationIds(current.timestamp(),
-                                       current.unique_id());
+  delegate_->TrackLocalNavigationId(current.timestamp(), current.unique_id());
 
   bool found_tabbed_window = ScanForTabbedWindow();
   std::unique_ptr<WriteBatch> batch = delegate_->CreateLocalSessionWriteBatch();
@@ -474,7 +460,7 @@
     const SyncedTabDelegate& tab_delegate,
     SessionID::id_type new_tab_id,
     SessionID::id_type new_window_id,
-    WriteBatch* change_output) {
+    WriteBatch* batch) {
   DCHECK_NE(tab_delegate.GetSyncId(), TabNodePool::kInvalidTabNodeID);
 
   // It's possible the placeholder tab is associated with a tab node that's
@@ -495,20 +481,19 @@
       session_tracker_->GetTab(current_session_tag_, new_tab_id);
   local_tab->window_id.set_id(new_window_id);
 
-  AppendChangeForExistingTab(tab_delegate.GetSyncId(), *local_tab,
-                             change_output);
+  AppendChangeForExistingTab(tab_delegate.GetSyncId(), *local_tab, batch);
 }
 
 void LocalSessionEventHandlerImpl::AppendChangeForExistingTab(
     int sync_id,
     const sessions::SessionTab& tab,
-    WriteBatch* change_output) const {
+    WriteBatch* batch) const {
   // Rewrite the specifics based on the reassociated SessionTab to preserve
   // the new tab and window ids.
   auto specifics = std::make_unique<sync_pb::SessionSpecifics>();
   SessionTabToSpecifics(tab, current_session_tag_, sync_id)
       .Swap(specifics.get());
-  change_output->Update(std::move(specifics));
+  batch->Update(std::move(specifics));
 }
 
 void LocalSessionEventHandlerImpl::SetSessionTabFromDelegate(
diff --git a/components/sync_sessions/local_session_event_handler_impl.h b/components/sync_sessions/local_session_event_handler_impl.h
index 95346b1..3f03490 100644
--- a/components/sync_sessions/local_session_event_handler_impl.h
+++ b/components/sync_sessions/local_session_event_handler_impl.h
@@ -14,7 +14,6 @@
 #include "components/sessions/core/session_id.h"
 #include "components/sessions/core/session_types.h"
 #include "components/sync_sessions/local_session_event_router.h"
-#include "components/sync_sessions/sessions_global_id_mapper.h"
 #include "components/sync_sessions/synced_session.h"
 #include "components/sync_sessions/task_tracker.h"
 
@@ -51,33 +50,26 @@
    public:
     virtual ~Delegate();
     virtual std::unique_ptr<WriteBatch> CreateLocalSessionWriteBatch() = 0;
+    // Analogous to SessionsGlobalIdMapper.
+    virtual void TrackLocalNavigationId(base::Time timestamp,
+                                        int unique_id) = 0;
     // Analogous to the functions in FaviconCache.
     virtual void OnPageFaviconUpdated(const GURL& page_url) = 0;
     virtual void OnFaviconVisited(const GURL& page_url,
                                   const GURL& favicon_url) = 0;
   };
 
+  // Raw pointers must not be null and all pointees except |*initial_batch| must
+  // outlive this object. |*initial_batch| may or may not be initially empty
+  // (depending on whether the caller wants to bundle together other writes).
+  // This constructor populates |*initial_batch| to resync local window and tab
+  // information, but does *not* Commit() the batch.
   LocalSessionEventHandlerImpl(Delegate* delegate,
                                SyncSessionsClient* sessions_client,
-                               SyncedSessionTracker* session_tracker);
+                               SyncedSessionTracker* session_tracker,
+                               WriteBatch* initial_batch);
   ~LocalSessionEventHandlerImpl() override;
 
-  SessionsGlobalIdMapper* GetGlobalIdMapper();
-
-  // Resync local window and tab information. Updates the local sessions header
-  // node with the status of open windows and the order of tabs they contain.
-  // |change_output| must not be nullptr.
-  //
-  // Must be called before routing events to this class (typically a call to
-  // the router's StartRoutingTo()), that is, before using this object as
-  // LocalSessionEventHandler.
-  // TODO(crbug.com/681921): Revisit if this function can be merged with the
-  // constructor, since it's essentially a two-step initialization.
-  void AssociateWindowsAndTabs(const std::string& session_tag,
-                               const std::string& session_name,
-                               sync_pb::SyncEnums::DeviceType device_type,
-                               WriteBatch* change_output);
-
   // LocalSessionEventHandler implementation.
   void OnLocalTabModified(SyncedTabDelegate* modified_tab) override;
   void OnFaviconsChanged(const std::set<GURL>& page_urls,
@@ -93,16 +85,15 @@
   enum ReloadTabsOption { RELOAD_TABS, DONT_RELOAD_TABS };
   void AssociateWindows(ReloadTabsOption option,
                         bool has_tabbed_window,
-                        WriteBatch* change_output);
+                        WriteBatch* batch);
 
   // Loads and reassociates the local tab referenced in |tab|.
-  // |change_output| *must* be provided as a link to the SyncChange pipeline
-  // that exists in the caller's context. This function will append necessary
+  // |batch| must not be null. This function will append necessary
   // changes for processing later. Will only assign a new sync id if there is
   // a tabbed window, which results in failure for tabs without sync ids yet.
   void AssociateTab(SyncedTabDelegate* const tab,
                     bool has_tabbed_window,
-                    WriteBatch* change_output);
+                    WriteBatch* batch);
 
   // It's possible that when we associate windows, tabs aren't all loaded
   // into memory yet (e.g on android) and we don't have a WebContents. In this
@@ -113,13 +104,13 @@
   void AssociateRestoredPlaceholderTab(const SyncedTabDelegate& tab_delegate,
                                        SessionID::id_type new_tab_id,
                                        SessionID::id_type new_window_id,
-                                       WriteBatch* change_output);
+                                       WriteBatch* batch);
 
-  // Appends an ACTION_UPDATE for a sync tab entity onto |change_output| to
+  // Appends an ACTION_UPDATE for a sync tab entity onto |batch| to
   // reflect the contents of |tab|, given the tab node id |sync_id|.
   void AppendChangeForExistingTab(int sync_id,
                                   const sessions::SessionTab& tab,
-                                  WriteBatch* change_output) const;
+                                  WriteBatch* batch) const;
 
   // Set |session_tab| from |tab_delegate| and |mtime|.
   void SetSessionTabFromDelegate(const SyncedTabDelegate& tab_delegate,
@@ -143,8 +134,6 @@
   SyncSessionsClient* const sessions_client_;
   SyncedSessionTracker* const session_tracker_;
 
-  SessionsGlobalIdMapper global_id_mapper_;
-
   // Tracks Chrome Tasks, which associates navigations, with tab and navigation
   // changes of current session.
   TaskTracker task_tracker_;
diff --git a/components/sync_sessions/local_session_event_handler_impl_unittest.cc b/components/sync_sessions/local_session_event_handler_impl_unittest.cc
index 63e60be..80defe3 100644
--- a/components/sync_sessions/local_session_event_handler_impl_unittest.cc
+++ b/components/sync_sessions/local_session_event_handler_impl_unittest.cc
@@ -150,6 +150,8 @@
 
   MOCK_METHOD0(CreateLocalSessionWriteBatch,
                std::unique_ptr<LocalSessionEventHandlerImpl::WriteBatch>());
+  MOCK_METHOD2(TrackLocalNavigationId,
+               void(base::Time timestamp, int unique_id));
   MOCK_METHOD1(OnPageFaviconUpdated, void(const GURL& page_url));
   MOCK_METHOD2(OnFaviconVisited,
                void(const GURL& page_url, const GURL& favicon_url));
@@ -158,14 +160,24 @@
 class LocalSessionEventHandlerImplTest : public testing::Test {
  public:
   LocalSessionEventHandlerImplTest()
-      : session_tracker_(&mock_sync_sessions_client_),
-        handler_(&mock_delegate_,
-                 &mock_sync_sessions_client_,
-                 &session_tracker_) {
+      : session_tracker_(&mock_sync_sessions_client_) {
     ON_CALL(mock_sync_sessions_client_, GetSyncedWindowDelegatesGetter())
         .WillByDefault(testing::Return(&window_getter_));
 
-    session_tracker_.SetLocalSessionTag(kSessionTag);
+    session_tracker_.InitLocalSession(kSessionTag, kSessionName,
+                                      sync_pb::SyncEnums_DeviceType_TYPE_PHONE);
+  }
+
+  void InitHandler(LocalSessionEventHandlerImpl::WriteBatch* initial_batch) {
+    handler_ = std::make_unique<LocalSessionEventHandlerImpl>(
+        &mock_delegate_, &mock_sync_sessions_client_, &session_tracker_,
+        initial_batch);
+    window_getter_.router()->StartRoutingTo(handler_.get());
+  }
+
+  void InitHandler() {
+    NiceMock<MockWriteBatch> initial_batch;
+    InitHandler(&initial_batch);
   }
 
   TestSyncedWindowDelegate* AddWindow(
@@ -194,7 +206,7 @@
   testing::NiceMock<MockSyncSessionsClient> mock_sync_sessions_client_;
   SyncedSessionTracker session_tracker_;
   TestSyncedWindowDelegatesGetter window_getter_;
-  LocalSessionEventHandlerImpl handler_;
+  std::unique_ptr<LocalSessionEventHandlerImpl> handler_;
 };
 
 // Populate the mock tab delegate with some data and navigation
@@ -220,7 +232,9 @@
       SerializedNavigationEntryTestHelper::CreateNavigation(
           "http://www.example.com", "Example"));
   session_tab.session_storage_persistent_id = "persistent id";
-  handler_.SetSessionTabFromDelegateForTest(*tab, kTime4, &session_tab);
+
+  InitHandler();
+  handler_->SetSessionTabFromDelegateForTest(*tab, kTime4, &session_tab);
 
   EXPECT_EQ(tab->GetWindowId(), session_tab.window_id.id());
   EXPECT_EQ(tab->GetSessionId(), session_tab.tab_id.id());
@@ -260,8 +274,10 @@
   }
   tab->set_current_entry_index(kNavs - 2);
 
+  InitHandler();
+
   sessions::SessionTab session_tab;
-  handler_.SetSessionTabFromDelegateForTest(*tab, kTime6, &session_tab);
+  handler_->SetSessionTabFromDelegateForTest(*tab, kTime6, &session_tab);
 
   EXPECT_EQ(6, session_tab.current_navigation_index);
   ASSERT_EQ(8u, session_tab.navigations.size());
@@ -281,8 +297,10 @@
   tab->Navigate(kBar2, kTime3);
   tab->set_current_entry_index(1);
 
+  InitHandler();
+
   sessions::SessionTab session_tab;
-  handler_.SetSessionTabFromDelegateForTest(*tab, kTime6, &session_tab);
+  handler_->SetSessionTabFromDelegateForTest(*tab, kTime6, &session_tab);
 
   EXPECT_EQ(2, session_tab.current_navigation_index);
   ASSERT_EQ(3u, session_tab.navigations.size());
@@ -325,7 +343,9 @@
       SerializedNavigationEntryTestHelper::CreateNavigation(
           "http://www.example.com", "Example"));
   session_tab.session_storage_persistent_id = "persistent id";
-  handler_.SetSessionTabFromDelegateForTest(*tab, kTime4, &session_tab);
+
+  InitHandler();
+  handler_->SetSessionTabFromDelegateForTest(*tab, kTime4, &session_tab);
 
   EXPECT_EQ(tab->GetWindowId(), session_tab.window_id.id());
   EXPECT_EQ(tab->GetSessionId(), session_tab.tab_id.id());
@@ -362,9 +382,7 @@
   EXPECT_CALL(mock_batch, DoUpdate(MatchesHeader(kSessionTag, /*num_windows=*/0,
                                                  /*num_tabs=*/0)));
 
-  handler_.AssociateWindowsAndTabs(kSessionTag, kSessionName,
-                                   sync_pb::SyncEnums_DeviceType_TYPE_PHONE,
-                                   &mock_batch);
+  InitHandler(&mock_batch);
 }
 
 // Tests that calling AssociateWindowsAndTabs() reflects the open tabs in a) the
@@ -395,20 +413,14 @@
               DoAdd(MatchesTab(kSessionTag, kWindowId2, kTabId3,
                                std::vector<std::string>{kBar2, kBaz1})));
 
-  handler_.AssociateWindowsAndTabs(kSessionTag, kSessionName,
-                                   sync_pb::SyncEnums_DeviceType_TYPE_PHONE,
-                                   &mock_batch);
+  InitHandler(&mock_batch);
 }
 
 TEST_F(LocalSessionEventHandlerImplTest, PropagateNewNavigation) {
   AddWindow(kWindowId1);
   TestSyncedTabDelegate* tab = AddTab(kWindowId1, kFoo1, kTabId1);
 
-  NiceMock<MockWriteBatch> initial_mock_batch;
-  handler_.AssociateWindowsAndTabs(kSessionTag, kSessionName,
-                                   sync_pb::SyncEnums_DeviceType_TYPE_PHONE,
-                                   &initial_mock_batch);
-  window_getter_.router()->StartRoutingTo(&handler_);
+  InitHandler();
 
   auto update_mock_batch = std::make_unique<StrictMock<MockWriteBatch>>();
   // Note that the header is reported again, although it hasn't changed. This is
@@ -431,11 +443,7 @@
   AddWindow(kWindowId1);
   AddTab(kWindowId1, kFoo1, kTabId1);
 
-  NiceMock<MockWriteBatch> initial_mock_batch;
-  handler_.AssociateWindowsAndTabs(kSessionTag, kSessionName,
-                                   sync_pb::SyncEnums_DeviceType_TYPE_PHONE,
-                                   &initial_mock_batch);
-  window_getter_.router()->StartRoutingTo(&handler_);
+  InitHandler();
 
   // Tab creation triggers an update event due to the tab parented notification,
   // so the event handler issues two commits as well (one for tab creation, one
@@ -468,11 +476,7 @@
   AddTab(kWindowId1, kFoo1, kTabId1);
   AddTab(kWindowId1, kBar1, kTabId2);
 
-  NiceMock<MockWriteBatch> initial_mock_batch;
-  handler_.AssociateWindowsAndTabs(kSessionTag, kSessionName,
-                                   sync_pb::SyncEnums_DeviceType_TYPE_PHONE,
-                                   &initial_mock_batch);
-  window_getter_.router()->StartRoutingTo(&handler_);
+  InitHandler();
 
   // Window creation triggers an update event due to the tab parented
   // notification, so the event handler issues two commits as well (one for
diff --git a/components/sync_sessions/sessions_global_id_mapper.cc b/components/sync_sessions/sessions_global_id_mapper.cc
index 3b467ed6..6eff6b8 100644
--- a/components/sync_sessions/sessions_global_id_mapper.cc
+++ b/components/sync_sessions/sessions_global_id_mapper.cc
@@ -48,8 +48,8 @@
   return global_id;
 }
 
-void SessionsGlobalIdMapper::TrackNavigationIds(const base::Time& timestamp,
-                                                int unique_id) {
+void SessionsGlobalIdMapper::TrackNavigationId(const base::Time& timestamp,
+                                               int unique_id) {
   // The expectation is that global_id will update for a given unique_id, which
   // should accurately and uniquely represent a single navigation. It is
   // theoretically possible for two unique_ids to map to the same global_id, but
diff --git a/components/sync_sessions/sessions_global_id_mapper.h b/components/sync_sessions/sessions_global_id_mapper.h
index 907cca3..58b5b391 100644
--- a/components/sync_sessions/sessions_global_id_mapper.h
+++ b/components/sync_sessions/sessions_global_id_mapper.h
@@ -23,7 +23,7 @@
   void AddGlobalIdChangeObserver(syncer::GlobalIdChange callback) override;
   int64_t GetLatestGlobalId(int64_t global_id) override;
 
-  void TrackNavigationIds(const base::Time& timestamp, int unique_id);
+  void TrackNavigationId(const base::Time& timestamp, int unique_id);
 
  private:
   void CleanupNavigationTracking();
diff --git a/components/sync_sessions/sessions_global_id_mapper_unittest.cc b/components/sync_sessions/sessions_global_id_mapper_unittest.cc
index 566b32c..23fa251 100644
--- a/components/sync_sessions/sessions_global_id_mapper_unittest.cc
+++ b/components/sync_sessions/sessions_global_id_mapper_unittest.cc
@@ -23,10 +23,10 @@
 TEST(SessionsGlobalIdMapperTest, GetLatestGlobalId) {
   SessionsGlobalIdMapper mapper;
 
-  mapper.TrackNavigationIds(kTime1, /*unique_id=*/1);
-  mapper.TrackNavigationIds(kTime2, /*unique_id=*/2);
-  mapper.TrackNavigationIds(kTime3, /*unique_id=*/2);
-  mapper.TrackNavigationIds(kTime4, /*unique_id=*/2);
+  mapper.TrackNavigationId(kTime1, /*unique_id=*/1);
+  mapper.TrackNavigationId(kTime2, /*unique_id=*/2);
+  mapper.TrackNavigationId(kTime3, /*unique_id=*/2);
+  mapper.TrackNavigationId(kTime4, /*unique_id=*/2);
 
   EXPECT_EQ(kTime1.ToInternalValue(),
             mapper.GetLatestGlobalId(kTime1.ToInternalValue()));
@@ -47,12 +47,12 @@
   SessionsGlobalIdMapper mapper;
 
   base::Time current_time = kTime1;
-  mapper.TrackNavigationIds(current_time, /*unique_id=*/1);
+  mapper.TrackNavigationId(current_time, /*unique_id=*/1);
 
   for (int i = 0; i < 105; i++) {
     current_time =
         base::Time::FromInternalValue(current_time.ToInternalValue() + 1);
-    mapper.TrackNavigationIds(current_time, /*unique_id=*/1);
+    mapper.TrackNavigationId(current_time, /*unique_id=*/1);
   }
 
   // Threshold is 100, kTime1 should be dropped, kTime1+10 should not.
@@ -67,7 +67,7 @@
 TEST(SessionsGlobalIdMapperTest, AddObserver) {
   SessionsGlobalIdMapper mapper;
 
-  mapper.TrackNavigationIds(kTime1, /*unique_id=*/1);
+  mapper.TrackNavigationId(kTime1, /*unique_id=*/1);
 
   base::MockCallback<syncer::GlobalIdChange> mock_callback;
   EXPECT_CALL(mock_callback, Run(_, _)).Times(0);
diff --git a/components/sync_sessions/sessions_sync_manager.cc b/components/sync_sessions/sessions_sync_manager.cc
index 144fe07..13727dc8d 100644
--- a/components/sync_sessions/sessions_sync_manager.cc
+++ b/components/sync_sessions/sessions_sync_manager.cc
@@ -150,13 +150,9 @@
           &favicon_cache_,
           base::BindRepeating(&SessionsSyncManager::DeleteForeignSessionFromUI,
                               base::Unretained(this))),
-      local_session_event_handler_(/*delegate=*/this,
-                                   sessions_client,
-                                   &session_tracker_),
       local_tab_pool_out_of_sync_(true),
       sync_prefs_(sync_prefs),
       local_device_(local_device),
-      current_device_type_(sync_pb::SyncEnums_DeviceType_TYPE_OTHER),
       local_session_header_node_id_(TabNodePool::kInvalidTabNodeID),
       stale_session_threshold_days_(kDefaultStaleSessionThresholdDays),
       local_event_router_(router),
@@ -179,6 +175,7 @@
     std::unique_ptr<syncer::SyncErrorFactory> error_handler) {
   syncer::SyncMergeResult merge_result(type);
   DCHECK(session_tracker_.Empty());
+  DCHECK(!local_session_event_handler_);
 
   error_handler_ = std::move(error_handler);
   sync_processor_ = std::move(sync_processor);
@@ -194,7 +191,6 @@
   }
 
   current_session_name_ = local_device_info->client_name();
-  current_device_type_ = local_device_info->device_type();
 
   // It's possible(via RebuildAssociations) for lost_navigations_recorder_ to
   // persist between sync being stopped and started. If it did persist, it's
@@ -214,7 +210,8 @@
     InitializeCurrentMachineTag(local_device_->GetLocalSyncCacheGUID());
   }
 
-  session_tracker_.SetLocalSessionTag(current_machine_tag());
+  session_tracker_.InitLocalSession(current_machine_tag_, current_session_name_,
+                                    local_device_info->device_type());
 
   // TODO(crbug.com/681921): Revisit the somewhat ugly use below of
   // SyncChangeListWriteBatch. Ideally InitFromSyncModel() could use the
@@ -229,7 +226,7 @@
     specifics->set_session_tag(current_machine_tag());
     sync_pb::SessionHeader* header_s = specifics->mutable_header();
     header_s->set_client_name(current_session_name_);
-    header_s->set_device_type(current_device_type_);
+    header_s->set_device_type(local_device_info->device_type());
     batch.Add(std::move(specifics));
   }
 
@@ -241,15 +238,14 @@
 #endif
 
   // Check if anything has changed on the local client side.
-  local_session_event_handler_.AssociateWindowsAndTabs(
-      current_machine_tag_, current_session_name_, current_device_type_,
-      &batch);
+  local_session_event_handler_ = std::make_unique<LocalSessionEventHandlerImpl>(
+      /*delegate=*/this, sessions_client_, &session_tracker_, &batch);
   local_tab_pool_out_of_sync_ = false;
 
   merge_result.set_error(sync_processor_->ProcessSyncChanges(
       FROM_HERE, *batch.sync_change_list()));
 
-  local_event_router_->StartRoutingTo(&local_session_event_handler_);
+  local_event_router_->StartRoutingTo(local_session_event_handler_.get());
   return merge_result;
 }
 
@@ -268,6 +264,7 @@
 
 void SessionsSyncManager::StopSyncing(syncer::ModelType type) {
   local_event_router_->Stop();
+  local_session_event_handler_.reset();
   if (sync_processor_.get() && lost_navigations_recorder_.get()) {
     sync_processor_->RemoveLocalChangeObserver(
         lost_navigations_recorder_.get());
@@ -604,6 +601,11 @@
                      base::AsWeakPtr(this)));
 }
 
+void SessionsSyncManager::TrackLocalNavigationId(base::Time timestamp,
+                                                 int unique_id) {
+  global_id_mapper_.TrackNavigationId(timestamp, unique_id);
+}
+
 void SessionsSyncManager::OnPageFaviconUpdated(const GURL& page_url) {
   favicon_cache_.OnPageFaviconUpdated(page_url, base::Time::Now());
 }
@@ -618,7 +620,7 @@
 }
 
 SessionsGlobalIdMapper* SessionsSyncManager::GetGlobalIdMapper() {
-  return local_session_event_handler_.GetGlobalIdMapper();
+  return &global_id_mapper_;
 }
 
 OpenTabsUIDelegate* SessionsSyncManager::GetOpenTabsUIDelegate() {
diff --git a/components/sync_sessions/sessions_sync_manager.h b/components/sync_sessions/sessions_sync_manager.h
index 94929cf..5c4377b 100644
--- a/components/sync_sessions/sessions_sync_manager.h
+++ b/components/sync_sessions/sessions_sync_manager.h
@@ -29,6 +29,7 @@
 #include "components/sync_sessions/local_session_event_router.h"
 #include "components/sync_sessions/lost_navigations_recorder.h"
 #include "components/sync_sessions/open_tabs_ui_delegate_impl.h"
+#include "components/sync_sessions/sessions_global_id_mapper.h"
 #include "components/sync_sessions/synced_session.h"
 #include "components/sync_sessions/synced_session_tracker.h"
 
@@ -76,6 +77,7 @@
   // LocalSessionEventHandlerImpl::Delegate implementation.
   std::unique_ptr<LocalSessionEventHandlerImpl::WriteBatch>
   CreateLocalSessionWriteBatch() override;
+  void TrackLocalNavigationId(base::Time timestamp, int unique_id) override;
   void OnPageFaviconUpdated(const GURL& page_url) override;
   void OnFaviconVisited(const GURL& page_url, const GURL& favicon_url) override;
 
@@ -167,9 +169,12 @@
   SyncSessionsClient* const sessions_client_;
 
   SyncedSessionTracker session_tracker_;
+  SessionsGlobalIdMapper global_id_mapper_;
   FaviconCache favicon_cache_;
   OpenTabsUIDelegateImpl open_tabs_ui_delegate_;
-  LocalSessionEventHandlerImpl local_session_event_handler_;
+
+  // Instantiated when sync is enabled.
+  std::unique_ptr<LocalSessionEventHandlerImpl> local_session_event_handler_;
 
   // Tracks whether our local representation of which sync nodes map to what
   // tabs (belonging to the current local session) is inconsistent.  This can
@@ -191,9 +196,8 @@
   // Unique client tag.
   std::string current_machine_tag_;
 
-  // User-visible machine name and device type to populate header.
+  // User-visible machine name to populate header.
   std::string current_session_name_;
-  sync_pb::SyncEnums::DeviceType current_device_type_;
 
   // SyncID for the sync node containing all the window information for this
   // client.
diff --git a/components/sync_sessions/synced_session_tracker.cc b/components/sync_sessions/synced_session_tracker.cc
index 6d9566e..173ebd16 100644
--- a/components/sync_sessions/synced_session_tracker.cc
+++ b/components/sync_sessions/synced_session_tracker.cc
@@ -132,11 +132,22 @@
   Clear();
 }
 
-void SyncedSessionTracker::SetLocalSessionTag(
-    const std::string& local_session_tag) {
+void SyncedSessionTracker::InitLocalSession(
+    const std::string& local_session_tag,
+    const std::string& local_session_name,
+    sync_pb::SyncEnums::DeviceType local_device_type) {
   DCHECK(local_session_tag_.empty());
   DCHECK(!local_session_tag.empty());
   local_session_tag_ = local_session_tag;
+
+  SyncedSession* local_session = GetSession(local_session_tag);
+  local_session->session_name = local_session_name;
+  local_session->device_type = local_device_type;
+  local_session->session_tag = local_session_tag;
+}
+
+const std::string& SyncedSessionTracker::GetLocalSessionTag() const {
+  return local_session_tag_;
 }
 
 bool SyncedSessionTracker::LookupAllForeignSessions(
diff --git a/components/sync_sessions/synced_session_tracker.h b/components/sync_sessions/synced_session_tracker.h
index 8510dfb..86c988bd2 100644
--- a/components/sync_sessions/synced_session_tracker.h
+++ b/components/sync_sessions/synced_session_tracker.h
@@ -156,9 +156,14 @@
 
   // **** Methods specific to the local session. ****
 
-  // Set the local session tag. Must be called before any other local session
-  // methods are invoked.
-  void SetLocalSessionTag(const std::string& local_session_tag);
+  // Set the local session information. Must be called before any other local
+  // session methods are invoked.
+  void InitLocalSession(const std::string& local_session_tag,
+                        const std::string& local_session_name,
+                        sync_pb::SyncEnums::DeviceType local_device_type);
+
+  // Gets the session tag previously set with InitLocalSession().
+  const std::string& GetLocalSessionTag() const;
 
   // Similar to CleanupForeignSession, but also marks any unmapped tabs as free
   // in the tab node pool and fills |deleted_node_ids| with the set of locally
diff --git a/components/sync_sessions/synced_session_tracker_unittest.cc b/components/sync_sessions/synced_session_tracker_unittest.cc
index 60102cb..69d99a5 100644
--- a/components/sync_sessions/synced_session_tracker_unittest.cc
+++ b/components/sync_sessions/synced_session_tracker_unittest.cc
@@ -21,6 +21,9 @@
 namespace {
 
 const char kValidUrl[] = "http://www.example.com";
+const char kSessionName[] = "sessionname";
+const sync_pb::SyncEnums::DeviceType kDeviceType =
+    sync_pb::SyncEnums_DeviceType_TYPE_PHONE;
 const char kTag[] = "tag";
 const char kTag2[] = "tag2";
 const char kTag3[] = "tag3";
@@ -442,7 +445,7 @@
   std::set<int> free_node_ids;
   int tab_node_id = TabNodePool::kInvalidTabNodeID;
 
-  GetTracker()->SetLocalSessionTag(kTag);
+  GetTracker()->InitLocalSession(kTag, kSessionName, kDeviceType);
 
   // Start with two restored tab nodes.
   GetTracker()->ReassociateLocalTab(kTabNode1, kTab1);
@@ -500,7 +503,7 @@
   std::set<int> free_node_ids;
 
   // First create the tab normally.
-  GetTracker()->SetLocalSessionTag(kTag);
+  GetTracker()->InitLocalSession(kTag, kSessionName, kDeviceType);
   EXPECT_FALSE(GetTracker()->IsLocalTabNodeAssociated(kTabNode1));
   GetTracker()->ReassociateLocalTab(kTabNode1, kTab1);
   ASSERT_TRUE(VerifyTabIntegrity(kTag));
@@ -551,7 +554,7 @@
   std::set<int> free_node_ids;
 
   // First create the tab normally.
-  GetTracker()->SetLocalSessionTag(kTag);
+  GetTracker()->InitLocalSession(kTag, kSessionName, kDeviceType);
   EXPECT_FALSE(GetTracker()->IsLocalTabNodeAssociated(kTabNode1));
   GetTracker()->ReassociateLocalTab(kTabNode1, kTab1);
   ASSERT_TRUE(VerifyTabIntegrity(kTag));
@@ -616,7 +619,7 @@
   std::set<int> free_node_ids;
 
   // First create the old tab in an unmapped state.
-  GetTracker()->SetLocalSessionTag(kTag);
+  GetTracker()->InitLocalSession(kTag, kSessionName, kDeviceType);
   EXPECT_FALSE(GetTracker()->IsLocalTabNodeAssociated(kTabNode1));
   GetTracker()->ReassociateLocalTab(kTabNode1, kTab1);
   ASSERT_TRUE(VerifyTabIntegrity(kTag));
@@ -652,7 +655,7 @@
   std::set<int> free_node_ids;
 
   // First create the old tab in an unmapped state.
-  GetTracker()->SetLocalSessionTag(kTag);
+  GetTracker()->InitLocalSession(kTag, kSessionName, kDeviceType);
   EXPECT_FALSE(GetTracker()->IsLocalTabNodeAssociated(kTabNode1));
   GetTracker()->ReassociateLocalTab(kTabNode1, kTab1);
   ASSERT_TRUE(VerifyTabIntegrity(kTag));
@@ -690,7 +693,7 @@
   std::set<int> free_node_ids;
 
   // First create the tab normally.
-  GetTracker()->SetLocalSessionTag(kTag);
+  GetTracker()->InitLocalSession(kTag, kSessionName, kDeviceType);
   EXPECT_FALSE(GetTracker()->IsLocalTabNodeAssociated(kTabNode1));
   GetTracker()->ReassociateLocalTab(kTabNode1, kTab1);
   ASSERT_TRUE(VerifyTabIntegrity(kTag));
@@ -740,7 +743,7 @@
   std::set<int> free_node_ids;
 
   // First create an unmapped tab.
-  GetTracker()->SetLocalSessionTag(kTag);
+  GetTracker()->InitLocalSession(kTag, kSessionName, kDeviceType);
   EXPECT_FALSE(GetTracker()->IsLocalTabNodeAssociated(kTabNode1));
   GetTracker()->ReassociateLocalTab(kTabNode1, kTab1);
   ASSERT_TRUE(VerifyTabIntegrity(kTag));
diff --git a/components/tracing/child/child_trace_message_filter.cc b/components/tracing/child/child_trace_message_filter.cc
index c772518..99de2f65 100644
--- a/components/tracing/child/child_trace_message_filter.cc
+++ b/components/tracing/child/child_trace_message_filter.cc
@@ -88,10 +88,10 @@
     base::Time computed_next_allowed_time =
         histogram_last_changed_ +
         base::TimeDelta::FromSeconds(kMinTimeBetweenHistogramChangesInSeconds);
-    if (computed_next_allowed_time > base::Time::Now())
+    if (computed_next_allowed_time > TRACE_TIME_NOW())
       return;
   }
-  histogram_last_changed_ = base::Time::Now();
+  histogram_last_changed_ = TRACE_TIME_NOW();
 
   if (sender_)
     sender_->Send(new TracingHostMsg_TriggerBackgroundTrace(histogram_name));
diff --git a/components/unzip_service/public/cpp/unzip.cc b/components/unzip_service/public/cpp/unzip.cc
index b5f2986..a8ab1f5 100644
--- a/components/unzip_service/public/cpp/unzip.cc
+++ b/components/unzip_service/public/cpp/unzip.cc
@@ -92,6 +92,7 @@
 
 void UnzipDone(scoped_refptr<UnzipParams> params, bool success) {
   params->InvokeCallback(success);
+  params->unzipper()->reset();
 }
 
 void DoUnzipWithFilter(
diff --git a/components/viz/service/display/gl_renderer.cc b/components/viz/service/display/gl_renderer.cc
index 3db30fc..7b96160 100644
--- a/components/viz/service/display/gl_renderer.cc
+++ b/components/viz/service/display/gl_renderer.cc
@@ -1469,7 +1469,7 @@
     }
   }
 
-  SetShaderOpacity(params->quad);
+  SetShaderOpacity(params->quad->shared_quad_state->opacity);
   SetShaderQuadF(params->surface_quad);
 }
 
@@ -1964,7 +1964,7 @@
 
   // Blending is required for antialiasing.
   SetBlendEnabled(true);
-  SetShaderOpacity(quad);
+  SetShaderOpacity(quad->shared_quad_state->opacity);
 
   // Draw the quad with antialiasing.
   DrawQuadGeometryWithAA(quad, &local_quad, tile_rect);
@@ -2001,11 +2001,9 @@
   // the way to the edge and are using bilinear filtering.
   gfx::Size texture_size = quad->texture_size;
   bool fills_right_edge =
-      quad->shared_quad_state->quad_layer_rect.right() != quad->rect.right() ||
-      texture_size.width() == tex_coord_rect.right();
-  bool fills_bottom_edge = quad->shared_quad_state->quad_layer_rect.bottom() !=
-                               quad->rect.bottom() ||
-                           texture_size.height() == tex_coord_rect.bottom();
+      !quad->IsRightEdge() || texture_size.width() == tex_coord_rect.right();
+  bool fills_bottom_edge =
+      !quad->IsBottomEdge() || texture_size.height() == tex_coord_rect.bottom();
   bool has_tex_clamp_rect =
       filter == GL_LINEAR && (!fills_right_edge || !fills_bottom_edge);
   gfx::SizeF tex_clamp_size(texture_size);
@@ -2052,7 +2050,7 @@
 
   SetBlendEnabled(quad->ShouldDrawWithBlending());
 
-  SetShaderOpacity(quad);
+  SetShaderOpacity(quad->shared_quad_state->opacity);
 
   // Pass quad coordinates to the uniform in the same order as GeometryBinding
   // does, then vertices will match the texture mapping in the vertex buffer.
@@ -2236,7 +2234,7 @@
   // it. This is why this centered rect is used and not the original quad_rect.
   auto tile_rect = gfx::RectF(quad->rect);
 
-  SetShaderOpacity(quad);
+  SetShaderOpacity(quad->shared_quad_state->opacity);
   if (!clip_region) {
     DrawQuadGeometry(current_frame()->projection_matrix,
                      quad->shared_quad_state->quad_to_target_transform,
@@ -2280,7 +2278,7 @@
   gl_->UniformMatrix4fvStreamTextureMatrixCHROMIUM(
       current_program_->tex_matrix_location(), false, gl_matrix);
 
-  SetShaderOpacity(quad);
+  SetShaderOpacity(quad->shared_quad_state->opacity);
   gfx::Size texture_size = lock.size();
   gfx::Vector2dF uv = quad->matrix.Scale2d();
   gfx::RectF uv_visible_rect(0, 0, uv.x(), uv.y());
@@ -2620,11 +2618,10 @@
   gl_->Uniform2fv(current_program_->quad_location(), 4, gl_quad);
 }
 
-void GLRenderer::SetShaderOpacity(const DrawQuad* quad) {
+void GLRenderer::SetShaderOpacity(float opacity) {
   if (!current_program_ || current_program_->alpha_location() == -1)
     return;
-  gl_->Uniform1f(current_program_->alpha_location(),
-                 quad->shared_quad_state->opacity);
+  gl_->Uniform1f(current_program_->alpha_location(), opacity);
 }
 
 void GLRenderer::SetShaderMatrix(const gfx::Transform& transform) {
diff --git a/components/viz/service/display/gl_renderer.h b/components/viz/service/display/gl_renderer.h
index d0e4761..4e897a68 100644
--- a/components/viz/service/display/gl_renderer.h
+++ b/components/viz/service/display/gl_renderer.h
@@ -244,7 +244,7 @@
                         const gfx::QuadF* clip_region);
   void DrawOverlayCandidateQuadBorder(float* gl_matrix);
 
-  void SetShaderOpacity(const DrawQuad* quad);
+  void SetShaderOpacity(float opacity);
   void SetShaderQuadF(const gfx::QuadF& quad);
   void SetShaderMatrix(const gfx::Transform& transform);
   void SetShaderColor(SkColor color, float opacity);
diff --git a/content/app/content_main_runner.cc b/content/app/content_main_runner.cc
index 00864253..1b41368 100644
--- a/content/app/content_main_runner.cc
+++ b/content/app/content_main_runner.cc
@@ -52,7 +52,7 @@
 #include "content/public/common/content_switches.h"
 #include "content/public/common/main_function_params.h"
 #include "content/public/common/sandbox_init.h"
-#include "content/public/common/zygote_features.h"
+#include "content/public/common/zygote_buildflags.h"
 #include "gin/v8_initializer.h"
 #include "media/base/media.h"
 #include "media/media_features.h"
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index d967c234..603d414 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -79,10 +79,10 @@
     "//content/browser/service_worker:service_worker_proto",
     "//content/browser/speech/proto",
     "//content/common",
-    "//content/common:features",
+    "//content/common:buildflags",
     "//content/common:mojo_bindings",
     "//content/public/common:common_sources",
-    "//content/public/common:zygote_features",
+    "//content/public/common:zygote_buildflags",
     "//crypto",
     "//device/bluetooth",
     "//device/fido",
@@ -203,7 +203,7 @@
   ]
 
   public_deps = [
-    ":accessibility_flags",
+    ":accessibility_buildflags",
     "//ipc",
     "//media/mojo/interfaces:remoting",
     "//third_party/WebKit/public:media_devices_mojo_bindings",
@@ -2366,8 +2366,8 @@
   }
 }
 
-buildflag_header("accessibility_flags") {
-  header = "accessibility_flags.h"
+buildflag_header("accessibility_buildflags") {
+  header = "accessibility_buildflags.h"
   header_dir = "content/browser/accessibility"
   flags = [ "USE_ATK=$use_atk" ]
 }
diff --git a/content/browser/accessibility/browser_accessibility.h b/content/browser/accessibility/browser_accessibility.h
index a0bb8dd..55db6d1c0 100644
--- a/content/browser/accessibility/browser_accessibility.h
+++ b/content/browser/accessibility/browser_accessibility.h
@@ -15,7 +15,7 @@
 #include "base/strings/string16.h"
 #include "base/strings/string_split.h"
 #include "build/build_config.h"
-#include "content/browser/accessibility/accessibility_flags.h"
+#include "content/browser/accessibility/accessibility_buildflags.h"
 #include "content/browser/accessibility/browser_accessibility_position.h"
 #include "content/common/content_export.h"
 #include "third_party/WebKit/public/web/WebAXEnums.h"
diff --git a/content/browser/accessibility/browser_accessibility_manager.h b/content/browser/accessibility/browser_accessibility_manager.h
index 17912e34..08df1b42 100644
--- a/content/browser/accessibility/browser_accessibility_manager.h
+++ b/content/browser/accessibility/browser_accessibility_manager.h
@@ -14,7 +14,7 @@
 #include "base/containers/hash_tables.h"
 #include "base/macros.h"
 #include "build/build_config.h"
-#include "content/browser/accessibility/accessibility_flags.h"
+#include "content/browser/accessibility/accessibility_buildflags.h"
 #include "content/browser/accessibility/browser_accessibility_position.h"
 #include "content/common/content_export.h"
 #include "content/public/browser/ax_event_notification_details.h"
diff --git a/content/browser/accessibility/browser_accessibility_position.cc b/content/browser/accessibility/browser_accessibility_position.cc
index b7f02796..74ba663 100644
--- a/content/browser/accessibility/browser_accessibility_position.cc
+++ b/content/browser/accessibility/browser_accessibility_position.cc
@@ -6,7 +6,7 @@
 
 #include "base/strings/string_util.h"
 #include "build/build_config.h"
-#include "content/browser/accessibility/accessibility_flags.h"
+#include "content/browser/accessibility/accessibility_buildflags.h"
 #include "content/browser/accessibility/browser_accessibility.h"
 #include "content/browser/accessibility/browser_accessibility_manager.h"
 #include "ui/accessibility/ax_enums.mojom.h"
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc
index e903e78..6300f92 100644
--- a/content/browser/browser_main_loop.cc
+++ b/content/browser/browser_main_loop.cc
@@ -106,7 +106,7 @@
 #include "content/public/common/main_function_params.h"
 #include "content/public/common/result_codes.h"
 #include "content/public/common/service_names.mojom.h"
-#include "content/public/common/zygote_features.h"
+#include "content/public/common/zygote_buildflags.h"
 #include "device/gamepad/gamepad_service.h"
 #include "gpu/vulkan/features.h"
 #include "media/audio/audio_manager.h"
diff --git a/content/browser/child_process_launcher_helper.h b/content/browser/child_process_launcher_helper.h
index 30d314f3..b9b7a82 100644
--- a/content/browser/child_process_launcher_helper.h
+++ b/content/browser/child_process_launcher_helper.h
@@ -14,7 +14,7 @@
 #include "build/build_config.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/common/result_codes.h"
-#include "content/public/common/zygote_features.h"
+#include "content/public/common/zygote_buildflags.h"
 #include "mojo/edk/embedder/embedder.h"
 #include "mojo/edk/embedder/outgoing_broker_client_invitation.h"
 #include "mojo/edk/embedder/scoped_platform_handle.h"
diff --git a/content/browser/devtools/devtools_http_handler.cc b/content/browser/devtools/devtools_http_handler.cc
index 1a93ba9..77e0d258 100644
--- a/content/browser/devtools/devtools_http_handler.cc
+++ b/content/browser/devtools/devtools_http_handler.cc
@@ -551,8 +551,9 @@
         kTargetWebSocketDebuggerUrlField,
         base::StringPrintf("ws://%s%s", host.c_str(), browser_guid_.c_str()));
 #if defined(OS_ANDROID)
-    version.SetString("Android-Package",
-        base::android::BuildInfo::GetInstance()->package_name());
+    version.SetString(
+        "Android-Package",
+        base::android::BuildInfo::GetInstance()->host_package_name());
 #endif
     SendJson(connection_id, net::HTTP_OK, &version, std::string());
     return;
diff --git a/content/browser/fileapi/DEPS b/content/browser/fileapi/DEPS
index 87b83c0..743a2f3b 100644
--- a/content/browser/fileapi/DEPS
+++ b/content/browser/fileapi/DEPS
@@ -1,3 +1,3 @@
 include_rules = [
-  "+third_party/leveldatabase/src/include/leveldb",
+  "+third_party/leveldatabase",
 ]
diff --git a/content/browser/fileapi/browser_file_system_helper.cc b/content/browser/fileapi/browser_file_system_helper.cc
index fb3533d5..4d8ecc2b 100644
--- a/content/browser/fileapi/browser_file_system_helper.cc
+++ b/content/browser/fileapi/browser_file_system_helper.cc
@@ -33,6 +33,7 @@
 #include "storage/browser/fileapi/file_system_url.h"
 #include "storage/browser/fileapi/isolated_context.h"
 #include "storage/browser/quota/quota_manager.h"
+#include "third_party/leveldatabase/leveldb_chrome.h"
 #include "url/gurl.h"
 #include "url/url_constants.h"
 
@@ -61,7 +62,11 @@
           switches::kAllowFileAccessFromFiles)) {
     additional_allowed_schemes.push_back(url::kFileScheme);
   }
-  return FileSystemOptions(profile_mode, additional_allowed_schemes, nullptr);
+  leveldb::Env* env_override = nullptr;
+  if (is_incognito)
+    env_override = leveldb_chrome::NewMemEnv(leveldb::Env::Default());
+  return FileSystemOptions(profile_mode, additional_allowed_schemes,
+                           env_override);
 }
 
 }  // namespace
diff --git a/content/browser/frame_host/interstitial_page_impl.cc b/content/browser/frame_host/interstitial_page_impl.cc
index 7c83d2a6..c34ab5d1d 100644
--- a/content/browser/frame_host/interstitial_page_impl.cc
+++ b/content/browser/frame_host/interstitial_page_impl.cc
@@ -38,7 +38,7 @@
 #include "content/browser/site_instance_impl.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/browser/web_contents/web_contents_view.h"
-#include "content/common/features.h"
+#include "content/common/buildflags.h"
 #include "content/common/frame_messages.h"
 #include "content/common/input_messages.h"
 #include "content/common/view_messages.h"
diff --git a/content/browser/frame_host/navigator_impl.cc b/content/browser/frame_host/navigator_impl.cc
index b5c2160..a7a55bf 100644
--- a/content/browser/frame_host/navigator_impl.cc
+++ b/content/browser/frame_host/navigator_impl.cc
@@ -312,9 +312,10 @@
   // "Open link in new tab"). We need to keep it above RFHM::Navigate() call to
   // capture the time needed for the RenderFrameHost initialization.
   base::TimeTicks navigation_start = base::TimeTicks::Now();
+  base::TimeTicks tracing_navigation_start = TRACE_TIME_TICKS_NOW();
   TRACE_EVENT_INSTANT_WITH_TIMESTAMP0(
       "navigation,rail", "NavigationTiming navigationStart",
-      TRACE_EVENT_SCOPE_GLOBAL, navigation_start);
+      TRACE_EVENT_SCOPE_GLOBAL, tracing_navigation_start);
 
   // Determine if Previews should be used for the navigation.
   PreviewsState previews_state = PREVIEWS_UNSPECIFIED;
@@ -349,7 +350,7 @@
     TRACE_EVENT_ASYNC_BEGIN_WITH_TIMESTAMP1(
         "navigation", "Navigation timeToNetworkStack",
         frame_tree_node->navigation_request()->navigation_handle(),
-        navigation_start, "FrameTreeNode id",
+        tracing_navigation_start, "FrameTreeNode id",
         frame_tree_node->frame_tree_node_id());
   }
 
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h
index 72b5266..2f94378 100644
--- a/content/browser/frame_host/render_frame_host_impl.h
+++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -36,10 +36,10 @@
 #include "content/browser/site_instance_impl.h"
 #include "content/browser/webui/web_ui_impl.h"
 #include "content/common/ax_content_node_data.h"
+#include "content/common/buildflags.h"
 #include "content/common/content_export.h"
 #include "content/common/content_security_policy/csp_context.h"
 #include "content/common/download/mhtml_save_status.h"
-#include "content/common/features.h"
 #include "content/common/frame.mojom.h"
 #include "content/common/frame_message_enums.h"
 #include "content/common/frame_replication_state.h"
diff --git a/content/browser/gpu/compositor_util.cc b/content/browser/gpu/compositor_util.cc
index 4479fa5..63705c8f 100644
--- a/content/browser/gpu/compositor_util.cc
+++ b/content/browser/gpu/compositor_util.cc
@@ -19,6 +19,7 @@
 #include "base/sys_info.h"
 #include "build/build_config.h"
 #include "cc/base/switches.h"
+#include "components/viz/common/features.h"
 #include "content/browser/gpu/gpu_data_manager_impl.h"
 #include "content/public/common/content_features.h"
 #include "content/public/common/content_switches.h"
@@ -117,6 +118,11 @@
        "Native GpuMemoryBuffers have been disabled, either via about:flags"
        " or command line.",
        true},
+      {"surface_synchronization", gpu::kGpuFeatureStatusEnabled,
+       !features::IsSurfaceSynchronizationEnabled(),
+       "Surface synchronization has been disabled by Finch trial or command "
+       "line.",
+       false},
       {"webgl2",
        manager->GetFeatureStatus(gpu::GPU_FEATURE_TYPE_ACCELERATED_WEBGL2),
        (command_line.HasSwitch(switches::kDisableWebGL) ||
@@ -318,6 +324,10 @@
           status += "_force";
         status += "_on";
       }
+      if (gpu_feature_data.name == "surface_synchronization") {
+        if (features::IsSurfaceSynchronizationEnabled())
+          status += "_on";
+      }
     }
     feature_status_dict->SetString(gpu_feature_data.name, status);
   }
diff --git a/content/browser/ppapi_plugin_process_host.cc b/content/browser/ppapi_plugin_process_host.cc
index ff3d4c4..456dc18 100644
--- a/content/browser/ppapi_plugin_process_host.cc
+++ b/content/browser/ppapi_plugin_process_host.cc
@@ -31,7 +31,7 @@
 #include "content/public/common/process_type.h"
 #include "content/public/common/sandboxed_process_launcher_delegate.h"
 #include "content/public/common/service_names.mojom.h"
-#include "content/public/common/zygote_features.h"
+#include "content/public/common/zygote_buildflags.h"
 #include "mojo/edk/embedder/embedder.h"
 #include "net/base/network_change_notifier.h"
 #include "ppapi/proxy/ppapi_messages.h"
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 5379142..d9b5be1 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -166,7 +166,7 @@
 #include "content/public/common/sandboxed_process_launcher_delegate.h"
 #include "content/public/common/service_names.mojom.h"
 #include "content/public/common/url_constants.h"
-#include "content/public/common/zygote_features.h"
+#include "content/public/common/zygote_buildflags.h"
 #include "device/gamepad/gamepad_haptics_manager.h"
 #include "device/gamepad/gamepad_monitor.h"
 #include "gpu/GLES2/gl2extchromium.h"
diff --git a/content/browser/renderer_host/render_view_host_delegate_view.h b/content/browser/renderer_host/render_view_host_delegate_view.h
index 2576982a..5b30fd8 100644
--- a/content/browser/renderer_host/render_view_host_delegate_view.h
+++ b/content/browser/renderer_host/render_view_host_delegate_view.h
@@ -9,9 +9,9 @@
 
 #include "base/callback.h"
 #include "build/build_config.h"
+#include "content/common/buildflags.h"
 #include "content/common/content_export.h"
 #include "content/common/drag_event_source_info.h"
-#include "content/common/features.h"
 #include "content/public/common/input_event_ack_state.h"
 #include "third_party/WebKit/public/platform/WebDragOperation.h"
 
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc
index a016a43..f4f6c45 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura.cc
@@ -148,14 +148,8 @@
 // is obscured by the on screen keyboard.
 class WinScreenKeyboardObserver : public ui::OnScreenKeyboardObserver {
  public:
-  WinScreenKeyboardObserver(RenderWidgetHostViewAura* host_view,
-                            const gfx::Point& location_in_screen,
-                            float scale_factor,
-                            aura::Window* window)
-      : host_view_(host_view),
-        location_in_screen_(location_in_screen),
-        device_scale_factor_(scale_factor),
-        window_(window) {
+  WinScreenKeyboardObserver(RenderWidgetHostViewAura* host_view)
+      : host_view_(host_view) {
     host_view_->SetInsets(gfx::Insets());
   }
 
@@ -165,65 +159,18 @@
   }
 
   // base::win::OnScreenKeyboardObserver overrides.
-  void OnKeyboardVisible(const gfx::Rect& keyboard_rect_pixels) override {
-    gfx::Point location_in_pixels =
-        gfx::ConvertPointToPixel(device_scale_factor_, location_in_screen_);
-
-    // Restore the viewport.
-    host_view_->SetInsets(gfx::Insets());
-
-    if (keyboard_rect_pixels.Contains(location_in_pixels)) {
-      aura::client::ScreenPositionClient* screen_position_client =
-          aura::client::GetScreenPositionClient(window_->GetRootWindow());
-      if (!screen_position_client)
-        return;
-
-      DVLOG(1) << "OSK covering focus point.";
-      gfx::Rect keyboard_rect =
-          gfx::ConvertRectToDIP(device_scale_factor_, keyboard_rect_pixels);
-      gfx::Rect bounds_in_screen = window_->GetBoundsInScreen();
-
-      DCHECK(bounds_in_screen.bottom() > keyboard_rect.y());
-
-      // Set the viewport of the window to be just above the on screen
-      // keyboard.
-      int viewport_bottom = bounds_in_screen.bottom() - keyboard_rect.y();
-
-      // If the viewport is bigger than the view, then we cannot handle it
-      // with the current approach. Moving the window above the OSK is one way.
-      // That for a later patchset.
-      if (viewport_bottom > bounds_in_screen.height())
-        return;
-
-      host_view_->SetInsets(gfx::Insets(0, 0, viewport_bottom, 0));
-
-      gfx::Point origin(location_in_screen_);
-      screen_position_client->ConvertPointFromScreen(window_, &origin);
-
-      // TODO(ekaramad): We should support the case where the focused node is
-      // inside an OOPIF (https://crbug.com/676037).
-      // We want to scroll the node into a rectangle which originates from
-      // the touch point and a small offset (10) in either direction.
-      gfx::Rect node_rect(origin.x(), origin.y(), 10, 10);
-
-      host_view_->ScrollFocusedEditableNodeIntoRect(node_rect);
-    }
+  void OnKeyboardVisible(const gfx::Rect& keyboard_rect) override {
+    host_view_->SetInsets(gfx::Insets(
+        0, 0, keyboard_rect.IsEmpty() ? 0 : keyboard_rect.height(), 0));
   }
 
-  void OnKeyboardHidden(const gfx::Rect& keyboard_rect_pixels) override {
+  void OnKeyboardHidden() override {
     // Restore the viewport.
     host_view_->SetInsets(gfx::Insets());
   }
 
  private:
   RenderWidgetHostViewAura* host_view_;
-  // The location in DIPs where the touch occurred.
-  gfx::Point location_in_screen_;
-  // The current device scale factor.
-  float device_scale_factor_;
-
-  // The content Window.
-  aura::Window* window_;
 
   DISALLOW_COPY_AND_ASSIGN(WinScreenKeyboardObserver);
 };
@@ -811,15 +758,13 @@
 }
 
 void RenderWidgetHostViewAura::FocusedNodeTouched(
-    const gfx::Point& location_dips_screen,
     bool editable) {
 #if defined(OS_WIN)
   ui::OnScreenKeyboardDisplayManager* osk_display_manager =
       ui::OnScreenKeyboardDisplayManager::GetInstance();
   DCHECK(osk_display_manager);
   if (editable && host_->GetView() && host_->delegate()) {
-    keyboard_observer_.reset(new WinScreenKeyboardObserver(
-        this, location_dips_screen, device_scale_factor_, window_));
+    keyboard_observer_.reset(new WinScreenKeyboardObserver(this));
     if (!osk_display_manager->DisplayVirtualKeyboard(keyboard_observer_.get()))
       keyboard_observer_.reset(nullptr);
     virtual_keyboard_requested_ = keyboard_observer_.get();
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.h b/content/browser/renderer_host/render_widget_host_view_aura.h
index 54b286d1..de586d9 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.h
+++ b/content/browser/renderer_host/render_widget_host_view_aura.h
@@ -121,8 +121,7 @@
   bool IsMouseLocked() override;
   gfx::Size GetVisibleViewportSize() const override;
   void SetInsets(const gfx::Insets& insets) override;
-  void FocusedNodeTouched(const gfx::Point& location_dips_screen,
-                          bool editable) override;
+  void FocusedNodeTouched(bool editable) override;
   void SetNeedsBeginFrames(bool needs_begin_frames) override;
   void SetWantsAnimateOnlyBeginFrames() override;
   TouchSelectionControllerClientManager*
diff --git a/content/browser/renderer_host/render_widget_host_view_base.cc b/content/browser/renderer_host/render_widget_host_view_base.cc
index 10cc19e..c6b83be 100644
--- a/content/browser/renderer_host/render_widget_host_view_base.cc
+++ b/content/browser/renderer_host/render_widget_host_view_base.cc
@@ -308,7 +308,6 @@
 }
 
 void RenderWidgetHostViewBase::FocusedNodeTouched(
-    const gfx::Point& location_dips_screen,
     bool editable) {
   DVLOG(1) << "FocusedNodeTouched: " << editable;
 }
diff --git a/content/browser/renderer_host/render_widget_host_view_base.h b/content/browser/renderer_host/render_widget_host_view_base.h
index a88faed..9b8f8ad 100644
--- a/content/browser/renderer_host/render_widget_host_view_base.h
+++ b/content/browser/renderer_host/render_widget_host_view_base.h
@@ -119,8 +119,7 @@
       const gfx::Rect& src_rect,
       const gfx::Size& output_size,
       base::OnceCallback<void(const SkBitmap&)> callback) override;
-  void FocusedNodeTouched(const gfx::Point& location_dips_screen,
-                          bool editable) override;
+  void FocusedNodeTouched(bool editable) override;
   void GetScreenInfo(ScreenInfo* screen_info) const override;
   float GetDeviceScaleFactor() const final;
   TouchSelectionControllerClientManager*
diff --git a/content/browser/resources/gpu/info_view.js b/content/browser/resources/gpu/info_view.js
index 219c2e8..c9fb6bcf 100644
--- a/content/browser/resources/gpu/info_view.js
+++ b/content/browser/resources/gpu/info_view.js
@@ -113,6 +113,7 @@
         'rasterization': 'Rasterization',
         'multiple_raster_threads': 'Multiple Raster Threads',
         'native_gpu_memory_buffers': 'Native GpuMemoryBuffers',
+        'surface_synchronization': 'Surface Synchronization',
         'vpx_decode': 'VPx Video Decode',
         'webgl2': 'WebGL2',
         'checker_imaging': 'CheckerImaging',
diff --git a/content/browser/streams/stream.cc b/content/browser/streams/stream.cc
index 5cb066a..8a018a7 100644
--- a/content/browser/streams/stream.cc
+++ b/content/browser/streams/stream.cc
@@ -87,15 +87,7 @@
 
 void Stream::OnResponseStarted(const net::HttpResponseInfo& response_info) {
   DCHECK(!metadata_);
-  if (response_info.headers) {
-    metadata_.reset(new StreamMetadata(response_info));
-    return;
-  }
-  // Assume request wasn't backed by HTTP and produce fake "200 OK" response,
-  // as some consumers expect it for, say, data urls.
-  net::HttpResponseInfo fake_response_info = response_info;
-  fake_response_info.headers = new net::HttpResponseHeaders("HTTP/1.1 200 OK");
-  metadata_ = std::make_unique<StreamMetadata>(fake_response_info);
+  metadata_ = std::make_unique<StreamMetadata>(response_info);
 }
 
 void Stream::UpdateNetworkStats(int64_t raw_body_bytes, int64_t total_bytes) {
diff --git a/content/browser/tracing/etw_tracing_agent_win.cc b/content/browser/tracing/etw_tracing_agent_win.cc
index 7b9a956..adc428b 100644
--- a/content/browser/tracing/etw_tracing_agent_win.cc
+++ b/content/browser/tracing/etw_tracing_agent_win.cc
@@ -166,8 +166,8 @@
 
 void EtwTracingAgent::AddSyncEventToBuffer() {
   // Sync the clocks.
-  base::Time walltime = base::Time::NowFromSystemTime();
-  base::TimeTicks now = base::TimeTicks::Now();
+  base::Time walltime = base::subtle::TimeNowFromSystemTimeIgnoringOverride();
+  base::TimeTicks now = TRACE_TIME_TICKS_NOW();
 
   LARGE_INTEGER walltime_in_us;
   walltime_in_us.QuadPart = walltime.ToInternalValue();
diff --git a/content/browser/tracing/power_tracing_agent.cc b/content/browser/tracing/power_tracing_agent.cc
index 515144b6..af496fb 100644
--- a/content/browser/tracing/power_tracing_agent.cc
+++ b/content/browser/tracing/power_tracing_agent.cc
@@ -158,7 +158,7 @@
   }
 
   request_clock_sync_marker_callback_ = callback;
-  request_clock_sync_marker_start_time_ = base::TimeTicks::Now();
+  request_clock_sync_marker_start_time_ = TRACE_TIME_TICKS_NOW();
   battor_agent_->RecordClockSyncMarker(sync_id);
 }
 
@@ -167,7 +167,7 @@
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
   base::TimeTicks issue_start_ts = request_clock_sync_marker_start_time_;
-  base::TimeTicks issue_end_ts = base::TimeTicks::Now();
+  base::TimeTicks issue_end_ts = TRACE_TIME_TICKS_NOW();
 
   if (error != battor::BATTOR_ERROR_NONE)
     issue_start_ts = issue_end_ts = base::TimeTicks();
diff --git a/content/browser/tracing/tracing_controller_impl.cc b/content/browser/tracing/tracing_controller_impl.cc
index 568e011..a336ae6 100644
--- a/content/browser/tracing/tracing_controller_impl.cc
+++ b/content/browser/tracing/tracing_controller_impl.cc
@@ -239,7 +239,7 @@
       base::CommandLine::ForCurrentProcess()->GetCommandLineString());
 
   base::Time::Exploded ctime;
-  base::Time::Now().UTCExplode(&ctime);
+  TRACE_TIME_NOW().UTCExplode(&ctime);
   std::string time_string = base::StringPrintf(
       "%u-%u-%u %d:%d:%d", ctime.year, ctime.month, ctime.day_of_month,
       ctime.hour, ctime.minute, ctime.second);
diff --git a/content/browser/utility_process_host_impl.cc b/content/browser/utility_process_host_impl.cc
index 51f997c2..229bcde 100644
--- a/content/browser/utility_process_host_impl.cc
+++ b/content/browser/utility_process_host_impl.cc
@@ -30,7 +30,7 @@
 #include "content/public/common/sandboxed_process_launcher_delegate.h"
 #include "content/public/common/service_manager_connection.h"
 #include "content/public/common/service_names.mojom.h"
-#include "content/public/common/zygote_features.h"
+#include "content/public/common/zygote_buildflags.h"
 #include "media/base/media_switches.h"
 #include "services/network/public/cpp/network_switches.h"
 #include "services/service_manager/public/cpp/interface_provider.h"
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 44764ef9..13c64464 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -6093,16 +6093,10 @@
 
 void WebContentsImpl::FocusedNodeTouched(bool editable) {
 #if defined(OS_WIN)
-  // We use the cursor position to determine where the touch occurred.
   RenderWidgetHostView* view = GetRenderWidgetHostView();
   if (!view)
     return;
-  POINT cursor_pos = {};
-  ::GetCursorPos(&cursor_pos);
-  float scale = GetScaleFactorForView(view);
-  gfx::Point location_dips_screen =
-      gfx::ConvertPointToDIP(scale, gfx::Point(cursor_pos));
-  view->FocusedNodeTouched(location_dips_screen, editable);
+  view->FocusedNodeTouched(editable);
 #endif
 }
 
diff --git a/content/browser/web_contents/web_contents_view_aura.h b/content/browser/web_contents/web_contents_view_aura.h
index 50c22b1..4aa7af32 100644
--- a/content/browser/web_contents/web_contents_view_aura.h
+++ b/content/browser/web_contents/web_contents_view_aura.h
@@ -16,8 +16,8 @@
 #include "content/browser/renderer_host/overscroll_controller_delegate.h"
 #include "content/browser/renderer_host/render_view_host_delegate_view.h"
 #include "content/browser/web_contents/web_contents_view.h"
+#include "content/common/buildflags.h"
 #include "content/common/content_export.h"
-#include "content/common/features.h"
 #include "ui/aura/client/drag_drop_delegate.h"
 #include "ui/aura/window_delegate.h"
 #include "ui/aura/window_observer.h"
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn
index c8cfb65..d47a0adf 100644
--- a/content/common/BUILD.gn
+++ b/content/common/BUILD.gn
@@ -17,8 +17,8 @@
 
 # For feature flags internal to content. See content/public/common:features
 # for feature flags that clients of contents need to know about.
-buildflag_header("features") {
-  header = "features.h"
+buildflag_header("buildflags") {
+  header = "buildflags.h"
 
   flags = [
     "USE_EXTERNAL_POPUP_MENU=$use_external_popup_menu",
@@ -323,7 +323,7 @@
     "//ui/accessibility",
   ]
   deps = [
-    ":features",
+    ":buildflags",
     "//base",
     "//base/third_party/dynamic_annotations",
     "//build/util:webkit_version",
@@ -336,7 +336,7 @@
     "//content/app/resources",
     "//content/public/common:interfaces",
     "//content/public/common:service_names",
-    "//content/public/common:zygote_features",
+    "//content/public/common:zygote_buildflags",
     "//device/base/synchronization",
     "//device/bluetooth",
     "//gpu",
diff --git a/content/common/frame_messages.h b/content/common/frame_messages.h
index abc8e643..2799f2aa 100644
--- a/content/common/frame_messages.h
+++ b/content/common/frame_messages.h
@@ -19,12 +19,12 @@
 #include "build/build_config.h"
 #include "components/viz/common/surfaces/surface_id.h"
 #include "components/viz/common/surfaces/surface_info.h"
+#include "content/common/buildflags.h"
 #include "content/common/content_export.h"
 #include "content/common/content_param_traits.h"
 #include "content/common/content_security_policy/csp_context.h"
 #include "content/common/content_security_policy_header.h"
 #include "content/common/download/mhtml_save_status.h"
-#include "content/common/features.h"
 #include "content/common/frame_message_enums.h"
 #include "content/common/frame_message_structs.h"
 #include "content/common/frame_owner_properties.h"
diff --git a/content/common/native_types.typemap b/content/common/native_types.typemap
index 8e2f44e0..0e630441 100644
--- a/content/common/native_types.typemap
+++ b/content/common/native_types.typemap
@@ -47,7 +47,7 @@
   # transitive allowance, so those targets' own public_deps aren't included in
   # the set of implied dependencies.
   "//cc/ipc",
-  "//content/common:features",
+  "//content/common:buildflags",
   "//media",
   "//media/base/ipc",
   "//net",
diff --git a/content/public/android/java/src/org/chromium/content/browser/remoteobjects/RemoteObjectImpl.java b/content/public/android/java/src/org/chromium/content/browser/remoteobjects/RemoteObjectImpl.java
index 5dcd0f8..af0f1f3 100644
--- a/content/public/android/java/src/org/chromium/content/browser/remoteobjects/RemoteObjectImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/remoteobjects/RemoteObjectImpl.java
@@ -136,6 +136,14 @@
             callback.call(makeErrorResult(RemoteInvocationError.OBJECT_GET_CLASS_BLOCKED));
             return;
         }
+        if (method.getReturnType().isArray()) {
+            // LIVECONNECT_COMPLIANCE: Existing behavior is to not call methods that
+            // return arrays. Spec requires calling the method and converting the
+            // result to a JavaScript array.
+            RemoteInvocationResult result = new RemoteInvocationResult();
+            callback.call(result);
+            return;
+        }
 
         Class<?>[] parameterTypes = method.getParameterTypes();
         Object[] args = new Object[numArguments];
diff --git a/content/public/android/junit/src/org/chromium/content/browser/remoteobjects/RemoteObjectImplTest.java b/content/public/android/junit/src/org/chromium/content/browser/remoteobjects/RemoteObjectImplTest.java
index de91d2c2..e5ac6242 100644
--- a/content/public/android/junit/src/org/chromium/content/browser/remoteobjects/RemoteObjectImplTest.java
+++ b/content/public/android/junit/src/org/chromium/content/browser/remoteobjects/RemoteObjectImplTest.java
@@ -282,6 +282,23 @@
     }
 
     @Test
+    public void testMethodReturningArrayIgnored() {
+        Object target = new Object() {
+            @TestJavascriptInterface
+            public int[] returnsIntArray() {
+                Assert.fail("Method returning array should not be called.");
+                return null;
+            }
+        };
+
+        RemoteObject remoteObject = new RemoteObjectImpl(target, TestJavascriptInterface.class);
+        RemoteObject.InvokeMethodResponse response = mock(RemoteObject.InvokeMethodResponse.class);
+        remoteObject.invokeMethod("returnsIntArray", new RemoteInvocationArgument[] {}, response);
+
+        verify(response).call(resultIsOk());
+    }
+
+    @Test
     public void testInvocationTargetException() {
         Object target = new Object() {
             @TestJavascriptInterface
diff --git a/content/public/browser/render_widget_host_view.h b/content/public/browser/render_widget_host_view.h
index 71f3b3c..ffcf44f 100644
--- a/content/public/browser/render_widget_host_view.h
+++ b/content/public/browser/render_widget_host_view.h
@@ -191,12 +191,9 @@
       base::OnceCallback<void(const SkBitmap&)> callback) = 0;
 
   // Notification that a node was touched.
-  // The |location_dips_screen| parameter contains the location where the touch
-  // occurred in DIPs in screen coordinates.
   // The |editable| parameter indicates if the node is editable, for e.g.
   // an input field, etc.
-  virtual void FocusedNodeTouched(const gfx::Point& location_dips_screen,
-                                  bool editable) = 0;
+  virtual void FocusedNodeTouched(bool editable) = 0;
 
   // Informs the view that its associated render widget has frames to draw and
   // wants to have BeginFrame messages sent to it.  This should only be called
diff --git a/content/public/common/BUILD.gn b/content/public/common/BUILD.gn
index c92262c7..f2f3d55 100644
--- a/content/public/common/BUILD.gn
+++ b/content/public/common/BUILD.gn
@@ -255,6 +255,7 @@
   public_deps = [
     ":interfaces",
     ":service_names",
+    ":zygote_buildflags",
     "//content/common",
     "//ipc",
     "//media/capture:capture_base",
@@ -274,7 +275,6 @@
   ]
   deps = [
     ":content_descriptor_keys",
-    ":zygote_features",
 
     # This looks needless as we have //content/common in public_deps, but it's
     # needed because of allow_circular_includes_from.
@@ -332,14 +332,14 @@
   }
 }
 
-buildflag_header("features") {
-  header = "features.h"
+buildflag_header("buildflags") {
+  header = "buildflags.h"
   flags = [ "RTC_USE_H264=$rtc_use_h264" ]
 }
 
 source_set("feature_h264_with_openh264_ffmpeg") {
   deps = [
-    ":features",
+    ":buildflags",
     "//base",
     "//media:media_features",
   ]
@@ -349,8 +349,8 @@
   ]
 }
 
-buildflag_header("zygote_features") {
-  header = "zygote_features.h"
+buildflag_header("zygote_buildflags") {
+  header = "zygote_buildflags.h"
   flags = [ "USE_ZYGOTE_HANDLE=$use_zygote_handle" ]
 }
 
diff --git a/content/public/common/feature_h264_with_openh264_ffmpeg.h b/content/public/common/feature_h264_with_openh264_ffmpeg.h
index 2ee9bf8..6d81d73 100644
--- a/content/public/common/feature_h264_with_openh264_ffmpeg.h
+++ b/content/public/common/feature_h264_with_openh264_ffmpeg.h
@@ -6,7 +6,7 @@
 #define CONTENT_PUBLIC_COMMON_FEATURE_H264_WITH_OPENH264_FFMPEG_H_
 
 #include "base/feature_list.h"
-#include "content/public/common/features.h"
+#include "content/public/common/buildflags.h"
 #include "media/media_features.h"
 
 namespace content {
diff --git a/content/public/common/sandboxed_process_launcher_delegate.cc b/content/public/common/sandboxed_process_launcher_delegate.cc
index b7e61e5ed..2574f49 100644
--- a/content/public/common/sandboxed_process_launcher_delegate.cc
+++ b/content/public/common/sandboxed_process_launcher_delegate.cc
@@ -5,7 +5,7 @@
 #include "content/public/common/sandboxed_process_launcher_delegate.h"
 
 #include "build/build_config.h"
-#include "content/public/common/zygote_features.h"
+#include "content/public/common/zygote_buildflags.h"
 
 #if BUILDFLAG(USE_ZYGOTE_HANDLE)
 #include "content/public/common/zygote_handle.h"
diff --git a/content/public/common/sandboxed_process_launcher_delegate.h b/content/public/common/sandboxed_process_launcher_delegate.h
index 6af3c28..80043c8 100644
--- a/content/public/common/sandboxed_process_launcher_delegate.h
+++ b/content/public/common/sandboxed_process_launcher_delegate.h
@@ -10,7 +10,7 @@
 #include "base/process/process.h"
 #include "build/build_config.h"
 #include "content/common/content_export.h"
-#include "content/public/common/zygote_features.h"
+#include "content/public/common/zygote_buildflags.h"
 #include "services/service_manager/sandbox/sandbox_delegate.h"
 #include "services/service_manager/sandbox/sandbox_type.h"
 
diff --git a/content/public/common/zygote_handle.h b/content/public/common/zygote_handle.h
index dfa9628..5c21c883 100644
--- a/content/public/common/zygote_handle.h
+++ b/content/public/common/zygote_handle.h
@@ -10,7 +10,7 @@
 #include "base/files/scoped_file.h"
 #include "build/build_config.h"
 #include "content/common/content_export.h"
-#include "content/public/common/zygote_features.h"
+#include "content/public/common/zygote_buildflags.h"
 
 #if !BUILDFLAG(USE_ZYGOTE_HANDLE)
 #error "Can not use zygote handles without USE_ZYGOTE_HANDLE"
diff --git a/content/public/renderer/BUILD.gn b/content/public/renderer/BUILD.gn
index 1094933..481fb69e 100644
--- a/content/public/renderer/BUILD.gn
+++ b/content/public/renderer/BUILD.gn
@@ -128,8 +128,8 @@
       "webrtc_log_message_delegate.h",
     ]
     deps += [
+      "//content/public/common:buildflags",
       "//content/public/common:feature_h264_with_openh264_ffmpeg",
-      "//content/public/common:features",
       "//third_party/webrtc_overrides",
     ]
   }
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn
index b5c90ea4..233d4e1 100644
--- a/content/renderer/BUILD.gn
+++ b/content/renderer/BUILD.gn
@@ -547,11 +547,11 @@
     "//content:resources",
     "//content/child",
     "//content/common",
-    "//content/common:features",
+    "//content/common:buildflags",
     "//content/gpu:gpu_sources",
     "//content/public/child:child_sources",
+    "//content/public/common:buildflags",
     "//content/public/common:feature_h264_with_openh264_ffmpeg",
-    "//content/public/common:features",
     "//content/public/common:service_names",
     "//crypto:platform",
     "//device/base/synchronization",
diff --git a/content/renderer/external_popup_menu.h b/content/renderer/external_popup_menu.h
index 79b97a1..e8a661a 100644
--- a/content/renderer/external_popup_menu.h
+++ b/content/renderer/external_popup_menu.h
@@ -9,7 +9,7 @@
 
 #include "base/macros.h"
 #include "build/build_config.h"
-#include "content/common/features.h"
+#include "content/common/buildflags.h"
 #include "third_party/WebKit/public/web/WebExternalPopupMenu.h"
 #include "third_party/WebKit/public/web/WebPopupMenuInfo.h"
 #include "ui/gfx/geometry/point_f.h"
diff --git a/content/renderer/media/webrtc/peer_connection_dependency_factory.cc b/content/renderer/media/webrtc/peer_connection_dependency_factory.cc
index 6eb1b5e..087e554 100644
--- a/content/renderer/media/webrtc/peer_connection_dependency_factory.cc
+++ b/content/renderer/media/webrtc/peer_connection_dependency_factory.cc
@@ -23,11 +23,11 @@
 #include "base/synchronization/waitable_event.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
+#include "content/public/common/buildflags.h"
 #include "content/public/common/content_client.h"
 #include "content/public/common/content_features.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/feature_h264_with_openh264_ffmpeg.h"
-#include "content/public/common/features.h"
 #include "content/public/common/renderer_preferences.h"
 #include "content/public/common/webrtc_ip_handling_policy.h"
 #include "content/public/renderer/content_renderer_client.h"
diff --git a/content/renderer/media_recorder/h264_encoder.h b/content/renderer/media_recorder/h264_encoder.h
index 524dd697..7074ffb3 100644
--- a/content/renderer/media_recorder/h264_encoder.h
+++ b/content/renderer/media_recorder/h264_encoder.h
@@ -5,7 +5,7 @@
 #ifndef CONTENT_RENDERER_MEDIA_RECORDER_H264_ENCODER_H_
 #define CONTENT_RENDERER_MEDIA_RECORDER_H264_ENCODER_H_
 
-#include "content/public/common/features.h"
+#include "content/public/common/buildflags.h"
 
 #if !BUILDFLAG(RTC_USE_H264)
 #error RTC_USE_H264 should be defined.
diff --git a/content/renderer/media_recorder/video_track_recorder.h b/content/renderer/media_recorder/video_track_recorder.h
index df288c0f..2eed0e2b 100644
--- a/content/renderer/media_recorder/video_track_recorder.h
+++ b/content/renderer/media_recorder/video_track_recorder.h
@@ -12,7 +12,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_checker.h"
-#include "content/public/common/features.h"
+#include "content/public/common/buildflags.h"
 #include "content/public/renderer/media_stream_video_sink.h"
 #include "media/muxers/webm_muxer.h"
 #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h"
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index c67c9882..5bb6141 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -30,8 +30,8 @@
 #include "base/unguessable_token.h"
 #include "build/build_config.h"
 #include "content/common/associated_interface_registry_impl.h"
+#include "content/common/buildflags.h"
 #include "content/common/download/mhtml_save_status.h"
-#include "content/common/features.h"
 #include "content/common/frame.mojom.h"
 #include "content/common/frame_message_enums.h"
 #include "content/common/host_zoom.mojom.h"
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index affc7ad..1d44950 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -60,9 +60,9 @@
 #include "content/child/memory/child_memory_coordinator_impl.h"
 #include "content/child/runtime_features.h"
 #include "content/child/thread_safe_sender.h"
+#include "content/common/buildflags.h"
 #include "content/common/content_constants_internal.h"
 #include "content/common/dom_storage/dom_storage_messages.h"
-#include "content/common/features.h"
 #include "content/common/frame_messages.h"
 #include "content/common/frame_owner_properties.h"
 #include "content/common/gpu_stream_constants.h"
diff --git a/content/renderer/render_widget.h b/content/renderer/render_widget.h
index 3e8c9df5..ed92b75 100644
--- a/content/renderer/render_widget.h
+++ b/content/renderer/render_widget.h
@@ -26,11 +26,11 @@
 #include "cc/input/overscroll_behavior.h"
 #include "cc/input/touch_action.h"
 #include "components/viz/common/surfaces/local_surface_id.h"
+#include "content/common/buildflags.h"
 #include "content/common/content_export.h"
 #include "content/common/cursors/webcursor.h"
 #include "content/common/drag_event_source_info.h"
 #include "content/common/edit_command.h"
-#include "content/common/features.h"
 #include "content/common/widget.mojom.h"
 #include "content/public/common/drop_data.h"
 #include "content/public/common/screen_info.h"
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 58a44ca..7198af3 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -1022,6 +1022,7 @@
     ]
     sources -= [
       "../browser/media/session/audio_focus_delegate_default_browsertest.cc",
+      "../browser/network_service_restart_browsertest.cc",
       "../browser/pointer_lock_browsertest.cc",
       "../browser/pointer_lock_browsertest.h",
     ]
@@ -1100,7 +1101,7 @@
       "../browser/webrtc/webrtc_webcam_browsertest.h",
     ]
     deps += [
-      "//content/public/common:features",
+      "//content/public/common:buildflags",
       "//testing/perf",
     ]
   }
diff --git a/device/vr/android/gvr/gvr_delegate.cc b/device/vr/android/gvr/gvr_delegate.cc
index 0418f435..fd331cd 100644
--- a/device/vr/android/gvr/gvr_delegate.cc
+++ b/device/vr/android/gvr/gvr_delegate.cc
@@ -81,12 +81,6 @@
   return omega_vec;
 }
 
-void PostRotateZ(gfx::Transform* transform, float degrees) {
-  gfx::Transform rotate;
-  rotate.RotateAboutZAxis(degrees);
-  transform->ConcatTransform(rotate);
-}
-
 }  // namespace
 
 /* static */
@@ -140,7 +134,6 @@
 mojom::VRPosePtr GvrDelegate::GetVRPosePtrWithNeckModel(
     gvr::GvrApi* gvr_api,
     gfx::Transform* head_mat_out,
-    int rotate_degrees,
     int64_t prediction_time) {
   gvr::ClockTimePoint target_time = gvr::GvrApi::GetTimePointNow();
   target_time.monotonic_system_time_nanos += prediction_time;
@@ -154,9 +147,6 @@
     head_mat_ptr = &head_mat;
   GvrMatToTransform(gvr_head_mat, head_mat_ptr);
 
-  if (rotate_degrees != 0)
-    PostRotateZ(head_mat_ptr, rotate_degrees);
-
   mojom::VRPosePtr pose = GvrDelegate::VRPosePtrFromGvrPose(*head_mat_ptr);
 
   // Get a second pose a bit later to calculate angular velocity.
@@ -166,9 +156,6 @@
   gfx::Transform head_mat_2;
   GvrMatToTransform(gvr_head_mat_2, &head_mat_2);
 
-  if (rotate_degrees != 0)
-    PostRotateZ(&head_mat_2, rotate_degrees);
-
   // Add headset angular velocity to the pose.
   pose->angularVelocity.emplace(3);
   double epsilon_seconds = kAngularVelocityEpsilonNanos * 1e-9;
@@ -184,9 +171,8 @@
 /* static */
 mojom::VRPosePtr GvrDelegate::GetVRPosePtrWithNeckModel(
     gvr::GvrApi* gvr_api,
-    gfx::Transform* head_mat_out,
-    int rotate_degrees) {
-  return GetVRPosePtrWithNeckModel(gvr_api, head_mat_out, rotate_degrees,
+    gfx::Transform* head_mat_out) {
+  return GetVRPosePtrWithNeckModel(gvr_api, head_mat_out,
                                    kPredictionTimeWithoutVsyncNanos);
 }
 
diff --git a/device/vr/android/gvr/gvr_delegate.h b/device/vr/android/gvr/gvr_delegate.h
index 6baa7c6..efe3c86 100644
--- a/device/vr/android/gvr/gvr_delegate.h
+++ b/device/vr/android/gvr/gvr_delegate.h
@@ -33,12 +33,10 @@
   static mojom::VRPosePtr GetVRPosePtrWithNeckModel(
       gvr::GvrApi* gvr_api,
       gfx::Transform* head_mat_out,
-      int rotate_degrees,
       int64_t prediction_time);
   static mojom::VRPosePtr GetVRPosePtrWithNeckModel(
       gvr::GvrApi* gvr_api,
-      gfx::Transform* head_mat_out,
-      int rotate_degrees);
+      gfx::Transform* head_mat_out);
 };
 
 }  // namespace device
diff --git a/device/vr/android/gvr/gvr_device.cc b/device/vr/android/gvr/gvr_device.cc
index c2963e3..33ad3bd 100644
--- a/device/vr/android/gvr/gvr_device.cc
+++ b/device/vr/android/gvr/gvr_device.cc
@@ -188,8 +188,8 @@
 
 void GvrDevice::OnMagicWindowPoseRequest(
     mojom::VRMagicWindowProvider::GetPoseCallback callback) {
-  std::move(callback).Run(GvrDelegate::GetVRPosePtrWithNeckModel(
-      gvr_api_.get(), nullptr, rotation_degrees_));
+  std::move(callback).Run(
+      GvrDelegate::GetVRPosePtrWithNeckModel(gvr_api_.get(), nullptr));
 }
 
 void GvrDevice::OnListeningForActivate(bool listening) {
@@ -201,10 +201,14 @@
 
 void GvrDevice::PauseTracking() {
   gvr_api_->PauseTracking();
+  JNIEnv* env = base::android::AttachCurrentThread();
+  Java_NonPresentingGvrContext_pause(env, non_presenting_context_);
 }
 
 void GvrDevice::ResumeTracking() {
   gvr_api_->ResumeTracking();
+  JNIEnv* env = base::android::AttachCurrentThread();
+  Java_NonPresentingGvrContext_resume(env, non_presenting_context_);
 }
 
 GvrDelegateProvider* GvrDevice::GetGvrDelegateProvider() {
@@ -216,16 +220,11 @@
   return delegate_provider;
 }
 
-void GvrDevice::OnDIPScaleChanged(JNIEnv* env, const JavaRef<jobject>& obj) {
+void GvrDevice::OnDisplayConfigurationChanged(JNIEnv* env,
+                                              const JavaRef<jobject>& obj) {
   SetVRDisplayInfo(CreateVRDisplayInfo(gvr_api_.get(), GetId()));
 }
 
-void GvrDevice::OnRotationChanged(JNIEnv* env,
-                                  const JavaRef<jobject>& obj,
-                                  jint rotation_degrees) {
-  rotation_degrees_ = rotation_degrees;
-}
-
 void GvrDevice::Activate(mojom::VRDisplayEventReason reason,
                          base::Callback<void(bool)> on_handled) {
   OnActivate(reason, std::move(on_handled));
diff --git a/device/vr/android/gvr/gvr_device.h b/device/vr/android/gvr/gvr_device.h
index e041c2e..e362ce2 100644
--- a/device/vr/android/gvr/gvr_device.h
+++ b/device/vr/android/gvr/gvr_device.h
@@ -36,11 +36,9 @@
   void PauseTracking() override;
   void ResumeTracking() override;
 
-  void OnDIPScaleChanged(JNIEnv* env,
-                         const base::android::JavaRef<jobject>& obj);
-  void OnRotationChanged(JNIEnv* env,
-                         const base::android::JavaRef<jobject>& obj,
-                         jint rotation_degrees);
+  void OnDisplayConfigurationChanged(
+      JNIEnv* env,
+      const base::android::JavaRef<jobject>& obj);
 
   void Activate(mojom::VRDisplayEventReason reason,
                 base::Callback<void(bool)> on_handled);
@@ -62,7 +60,6 @@
 
   base::android::ScopedJavaGlobalRef<jobject> non_presenting_context_;
   std::unique_ptr<gvr::GvrApi> gvr_api_;
-  int rotation_degrees_;
 
   base::WeakPtrFactory<GvrDevice> weak_ptr_factory_;
 
diff --git a/device/vr/android/java/src/org/chromium/device/vr/NonPresentingGvrContext.java b/device/vr/android/java/src/org/chromium/device/vr/NonPresentingGvrContext.java
index 9e764510..d7ba07e6 100644
--- a/device/vr/android/java/src/org/chromium/device/vr/NonPresentingGvrContext.java
+++ b/device/vr/android/java/src/org/chromium/device/vr/NonPresentingGvrContext.java
@@ -7,7 +7,6 @@
 import android.content.Context;
 import android.os.StrictMode;
 import android.view.Display;
-import android.view.Surface;
 import android.view.WindowManager;
 
 import com.google.vr.cardboard.DisplaySynchronizer;
@@ -16,7 +15,6 @@
 import org.chromium.base.ContextUtils;
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
-import org.chromium.ui.display.DisplayAndroid;
 
 /**
  * Creates an active GvrContext from a GvrApi created from the Application Context. This GvrContext
@@ -24,9 +22,10 @@
  * parameters.
  */
 @JNINamespace("device")
-public class NonPresentingGvrContext implements DisplayAndroid.DisplayAndroidObserver {
+public class NonPresentingGvrContext {
     private GvrApi mGvrApi;
-    private DisplayAndroid mDisplayAndroid;
+    private DisplaySynchronizer mDisplaySynchronizer;
+    private boolean mResumed;
 
     private long mNativeGvrDevice;
 
@@ -36,18 +35,22 @@
         WindowManager windowManager =
                 (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
         Display display = windowManager.getDefaultDisplay();
-        DisplaySynchronizer synchronizer = new DisplaySynchronizer(context, display);
+        mDisplaySynchronizer = new DisplaySynchronizer(context, display) {
+            @Override
+            public void onConfigurationChanged() {
+                super.onConfigurationChanged();
+                onDisplayConfigurationChanged();
+            }
+        };
 
         // Creating the GvrApi can sometimes create the Daydream config file.
         StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
         try {
-            mGvrApi = new GvrApi(context, synchronizer);
+            mGvrApi = new GvrApi(context, mDisplaySynchronizer);
         } finally {
             StrictMode.setThreadPolicy(oldPolicy);
         }
-        mDisplayAndroid = DisplayAndroid.getNonMultiDisplay(context);
-        mDisplayAndroid.addObserver(this);
-        onRotationChanged(mDisplayAndroid.getRotation());
+        resume();
     }
 
     @CalledByNative
@@ -65,40 +68,30 @@
     }
 
     @CalledByNative
+    private void pause() {
+        if (!mResumed) return;
+        mResumed = false;
+        mDisplaySynchronizer.onPause();
+    }
+
+    @CalledByNative
+    private void resume() {
+        if (mResumed) return;
+        mResumed = true;
+        mDisplaySynchronizer.onResume();
+    }
+
+    @CalledByNative
     private void shutdown() {
+        mDisplaySynchronizer.shutdown();
         mGvrApi.shutdown();
-        mDisplayAndroid.removeObserver(this);
         mNativeGvrDevice = 0;
     }
 
-    private int rotationToDegrees(int rotation) {
-        switch (rotation) {
-            case Surface.ROTATION_0:
-                return 0;
-            case Surface.ROTATION_90:
-                return 90;
-            case Surface.ROTATION_180:
-                return 180;
-            case Surface.ROTATION_270:
-                return 270;
-        }
-        assert false;
-        return 0;
-    }
-
-    @Override
-    public void onRotationChanged(int rotation) {
-        if (mNativeGvrDevice != 0) {
-            nativeOnRotationChanged(mNativeGvrDevice, rotationToDegrees(rotation));
-        }
-    }
-
-    @Override
-    public void onDIPScaleChanged(float dipScale) {
+    public void onDisplayConfigurationChanged() {
         mGvrApi.refreshDisplayMetrics();
-        if (mNativeGvrDevice != 0) nativeOnDIPScaleChanged(mNativeGvrDevice);
+        if (mNativeGvrDevice != 0) nativeOnDisplayConfigurationChanged(mNativeGvrDevice);
     }
 
-    private native void nativeOnDIPScaleChanged(long nativeGvrDevice);
-    private native void nativeOnRotationChanged(long nativeGvrDevice, int rotationDegrees);
+    private native void nativeOnDisplayConfigurationChanged(long nativeGvrDevice);
 }
diff --git a/docs/ios/coverage.md b/docs/ios/coverage.md
deleted file mode 100644
index 7285718..0000000
--- a/docs/ios/coverage.md
+++ /dev/null
@@ -1,78 +0,0 @@
-# Generate code coverage data
-
-1.  Build a test target for coverage:
-
-    ```
-    ninja -C out/Coverage-iphonesimulator ios_chrome_unittests
-    ```
-
-    Targets that support code coverage need to call
-    `coverage_util::ConfigureCoverageReportPath()`.
-    If you don't use `setup-gn.py`, you can set the gn argument
-    `ios_enable_coverage` to `true`.
-
-1.  Run the test target. If using Xcode, don't forget to set `Coverage` in the
-    target's scheme:
-
-    ![](images/coverage_xcode.png)
-
-1.  Find the `coverage.profraw` in the `Documents` folder of the app. You can
-    look in the console output of the instrumented target. For example:
-
-    ```
-    Coverage data at /Users/johndoe/Library/Developer/CoreSimulator/Devices/
-    82D642FA-FC18-4EDB-AFE0-A17454804BE4/data/Containers/Data/Application/
-    E6B2B898-CE13-4958-93F3-E8B500446381/Documents/coverage.profraw
-    ```
-
-1.  Create a `coverage.profdata` file out of the `coverage.profraw` file:
-
-    ```
-    xcrun llvm-profdata merge \
-        -o out/Coverage-iphonesimulator/coverage.profdata \
-        path/to/coverage.profraw
-    ```
-
-1.  To see the **line coverage** for *all the instrumented source files*:
-
-    ```
-    xcrun llvm-cov show \
-        out/Coverage-iphonesimulator/ios_chrome_unittests.app/ios_chrome_unittests \
-        -instr-profile=out/Coverage-iphonesimulator/coverage.profdata \
-        -arch=x86_64
-    ```
-
-    ![](images/llvm-cov_show.png)
-
-    To see the **line coverage** for a *specific instrumented source
-    file/folder* (e.g.
-    `ios/chrome/browser/ui/coordinators/browser_coordinator.mm`):
-
-    ```
-    xcrun llvm-cov show \
-        out/Coverage-iphonesimulator/ios_chrome_unittests.app/ios_chrome_unittests \
-        -instr-profile=out/Coverage-iphonesimulator/coverage.profdata \
-        -arch=x86_64 ios/chrome/browser/ui/coordinators/browser_coordinator.mm
-    ```
-
-    ![](images/llvm-cov_show_file.png)
-
-    To see a **complete report**:
-
-    ```
-    xcrun llvm-cov report \
-        out/Coverage-iphonesimulator/ios_chrome_unittests.app/ios_chrome_unittests \
-        -instr-profile=path/to/coverage.profdata -arch=x86_64
-    ```
-
-    ![](images/llvm-cov_report.png)
-
-    To see a **report** for a *folder/file* (e.g. `ios/chrome/browser` folder):
-
-    ```
-    xcrun llvm-cov show \
-        out/Coverage-iphonesimulator/ios_chrome_unittests.app/ios_chrome_unittests \
-        -instr-profile=path/to/coverage.profdata -arch=x86_64 ios/chrome/browser
-    ```
-
-    ![](images/llvm-cov_report_folder.png)
diff --git a/docs/ios/images/coverage_xcode.png b/docs/ios/images/coverage_xcode.png
deleted file mode 100644
index 73607346..0000000
--- a/docs/ios/images/coverage_xcode.png
+++ /dev/null
Binary files differ
diff --git a/docs/ios/images/llvm-cov_report.png b/docs/ios/images/llvm-cov_report.png
deleted file mode 100644
index aac9e13..0000000
--- a/docs/ios/images/llvm-cov_report.png
+++ /dev/null
Binary files differ
diff --git a/docs/ios/images/llvm-cov_report_folder.png b/docs/ios/images/llvm-cov_report_folder.png
deleted file mode 100644
index 510badd..0000000
--- a/docs/ios/images/llvm-cov_report_folder.png
+++ /dev/null
Binary files differ
diff --git a/docs/ios/images/llvm-cov_show.png b/docs/ios/images/llvm-cov_show.png
deleted file mode 100644
index bf5c9c7..0000000
--- a/docs/ios/images/llvm-cov_show.png
+++ /dev/null
Binary files differ
diff --git a/docs/ios/images/llvm-cov_show_file.png b/docs/ios/images/llvm-cov_show_file.png
deleted file mode 100644
index 45a18a3..0000000
--- a/docs/ios/images/llvm-cov_show_file.png
+++ /dev/null
Binary files differ
diff --git a/extensions/browser/device_local_account_util.cc b/extensions/browser/device_local_account_util.cc
index 4ecc3674..c4f3fe5b 100644
--- a/extensions/browser/device_local_account_util.cc
+++ b/extensions/browser/device_local_account_util.cc
@@ -25,6 +25,7 @@
     "pmnllmkmjilbojkpgplbdmckghmaocjh",  // Scan app by François Beaufort
     "haeblkpifdemlfnkogkipmghfcbonief",  // Charismathics Smart Card Middleware
     "mpnkhdpphjiihmlmkcamhpogecnnfffa",  // Service NSW Kiosk Utility
+    "npilppbicblkkgjfnbmibmhhgjhobpll",  // QwickACCESS
 
     // Libraries:
     "aclofikceldphonlfmghmimkodjdmhck",  // Ancoris login component
diff --git a/extensions/browser/extension_web_contents_observer.cc b/extensions/browser/extension_web_contents_observer.cc
index 794156e..52be0b4 100644
--- a/extensions/browser/extension_web_contents_observer.cc
+++ b/extensions/browser/extension_web_contents_observer.cc
@@ -4,6 +4,7 @@
 
 #include "extensions/browser/extension_web_contents_observer.h"
 
+#include "base/logging.h"
 #include "content/public/browser/child_process_security_policy.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/render_frame_host.h"
@@ -34,14 +35,31 @@
       web_contents);
 }
 
+void ExtensionWebContentsObserver::Initialize() {
+  if (initialized_)
+    return;
+
+  initialized_ = true;
+  for (content::RenderFrameHost* rfh : web_contents()->GetAllFrames()) {
+    // We only initialize the frame if the renderer counterpart is live;
+    // otherwise we wait for the RenderFrameCreated notification.
+    if (!rfh->IsRenderFrameLive())
+      continue;
+
+    // Initialize the FrameData for this frame here since we didn't receive the
+    // RenderFrameCreated notification for it.
+    ExtensionApiFrameIdMap::Get()->InitializeRenderFrameData(rfh);
+
+    InitializeRenderFrame(rfh);
+  }
+}
+
 ExtensionWebContentsObserver::ExtensionWebContentsObserver(
     content::WebContents* web_contents)
     : content::WebContentsObserver(web_contents),
       browser_context_(web_contents->GetBrowserContext()),
-      dispatcher_(browser_context_) {
-  web_contents->ForEachFrame(
-      base::BindRepeating(&ExtensionWebContentsObserver::InitializeFrameHelper,
-                          base::Unretained(this)));
+      dispatcher_(browser_context_),
+      initialized_(false) {
   dispatcher_.set_delegate(this);
 }
 
@@ -50,6 +68,7 @@
 
 void ExtensionWebContentsObserver::InitializeRenderFrame(
     content::RenderFrameHost* render_frame_host) {
+  DCHECK(initialized_);
   DCHECK(render_frame_host);
   DCHECK(render_frame_host->IsRenderFrameLive());
 
@@ -83,11 +102,13 @@
 
 content::WebContents* ExtensionWebContentsObserver::GetAssociatedWebContents()
     const {
+  DCHECK(initialized_);
   return web_contents();
 }
 
 void ExtensionWebContentsObserver::RenderFrameCreated(
     content::RenderFrameHost* render_frame_host) {
+  DCHECK(initialized_);
   // Optimization: Look up the extension API frame ID to force the mapping to be
   // cached. This minimizes the number of IO->UI->IO thread hops when the ID is
   // looked up again on the IO thread for the webRequest API.
@@ -131,6 +152,7 @@
 
 void ExtensionWebContentsObserver::RenderFrameDeleted(
     content::RenderFrameHost* render_frame_host) {
+  DCHECK(initialized_);
   ProcessManager::Get(browser_context_)
       ->UnregisterRenderFrameHost(render_frame_host);
   ExtensionApiFrameIdMap::Get()->OnRenderFrameDeleted(render_frame_host);
@@ -149,6 +171,7 @@
 
 void ExtensionWebContentsObserver::DidFinishNavigation(
     content::NavigationHandle* navigation_handle) {
+  DCHECK(initialized_);
   if (!navigation_handle->HasCommitted())
     return;
 
@@ -171,12 +194,14 @@
     content::RenderFrameHost* render_frame_host,
     const std::string& interface_name,
     mojo::ScopedMessagePipeHandle* interface_pipe) {
+  DCHECK(initialized_);
   registry_.TryBindInterface(interface_name, interface_pipe, render_frame_host);
 }
 
 bool ExtensionWebContentsObserver::OnMessageReceived(
     const IPC::Message& message,
     content::RenderFrameHost* render_frame_host) {
+  DCHECK(initialized_);
   bool handled = true;
   IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(
       ExtensionWebContentsObserver, message, render_frame_host)
@@ -187,6 +212,7 @@
 }
 
 void ExtensionWebContentsObserver::PepperInstanceCreated() {
+  DCHECK(initialized_);
   if (GetViewType(web_contents()) == VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) {
     ProcessManager* const process_manager =
         ProcessManager::Get(browser_context_);
@@ -198,6 +224,7 @@
 }
 
 void ExtensionWebContentsObserver::PepperInstanceDeleted() {
+  DCHECK(initialized_);
   if (GetViewType(web_contents()) == VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) {
     ProcessManager* const process_manager =
         ProcessManager::Get(browser_context_);
@@ -210,6 +237,7 @@
 
 std::string ExtensionWebContentsObserver::GetExtensionIdFromFrame(
     content::RenderFrameHost* render_frame_host) const {
+  DCHECK(initialized_);
   const GURL& site = render_frame_host->GetSiteInstance()->GetSiteURL();
   if (!site.SchemeIs(kExtensionScheme))
     return std::string();
@@ -220,6 +248,7 @@
 const Extension* ExtensionWebContentsObserver::GetExtensionFromFrame(
     content::RenderFrameHost* render_frame_host,
     bool verify_url) const {
+  DCHECK(initialized_);
   std::string extension_id = GetExtensionIdFromFrame(render_frame_host);
   if (extension_id.empty())
     return nullptr;
@@ -250,23 +279,9 @@
 void ExtensionWebContentsObserver::OnRequest(
     content::RenderFrameHost* render_frame_host,
     const ExtensionHostMsg_Request_Params& params) {
+  DCHECK(initialized_);
   dispatcher_.Dispatch(params, render_frame_host,
                        render_frame_host->GetProcess()->GetID());
 }
 
-void ExtensionWebContentsObserver::InitializeFrameHelper(
-    content::RenderFrameHost* render_frame_host) {
-  // Since this is called for all existing RenderFrameHosts during the
-  // ExtensionWebContentsObserver's creation, it's possible that not all hosts
-  // are ready.
-  // We only initialize the frame if the renderer counterpart is live; otherwise
-  // we wait for the RenderFrameCreated notification.
-  if (render_frame_host->IsRenderFrameLive()) {
-    // Initialize the FrameData for this frame here since we didn't receive the
-    // RenderFrameCreated notification for it.
-    ExtensionApiFrameIdMap::Get()->InitializeRenderFrameData(render_frame_host);
-    InitializeRenderFrame(render_frame_host);
-  }
-}
-
 }  // namespace extensions
diff --git a/extensions/browser/extension_web_contents_observer.h b/extensions/browser/extension_web_contents_observer.h
index 9b76d03..685e4154 100644
--- a/extensions/browser/extension_web_contents_observer.h
+++ b/extensions/browser/extension_web_contents_observer.h
@@ -55,6 +55,9 @@
   static ExtensionWebContentsObserver* GetForWebContents(
       content::WebContents* web_contents);
 
+  // This must be called by clients directly after the EWCO has been created.
+  void Initialize();
+
   ExtensionFunctionDispatcher* dispatcher() { return &dispatcher_; }
 
   // Returns the extension associated with the given |render_frame_host|, or
@@ -70,6 +73,8 @@
   explicit ExtensionWebContentsObserver(content::WebContents* web_contents);
   ~ExtensionWebContentsObserver() override;
 
+  bool initialized() const { return initialized_; }
+
   content::BrowserContext* browser_context() { return browser_context_; }
 
   // Initializes a new render frame. Subclasses should invoke this
@@ -111,15 +116,14 @@
   void OnRequest(content::RenderFrameHost* render_frame_host,
                  const ExtensionHostMsg_Request_Params& params);
 
-  // A helper function for initializing render frames at the creation of the
-  // observer.
-  void InitializeFrameHelper(content::RenderFrameHost* render_frame_host);
-
   // The BrowserContext associated with the WebContents being observed.
   content::BrowserContext* browser_context_;
 
   ExtensionFunctionDispatcher dispatcher_;
 
+  // Whether this object has been initialized.
+  bool initialized_;
+
   service_manager::BinderRegistryWithArgs<content::RenderFrameHost*> registry_;
 
   DISALLOW_COPY_AND_ASSIGN(ExtensionWebContentsObserver);
diff --git a/extensions/shell/browser/shell_extension_web_contents_observer.cc b/extensions/shell/browser/shell_extension_web_contents_observer.cc
index 9dc3691..842fc5d 100644
--- a/extensions/shell/browser/shell_extension_web_contents_observer.cc
+++ b/extensions/shell/browser/shell_extension_web_contents_observer.cc
@@ -17,4 +17,13 @@
 ShellExtensionWebContentsObserver::~ShellExtensionWebContentsObserver() {
 }
 
+void ShellExtensionWebContentsObserver::CreateForWebContents(
+    content::WebContents* web_contents) {
+  content::WebContentsUserData<
+      ShellExtensionWebContentsObserver>::CreateForWebContents(web_contents);
+
+  // Initialize this instance if necessary.
+  FromWebContents(web_contents)->Initialize();
+}
+
 }  // namespace extensions
diff --git a/extensions/shell/browser/shell_extension_web_contents_observer.h b/extensions/shell/browser/shell_extension_web_contents_observer.h
index dc458fd..44a27d1 100644
--- a/extensions/shell/browser/shell_extension_web_contents_observer.h
+++ b/extensions/shell/browser/shell_extension_web_contents_observer.h
@@ -18,6 +18,10 @@
  public:
   ~ShellExtensionWebContentsObserver() override;
 
+  // Creates and initializes an instance of this class for the given
+  // |web_contents|, if it doesn't already exist.
+  static void CreateForWebContents(content::WebContents* web_contents);
+
  private:
   friend class content::WebContentsUserData<ShellExtensionWebContentsObserver>;
 
diff --git a/extensions/test/data/api_test/audio/add_nodes/manifest.json b/extensions/test/data/api_test/audio/add_nodes/manifest.json
index 587b70a..65fba2f 100644
--- a/extensions/test/data/api_test/audio/add_nodes/manifest.json
+++ b/extensions/test/data/api_test/audio/add_nodes/manifest.json
@@ -1,5 +1,6 @@
 {
   "name": "chrome.audio.OnNodesChangedAddNodes",
+  "manifest_version": 2,
   "version": "1.0",
   "description": "browser test for chrome.audio.OnNodesChanged event",
   "app": {
diff --git a/extensions/test/data/api_test/audio/input_mute_change/manifest.json b/extensions/test/data/api_test/audio/input_mute_change/manifest.json
index 014be98..a2e7f360e 100644
--- a/extensions/test/data/api_test/audio/input_mute_change/manifest.json
+++ b/extensions/test/data/api_test/audio/input_mute_change/manifest.json
@@ -1,5 +1,6 @@
 {
   "name": "chrome.audio.OnInputMuteChanged",
+  "manifest_version": 2,
   "version": "1.0",
   "description": "browser test for chrome.audio.OnInputMuteChanged event",
   "app": {
diff --git a/extensions/test/data/api_test/audio/output_mute_change/manifest.json b/extensions/test/data/api_test/audio/output_mute_change/manifest.json
index d91d3dc8..7ff4896 100644
--- a/extensions/test/data/api_test/audio/output_mute_change/manifest.json
+++ b/extensions/test/data/api_test/audio/output_mute_change/manifest.json
@@ -1,5 +1,6 @@
 {
   "name": "chrome.audio.OnOutputMuteChanged",
+  "manifest_version": 2,
   "version": "1.0",
   "description": "browser test for chrome.audio.OnOutputMuteChanged event",
   "app": {
diff --git a/extensions/test/data/api_test/audio/remove_nodes/manifest.json b/extensions/test/data/api_test/audio/remove_nodes/manifest.json
index d55c69b..93104b1 100644
--- a/extensions/test/data/api_test/audio/remove_nodes/manifest.json
+++ b/extensions/test/data/api_test/audio/remove_nodes/manifest.json
@@ -1,5 +1,6 @@
 {
   "name": "chrome.audio.OnNodesChangedRemoveNodes",
+  "manifest_version": 2,
   "version": "1.0",
   "description": "browser test for chrome.audio.OnNodesChanged event",
   "app": {
diff --git a/extensions/test/data/api_test/audio/volume_change/manifest.json b/extensions/test/data/api_test/audio/volume_change/manifest.json
index a039b942..258bed8 100644
--- a/extensions/test/data/api_test/audio/volume_change/manifest.json
+++ b/extensions/test/data/api_test/audio/volume_change/manifest.json
@@ -1,5 +1,6 @@
 {
   "name": "chrome.audio.OnOutputNodeVolumeChanged",
+  "manifest_version": 2,
   "version": "1.0",
   "description": "browser test for chrome.audio.OnOutputNodeVolumeChanged event",
   "app": {
diff --git a/extensions/test/data/api_test/display_source/api/manifest.json b/extensions/test/data/api_test/display_source/api/manifest.json
index c390d3c..8345dfcd 100644
--- a/extensions/test/data/api_test/display_source/api/manifest.json
+++ b/extensions/test/data/api_test/display_source/api/manifest.json
@@ -1,5 +1,6 @@
 {
   "name": "chrome.displaySource",
+  "manifest_version": 2,
   "version": "0.1",
   "description": "end-to-end browser test for chrome.displaySource API",
   "app": {
diff --git a/extensions/test/data/api_test/dns/api/manifest.json b/extensions/test/data/api_test/dns/api/manifest.json
index ba0677d..36ba8407 100644
--- a/extensions/test/data/api_test/dns/api/manifest.json
+++ b/extensions/test/data/api_test/dns/api/manifest.json
@@ -1,5 +1,6 @@
 {
   "name": "chrome.experimental.dns",
+  "manifest_version": 2,
   "version": "0.1",
   "description": "end-to-end browser test for chrome.experimental.dns API",
   "app": {
diff --git a/extensions/test/data/api_test/hid/add_event/manifest.json b/extensions/test/data/api_test/hid/add_event/manifest.json
index 81ed784..d14fd9b 100644
--- a/extensions/test/data/api_test/hid/add_event/manifest.json
+++ b/extensions/test/data/api_test/hid/add_event/manifest.json
@@ -1,5 +1,6 @@
 {
   "name": "chrome.hid.onDeviceAdded",
+  "manifest_version": 2,
   "version": "0.1",
   "description": "browser test for chrome.hid.onDeviceAdded event",
   "app": {
diff --git a/extensions/test/data/api_test/hid/api/manifest.json b/extensions/test/data/api_test/hid/api/manifest.json
index e17391b5..ca5cbbf 100644
--- a/extensions/test/data/api_test/hid/api/manifest.json
+++ b/extensions/test/data/api_test/hid/api/manifest.json
@@ -1,5 +1,6 @@
 {
   "name": "chrome.hid",
+  "manifest_version": 2,
   "version": "0.1",
   "description": "end-to-end browser tests for chrome.hid API",
   "app": {
diff --git a/extensions/test/data/api_test/hid/get_user_selected_devices/manifest.json b/extensions/test/data/api_test/hid/get_user_selected_devices/manifest.json
index 6245f2d..29816df 100644
--- a/extensions/test/data/api_test/hid/get_user_selected_devices/manifest.json
+++ b/extensions/test/data/api_test/hid/get_user_selected_devices/manifest.json
@@ -1,5 +1,6 @@
 {
   "name": "chrome.hid.getUserSelectedDevices",
+  "manifest_version": 2,
   "version": "0.1",
   "description": "browser test for chrome.hid.getUserSelectedDevices",
   "app": {
diff --git a/extensions/test/data/api_test/hid/remove_event/manifest.json b/extensions/test/data/api_test/hid/remove_event/manifest.json
index 22da39f..f57d024b 100644
--- a/extensions/test/data/api_test/hid/remove_event/manifest.json
+++ b/extensions/test/data/api_test/hid/remove_event/manifest.json
@@ -1,5 +1,6 @@
 {
   "name": "chrome.hid.onDeviceRemoved",
+  "manifest_version": 2,
   "version": "0.1",
   "description": "browser test for chrome.hid.onDeviceRemoved event",
   "app": {
diff --git a/extensions/test/data/api_test/usb/add_event/manifest.json b/extensions/test/data/api_test/usb/add_event/manifest.json
index d5a7d6f0..f511215 100644
--- a/extensions/test/data/api_test/usb/add_event/manifest.json
+++ b/extensions/test/data/api_test/usb/add_event/manifest.json
@@ -1,5 +1,6 @@
 {
   "name": "chrome.usb.onDeviceAdded",
+  "manifest_version": 2,
   "version": "0.1",
   "description": "browser test for chrome.usb.onDeviceAdded event",
   "app": {
diff --git a/extensions/test/data/api_test/usb/device_handling/manifest.json b/extensions/test/data/api_test/usb/device_handling/manifest.json
index ebfaf62..d9a27c8 100644
--- a/extensions/test/data/api_test/usb/device_handling/manifest.json
+++ b/extensions/test/data/api_test/usb/device_handling/manifest.json
@@ -1,5 +1,6 @@
 {
   "name": "USB Device Handling",
+  "manifest_version": 2,
   "version": "0.1",
   "app": {
     "background": {
diff --git a/extensions/test/data/api_test/usb/get_user_selected_devices/manifest.json b/extensions/test/data/api_test/usb/get_user_selected_devices/manifest.json
index 11e58c938..bea3b273 100644
--- a/extensions/test/data/api_test/usb/get_user_selected_devices/manifest.json
+++ b/extensions/test/data/api_test/usb/get_user_selected_devices/manifest.json
@@ -1,5 +1,6 @@
 {
   "name": "chrome.usb.getUserSelectedDevices",
+  "manifest_version": 2,
   "version": "0.1",
   "description": "browser test for chrome.usb.getUserSelectedDevices",
   "app": {
diff --git a/extensions/test/data/api_test/usb/invalid_length_transfer/manifest.json b/extensions/test/data/api_test/usb/invalid_length_transfer/manifest.json
index 8f2a53f..a20e02b9 100644
--- a/extensions/test/data/api_test/usb/invalid_length_transfer/manifest.json
+++ b/extensions/test/data/api_test/usb/invalid_length_transfer/manifest.json
@@ -1,5 +1,6 @@
 {
   "name": "USB Invalid-Length Transfer",
+  "manifest_version": 2,
   "version": "0.1",
   "app": {
     "background": {
diff --git a/extensions/test/data/api_test/usb/invalid_timeout/manifest.json b/extensions/test/data/api_test/usb/invalid_timeout/manifest.json
index 7695a90..868ad4f 100644
--- a/extensions/test/data/api_test/usb/invalid_timeout/manifest.json
+++ b/extensions/test/data/api_test/usb/invalid_timeout/manifest.json
@@ -1,5 +1,6 @@
 {
   "name": "USB Invalid Transfer Timeout",
+  "manifest_version": 2,
   "version": "0.1",
   "app": {
     "background": {
diff --git a/extensions/test/data/api_test/usb/list_interfaces/manifest.json b/extensions/test/data/api_test/usb/list_interfaces/manifest.json
index f1e4722..6b05630c 100644
--- a/extensions/test/data/api_test/usb/list_interfaces/manifest.json
+++ b/extensions/test/data/api_test/usb/list_interfaces/manifest.json
@@ -1,5 +1,6 @@
 {
   "name": "USB List Interfaces",
+  "manifest_version": 2,
   "version": "0.1",
   "app": {
     "background": {
diff --git a/extensions/test/data/api_test/usb/remove_event/manifest.json b/extensions/test/data/api_test/usb/remove_event/manifest.json
index 2dce9e8a..6dff021c 100644
--- a/extensions/test/data/api_test/usb/remove_event/manifest.json
+++ b/extensions/test/data/api_test/usb/remove_event/manifest.json
@@ -1,5 +1,6 @@
 {
   "name": "chrome.usb.onDeviceRemoved",
+  "manifest_version": 2,
   "version": "0.1",
   "description": "browser test for chrome.usb.onDeviceRemoved event",
   "app": {
diff --git a/extensions/test/data/api_test/usb/reset_device/manifest.json b/extensions/test/data/api_test/usb/reset_device/manifest.json
index ebfaf62..d9a27c8 100644
--- a/extensions/test/data/api_test/usb/reset_device/manifest.json
+++ b/extensions/test/data/api_test/usb/reset_device/manifest.json
@@ -1,5 +1,6 @@
 {
   "name": "USB Device Handling",
+  "manifest_version": 2,
   "version": "0.1",
   "app": {
     "background": {
diff --git a/extensions/test/data/api_test/usb/set_configuration/manifest.json b/extensions/test/data/api_test/usb/set_configuration/manifest.json
index a496ee5..44e57cf 100644
--- a/extensions/test/data/api_test/usb/set_configuration/manifest.json
+++ b/extensions/test/data/api_test/usb/set_configuration/manifest.json
@@ -1,5 +1,6 @@
 {
   "name": "USB Set Configuration",
+  "manifest_version": 2,
   "version": "0.1",
   "app": {
     "background": {
diff --git a/extensions/test/data/api_test/usb/transfer_event/manifest.json b/extensions/test/data/api_test/usb/transfer_event/manifest.json
index 44c51151..d6ffa90 100644
--- a/extensions/test/data/api_test/usb/transfer_event/manifest.json
+++ b/extensions/test/data/api_test/usb/transfer_event/manifest.json
@@ -1,5 +1,6 @@
 {
   "name": "USB Transfer Events",
+  "manifest_version": 2,
   "version": "0.1",
   "app": {
     "background": {
diff --git a/extensions/test/data/api_test/usb/transfer_failure/manifest.json b/extensions/test/data/api_test/usb/transfer_failure/manifest.json
index fd9e0bf4..732a6cd1 100644
--- a/extensions/test/data/api_test/usb/transfer_failure/manifest.json
+++ b/extensions/test/data/api_test/usb/transfer_failure/manifest.json
@@ -1,5 +1,6 @@
 {
   "name": "USB Transfer Failure",
+  "manifest_version": 2,
   "version": "0.1",
   "app": {
     "background": {
diff --git a/extensions/test/data/api_test/usb/zero_length_transfer/manifest.json b/extensions/test/data/api_test/usb/zero_length_transfer/manifest.json
index 31fbb829..a611d31 100644
--- a/extensions/test/data/api_test/usb/zero_length_transfer/manifest.json
+++ b/extensions/test/data/api_test/usb/zero_length_transfer/manifest.json
@@ -1,5 +1,6 @@
 {
   "name": "USB Zero-Length Transfer",
+  "manifest_version": 2,
   "version": "0.1",
   "app": {
     "background": {
diff --git a/extensions/test/data/sockets_tcp/api/manifest.json b/extensions/test/data/sockets_tcp/api/manifest.json
index d780cf2..bf1fe89 100644
--- a/extensions/test/data/sockets_tcp/api/manifest.json
+++ b/extensions/test/data/sockets_tcp/api/manifest.json
@@ -1,5 +1,6 @@
 {
   "name": "chrome.sockets.tcp",
+  "manifest_version": 2,
   "version": "0.1",
   "description": "end-to-end browser test for chrome.sockets.tcp API",
   "app": {
diff --git a/extensions/test/data/sockets_tcp_server/api/manifest.json b/extensions/test/data/sockets_tcp_server/api/manifest.json
index 9e2923cf..3d5e3a9 100644
--- a/extensions/test/data/sockets_tcp_server/api/manifest.json
+++ b/extensions/test/data/sockets_tcp_server/api/manifest.json
@@ -1,5 +1,6 @@
 {
   "name": "chrome.sockets.tcpServer extension",
+  "manifest_version": 2,
   "version": "0.1",
   "description": "end-to-end browser test for chrome.sockets.tcpServer API",
   "app": {
diff --git a/extensions/test/data/sockets_tcp_server/unload/manifest.json b/extensions/test/data/sockets_tcp_server/unload/manifest.json
index 3e508ce..f91f64b6 100644
--- a/extensions/test/data/sockets_tcp_server/unload/manifest.json
+++ b/extensions/test/data/sockets_tcp_server/unload/manifest.json
@@ -1,5 +1,6 @@
 {
   "name": "chrome.sockets.tcpServer unload",
+  "manifest_version": 2,
   "version": "0.1",
   "description": "browser test for chrome.sockets.tcpServer API to make sure sockets are free'd when extension is reloaded",
   "app": {
diff --git a/extensions/test/data/system/cpu/manifest.json b/extensions/test/data/system/cpu/manifest.json
index 8ece45ee..f44cc11 100644
--- a/extensions/test/data/system/cpu/manifest.json
+++ b/extensions/test/data/system/cpu/manifest.json
@@ -1,5 +1,6 @@
 {
   "name": "system.cpu test",
+  "manifest_version": 2,
   "version": "1.0",
   "description": "Test system.cpu API",
   "permissions": ["system.cpu"],
diff --git a/extensions/test/data/system/display/info/manifest.json b/extensions/test/data/system/display/info/manifest.json
index 11792b6..0150ed3 100644
--- a/extensions/test/data/system/display/info/manifest.json
+++ b/extensions/test/data/system/display/info/manifest.json
@@ -1,5 +1,6 @@
 {
   "name": "displayinfo",
+  "manifest_version": 2,
   "version": "1.0",
   "description": "Test system.display API",
   "permissions": ["system.display"],
diff --git a/extensions/test/data/system/display/overscan/manifest.json b/extensions/test/data/system/display/overscan/manifest.json
index 2500bd4..9ea8310 100644
--- a/extensions/test/data/system/display/overscan/manifest.json
+++ b/extensions/test/data/system/display/overscan/manifest.json
@@ -1,5 +1,6 @@
 {
   "name": "overscan",
+  "manifest_version": 2,
   "version": "1.0",
   "description": "Test system.display.overscan* API",
   "permissions": ["system.display"],
diff --git a/extensions/test/data/system/display/overscan_no_complete/manifest.json b/extensions/test/data/system/display/overscan_no_complete/manifest.json
index 56f428d8..2c91787 100644
--- a/extensions/test/data/system/display/overscan_no_complete/manifest.json
+++ b/extensions/test/data/system/display/overscan_no_complete/manifest.json
@@ -1,5 +1,6 @@
 {
   "name": "overscan",
+  "manifest_version": 2,
   "version": "1.0",
   "description": "Test system.display.overscan* with no complete call",
   "permissions": ["system.display"],
diff --git a/extensions/test/data/system/memory/manifest.json b/extensions/test/data/system/memory/manifest.json
index 50936bd..08bcbc5 100644
--- a/extensions/test/data/system/memory/manifest.json
+++ b/extensions/test/data/system/memory/manifest.json
@@ -1,5 +1,6 @@
 {
   "name": "system.memory test",
+  "manifest_version": 2,
   "version": "1.0",
   "description": "Test system.memory API",
   "permissions": ["system.memory"],
diff --git a/extensions/test/data/system/network/manifest.json b/extensions/test/data/system/network/manifest.json
index 3ffb980..b9a42eb 100644
--- a/extensions/test/data/system/network/manifest.json
+++ b/extensions/test/data/system/network/manifest.json
@@ -1,5 +1,6 @@
 {
   "name": "chrome.system.network extension",
+  "manifest_version": 2,
   "version": "0.1",
   "description": "end-to-end browser test for chrome.system.network API",
   "app": {
diff --git a/extensions/test/data/unpacker/empty_default_locale/manifest.json b/extensions/test/data/unpacker/empty_default_locale/manifest.json
index 6f43cf249..bfeb7630 100644
--- a/extensions/test/data/unpacker/empty_default_locale/manifest.json
+++ b/extensions/test/data/unpacker/empty_default_locale/manifest.json
@@ -1,5 +1,6 @@
 {
   "description": "Default locale can't be empty",
+  "manifest_version": 2,
   "name": "empty_default_locale",
   "default_locale": "",
   "version": "1.0"
diff --git a/extensions/test/data/unpacker/good_l10n/manifest.json b/extensions/test/data/unpacker/good_l10n/manifest.json
index cf2e2a9..0893005 100644
--- a/extensions/test/data/unpacker/good_l10n/manifest.json
+++ b/extensions/test/data/unpacker/good_l10n/manifest.json
@@ -1,5 +1,6 @@
 {
   "description": "All is well",
+  "manifest_version": 2,
   "name": "good_l10n",
   "default_locale": "sr",
   "version": "1.0"
diff --git a/extensions/test/data/unpacker/has_default_missing_locales/manifest.json b/extensions/test/data/unpacker/has_default_missing_locales/manifest.json
index e572fc2f..1dbc1307 100644
--- a/extensions/test/data/unpacker/has_default_missing_locales/manifest.json
+++ b/extensions/test/data/unpacker/has_default_missing_locales/manifest.json
@@ -1,5 +1,6 @@
 {
   "description": "Cannot have default_locale but skip _locales",
+  "manifest_version": 2,
   "name": "has_default_missing_locales",
   "default_locale": "en_US",
   "version": "1.0"
diff --git a/extensions/test/data/unpacker/invalid_default_locale/manifest.json b/extensions/test/data/unpacker/invalid_default_locale/manifest.json
index ecf7d82..bef2d5c 100644
--- a/extensions/test/data/unpacker/invalid_default_locale/manifest.json
+++ b/extensions/test/data/unpacker/invalid_default_locale/manifest.json
@@ -1,5 +1,6 @@
 {
   "description": "Default locale has to be string and can't be empty",
+  "manifest_version": 2,
   "name": "invalid_default_locale",
   "default_locale": 5,
   "version": "1.0"
diff --git a/extensions/test/data/unpacker/invalid_messages_file/manifest.json b/extensions/test/data/unpacker/invalid_messages_file/manifest.json
index 7a4b9efb..7e946e60 100644
--- a/extensions/test/data/unpacker/invalid_messages_file/manifest.json
+++ b/extensions/test/data/unpacker/invalid_messages_file/manifest.json
@@ -1,5 +1,6 @@
 {
   "description": "Fail if messages.json is not valid (check JSON syntax only)",
+  "manifest_version": 2,
   "name": "invalid_messages_file",
   "default_locale": "en_US",
   "version": "1.0"
diff --git a/extensions/test/data/unpacker/missing_default_data/manifest.json b/extensions/test/data/unpacker/missing_default_data/manifest.json
index 03ecc4a..a4d2a22 100644
--- a/extensions/test/data/unpacker/missing_default_data/manifest.json
+++ b/extensions/test/data/unpacker/missing_default_data/manifest.json
@@ -1,5 +1,6 @@
 {
   "description": "Data for default_locale has to be present",
+  "manifest_version": 2,
   "name": "missing_default_data",
   "default_locale": "sr",
   "version": "1.0"
diff --git a/extensions/test/data/unpacker/missing_default_has_locales/manifest.json b/extensions/test/data/unpacker/missing_default_has_locales/manifest.json
index 13a5d4b2..c84616c 100644
--- a/extensions/test/data/unpacker/missing_default_has_locales/manifest.json
+++ b/extensions/test/data/unpacker/missing_default_has_locales/manifest.json
@@ -1,5 +1,6 @@
 {
   "description": "If _locales is present, default_locale has to be defined too.",
+  "manifest_version": 2,
   "name": "missing_default_has_locales",
   "version": "1.0"
 }
diff --git a/extensions/test/data/unpacker/missing_messages_file/manifest.json b/extensions/test/data/unpacker/missing_messages_file/manifest.json
index a3ccf4b..19994e0 100644
--- a/extensions/test/data/unpacker/missing_messages_file/manifest.json
+++ b/extensions/test/data/unpacker/missing_messages_file/manifest.json
@@ -1,5 +1,6 @@
 {
   "description": "Each locale has to have messages.json file",
+  "manifest_version": 2,
   "name": "missing_messages_file",
   "default_locale": "en_US",
   "version": "1.0"
diff --git a/extensions/test/data/unpacker/no_l10n/manifest.json b/extensions/test/data/unpacker/no_l10n/manifest.json
index 8ba809fa93..eec831f 100644
--- a/extensions/test/data/unpacker/no_l10n/manifest.json
+++ b/extensions/test/data/unpacker/no_l10n/manifest.json
@@ -1,5 +1,6 @@
 {
   "description": "This extension is not localized.",
+  "manifest_version": 2,
   "name": "no_l10n",
   "version": "1.0"
 }
diff --git a/extensions/test/data/unpacker/no_locale_data/manifest.json b/extensions/test/data/unpacker/no_locale_data/manifest.json
index c4d68b4..3c5e5d6 100644
--- a/extensions/test/data/unpacker/no_locale_data/manifest.json
+++ b/extensions/test/data/unpacker/no_locale_data/manifest.json
@@ -1,5 +1,6 @@
 {
   "description": "_locales can't be empty",
+  "manifest_version": 2,
   "name": "no_locale_data",
   "default_locale": "en_US",
   "version": "1.0"
diff --git a/extensions/test/data/web_view/accept_touch_events/manifest.json b/extensions/test/data/web_view/accept_touch_events/manifest.json
index 79c79df..457d5de 100644
--- a/extensions/test/data/web_view/accept_touch_events/manifest.json
+++ b/extensions/test/data/web_view/accept_touch_events/manifest.json
@@ -1,5 +1,6 @@
 {
   "name": "<webview> touch handler registration test.",
+  "manifest_version": 2,
   "version": "1",
   "permissions": [
     "webview"
diff --git a/extensions/test/data/web_view/close_on_loadcommit/manifest.json b/extensions/test/data/web_view/close_on_loadcommit/manifest.json
index 944fa0ee6..9441ab3 100644
--- a/extensions/test/data/web_view/close_on_loadcommit/manifest.json
+++ b/extensions/test/data/web_view/close_on_loadcommit/manifest.json
@@ -1,5 +1,6 @@
 {
   "name": "<webview> close on loadcommit",
+  "manifest_version": 2,
   "version": "1",
   "permissions": [
     "webview"
diff --git a/extensions/test/data/web_view/display_none_set_src/manifest.json b/extensions/test/data/web_view/display_none_set_src/manifest.json
index 1413e28b..9e0c096 100644
--- a/extensions/test/data/web_view/display_none_set_src/manifest.json
+++ b/extensions/test/data/web_view/display_none_set_src/manifest.json
@@ -1,5 +1,6 @@
 {
   "name": "<webview> check set src multiple times while display: none.",
+  "manifest_version": 2,
   "version": "1",
   "permissions": [
     "webview"
diff --git a/extensions/test/data/web_view/inside_iframe/manifest.json b/extensions/test/data/web_view/inside_iframe/manifest.json
index d76390bc..7067e2b 100644
--- a/extensions/test/data/web_view/inside_iframe/manifest.json
+++ b/extensions/test/data/web_view/inside_iframe/manifest.json
@@ -1,5 +1,6 @@
 {
   "name": "<webview> inside iframe.",
+  "manifest_version": 2,
   "version": "1",
   "permissions": [
     "webview"
diff --git a/extensions/test/data/web_view/media_access/check/manifest.json b/extensions/test/data/web_view/media_access/check/manifest.json
index d7488e98..092aa68 100644
--- a/extensions/test/data/web_view/media_access/check/manifest.json
+++ b/extensions/test/data/web_view/media_access/check/manifest.json
@@ -1,5 +1,6 @@
 {
   "name": "Platform App Test: <webview> media",
+  "manifest_version": 2,
   "description": "Loads a guest which requests media sources, this triggers checking existing permission",
   "version": "1",
   "permissions": [
diff --git a/extensions/test/data/web_view/media_access/deny/manifest.json b/extensions/test/data/web_view/media_access/deny/manifest.json
index ea2ad29..990ff99f 100644
--- a/extensions/test/data/web_view/media_access/deny/manifest.json
+++ b/extensions/test/data/web_view/media_access/deny/manifest.json
@@ -1,5 +1,6 @@
 {
   "name": "Platform App Test: <webview> media",
+  "manifest_version": 2,
   "description": "Loads a guest which requests media access permission",
   "version": "1",
   "permissions": [
diff --git a/extensions/test/data/web_view/visibility_changed/manifest.json b/extensions/test/data/web_view/visibility_changed/manifest.json
index 585c11e..c7b11719 100644
--- a/extensions/test/data/web_view/visibility_changed/manifest.json
+++ b/extensions/test/data/web_view/visibility_changed/manifest.json
@@ -1,5 +1,6 @@
 {
   "name": "<webview> visibility checking tests.",
+  "manifest_version": 2,
   "version": "1",
   "permissions": [
     "webview"
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 0275bf1..98cc319f 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -8950,8 +8950,12 @@
   // These formats have been selected because they are very common or are known
   // to be used by the WebGL backbuffer. If problems are observed with other
   // color formats they can be added here.
+  GLenum pixel_format = GL_RGBA;
+  GLenum pixel_type = GL_UNSIGNED_BYTE;
   switch (format) {
     case GL_RGB8:
+      pixel_format = GL_RGB;
+      break;
     case GL_RGBA8:
       break;
     default:
@@ -8980,7 +8984,8 @@
 
     // Texture only needs to be 1x1.
     api()->glBindTextureFn(GL_TEXTURE_2D, validation_texture);
-    api()->glTexStorage2DEXTFn(GL_TEXTURE_2D, 1, format, 1, 1);
+    api()->glTexImage2DFn(GL_TEXTURE_2D, 0, format, 1, 1, 0, pixel_format,
+                          pixel_type, NULL);
   } else {
     validation_texture = iter->second;
   }
diff --git a/ios/chrome/app/main_controller.mm b/ios/chrome/app/main_controller.mm
index bd41580..846d209f 100644
--- a/ios/chrome/app/main_controller.mm
+++ b/ios/chrome/app/main_controller.mm
@@ -2486,6 +2486,11 @@
         << " Main coordinator not created when tab switcher needed.";
     TabGridCoordinator* tabGridCoordinator =
         base::mac::ObjCCastStrict<TabGridCoordinator>(self.mainCoordinator);
+    // Call -restoreInternalState so that the grid shows the correct panel.
+    [tabGridCoordinator.tabSwitcher
+        restoreInternalStateWithMainTabModel:self.mainTabModel
+                                 otrTabModel:self.otrTabModel
+                              activeTabModel:self.currentTabModel];
     return tabGridCoordinator.tabSwitcher;
   } else {
     if (IsIPadIdiom()) {
diff --git a/ios/chrome/app/tests_fake_hook.mm b/ios/chrome/app/tests_fake_hook.mm
index da4a92e59..f0e7c98 100644
--- a/ios/chrome/app/tests_fake_hook.mm
+++ b/ios/chrome/app/tests_fake_hook.mm
@@ -31,6 +31,10 @@
 bool ForceUIRefreshPhase1() {
   return false;
 }
+// TODO(crbug.com/818560) : Remove this hook.
+bool ForceTabSwitcherTabGrid() {
+  return false;
+}
 void SetUpTestsIfPresent() {}
 void RunTestsIfPresent() {}
 
diff --git a/ios/chrome/app/tests_hook.h b/ios/chrome/app/tests_hook.h
index afd241f..49e875c 100644
--- a/ios/chrome/app/tests_hook.h
+++ b/ios/chrome/app/tests_hook.h
@@ -36,6 +36,11 @@
 // overriding the flag value.
 bool ForceUIRefreshPhase1();
 
+// TODO(crbug.com/818560): Removes this hook.
+// Returns true if the tab grid will be displayed as the tab switcher,
+// overriding the flag value.
+bool ForceTabSwitcherTabGrid();
+
 // Global integration tests setup.  This is not used by EarlGrey-based
 // integration tests.
 void SetUpTestsIfPresent();
diff --git a/ios/chrome/browser/browser_state/BUILD.gn b/ios/chrome/browser/browser_state/BUILD.gn
index 73fa0a2..0a714c9 100644
--- a/ios/chrome/browser/browser_state/BUILD.gn
+++ b/ios/chrome/browser/browser_state/BUILD.gn
@@ -81,6 +81,7 @@
     "//ios/chrome/browser/bookmarks",
     "//ios/chrome/browser/browser_state_metrics",
     "//ios/chrome/browser/browsing_data",
+    "//ios/chrome/browser/consent_auditor",
     "//ios/chrome/browser/content_settings",
     "//ios/chrome/browser/desktop_promotion",
     "//ios/chrome/browser/dom_distiller",
diff --git a/ios/chrome/browser/browser_state/browser_state_keyed_service_factories.mm b/ios/chrome/browser/browser_state/browser_state_keyed_service_factories.mm
index 62631bf..d185b84 100644
--- a/ios/chrome/browser/browser_state/browser_state_keyed_service_factories.mm
+++ b/ios/chrome/browser/browser_state/browser_state_keyed_service_factories.mm
@@ -12,6 +12,7 @@
 #include "ios/chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "ios/chrome/browser/bookmarks/startup_task_runner_service_factory.h"
 #include "ios/chrome/browser/browsing_data/browsing_data_remover_factory.h"
+#include "ios/chrome/browser/consent_auditor/consent_auditor_factory.h"
 #include "ios/chrome/browser/content_settings/cookie_settings_factory.h"
 #include "ios/chrome/browser/desktop_promotion/desktop_promotion_sync_service_factory.h"
 #include "ios/chrome/browser/dom_distiller/dom_distiller_service_factory.h"
@@ -103,6 +104,7 @@
   BrowserListFactory::GetInstance();
   BrowserListSessionServiceFactory::GetInstance();
   BrowsingDataRemoverFactory::GetInstance();
+  ConsentAuditorFactory::GetInstance();
   DesktopPromotionSyncServiceFactory::GetInstance();
   feature_engagement::TrackerFactory::GetInstance();
   IOSChromeGCMProfileServiceFactory::GetInstance();
diff --git a/ios/chrome/browser/browser_state/chrome_browser_state_manager_impl.cc b/ios/chrome/browser/browser_state/chrome_browser_state_manager_impl.cc
index cf20f4d..007fc3a 100644
--- a/ios/chrome/browser/browser_state/chrome_browser_state_manager_impl.cc
+++ b/ios/chrome/browser/browser_state/chrome_browser_state_manager_impl.cc
@@ -40,6 +40,7 @@
 #include "ios/chrome/browser/signin/gaia_cookie_manager_service_factory.h"
 #include "ios/chrome/browser/signin/signin_manager_factory.h"
 #include "ios/chrome/browser/sync/ios_chrome_profile_sync_service_factory.h"
+#include "ios/chrome/browser/sync/ios_user_event_service_factory.h"
 
 namespace {
 
@@ -223,6 +224,10 @@
       ->SetupInvalidationsOnProfileLoad(invalidation_service);
   ios::AccountReconcilorFactory::GetForBrowserState(browser_state);
   DesktopPromotionSyncServiceFactory::GetForBrowserState(browser_state);
+  // TODO(crbug.com/709094), TODO(crbug.com/761485): Remove this following line
+  // when UserEventService will be initialized synchronously. Until then, the
+  // service has to be created as early as possible.
+  IOSUserEventServiceFactory::GetForBrowserState(browser_state);
 }
 
 void ChromeBrowserStateManagerImpl::AddBrowserStateToCache(
diff --git a/ios/chrome/browser/consent_auditor/BUILD.gn b/ios/chrome/browser/consent_auditor/BUILD.gn
new file mode 100644
index 0000000..6a1e61d
--- /dev/null
+++ b/ios/chrome/browser/consent_auditor/BUILD.gn
@@ -0,0 +1,22 @@
+# 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.
+
+source_set("consent_auditor") {
+  configs += [ "//build/config/compiler:enable_arc" ]
+  sources = [
+    "consent_auditor_factory.cc",
+    "consent_auditor_factory.h",
+  ]
+  deps = [
+    "//base",
+    "//components/consent_auditor",
+    "//components/keyed_service/ios",
+    "//components/pref_registry",
+    "//components/version_info",
+    "//ios/chrome/browser",
+    "//ios/chrome/browser/browser_state",
+    "//ios/chrome/browser/sync",
+    "//ios/web/public",
+  ]
+}
diff --git a/ios/chrome/browser/consent_auditor/DEPS b/ios/chrome/browser/consent_auditor/DEPS
new file mode 100644
index 0000000..f79e7c6
--- /dev/null
+++ b/ios/chrome/browser/consent_auditor/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+components/consent_auditor",
+]
diff --git a/ios/chrome/browser/consent_auditor/OWNERS b/ios/chrome/browser/consent_auditor/OWNERS
new file mode 100644
index 0000000..ed987e2
--- /dev/null
+++ b/ios/chrome/browser/consent_auditor/OWNERS
@@ -0,0 +1,5 @@
+jlebel@chromium.org
+msarda@chromium.org
+msramek@google.com
+
+# COMPONENT: Privacy
diff --git a/ios/chrome/browser/consent_auditor/consent_auditor_factory.cc b/ios/chrome/browser/consent_auditor/consent_auditor_factory.cc
new file mode 100644
index 0000000..5c85778
--- /dev/null
+++ b/ios/chrome/browser/consent_auditor/consent_auditor_factory.cc
@@ -0,0 +1,68 @@
+// 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 "ios/chrome/browser/consent_auditor/consent_auditor_factory.h"
+
+#include "base/memory/ptr_util.h"
+#include "base/memory/singleton.h"
+#include "components/consent_auditor/consent_auditor.h"
+#include "components/keyed_service/ios/browser_state_dependency_manager.h"
+#include "components/pref_registry/pref_registry_syncable.h"
+#include "components/version_info/version_info.h"
+#include "ios/chrome/browser/application_context.h"
+#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
+#include "ios/chrome/browser/sync/ios_user_event_service_factory.h"
+#include "ios/web/public/browser_state.h"
+
+// static
+consent_auditor::ConsentAuditor* ConsentAuditorFactory::GetForBrowserState(
+    ios::ChromeBrowserState* browser_state) {
+  return static_cast<consent_auditor::ConsentAuditor*>(
+      GetInstance()->GetServiceForBrowserState(browser_state, true));
+}
+
+// static
+consent_auditor::ConsentAuditor*
+ConsentAuditorFactory::GetForBrowserStateIfExists(
+    ios::ChromeBrowserState* browser_state) {
+  return static_cast<consent_auditor::ConsentAuditor*>(
+      GetInstance()->GetServiceForBrowserState(browser_state, false));
+}
+
+// static
+ConsentAuditorFactory* ConsentAuditorFactory::GetInstance() {
+  return base::Singleton<ConsentAuditorFactory>::get();
+}
+
+ConsentAuditorFactory::ConsentAuditorFactory()
+    : BrowserStateKeyedServiceFactory(
+          "ConsentAuditor",
+          BrowserStateDependencyManager::GetInstance()) {
+  DependsOn(IOSUserEventServiceFactory::GetInstance());
+}
+
+ConsentAuditorFactory::~ConsentAuditorFactory() {}
+
+std::unique_ptr<KeyedService> ConsentAuditorFactory::BuildServiceInstanceFor(
+    web::BrowserState* browser_state) const {
+  ios::ChromeBrowserState* ios_browser_state =
+      ios::ChromeBrowserState::FromBrowserState(browser_state);
+  syncer::UserEventService* const user_event_service =
+      IOSUserEventServiceFactory::GetForBrowserState(ios_browser_state);
+  return std::make_unique<consent_auditor::ConsentAuditor>(
+      ios_browser_state->GetPrefs(), user_event_service,
+      // The browser version and locale do not change runtime, so we can pass
+      // them directly.
+      version_info::GetVersionNumber(),
+      GetApplicationContext()->GetApplicationLocale());
+}
+
+bool ConsentAuditorFactory::ServiceIsNULLWhileTesting() const {
+  return true;
+}
+
+void ConsentAuditorFactory::RegisterBrowserStatePrefs(
+    user_prefs::PrefRegistrySyncable* registry) {
+  consent_auditor::ConsentAuditor::RegisterProfilePrefs(registry);
+}
diff --git a/ios/chrome/browser/consent_auditor/consent_auditor_factory.h b/ios/chrome/browser/consent_auditor/consent_auditor_factory.h
new file mode 100644
index 0000000..df19cf1
--- /dev/null
+++ b/ios/chrome/browser/consent_auditor/consent_auditor_factory.h
@@ -0,0 +1,45 @@
+// 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 IOS_CHROME_BROWSER_CONSENT_AUDITOR_CONSENT_AUDITOR_FACTORY_H_
+#define IOS_CHROME_BROWSER_CONSENT_AUDITOR_CONSENT_AUDITOR_FACTORY_H_
+
+#include "base/memory/singleton.h"
+#include "components/keyed_service/ios/browser_state_keyed_service_factory.h"
+
+namespace consent_auditor {
+class ConsentAuditor;
+}  // namespace consent_auditor
+
+namespace ios {
+class ChromeBrowserState;
+}  // namespace ios
+
+// Singleton that owns all ConsentAuditors and associates them with
+// ios::ChromeBrowserState.
+class ConsentAuditorFactory : public BrowserStateKeyedServiceFactory {
+ public:
+  static consent_auditor::ConsentAuditor* GetForBrowserState(
+      ios::ChromeBrowserState* browser_state);
+  static consent_auditor::ConsentAuditor* GetForBrowserStateIfExists(
+      ios::ChromeBrowserState* browser_state);
+  static ConsentAuditorFactory* GetInstance();
+
+ private:
+  friend struct base::DefaultSingletonTraits<ConsentAuditorFactory>;
+
+  ConsentAuditorFactory();
+  ~ConsentAuditorFactory() override;
+
+  // BrowserStateKeyedServiceFactory implementation.
+  std::unique_ptr<KeyedService> BuildServiceInstanceFor(
+      web::BrowserState* context) const override;
+  bool ServiceIsNULLWhileTesting() const override;
+  void RegisterBrowserStatePrefs(
+      user_prefs::PrefRegistrySyncable* registry) override;
+
+  DISALLOW_COPY_AND_ASSIGN(ConsentAuditorFactory);
+};
+
+#endif  // IOS_CHROME_BROWSER_CONSENT_AUDITOR_CONSENT_AUDITOR_FACTORY_H_
diff --git a/ios/chrome/browser/prefs/BUILD.gn b/ios/chrome/browser/prefs/BUILD.gn
index 5688c72d..9ad04fe2 100644
--- a/ios/chrome/browser/prefs/BUILD.gn
+++ b/ios/chrome/browser/prefs/BUILD.gn
@@ -60,6 +60,7 @@
     "//components/web_resource",
     "//ios/chrome/browser",
     "//ios/chrome/browser/browser_state",
+    "//ios/chrome/browser/consent_auditor",
     "//ios/chrome/browser/desktop_promotion",
     "//ios/chrome/browser/first_run",
     "//ios/chrome/browser/geolocation",
diff --git a/ios/chrome/browser/sync/ios_chrome_sync_client.mm b/ios/chrome/browser/sync/ios_chrome_sync_client.mm
index d0d6528d..7ecdcde 100644
--- a/ios/chrome/browser/sync/ios_chrome_sync_client.mm
+++ b/ios/chrome/browser/sync/ios_chrome_sync_client.mm
@@ -11,7 +11,6 @@
 #include "base/logging.h"
 #include "base/macros.h"
 #include "components/autofill/core/browser/webdata/autocomplete_sync_bridge.h"
-#include "components/autofill/core/browser/webdata/autocomplete_syncable_service.h"
 #include "components/autofill/core/browser/webdata/autofill_profile_syncable_service.h"
 #include "components/autofill/core/browser/webdata/autofill_wallet_metadata_syncable_service.h"
 #include "components/autofill/core/browser/webdata/autofill_wallet_syncable_service.h"
@@ -271,17 +270,12 @@
       return browser_state_->GetSyncablePrefs()
           ->GetSyncableService(syncer::PRIORITY_PREFERENCES)
           ->AsWeakPtr();
-    case syncer::AUTOFILL:
     case syncer::AUTOFILL_PROFILE:
     case syncer::AUTOFILL_WALLET_DATA:
     case syncer::AUTOFILL_WALLET_METADATA: {
       if (!web_data_service_)
         return base::WeakPtr<syncer::SyncableService>();
-      if (type == syncer::AUTOFILL) {
-        return autofill::AutocompleteSyncableService::FromWebDataService(
-                   web_data_service_.get())
-            ->AsWeakPtr();
-      } else if (type == syncer::AUTOFILL_PROFILE) {
+      if (type == syncer::AUTOFILL_PROFILE) {
         return autofill::AutofillProfileSyncableService::FromWebDataService(
                    web_data_service_.get())
             ->AsWeakPtr();
diff --git a/ios/chrome/browser/ui/authentication/BUILD.gn b/ios/chrome/browser/ui/authentication/BUILD.gn
index e79bde3..b04e255f 100644
--- a/ios/chrome/browser/ui/authentication/BUILD.gn
+++ b/ios/chrome/browser/ui/authentication/BUILD.gn
@@ -34,6 +34,7 @@
     "resources:signin_confirmation_more",
     "resources:signin_promo_close_gray",
     "//base",
+    "//components/consent_auditor",
     "//components/google/core/browser",
     "//components/infobars/core",
     "//components/prefs",
@@ -46,6 +47,7 @@
     "//ios/chrome/browser",
     "//ios/chrome/browser/browser_state",
     "//ios/chrome/browser/browsing_data",
+    "//ios/chrome/browser/consent_auditor",
     "//ios/chrome/browser/infobars",
     "//ios/chrome/browser/signin",
     "//ios/chrome/browser/sync",
diff --git a/ios/chrome/browser/ui/authentication/DEPS b/ios/chrome/browser/ui/authentication/DEPS
new file mode 100644
index 0000000..f79e7c6
--- /dev/null
+++ b/ios/chrome/browser/ui/authentication/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+components/consent_auditor",
+]
diff --git a/ios/chrome/browser/ui/authentication/chrome_signin_view_controller.mm b/ios/chrome/browser/ui/authentication/chrome_signin_view_controller.mm
index b6afaab..ad75236 100644
--- a/ios/chrome/browser/ui/authentication/chrome_signin_view_controller.mm
+++ b/ios/chrome/browser/ui/authentication/chrome_signin_view_controller.mm
@@ -18,10 +18,12 @@
 #import "base/strings/sys_string_conversions.h"
 #include "base/timer/elapsed_timer.h"
 #include "base/timer/timer.h"
+#include "components/consent_auditor/consent_auditor.h"
 #include "components/signin/core/browser/signin_metrics.h"
 #include "components/strings/grit/components_strings.h"
 #import "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/chrome_url_constants.h"
+#include "ios/chrome/browser/consent_auditor/consent_auditor_factory.h"
 #import "ios/chrome/browser/signin/authentication_service.h"
 #import "ios/chrome/browser/signin/authentication_service_factory.h"
 #import "ios/chrome/browser/signin/chrome_identity_service_observer_bridge.h"
@@ -229,6 +231,15 @@
 
 - (void)acceptSignInAndShowAccountsSettings:(BOOL)showAccountsSettings {
   signin_metrics::LogSigninAccessPointCompleted(_accessPoint, _promoAction);
+  DCHECK(_confirmationVC);
+  const std::vector<int>& consent_text_ids = _confirmationVC.consentStringIds;
+  int consent_confirmation_id = showAccountsSettings
+                                    ? _confirmationVC.openSettingsStringId
+                                    : [self acceptSigninButtonStringId];
+  ConsentAuditorFactory::GetForBrowserState(_browserState)
+      ->RecordGaiaConsent(consent_auditor::Feature::CHROME_SYNC,
+                          consent_text_ids, consent_confirmation_id,
+                          consent_auditor::ConsentStatus::GIVEN);
   _didAcceptSignIn = YES;
   if (!_didFinishSignIn) {
     _didFinishSignIn = YES;
@@ -285,9 +296,12 @@
   return l10n_util::GetNSString(IDS_IOS_ACCOUNT_CONSISTENCY_SETUP_TITLE);
 }
 
+- (int)acceptSigninButtonStringId {
+  return IDS_IOS_ACCOUNT_CONSISTENCY_CONFIRMATION_OK_BUTTON;
+}
+
 - (NSString*)acceptSigninButtonTitle {
-  return l10n_util::GetNSString(
-      IDS_IOS_ACCOUNT_CONSISTENCY_CONFIRMATION_OK_BUTTON);
+  return l10n_util::GetNSString([self acceptSigninButtonStringId]);
 }
 
 - (NSString*)skipSigninButtonTitle {
diff --git a/ios/chrome/browser/ui/authentication/signin_confirmation_view_controller.h b/ios/chrome/browser/ui/authentication/signin_confirmation_view_controller.h
index 2cdf2c2..51766eb 100644
--- a/ios/chrome/browser/ui/authentication/signin_confirmation_view_controller.h
+++ b/ios/chrome/browser/ui/authentication/signin_confirmation_view_controller.h
@@ -7,6 +7,8 @@
 
 #import <UIKit/UIKit.h>
 
+#include <vector>
+
 #import "ios/chrome/browser/ui/collection_view/collection_view_controller.h"
 
 extern NSString* const kSigninConfirmationCollectionViewId;
@@ -30,6 +32,12 @@
 // Controller of the sign-in confirmation collection view.
 @interface SigninConfirmationViewController : CollectionViewController
 
+@property(nonatomic, weak) id<SigninConfirmationViewControllerDelegate>
+    delegate;
+
+// String id for text to open the settings.
+@property(nonatomic, readonly) int openSettingsStringId;
+
 - (instancetype)initWithIdentity:(ChromeIdentity*)identity
     NS_DESIGNATED_INITIALIZER;
 
@@ -40,8 +48,9 @@
 // Scrolls the confirmation view to the bottom of its content.
 - (void)scrollToBottom;
 
-@property(nonatomic, weak) id<SigninConfirmationViewControllerDelegate>
-    delegate;
+// List of string ids used for the user consent. The string ids order matches
+// the way they appear on the screen.
+- (const std::vector<int>&)consentStringIds;
 
 @end
 
diff --git a/ios/chrome/browser/ui/authentication/signin_confirmation_view_controller.mm b/ios/chrome/browser/ui/authentication/signin_confirmation_view_controller.mm
index 1c512b5..d1a5dce 100644
--- a/ios/chrome/browser/ui/authentication/signin_confirmation_view_controller.mm
+++ b/ios/chrome/browser/ui/authentication/signin_confirmation_view_controller.mm
@@ -87,6 +87,9 @@
   UIImageView* _imageView;
   UILabel* _titleLabel;
   UILabel* _emailLabel;
+  // List of string ids used for the user consent. The string ids order matches
+  // the way they appear on the screen.
+  std::vector<int> _consentStringIds;
 }
 @end
 
@@ -113,6 +116,14 @@
   [self.collectionView setContentOffset:bottomOffset animated:YES];
 }
 
+- (const std::vector<int>&)consentStringIds {
+  return _consentStringIds;
+}
+
+- (int)openSettingsStringId {
+  return IDS_IOS_ACCOUNT_CONSISTENCY_CONFIRMATION_OPEN_SETTINGS;
+}
+
 #pragma mark - UIViewController
 
 - (void)viewDidLoad {
@@ -253,10 +264,11 @@
 - (CollectionViewItem*)syncItem {
   AccountControlItem* item =
       [[AccountControlItem alloc] initWithType:ItemTypeSync];
-  item.text = l10n_util::GetNSString(
-      IDS_IOS_ACCOUNT_CONSISTENCY_CONFIRMATION_SYNC_TITLE);
-  item.detailText = l10n_util::GetNSString(
-      IDS_IOS_ACCOUNT_CONSISTENCY_CONFIRMATION_SYNC_DESCRIPTION);
+  item.text = [self localizedConsentStringWithId:
+                        IDS_IOS_ACCOUNT_CONSISTENCY_CONFIRMATION_SYNC_TITLE];
+  item.detailText =
+      [self localizedConsentStringWithId:
+                IDS_IOS_ACCOUNT_CONSISTENCY_CONFIRMATION_SYNC_DESCRIPTION];
   item.image = ios::GetChromeBrowserProvider()
                    ->GetBrandedImageProvider()
                    ->GetSigninConfirmationSyncSettingsImage();
@@ -266,10 +278,12 @@
 - (CollectionViewItem*)googleServicesItem {
   AccountControlItem* item =
       [[AccountControlItem alloc] initWithType:ItemTypeGoogleServices];
-  item.text = l10n_util::GetNSString(
-      IDS_IOS_ACCOUNT_CONSISTENCY_CONFIRMATION_SERVICES_TITLE);
-  item.detailText = l10n_util::GetNSString(
-      IDS_IOS_ACCOUNT_CONSISTENCY_CONFIRMATION_SERVICES_DESCRIPTION);
+  item.text =
+      [self localizedConsentStringWithId:
+                IDS_IOS_ACCOUNT_CONSISTENCY_CONFIRMATION_SERVICES_TITLE];
+  item.detailText =
+      [self localizedConsentStringWithId:
+                IDS_IOS_ACCOUNT_CONSISTENCY_CONFIRMATION_SERVICES_DESCRIPTION];
   item.image = ios::GetChromeBrowserProvider()
                    ->GetBrandedImageProvider()
                    ->GetSigninConfirmationPersonalizeServicesImage();
@@ -279,8 +293,7 @@
 - (CollectionViewItem*)openSettingsItem {
   CollectionViewFooterItem* item =
       [[CollectionViewFooterItem alloc] initWithType:ItemTypeFooter];
-  item.text = l10n_util::GetNSString(
-      IDS_IOS_ACCOUNT_CONSISTENCY_CONFIRMATION_OPEN_SETTINGS);
+  item.text = [self localizedConsentStringWithId:self.openSettingsStringId];
   item.linkURL = google_util::AppendGoogleLocaleParam(
       GURL("internal://settings-sync"),
       GetApplicationContext()->GetApplicationLocale());
@@ -304,6 +317,13 @@
   return NO;
 }
 
+// Adds the string id to the list of string for the user consent, and returns
+// the NSString related to the string id.
+- (NSString*)localizedConsentStringWithId:(int)stringId {
+  _consentStringIds.push_back(stringId);
+  return l10n_util::GetNSString(stringId);
+}
+
 #pragma mark - ChromeIdentityServiceObserver
 
 - (void)profileUpdate:(ChromeIdentity*)identity {
diff --git a/ios/chrome/browser/ui/content_suggestions/BUILD.gn b/ios/chrome/browser/ui/content_suggestions/BUILD.gn
index 2085060..fe1f7d8 100644
--- a/ios/chrome/browser/ui/content_suggestions/BUILD.gn
+++ b/ios/chrome/browser/ui/content_suggestions/BUILD.gn
@@ -115,6 +115,7 @@
     ":content_suggestions_ui_util",
     "resources:content_suggestions_no_image",
     "resources:content_suggestions_offline",
+    "resources:ntp_search_icon",
     "//base",
     "//components/strings",
     "//ios/chrome/browser/ui",
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_action_cell.mm b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_action_cell.mm
index cfdc42f..437e146e 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_action_cell.mm
+++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_action_cell.mm
@@ -41,8 +41,9 @@
   self = [super initWithFrame:frame];
   if (self) {
     _titleLabel = [[UILabel alloc] init];
-    _titleLabel.textColor = [UIColor colorWithWhite:kLabelTextColor alpha:1.0];
-    _titleLabel.font = [MDCTypography captionFont];
+    _titleLabel.textColor = [UIColor colorWithWhite:0 alpha:kTitleAlpha];
+    _titleLabel.font =
+        [UIFont preferredFontForTextStyle:UIFontTextStyleCaption1];
     _titleLabel.textAlignment = NSTextAlignmentCenter;
     _titleLabel.preferredMaxLayoutWidth = [[self class] defaultSize].width;
     _titleLabel.numberOfLines = kLabelNumLines;
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_cell.mm b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_cell.mm
index a157c43..9293b38b 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_cell.mm
+++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_cell.mm
@@ -31,14 +31,26 @@
   self = [super initWithFrame:frame];
   if (self) {
     _titleLabel = [[UILabel alloc] init];
-    _titleLabel.textColor = [UIColor colorWithWhite:kLabelTextColor alpha:1.0];
-    _titleLabel.font = [MDCTypography captionFont];
+    if (IsUIRefreshPhase1Enabled()) {
+      _titleLabel.textColor = [UIColor colorWithWhite:0 alpha:kTitleAlpha];
+      _titleLabel.font =
+          [UIFont preferredFontForTextStyle:UIFontTextStyleCaption1];
+    } else {
+      _titleLabel.textColor =
+          [UIColor colorWithWhite:kLabelTextColor alpha:1.0];
+      _titleLabel.font = [MDCTypography captionFont];
+    }
     _titleLabel.textAlignment = NSTextAlignmentCenter;
     _titleLabel.preferredMaxLayoutWidth = [[self class] defaultSize].width;
     _titleLabel.numberOfLines = kLabelNumLines;
 
     _faviconView = [[FaviconViewNew alloc] init];
-    _faviconView.font = [MDCTypography headlineFont];
+    if (IsUIRefreshPhase1Enabled()) {
+      _faviconView.font =
+          [UIFont preferredFontForTextStyle:UIFontTextStyleTitle2];
+    } else {
+      _faviconView.font = [MDCTypography headlineFont];
+    }
 
     _titleLabel.translatesAutoresizingMaskIntoConstraints = NO;
     _faviconView.translatesAutoresizingMaskIntoConstraints = NO;
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_constants.h b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_constants.h
index 30c6651..947ff84 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_constants.h
+++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_constants.h
@@ -22,4 +22,7 @@
 // Size of a Most Visited cell.
 extern const CGSize kCellSize;
 
+// The alpha value for text.
+extern const CGFloat kTitleAlpha;
+
 #endif  // IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_CELLS_CONTENT_SUGGESTIONS_MOST_VISITED_CONSTANTS_H_
diff --git a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_constants.mm b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_constants.mm
index 844593cb..8d30ced 100644
--- a/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_constants.mm
+++ b/ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_constants.mm
@@ -13,3 +13,4 @@
 const NSInteger kLabelNumLines = 2;
 const CGFloat kSpaceIconTitle = 10;
 const CGSize kCellSize = {73, 100};
+const CGFloat kTitleAlpha = 0.41;
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils.h b/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils.h
index 7c619504..1763468 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils.h
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils.h
@@ -11,6 +11,8 @@
 
 extern const CGFloat kSearchFieldHeight;
 
+extern const int kSearchFieldBackgroundColor;
+
 // Returns the maximum number of tiles fitting in |availableWidth|, limited to
 // 4.
 NSUInteger numberOfTilesForWidth(CGFloat availableWidth);
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils.mm
index aad5e08..f75ba76 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils.mm
@@ -11,6 +11,7 @@
 #import "ios/chrome/browser/ui/location_bar/location_bar_constants.h"
 #import "ios/chrome/browser/ui/ntp/new_tab_page_header_constants.h"
 #include "ios/chrome/browser/ui/ui_util.h"
+#import "ios/chrome/browser/ui/uikit_ui_util.h"
 #include "ios/chrome/grit/ios_strings.h"
 #import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -20,28 +21,53 @@
 #endif
 
 namespace {
+
+// Spacing between tiles.
 const CGFloat kSpacingIPhone = 16;
 const CGFloat kSpacingIPad = 24;
 
-const CGFloat kMinSearchFieldWidth = 50;
+// Width of search field.
+const CGFloat kSearchFieldLarge = 432;
+const CGFloat kSearchFieldSmall = 343;
+const CGFloat kSearchFieldMinMargin = 8;
+const CGFloat kMinSearchFieldWidthLegacy = 50;
 
+// Veritcla margin of search hint text.
 const CGFloat kSearchHintMargin = 3;
+
 // Offset to align the hint of the fake omnibox with the one in the toolbar.
 const CGFloat kSearchHintVerticalOffset = 0.5;
-
+// Maximum margin for the search field.
 const CGFloat kMaxSearchFieldFrameMargin = 200;
-const CGFloat kDoodleTopMarginIPad = 82;
-const CGFloat kSearchFieldTopMarginIPhone = 32;
-const CGFloat kSearchFieldTopMarginIPad = 82;
+
+// Top margin for the doodle.
+const CGFloat kDoodleTopMarginRegularXRegular = 162;
+const CGFloat kDoodleTopMarginOther = 48;
+const CGFloat kDoodleTopMarginIPadLegacy = 82;
+
+// Top margin for the search field
+const CGFloat kSearchFieldTopMargin = 32;
+const CGFloat kSearchFieldTopMarginIPhoneLegacy = 32;
+const CGFloat kSearchFieldTopMarginIPadLegacy = 82;
+
+// Bottom margin for the search field.
 const CGFloat kNTPSearchFieldBottomPadding = 16;
 
+// Alpha for search hint text.
+const CGFloat kHintAlpha = 0.3;
+
 const CGFloat kTopSpacingMaterial = 24;
 
 const CGFloat kVoiceSearchButtonWidth = 48;
 
-const CGFloat kGoogleSearchDoodleHeight = 120;
+// Height for the doodle frame.
+const CGFloat kGoogleSearchDoodleHeightRegularXRegular = 85;
+const CGFloat kGoogleSearchDoodleHeightOther = 68;
+const CGFloat kGoogleSearchDoodleHeightLegacy = 120;
+
 // Height for the doodle frame when Google is not the default search engine.
 const CGFloat kNonGoogleSearchDoodleHeight = 60;
+
 // Height for the header view on tablet when Google is not the default search
 // engine.
 const CGFloat kNonGoogleSearchHeaderHeightIPad = 10;
@@ -57,6 +83,7 @@
 namespace content_suggestions {
 
 const CGFloat kSearchFieldHeight = 50;
+const int kSearchFieldBackgroundColor = 0xF1F3F4;
 
 const NSUInteger kMostVisitedItemsPerLine = 4;
 
@@ -100,26 +127,48 @@
 CGFloat doodleHeight(BOOL logoIsShowing) {
   if (!IsIPadIdiom() && !logoIsShowing)
     return kNonGoogleSearchDoodleHeight;
-  return kGoogleSearchDoodleHeight;
+
+  if (IsUIRefreshPhase1Enabled()) {
+    if (!IsCompactWidth() && !IsCompactHeight())
+      return kGoogleSearchDoodleHeightRegularXRegular;
+    return kGoogleSearchDoodleHeightOther;
+  }
+
+  return kGoogleSearchDoodleHeightLegacy;
 }
 
 CGFloat doodleTopMargin(BOOL toolbarPresent) {
+  if (IsUIRefreshPhase1Enabled()) {
+    if (!IsCompactWidth() && !IsCompactHeight())
+      return kDoodleTopMarginRegularXRegular;
+    return kDoodleTopMarginOther;
+  }
   if (IsIPadIdiom())
-    return kDoodleTopMarginIPad;
-  return toolbarPresent ? ntp_header::kToolbarHeight : 0;
+    return kDoodleTopMarginIPadLegacy;
+  return toolbarPresent ? ntp_header::ToolbarHeight() : 0;
 }
 
 CGFloat searchFieldTopMargin() {
+  if (IsUIRefreshPhase1Enabled()) {
+    return kSearchFieldTopMargin;
+  }
   if (IsIPadIdiom())
-    return kSearchFieldTopMarginIPad;
-  return kSearchFieldTopMarginIPhone;
+    return kSearchFieldTopMarginIPadLegacy;
+  return kSearchFieldTopMarginIPhoneLegacy;
 }
 
 CGFloat searchFieldWidth(CGFloat superviewWidth) {
+  if (IsUIRefreshPhase1Enabled()) {
+    if (!IsCompactWidth() && !IsCompactHeight())
+      return kSearchFieldLarge;
+
+    // Special case for narrow sizes.
+    return MIN(kSearchFieldSmall, superviewWidth - kSearchFieldMinMargin * 2);
+  }
   CGFloat margin = centeredTilesMarginForWidth(superviewWidth);
   if (margin > kMaxSearchFieldFrameMargin)
     margin = kMaxSearchFieldFrameMargin;
-  return fmax(superviewWidth - 2 * margin, kMinSearchFieldWidth);
+  return fmax(superviewWidth - 2 * margin, kMinSearchFieldWidthLegacy);
 }
 
 CGFloat heightForLogoHeader(BOOL logoIsShowing,
@@ -147,23 +196,37 @@
 
   [searchTapTarget addSubview:searchHintLabel];
 
-  [NSLayoutConstraint activateConstraints:@[
-    [searchHintLabel.heightAnchor
-        constraintEqualToConstant:kSearchFieldHeight - 2 * kSearchHintMargin],
-    [searchHintLabel.centerYAnchor
-        constraintEqualToAnchor:searchTapTarget.centerYAnchor
-                       constant:kSearchHintVerticalOffset]
-  ]];
+  if (IsUIRefreshPhase1Enabled()) {
+    [NSLayoutConstraint activateConstraints:@[
+      [searchHintLabel.centerYAnchor
+          constraintEqualToAnchor:searchTapTarget.centerYAnchor]
+    ]];
+  } else {
+    [NSLayoutConstraint activateConstraints:@[
+      [searchHintLabel.heightAnchor
+          constraintEqualToConstant:kSearchFieldHeight - 2 * kSearchHintMargin],
+      [searchHintLabel.centerYAnchor
+          constraintEqualToAnchor:searchTapTarget.centerYAnchor
+                         constant:kSearchHintVerticalOffset]
+    ]];
+  }
 
   [searchHintLabel setText:l10n_util::GetNSString(IDS_OMNIBOX_EMPTY_HINT)];
   if (base::i18n::IsRTL()) {
     [searchHintLabel setTextAlignment:NSTextAlignmentRight];
   }
-  [searchHintLabel
-      setTextColor:
-          [UIColor colorWithWhite:kiPhoneLocationBarPlaceholderColorBrightness
-                            alpha:1.0]];
-  [searchHintLabel setFont:[MDCTypography subheadFont]];
+  if (IsUIRefreshPhase1Enabled()) {
+    [searchHintLabel setTextColor:[UIColor colorWithWhite:0 alpha:kHintAlpha]];
+    searchHintLabel.font =
+        [UIFont preferredFontForTextStyle:UIFontTextStyleTitle3];
+    searchHintLabel.adjustsFontSizeToFitWidth = YES;
+  } else {
+    [searchHintLabel
+        setTextColor:
+            [UIColor colorWithWhite:kiPhoneLocationBarPlaceholderColorBrightness
+                              alpha:1.0]];
+    [searchHintLabel setFont:[MDCTypography subheadFont]];
+  }
 }
 
 void configureVoiceSearchButton(UIButton* voiceSearchButton,
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils_unittest.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils_unittest.mm
index bb51e62d..04902648 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils_unittest.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils_unittest.mm
@@ -6,6 +6,7 @@
 
 #include <memory>
 
+#include "ios/chrome/browser/ui/ui_util.h"
 #import "ios/chrome/test/base/scoped_block_swizzler.h"
 #include "testing/platform_test.h"
 #import "third_party/ocmock/OCMock/OCMock.h"
@@ -84,9 +85,14 @@
   CGFloat topMarginNoToolbar = doodleTopMargin(NO);
 
   // Test.
-  EXPECT_EQ(120, height);
-  EXPECT_EQ(82, topMargin);
-  EXPECT_EQ(82, topMarginNoToolbar);
+  if (IsUIRefreshPhase1Enabled()) {
+    EXPECT_EQ(68, height);
+    EXPECT_EQ(48, topMargin);
+  } else {
+    EXPECT_EQ(120, height);
+    EXPECT_EQ(82, topMargin);
+    EXPECT_EQ(82, topMarginNoToolbar);
+  }
 }
 
 TEST_F(ContentSuggestionsCollectionUtilsTest, doodleFrameIPhonePortrait) {
@@ -101,10 +107,16 @@
   CGFloat topMarginNoToolbar = doodleTopMargin(NO);
 
   // Test.
-  EXPECT_EQ(120, heightLogo);
-  EXPECT_EQ(60, heightNoLogo);
-  EXPECT_EQ(56, topMargin);
-  EXPECT_EQ(0, topMarginNoToolbar);
+  if (IsUIRefreshPhase1Enabled()) {
+    EXPECT_EQ(68, heightLogo);
+    EXPECT_EQ(60, heightNoLogo);
+    EXPECT_EQ(48, topMargin);
+  } else {
+    EXPECT_EQ(120, heightLogo);
+    EXPECT_EQ(60, heightNoLogo);
+    EXPECT_EQ(56, topMargin);
+    EXPECT_EQ(0, topMarginNoToolbar);
+  }
 }
 
 TEST_F(ContentSuggestionsCollectionUtilsTest, doodleFrameIPhoneLandscape) {
@@ -119,10 +131,16 @@
   CGFloat topMarginNoToolbar = doodleTopMargin(NO);
 
   // Test.
-  EXPECT_EQ(120, heightLogo);
-  EXPECT_EQ(60, heightNoLogo);
-  EXPECT_EQ(56, topMargin);
-  EXPECT_EQ(0, topMarginNoToolbar);
+  if (IsUIRefreshPhase1Enabled()) {
+    EXPECT_EQ(68, heightLogo);
+    EXPECT_EQ(60, heightNoLogo);
+    EXPECT_EQ(48, topMargin);
+  } else {
+    EXPECT_EQ(120, heightLogo);
+    EXPECT_EQ(60, heightNoLogo);
+    EXPECT_EQ(56, topMargin);
+    EXPECT_EQ(0, topMarginNoToolbar);
+  }
 }
 
 TEST_F(ContentSuggestionsCollectionUtilsTest, searchFieldFrameIPad) {
@@ -138,9 +156,15 @@
   CGFloat topMargin = searchFieldTopMargin();
 
   // Test.
-  EXPECT_EQ(82, topMargin);
-  EXPECT_EQ(width - 2 * margin, resultWidth);
-  EXPECT_EQ(largeIPadWidth - 400, resultWidthLargeIPad);
+  if (IsUIRefreshPhase1Enabled()) {
+    EXPECT_EQ(32, topMargin);
+    EXPECT_EQ(343, resultWidth);
+    EXPECT_EQ(343, resultWidthLargeIPad);
+  } else {
+    EXPECT_EQ(82, topMargin);
+    EXPECT_EQ(width - 2 * margin, resultWidth);
+    EXPECT_EQ(largeIPadWidth - 400, resultWidthLargeIPad);
+  }
 }
 
 TEST_F(ContentSuggestionsCollectionUtilsTest, searchFieldFrameIPhonePortrait) {
@@ -155,8 +179,13 @@
   CGFloat topMargin = searchFieldTopMargin();
 
   // Test.
-  EXPECT_EQ(32, topMargin);
-  EXPECT_EQ(width - 2 * margin, resultWidth);
+  if (IsUIRefreshPhase1Enabled()) {
+    EXPECT_EQ(32, topMargin);
+    EXPECT_EQ(343, resultWidth);
+  } else {
+    EXPECT_EQ(32, topMargin);
+    EXPECT_EQ(width - 2 * margin, resultWidth);
+  }
 }
 
 TEST_F(ContentSuggestionsCollectionUtilsTest, searchFieldFrameIPhoneLandscape) {
@@ -171,8 +200,13 @@
   CGFloat topMargin = searchFieldTopMargin();
 
   // Test.
-  EXPECT_EQ(32, topMargin);
-  EXPECT_EQ(width - 2 * margin, resultWidth);
+  if (IsUIRefreshPhase1Enabled()) {
+    EXPECT_EQ(32, topMargin);
+    EXPECT_EQ(343, resultWidth);
+  } else {
+    EXPECT_EQ(32, topMargin);
+    EXPECT_EQ(width - 2 * margin, resultWidth);
+  }
 }
 
 TEST_F(ContentSuggestionsCollectionUtilsTest, heightForLogoHeaderIPad) {
@@ -180,10 +214,17 @@
   SetAsIPad();
 
   // Action, tests.
-  EXPECT_EQ(350, heightForLogoHeader(YES, YES, YES));
-  EXPECT_EQ(374, heightForLogoHeader(YES, NO, YES));
-  EXPECT_EQ(350, heightForLogoHeader(YES, YES, NO));
-  EXPECT_EQ(374, heightForLogoHeader(YES, NO, NO));
+  if (IsUIRefreshPhase1Enabled()) {
+    EXPECT_EQ(214, heightForLogoHeader(YES, YES, YES));
+    EXPECT_EQ(238, heightForLogoHeader(YES, NO, YES));
+    EXPECT_EQ(214, heightForLogoHeader(YES, YES, NO));
+    EXPECT_EQ(238, heightForLogoHeader(YES, NO, NO));
+  } else {
+    EXPECT_EQ(350, heightForLogoHeader(YES, YES, YES));
+    EXPECT_EQ(374, heightForLogoHeader(YES, NO, YES));
+    EXPECT_EQ(350, heightForLogoHeader(YES, YES, NO));
+    EXPECT_EQ(374, heightForLogoHeader(YES, NO, NO));
+  }
 }
 
 TEST_F(ContentSuggestionsCollectionUtilsTest, heightForLogoHeaderIPhone) {
@@ -191,10 +232,17 @@
   SetAsIPhone();
 
   // Action, tests.
-  EXPECT_EQ(274, heightForLogoHeader(YES, YES, YES));
-  EXPECT_EQ(274, heightForLogoHeader(YES, NO, YES));
-  EXPECT_EQ(218, heightForLogoHeader(YES, YES, NO));
-  EXPECT_EQ(218, heightForLogoHeader(YES, NO, NO));
+  if (IsUIRefreshPhase1Enabled()) {
+    EXPECT_EQ(214, heightForLogoHeader(YES, YES, YES));
+    EXPECT_EQ(214, heightForLogoHeader(YES, NO, YES));
+    EXPECT_EQ(214, heightForLogoHeader(YES, YES, NO));
+    EXPECT_EQ(214, heightForLogoHeader(YES, NO, NO));
+  } else {
+    EXPECT_EQ(274, heightForLogoHeader(YES, YES, YES));
+    EXPECT_EQ(274, heightForLogoHeader(YES, NO, YES));
+    EXPECT_EQ(218, heightForLogoHeader(YES, YES, NO));
+    EXPECT_EQ(218, heightForLogoHeader(YES, NO, NO));
+  }
 }
 
 TEST_F(ContentSuggestionsCollectionUtilsTest, SizeIPhone6) {
@@ -210,7 +258,11 @@
   SetAsIPhone();
 
   // Test.
-  EXPECT_EQ(3U, numberOfTilesForWidth(320));
+  if (IsUIRefreshPhase1Enabled()) {
+    EXPECT_EQ(4U, numberOfTilesForWidth(320));
+  } else {
+    EXPECT_EQ(3U, numberOfTilesForWidth(320));
+  }
 }
 
 // Test for iPad portrait and iPhone landscape.
@@ -224,7 +276,11 @@
   SetAsIPad();
 
   // Test.
-  EXPECT_EQ(3U, numberOfTilesForWidth(360));
+  if (IsUIRefreshPhase1Enabled()) {
+    EXPECT_EQ(4U, numberOfTilesForWidth(360));
+  } else {
+    EXPECT_EQ(3U, numberOfTilesForWidth(360));
+  }
 }
 
 TEST_F(ContentSuggestionsCollectionUtilsTest, NearestAncestor) {
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_synchronizer.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_synchronizer.mm
index fb97a24a..4ca63580 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_synchronizer.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_synchronizer.mm
@@ -168,7 +168,8 @@
 }
 
 - (void)updateFakeOmniboxOnNewWidth:(CGFloat)width {
-  if (self.shouldAnimateHeader && !IsIPadIdiom()) {
+  if (self.shouldAnimateHeader &&
+      (IsUIRefreshPhase1Enabled() || !IsIPadIdiom())) {
     [self.headerController
         updateFakeOmniboxForOffset:self.collectionView.contentOffset.y
                        screenWidth:width
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view.mm
index b1b53a3..b7d98af 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view.mm
@@ -14,14 +14,23 @@
 #import "ios/chrome/browser/ui/toolbar/buttons/toolbar_configuration.h"
 #import "ios/chrome/browser/ui/toolbar/buttons/toolbar_constants.h"
 #import "ios/chrome/browser/ui/toolbar/toolbar_snapshot_providing.h"
+#import "ios/chrome/browser/ui/uikit_ui_util.h"
 #import "ios/chrome/browser/ui/util/constraints_ui_util.h"
 #import "ios/chrome/browser/ui/util/named_guide.h"
+#import "ui/gfx/ios/NSString+CrStringDrawing.h"
 #import "ui/gfx/ios/uikit_util.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
 #endif
 
+namespace {
+
+// Left margin for search icon.
+const CGFloat kSearchIconLeftMargin = 9;
+
+}  // namespace
+
 @interface ContentSuggestionsHeaderView ()<ToolbarSnapshotProviding>
 
 // Layout constraints for fake omnibox background image.
@@ -82,16 +91,17 @@
   UIView* backgroundContainer = [[UIView alloc] init];
   backgroundContainer.userInteractionEnabled = NO;
   backgroundContainer.backgroundColor =
-      [UIColor colorWithWhite:0 alpha:kAdaptiveLocationBarBackgroundAlpha];
+      UIColorFromRGB(content_suggestions::kSearchFieldBackgroundColor);
   backgroundContainer.layer.cornerRadius = kAdaptiveLocationBarCornerRadius;
-  [searchField addSubview:backgroundContainer];
+  [searchField insertSubview:backgroundContainer atIndex:1];
+
   backgroundContainer.translatesAutoresizingMaskIntoConstraints = NO;
   self.backgroundLeadingConstraint = [backgroundContainer.leadingAnchor
       constraintEqualToAnchor:searchField.leadingAnchor];
   self.backgroundTrailingConstraint = [backgroundContainer.trailingAnchor
       constraintEqualToAnchor:searchField.trailingAnchor];
-  self.backgroundHeightConstraint =
-      [backgroundContainer.heightAnchor constraintEqualToConstant:0];
+  self.backgroundHeightConstraint = [backgroundContainer.heightAnchor
+      constraintEqualToConstant:content_suggestions::kSearchFieldHeight];
   [NSLayoutConstraint activateConstraints:@[
     [backgroundContainer.centerYAnchor
         constraintEqualToAnchor:searchField.centerYAnchor],
@@ -100,7 +110,17 @@
     self.backgroundHeightConstraint,
   ]];
 
-  // TODO(crbug.com/805644) Update fake omnibox theme.
+  UIImage* search_icon = [UIImage imageNamed:@"ntp_search_icon"];
+  UIImageView* search_view = [[UIImageView alloc] initWithImage:search_icon];
+  [searchField addSubview:search_view];
+  search_view.translatesAutoresizingMaskIntoConstraints = NO;
+  [NSLayoutConstraint activateConstraints:@[
+    [search_view.centerYAnchor
+        constraintEqualToAnchor:backgroundContainer.centerYAnchor],
+    [search_view.leadingAnchor
+        constraintEqualToAnchor:backgroundContainer.leadingAnchor
+                       constant:kSearchIconLeftMargin],
+  ]];
 }
 
 - (CGFloat)searchFieldProgressForOffset:(CGFloat)offset {
@@ -121,6 +141,8 @@
 - (void)updateSearchFieldWidth:(NSLayoutConstraint*)widthConstraint
                         height:(NSLayoutConstraint*)heightConstraint
                      topMargin:(NSLayoutConstraint*)topMarginConstraint
+                     hintLabel:(UILabel*)hintLabel
+                hintLabelWidth:(NSLayoutConstraint*)hintLabelWidthConstraint
             subviewConstraints:(NSArray*)constraints
                      forOffset:(CGFloat)offset
                    screenWidth:(CGFloat)screenWidth
@@ -130,22 +152,26 @@
   if (screenWidth == 0 || contentWidth == 0)
     return;
 
-  CGFloat percent = [self searchFieldProgressForOffset:offset];
-
-  if (self.cr_widthSizeClass == REGULAR && self.cr_heightSizeClass == REGULAR) {
-    self.alpha = 1 - percent;
-    return;
-  }
-
   CGFloat searchFieldNormalWidth =
       content_suggestions::searchFieldWidth(contentWidth);
 
+  CGFloat percent = [self searchFieldProgressForOffset:offset];
+  if (self.cr_widthSizeClass == REGULAR && self.cr_heightSizeClass == REGULAR) {
+    self.alpha = 1 - percent;
+    widthConstraint.constant = searchFieldNormalWidth;
+    hintLabelWidthConstraint.active = NO;
+    return;
+  } else {
+    hintLabelWidthConstraint.active = YES;
+    self.alpha = 1;
+  }
+
   // Calculate the amount to grow the width and height of searchField so that
   // its frame covers the entire toolbar area.
   CGFloat maxXInset =
       ui::AlignValueToUpperPixel((searchFieldNormalWidth - screenWidth) / 2);
   CGFloat maxHeightDiff =
-      ntp_header::kToolbarHeight - content_suggestions::kSearchFieldHeight;
+      ntp_header::ToolbarHeight() - content_suggestions::kSearchFieldHeight;
 
   widthConstraint.constant = searchFieldNormalWidth - 2 * maxXInset * percent;
   topMarginConstraint.constant = -content_suggestions::searchFieldTopMargin() -
@@ -157,22 +183,29 @@
   // it's where the focused adapative toolbar focuses.
   self.backgroundLeadingConstraint.constant =
       (safeAreaInsets.left + kExpandedLocationBarHorizontalMargin) * percent;
-  // TODO(crbug.com/805636) Placeholder for specifications. For now using hard
-  // coded size of cancel button of 64pt.
-  CGFloat kCancelButtonWidth = 64;
   self.backgroundTrailingConstraint.constant =
-      -(safeAreaInsets.right + kExpandedLocationBarHorizontalMargin +
-        kCancelButtonWidth) *
-      percent;
-  // TODO(crbug.com/805636) Placeholder for specifications. For now using hard
-  // coded height of location bar, which is 42 or
-  // kToolbarHeight - 2 * kLocationBarVerticalMargin
-  CGFloat kLocationBarHeight = 42;
+      -(safeAreaInsets.right + kExpandedLocationBarHorizontalMargin) * percent;
+  // TODO(crbug.com/805645) This should take into account the actual location
+  // bar height in the toolbar. Update this once that's been updated for the
+  // refresh and remove |kLocationBarHeight|.
+  CGFloat kLocationBarHeight = 38;
   CGFloat minHeightDiff =
       kLocationBarHeight - content_suggestions::kSearchFieldHeight;
   self.backgroundHeightConstraint.constant =
       content_suggestions::kSearchFieldHeight + minHeightDiff * percent;
 
+  // TODO(crbug.com/805645) This should take into account the actual label width
+  // of the toolbar location omnibox box hint text. Update this once that's been
+  // updated for the refresh and remove |kHintShrinkWidth|.
+  CGFloat kHintShrinkWidth = 30;
+  CGFloat hintWidth =
+      [hintLabel.text
+          cr_boundingSizeWithSize:CGSizeMake(widthConstraint.constant, INFINITY)
+                             font:hintLabel.font]
+          .width;
+  hintLabelWidthConstraint.constant = hintWidth - kHintShrinkWidth * percent;
+  hintLabelWidthConstraint.active = YES;
+
   // Adjust the position of the search field's subviews by adjusting their
   // constraint constant value.
   CGFloat constantDiff =
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.mm
index 27f91fe..38d510d9 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.mm
@@ -38,7 +38,6 @@
 
 namespace {
 const UIEdgeInsets kSearchBoxStretchInsets = {3, 3, 3, 3};
-const CGFloat kHintLabelSidePadding = 12;
 }  // namespace
 
 @interface ContentSuggestionsHeaderViewController ()
@@ -65,7 +64,9 @@
 
 @property(nonatomic, strong) UIView<NTPHeaderViewAdapter>* headerView;
 @property(nonatomic, strong) UIButton* fakeOmnibox;
+@property(nonatomic, strong) UILabel* searchHintLabel;
 @property(nonatomic, strong) NSLayoutConstraint* hintLabelLeadingConstraint;
+@property(nonatomic, strong) NSLayoutConstraint* hintLabelWidthConstraint;
 @property(nonatomic, strong) NSLayoutConstraint* voiceTapTrailingConstraint;
 @property(nonatomic, strong) NSLayoutConstraint* doodleHeightConstraint;
 @property(nonatomic, strong) NSLayoutConstraint* doodleTopMarginConstraint;
@@ -81,6 +82,7 @@
 @synthesize dispatcher = _dispatcher;
 @synthesize delegate = _delegate;
 @synthesize commandHandler = _commandHandler;
+@synthesize searchHintLabel = _searchHintLabel;
 @synthesize collectionSynchronizer = _collectionSynchronizer;
 @synthesize readingListModel = _readingListModel;
 @synthesize toolbarDelegate = _toolbarDelegate;
@@ -95,6 +97,7 @@
 @synthesize headerView = _headerView;
 @synthesize fakeOmnibox = _fakeOmnibox;
 @synthesize hintLabelLeadingConstraint = _hintLabelLeadingConstraint;
+@synthesize hintLabelWidthConstraint = _hintLabelWidthConstraint;
 @synthesize voiceTapTrailingConstraint = _voiceTapTrailingConstraint;
 @synthesize doodleHeightConstraint = _doodleHeightConstraint;
 @synthesize doodleTopMarginConstraint = _doodleTopMarginConstraint;
@@ -120,6 +123,29 @@
   return self.headerView.toolBarView;
 }
 
+- (void)willTransitionToTraitCollection:(UITraitCollection*)newCollection
+              withTransitionCoordinator:
+                  (id<UIViewControllerTransitionCoordinator>)coordinator {
+  [super willTransitionToTraitCollection:newCollection
+               withTransitionCoordinator:coordinator];
+  if (!IsUIRefreshPhase1Enabled())
+    return;
+
+  void (^transition)(id<UIViewControllerTransitionCoordinatorContext>) =
+      ^(id<UIViewControllerTransitionCoordinatorContext> context) {
+        // Ensure omnibox is reset when not a regular tablet.
+        if (IsCompactWidth(self) || IsCompactHeight(self)) {
+          [self.toolbarDelegate setScrollProgressForTabletOmnibox:1];
+        }
+
+        // Update the doodle top margin to the new -doodleTopMargin value.
+        self.doodleTopMarginConstraint.constant =
+            content_suggestions::doodleTopMargin(YES);
+      };
+
+  [coordinator animateAlongsideTransition:transition completion:nil];
+}
+
 #pragma mark - Property
 
 - (void)setIsShowing:(BOOL)isShowing {
@@ -146,6 +172,8 @@
   [self.headerView updateSearchFieldWidth:self.fakeOmniboxWidthConstraint
                                    height:self.fakeOmniboxHeightConstraint
                                 topMargin:self.fakeOmniboxTopMarginConstraint
+                                hintLabel:self.searchHintLabel
+                           hintLabelWidth:self.hintLabelWidthConstraint
                        subviewConstraints:constraints
                                 forOffset:offset
                               screenWidth:screenWidth
@@ -175,7 +203,7 @@
   CGFloat offsetY =
       headerHeight - ntp_header::kScrolledToTopOmniboxBottomMargin;
   if (!IsIPadIdiom())
-    offsetY -= ntp_header::kToolbarHeight;
+    offsetY -= ntp_header::ToolbarHeight();
 
   return offsetY;
 }
@@ -253,7 +281,7 @@
 // Initialize and add a search field tap target and a voice search button.
 - (void)addFakeOmnibox {
   self.fakeOmnibox = [[UIButton alloc] init];
-  if (IsIPadIdiom()) {
+  if (IsIPadIdiom() && !IsUIRefreshPhase1Enabled()) {
     UIImage* searchBoxImage = [[UIImage imageNamed:@"ntp_google_search_box"]
         resizableImageWithCapInsets:kSearchBoxStretchInsets];
     [self.fakeOmnibox setBackgroundImage:searchBoxImage
@@ -267,20 +295,28 @@
       ntp_home::FakeOmniboxAccessibilityID();
 
   // Set up fakebox hint label.
-  UILabel* searchHintLabel = [[UILabel alloc] init];
-  content_suggestions::configureSearchHintLabel(searchHintLabel,
+  _searchHintLabel = [[UILabel alloc] init];
+  content_suggestions::configureSearchHintLabel(_searchHintLabel,
                                                 self.fakeOmnibox);
 
-  self.hintLabelLeadingConstraint = [searchHintLabel.leadingAnchor
+  self.hintLabelLeadingConstraint = [_searchHintLabel.leadingAnchor
       constraintEqualToAnchor:[self.fakeOmnibox leadingAnchor]
-                     constant:kHintLabelSidePadding];
-  [_hintLabelLeadingConstraint setActive:YES];
+                     constant:ntp_header::kHintLabelSidePadding];
+  if (!IsUIRefreshPhase1Enabled())
+    self.hintLabelLeadingConstraint.constant =
+        ntp_header::kHintLabelSidePaddingLegacy;
+  [self.hintLabelLeadingConstraint setActive:YES];
+
+  if (IsUIRefreshPhase1Enabled()) {
+    self.hintLabelWidthConstraint =
+        [_searchHintLabel.widthAnchor constraintEqualToConstant:0];
+  }
 
   // Set a button the same size as the fake omnibox as the accessibility
   // element. If the hint is the only accessible element, when the fake omnibox
   // is taking the full width, there are few points that are not accessible and
   // allow to select the content below it.
-  searchHintLabel.isAccessibilityElement = NO;
+  _searchHintLabel.isAccessibilityElement = NO;
   UIButton* accessibilityButton = [[UIButton alloc] init];
   [accessibilityButton addTarget:self
                           action:@selector(fakeOmniboxTapped:)
@@ -299,11 +335,15 @@
 
   self.voiceTapTrailingConstraint = [voiceTapTarget.trailingAnchor
       constraintEqualToAnchor:[self.fakeOmnibox trailingAnchor]];
-  [NSLayoutConstraint activateConstraints:@[
-    [searchHintLabel.trailingAnchor
-        constraintEqualToAnchor:voiceTapTarget.leadingAnchor],
-    _voiceTapTrailingConstraint
-  ]];
+  if (IsUIRefreshPhase1Enabled()) {
+    [NSLayoutConstraint activateConstraints:@[ _voiceTapTrailingConstraint ]];
+  } else {
+    [NSLayoutConstraint activateConstraints:@[
+      [_searchHintLabel.trailingAnchor
+          constraintEqualToAnchor:voiceTapTarget.leadingAnchor],
+      _voiceTapTrailingConstraint
+    ]];
+  }
 
   if (self.voiceSearchIsEnabled) {
     [voiceTapTarget addTarget:self
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_layout.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_layout.mm
index 739171f..085157e 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_layout.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_layout.mm
@@ -24,7 +24,7 @@
   CGFloat minimumHeight = collectionViewHeight + headerHeight -
                           ntp_header::kScrolledToTopOmniboxBottomMargin;
   if (!IsIPadIdiom())
-    minimumHeight -= ntp_header::kToolbarHeight;
+    minimumHeight -= ntp_header::ToolbarHeight();
 
   CGSize contentSize = [super collectionViewContentSize];
   if (contentSize.height < minimumHeight) {
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm
index 01aa074e..b0909ca 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.mm
@@ -583,7 +583,7 @@
                    withVelocity:velocity
             targetContentOffset:targetContentOffset];
 
-  CGFloat toolbarHeight = ntp_header::kToolbarHeight;
+  CGFloat toolbarHeight = ntp_header::ToolbarHeight();
   CGFloat targetY = targetContentOffset->y;
 
   if (IsIPadIdiom() || targetY <= 0 || targetY >= toolbarHeight ||
@@ -620,7 +620,7 @@
   if (direction == UIAccessibilityScrollDirectionDown) {
     CGFloat newYOffset = self.collectionView.contentOffset.y +
                          self.collectionView.bounds.size.height -
-                         ntp_header::kToolbarHeight;
+                         ntp_header::ToolbarHeight();
     newYOffset = MIN(self.collectionView.contentSize.height -
                          self.collectionView.bounds.size.height,
                      newYOffset);
@@ -629,7 +629,7 @@
   } else if (direction == UIAccessibilityScrollDirectionUp) {
     CGFloat newYOffset = self.collectionView.contentOffset.y -
                          self.collectionView.bounds.size.height +
-                         ntp_header::kToolbarHeight;
+                         ntp_header::ToolbarHeight();
     newYOffset = MAX(0, newYOffset);
     self.collectionView.contentOffset =
         CGPointMake(self.collectionView.contentOffset.x, newYOffset);
diff --git a/ios/chrome/browser/ui/content_suggestions/ntp_home_mediator.mm b/ios/chrome/browser/ui/content_suggestions/ntp_home_mediator.mm
index f0df24a..d181cf7 100644
--- a/ios/chrome/browser/ui/content_suggestions/ntp_home_mediator.mm
+++ b/ios/chrome/browser/ui/content_suggestions/ntp_home_mediator.mm
@@ -201,7 +201,7 @@
     // offset, taking into account the size of the toolbar.
     offset = MAX(0, MIN(offset, collection.contentSize.height -
                                     collection.bounds.size.height -
-                                    ntp_header::kToolbarHeight));
+                                    ntp_header::ToolbarHeight()));
     collection.contentOffset = CGPointMake(0, offset);
     // Update the constraints in case the omnibox needs to be moved.
     [self.suggestionsViewController updateConstraints];
diff --git a/ios/chrome/browser/ui/content_suggestions/resources/BUILD.gn b/ios/chrome/browser/ui/content_suggestions/resources/BUILD.gn
index 599a408..ca385d9 100644
--- a/ios/chrome/browser/ui/content_suggestions/resources/BUILD.gn
+++ b/ios/chrome/browser/ui/content_suggestions/resources/BUILD.gn
@@ -21,3 +21,12 @@
     "content_suggestions_offline.imageset/content_suggestions_offline@3x.png",
   ]
 }
+
+imageset("ntp_search_icon") {
+  sources = [
+    "ntp_search_icon.imageset/Contents.json",
+    "ntp_search_icon.imageset/ntp_search_icon.png",
+    "ntp_search_icon.imageset/ntp_search_icon@2x.png",
+    "ntp_search_icon.imageset/ntp_search_icon@3x.png",
+  ]
+}
diff --git a/ios/chrome/browser/ui/content_suggestions/resources/ntp_search_icon.imageset/Contents.json b/ios/chrome/browser/ui/content_suggestions/resources/ntp_search_icon.imageset/Contents.json
new file mode 100644
index 0000000..bdee628
--- /dev/null
+++ b/ios/chrome/browser/ui/content_suggestions/resources/ntp_search_icon.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+    "images": [
+        {
+            "idiom": "universal",
+            "scale": "1x",
+            "filename": "ntp_search_icon.png"
+        },
+        {
+            "idiom": "universal",
+            "scale": "2x",
+            "filename": "ntp_search_icon@2x.png"
+        },
+        {
+            "idiom": "universal",
+            "scale": "3x",
+            "filename": "ntp_search_icon@3x.png"
+        }
+    ],
+    "info": {
+        "version": 1,
+        "author": "xcode"
+    }
+}
diff --git a/ios/chrome/browser/ui/content_suggestions/resources/ntp_search_icon.imageset/ntp_search_icon.png b/ios/chrome/browser/ui/content_suggestions/resources/ntp_search_icon.imageset/ntp_search_icon.png
new file mode 100644
index 0000000..7146a1e
--- /dev/null
+++ b/ios/chrome/browser/ui/content_suggestions/resources/ntp_search_icon.imageset/ntp_search_icon.png
Binary files differ
diff --git a/ios/chrome/browser/ui/content_suggestions/resources/ntp_search_icon.imageset/ntp_search_icon@2x.png b/ios/chrome/browser/ui/content_suggestions/resources/ntp_search_icon.imageset/ntp_search_icon@2x.png
new file mode 100644
index 0000000..af824f6
--- /dev/null
+++ b/ios/chrome/browser/ui/content_suggestions/resources/ntp_search_icon.imageset/ntp_search_icon@2x.png
Binary files differ
diff --git a/ios/chrome/browser/ui/content_suggestions/resources/ntp_search_icon.imageset/ntp_search_icon@3x.png b/ios/chrome/browser/ui/content_suggestions/resources/ntp_search_icon.imageset/ntp_search_icon@3x.png
new file mode 100644
index 0000000..a23d0df
--- /dev/null
+++ b/ios/chrome/browser/ui/content_suggestions/resources/ntp_search_icon.imageset/ntp_search_icon@3x.png
Binary files differ
diff --git a/ios/chrome/browser/ui/ntp/BUILD.gn b/ios/chrome/browser/ui/ntp/BUILD.gn
index 0c4f21c5..dfda704 100644
--- a/ios/chrome/browser/ui/ntp/BUILD.gn
+++ b/ios/chrome/browser/ui/ntp/BUILD.gn
@@ -10,6 +10,9 @@
     "new_tab_page_panel_protocol.h",
   ]
   configs += [ "//build/config/compiler:enable_arc" ]
+  deps = [
+    "//ios/chrome/browser/ui:ui_util",
+  ]
 }
 
 source_set("ntp_header") {
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 2b3b1b1..c20cec3 100644
--- a/ios/chrome/browser/ui/ntp/new_tab_page_controller.mm
+++ b/ios/chrome/browser/ui/ntp/new_tab_page_controller.mm
@@ -27,6 +27,7 @@
 #import "ios/chrome/browser/ui/content_suggestions/ntp_home_constant.h"
 #import "ios/chrome/browser/ui/ntp/incognito_view_controller.h"
 #import "ios/chrome/browser/ui/ntp/new_tab_page_bar_item.h"
+#import "ios/chrome/browser/ui/ntp/new_tab_page_header_constants.h"
 #import "ios/chrome/browser/ui/ntp/new_tab_page_view.h"
 #import "ios/chrome/browser/ui/rtl_geometry.h"
 #include "ios/chrome/browser/ui/ui_util.h"
@@ -41,10 +42,6 @@
 
 using base::UserMetricsAction;
 
-namespace {
-const CGFloat kToolbarHeight = 56;
-}
-
 @interface NewTabPageController () {
   ios::ChromeBrowserState* _browserState;  // weak.
   __weak id<UrlLoader> _loader;
@@ -377,7 +374,8 @@
 - (CGFloat)toolbarHeight {
   // If the google landing controller is nil, there is no toolbar visible in the
   // native content view, finally there is no toolbar on iPad.
-  return self.headerController && !IsIPadIdiom() ? kToolbarHeight : 0.0;
+  return self.headerController && !IsIPadIdiom() ? ntp_header::ToolbarHeight()
+                                                 : 0.0;
 }
 
 #pragma mark - NewTabPagePanelControllerDelegate
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_header_constants.h b/ios/chrome/browser/ui/ntp/new_tab_page_header_constants.h
index 023fff2..ace4fc2 100644
--- a/ios/chrome/browser/ui/ntp/new_tab_page_header_constants.h
+++ b/ios/chrome/browser/ui/ntp/new_tab_page_header_constants.h
@@ -17,11 +17,12 @@
 // initial frame to its final full bleed frame.
 extern const CGFloat kAnimationDistance;
 
-extern const CGFloat kToolbarHeight;
+CGFloat ToolbarHeight();
 
 extern const CGFloat kScrolledToTopOmniboxBottomMargin;
 
 extern const CGFloat kHintLabelSidePadding;
+extern const CGFloat kHintLabelSidePaddingLegacy;
 
 // The margin of the subviews of the fake omnibox when it is pinned to top.
 extern const CGFloat kMaxHorizontalMarginDiff;
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_header_constants.mm b/ios/chrome/browser/ui/ntp/new_tab_page_header_constants.mm
index 4fd1e8b..034a4ea 100644
--- a/ios/chrome/browser/ui/ntp/new_tab_page_header_constants.mm
+++ b/ios/chrome/browser/ui/ntp/new_tab_page_header_constants.mm
@@ -4,6 +4,9 @@
 
 #import "ios/chrome/browser/ui/ntp/new_tab_page_header_constants.h"
 
+#include "ios/chrome/browser/ui/ui_util.h"
+#import "ios/chrome/browser/ui/uikit_ui_util.h"
+
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
 #endif
@@ -12,10 +15,19 @@
 
 const CGFloat kMinHeaderHeight = 62;
 const CGFloat kAnimationDistance = 42;
-const CGFloat kToolbarHeight = 56;
+const CGFloat kToolbarHeightLegacy = 56;
+const CGFloat kToolbarHeight = 48;
 const CGFloat kScrolledToTopOmniboxBottomMargin = 4;
-const CGFloat kHintLabelSidePadding = 12;
+const CGFloat kHintLabelSidePadding = 37;
+const CGFloat kHintLabelSidePaddingLegacy = 12;
 const CGFloat kMaxHorizontalMarginDiff = 5;
 const CGFloat kMaxTopMarginDiff = 4;
 
+CGFloat ToolbarHeight() {
+  if (IsUIRefreshPhase1Enabled()) {
+    return kToolbarHeight;
+  }
+  return kToolbarHeightLegacy;
+}
+
 }  // ntp_header
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_header_view.mm b/ios/chrome/browser/ui/ntp/new_tab_page_header_view.mm
index 1d569b9..5048542 100644
--- a/ios/chrome/browser/ui/ntp/new_tab_page_header_view.mm
+++ b/ios/chrome/browser/ui/ntp/new_tab_page_header_view.mm
@@ -110,6 +110,8 @@
 - (void)updateSearchFieldWidth:(NSLayoutConstraint*)widthConstraint
                         height:(NSLayoutConstraint*)heightConstraint
                      topMargin:(NSLayoutConstraint*)topMarginConstraint
+                     hintLabel:(UILabel*)hintLabel
+                hintLabelWidth:(NSLayoutConstraint*)hintLabelWidthConstraint
             subviewConstraints:(NSArray*)constraints
                      forOffset:(CGFloat)offset
                    screenWidth:(CGFloat)screenWidth
@@ -139,7 +141,7 @@
   CGFloat maxXInset = ui::AlignValueToUpperPixel(
       (searchFieldNormalWidth - screenWidth) / 2 - 1);
   CGFloat maxHeightDiff =
-      ntp_header::kToolbarHeight - content_suggestions::kSearchFieldHeight;
+      ntp_header::ToolbarHeight() - content_suggestions::kSearchFieldHeight;
 
   widthConstraint.constant = searchFieldNormalWidth - 2 * maxXInset * percent;
   topMarginConstraint.constant = -content_suggestions::searchFieldTopMargin() -
@@ -156,7 +158,8 @@
       percent * (ntp_header::kMaxHorizontalMarginDiff + safeAreaInsets.left);
   for (NSLayoutConstraint* constraint in constraints) {
     if (constraint.constant > 0)
-      constraint.constant = constantDiff + ntp_header::kHintLabelSidePadding;
+      constraint.constant =
+          constantDiff + ntp_header::kHintLabelSidePaddingLegacy;
     else
       constraint.constant = -constantDiff;
   }
diff --git a/ios/chrome/browser/ui/ntp/ntp_header_view_adapter.h b/ios/chrome/browser/ui/ntp/ntp_header_view_adapter.h
index 9546eb4..d44515b 100644
--- a/ios/chrome/browser/ui/ntp/ntp_header_view_adapter.h
+++ b/ios/chrome/browser/ui/ntp/ntp_header_view_adapter.h
@@ -30,6 +30,8 @@
 - (void)updateSearchFieldWidth:(NSLayoutConstraint*)widthConstraint
                         height:(NSLayoutConstraint*)heightConstraint
                      topMargin:(NSLayoutConstraint*)topMarginConstraint
+                     hintLabel:(UILabel*)hintLabel
+                hintLabelWidth:(NSLayoutConstraint*)hintLabelWidthConstraint
             subviewConstraints:(NSArray*)constraints
                      forOffset:(CGFloat)offset
                    screenWidth:(CGFloat)screenWidth
diff --git a/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_coordinator.mm b/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_coordinator.mm
index e714224..4d7f141 100644
--- a/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_coordinator.mm
+++ b/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_coordinator.mm
@@ -4,6 +4,10 @@
 
 #import "ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_coordinator.h"
 
+#include "base/ios/block_types.h"
+#include "base/mac/foundation_util.h"
+#import "ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_handset_view_controller.h"
+#import "ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_mediator.h"
 #import "ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller.h"
 #import "ios/chrome/browser/ui/table_view/table_container_view_controller.h"
 #import "ios/chrome/browser/ui/util/form_sheet_navigation_controller.h"
@@ -14,15 +18,24 @@
 #error "This file requires ARC support."
 #endif
 
-@interface RecentTabsTableCoordinator ()
+// TODO(crbug.com/805135): Remove RecentTabsHandsetViewControllerCommand and
+// recent_tabs_handset_view_controller.h import. We need this to dismiss for
+// now, but it can be improved.
+@interface RecentTabsTableCoordinator ()<RecentTabsHandsetViewControllerCommand>
+// Completion block called once the recentTabsViewController is dismissed.
+@property(nonatomic, copy) ProceduralBlock completion;
+// Mediator being managed by this Coordinator.
+@property(nonatomic, strong) RecentTabsMediator* mediator;
 // ViewController being managed by this Coordinator.
 @property(nonatomic, strong)
     TableContainerViewController* recentTabsContainerViewController;
 @end
 
 @implementation RecentTabsTableCoordinator
+@synthesize completion = _completion;
 @synthesize dispatcher = _dispatcher;
 @synthesize loader = _loader;
+@synthesize mediator = _mediator;
 @synthesize recentTabsContainerViewController =
     _recentTabsContainerViewController;
 
@@ -33,6 +46,14 @@
   recentTabsTableViewController.browserState = self.browserState;
   recentTabsTableViewController.loader = self.loader;
   recentTabsTableViewController.dispatcher = self.dispatcher;
+  recentTabsTableViewController.handsetCommandHandler = self;
+
+  // Initialize and configure RecentTabsMediator.
+  self.mediator = [[RecentTabsMediator alloc] init];
+  self.mediator.browserState = self.browserState;
+  self.mediator.consumer = recentTabsTableViewController;
+  [self.mediator initObservers];
+  [self.mediator reloadSessions];
 
   // Initialize and configure RecentTabsViewController.
   self.recentTabsContainerViewController = [[TableContainerViewController alloc]
@@ -58,9 +79,24 @@
 }
 
 - (void)stop {
-  [self.recentTabsContainerViewController dismissViewControllerAnimated:YES
-                                                             completion:nil];
+  // TODO(crbug.com/805135): Move this dismissal code to RecentTabsContainerVC
+  // once its created. Remove "base/mac/foundation_util.h" import then.
+  RecentTabsTableViewController* recentTabsTableViewController =
+      base::mac::ObjCCastStrict<RecentTabsTableViewController>(
+          self.recentTabsContainerViewController.tableViewController);
+  [recentTabsTableViewController dismissModals];
+  [self.recentTabsContainerViewController
+      dismissViewControllerAnimated:YES
+                         completion:self.completion];
   self.recentTabsContainerViewController = nil;
+  [self.mediator disconnect];
+}
+
+#pragma mark - RecentTabsHandsetViewControllerCommand
+
+- (void)dismissRecentTabsWithCompletion:(void (^)())completion {
+  self.completion = completion;
+  [self stop];
 }
 
 @end
diff --git a/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller.h b/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller.h
index d70b742246..a6af262 100644
--- a/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller.h
+++ b/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller.h
@@ -13,6 +13,8 @@
 }
 
 @protocol ApplicationCommands;
+@protocol LegacyRecentTabsTableViewControllerDelegate;
+@protocol RecentTabsHandsetViewControllerCommand;
 @protocol UrlLoader;
 
 @interface RecentTabsTableViewController
@@ -23,6 +25,15 @@
 @property(nonatomic, weak) id<ApplicationCommands> dispatcher;
 // UrlLoader used by this ViewController.
 @property(nonatomic, weak) id<UrlLoader> loader;
+
+// RecentTabsTableViewControllerDelegate delegate.
+@property(nonatomic, weak) id<LegacyRecentTabsTableViewControllerDelegate>
+    delegate;
+
+// RecentTabsHandsetViewControllerCommand delegate.
+@property(nonatomic, weak) id<RecentTabsHandsetViewControllerCommand>
+    handsetCommandHandler;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_NTP_RECENT_TABS_RECENT_TABS_TABLE_VIEW_CONTROLLER_H_
diff --git a/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller.mm b/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller.mm
index 0a5255d7..0b58127 100644
--- a/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller.mm
+++ b/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller.mm
@@ -4,14 +4,119 @@
 
 #import "ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller.h"
 
+#include "base/logging.h"
+#include "base/metrics/user_metrics.h"
+#include "base/metrics/user_metrics_action.h"
+#include "base/strings/sys_string_conversions.h"
+#include "components/browser_sync/profile_sync_service.h"
+#include "components/sync/driver/sync_service.h"
+#include "components/sync_sessions/open_tabs_ui_delegate.h"
+#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
+#include "ios/chrome/browser/experimental_flags.h"
+#import "ios/chrome/browser/metrics/new_tab_page_uma.h"
+#include "ios/chrome/browser/sessions/tab_restore_service_delegate_impl_ios.h"
+#include "ios/chrome/browser/sessions/tab_restore_service_delegate_impl_ios_factory.h"
+#include "ios/chrome/browser/sync/ios_chrome_profile_sync_service_factory.h"
+#import "ios/chrome/browser/ui/authentication/signin_promo_view.h"
+#import "ios/chrome/browser/ui/authentication/signin_promo_view_configurator.h"
+#import "ios/chrome/browser/ui/authentication/signin_promo_view_consumer.h"
+#import "ios/chrome/browser/ui/authentication/signin_promo_view_mediator.h"
+#include "ios/chrome/browser/ui/commands/application_commands.h"
+#import "ios/chrome/browser/ui/commands/show_signin_command.h"
+#import "ios/chrome/browser/ui/context_menu/context_menu_coordinator.h"
+#import "ios/chrome/browser/ui/ntp/recent_tabs/legacy_recent_tabs_table_view_controller_delegate.h"
+#import "ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_constants.h"
+#import "ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_handset_view_controller.h"
+#include "ios/chrome/browser/ui/ntp/recent_tabs/synced_sessions.h"
+#import "ios/chrome/browser/ui/ntp/recent_tabs/views/generic_section_header_view.h"
+#import "ios/chrome/browser/ui/ntp/recent_tabs/views/header_of_collapsable_section_protocol.h"
+#import "ios/chrome/browser/ui/ntp/recent_tabs/views/session_section_header_view.h"
+#import "ios/chrome/browser/ui/ntp/recent_tabs/views/session_tab_data_view.h"
+#import "ios/chrome/browser/ui/ntp/recent_tabs/views/show_full_history_view.h"
+#import "ios/chrome/browser/ui/ntp/recent_tabs/views/signed_in_sync_in_progress_view.h"
+#import "ios/chrome/browser/ui/ntp/recent_tabs/views/signed_in_sync_off_view.h"
+#import "ios/chrome/browser/ui/ntp/recent_tabs/views/signed_in_sync_on_no_sessions_view.h"
+#import "ios/chrome/browser/ui/ntp/recent_tabs/views/spacers_view.h"
+#import "ios/chrome/browser/ui/settings/sync_utils/sync_presenter.h"
+#import "ios/chrome/browser/ui/signin_interaction/public/signin_presenter.h"
+#include "ios/chrome/browser/ui/ui_util.h"
+#import "ios/chrome/browser/ui/url_loader.h"
+#import "ios/chrome/browser/ui/util/constraints_ui_util.h"
+#import "ios/chrome/browser/ui/util/top_view_controller.h"
+#include "ios/chrome/grit/ios_chromium_strings.h"
+#include "ios/chrome/grit/ios_strings.h"
+#include "ios/web/public/referrer.h"
+#import "ios/web/public/web_state/context_menu_params.h"
+#include "ui/base/l10n/l10n_util.h"
+
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
 #endif
 
+namespace {
+
+// Key for saving whether the Other Device section is collapsed.
+NSString* const kOtherDeviceCollapsedKey = @"OtherDevicesCollapsed";
+
+// Key for saving whether the Recently Closed section is collapsed.
+NSString* const kRecentlyClosedCollapsedKey = @"RecentlyClosedCollapsed";
+
+// Tag to extract the section headers from the cells.
+enum { kSectionHeader = 1 };
+
+// Margin at the top of the sigin-in promo view.
+const CGFloat kSigninPromoViewTopMargin = 24;
+
+// Types of sections.
+enum SectionType {
+  SEPARATOR_SECTION,
+  CLOSED_TAB_SECTION,
+  OTHER_DEVICES_SECTION,
+  SESSION_SECTION,
+};
+
+// Types of cells.
+enum CellType {
+  CELL_CLOSED_TAB_SECTION_HEADER,
+  CELL_CLOSED_TAB_DATA,
+  CELL_SHOW_FULL_HISTORY,
+  CELL_SEPARATOR,
+  CELL_OTHER_DEVICES_SECTION_HEADER,
+  CELL_OTHER_DEVICES_SIGNED_IN_SYNC_OFF,
+  CELL_OTHER_DEVICES_SIGNED_IN_SYNC_ON_NO_SESSIONS,
+  CELL_OTHER_DEVICES_SIGNIN_PROMO,
+  CELL_OTHER_DEVICES_SYNC_IN_PROGRESS,
+  CELL_SESSION_SECTION_HEADER,
+  CELL_SESSION_TAB_DATA,
+};
+
+}  // namespace
+
+@interface RecentTabsTableViewController ()<SigninPromoViewConsumer,
+                                            SigninPresenter,
+                                            SyncPresenter,
+                                            UIGestureRecognizerDelegate> {
+  std::unique_ptr<synced_sessions::SyncedSessions> _syncedSessions;
+}
+// The service that manages the recently closed tabs
+@property(nonatomic, assign) sessions::TabRestoreService* tabRestoreService;
+// The sync state.
+@property(nonatomic, assign) SessionsSyncUserState sessionState;
+// Handles displaying the context menu for all form factors.
+@property(nonatomic, strong) ContextMenuCoordinator* contextMenuCoordinator;
+@property(nonatomic, strong) SigninPromoViewMediator* signinPromoViewMediator;
+@end
+
 @implementation RecentTabsTableViewController : ChromeTableViewController
 @synthesize browserState = _browserState;
+@synthesize contextMenuCoordinator = _contextMenuCoordinator;
+@synthesize delegate = delegate_;
 @synthesize dispatcher = _dispatcher;
+@synthesize handsetCommandHandler = _handsetCommandHandler;
 @synthesize loader = _loader;
+@synthesize sessionState = _sessionState;
+@synthesize signinPromoViewMediator = _signinPromoViewMediator;
+@synthesize tabRestoreService = _tabRestoreService;
 
 #pragma mark - Public Interface
 
@@ -23,23 +128,852 @@
     _dispatcher = dispatcher;
     _loader = loader;
     _browserState = browserState;
+    _sessionState = SessionsSyncUserState::USER_SIGNED_OUT;
+    _syncedSessions.reset(new synced_sessions::SyncedSessions());
   }
   return self;
 }
 
-// TODO(crbug.com/805135)
-- (void)refreshUserState:(SessionsSyncUserState)state {
+- (void)dealloc {
+  [_signinPromoViewMediator signinPromoViewRemoved];
 }
 
-// TODO(crbug.com/805135)
-- (void)refreshRecentlyClosedTabs {
+- (void)viewDidLoad {
+  [super viewDidLoad];
+  self.view.accessibilityIdentifier =
+      kRecentTabsTableViewControllerAccessibilityIdentifier;
+  self.tableView.rowHeight = UITableViewAutomaticDimension;
+  self.tableView.estimatedRowHeight =
+      [SessionTabDataView desiredHeightInUITableViewCell];
+  [self.tableView setSeparatorColor:[UIColor clearColor]];
+  [self.tableView setDataSource:self];
+  [self.tableView setDelegate:self];
+  UILongPressGestureRecognizer* longPress =
+      [[UILongPressGestureRecognizer alloc]
+          initWithTarget:self
+                  action:@selector(handleLongPress:)];
+  longPress.delegate = self;
+  [self.tableView addGestureRecognizer:longPress];
 }
 
-// TODO(crbug.com/805135)
-- (void)setTabRestoreService:(sessions::TabRestoreService*)tabRestoreService {
+- (SectionType)sectionType:(NSInteger)section {
+  if (section == 0) {
+    return CLOSED_TAB_SECTION;
+  }
+  if (section == 1) {
+    return SEPARATOR_SECTION;
+  }
+  if (section < [self numberOfSectionsBeforeSessionOrOtherDevicesSections]) {
+    return CLOSED_TAB_SECTION;
+  }
+  if (self.sessionState ==
+      SessionsSyncUserState::USER_SIGNED_IN_SYNC_ON_WITH_SESSIONS) {
+    return SESSION_SECTION;
+  }
+  // Other cases of recent_tabs::USER_SIGNED_IN_SYNC_OFF,
+  // recent_tabs::USER_SIGNED_IN_SYNC_ON_NO_SESSIONS, and
+  // recent_tabs::USER_SIGNED_OUT falls through to here.
+  return OTHER_DEVICES_SECTION;
 }
-// TODO(crbug.com/805135)
+
+- (CellType)cellType:(NSIndexPath*)indexPath {
+  SectionType sectionType = [self sectionType:indexPath.section];
+  switch (sectionType) {
+    case CLOSED_TAB_SECTION:
+      if (indexPath.row == 0) {
+        return CELL_CLOSED_TAB_SECTION_HEADER;
+      }
+      // The last cell of the section is to access the history panel.
+      if (indexPath.row ==
+          [self numberOfCellsInRecentlyClosedTabsSection] - 1) {
+        return CELL_SHOW_FULL_HISTORY;
+      }
+      return CELL_CLOSED_TAB_DATA;
+    case SEPARATOR_SECTION:
+      return CELL_SEPARATOR;
+    case SESSION_SECTION:
+      if (indexPath.row == 0) {
+        return CELL_SESSION_SECTION_HEADER;
+      }
+      return CELL_SESSION_TAB_DATA;
+    case OTHER_DEVICES_SECTION:
+      if (self.sessionState ==
+          SessionsSyncUserState::USER_SIGNED_IN_SYNC_IN_PROGRESS) {
+        return CELL_OTHER_DEVICES_SYNC_IN_PROGRESS;
+      }
+      if (indexPath.row == 0) {
+        return CELL_OTHER_DEVICES_SECTION_HEADER;
+      }
+      switch (self.sessionState) {
+        case SessionsSyncUserState::USER_SIGNED_OUT:
+          return CELL_OTHER_DEVICES_SIGNIN_PROMO;
+        case SessionsSyncUserState::USER_SIGNED_IN_SYNC_OFF:
+          return CELL_OTHER_DEVICES_SIGNED_IN_SYNC_OFF;
+        case SessionsSyncUserState::USER_SIGNED_IN_SYNC_ON_NO_SESSIONS:
+          return CELL_OTHER_DEVICES_SIGNED_IN_SYNC_ON_NO_SESSIONS;
+        case SessionsSyncUserState::USER_SIGNED_IN_SYNC_ON_WITH_SESSIONS:
+        case SessionsSyncUserState::USER_SIGNED_IN_SYNC_IN_PROGRESS:
+          NOTREACHED();
+          // These cases should never occur. Still, this method needs to
+          // return _something_, so it's returning the least wrong cell type.
+          return CELL_OTHER_DEVICES_SIGNED_IN_SYNC_ON_NO_SESSIONS;
+      }
+  }
+}
+
+- (NSInteger)sectionIndexForSectionType:(SectionType)sectionType {
+  NSUInteger sectionCount = [self numberOfSectionsInTableView:self.tableView];
+  for (NSUInteger sectionIndex = 0; sectionIndex < sectionCount;
+       ++sectionIndex) {
+    if ([self sectionType:sectionIndex] == sectionType)
+      return sectionIndex;
+  }
+  return NSNotFound;
+}
+
+- (NSInteger)numberOfSectionsBeforeSessionOrOtherDevicesSections {
+  // The 2 sections are CLOSED_TAB_SECTION and SEPARATOR_SECTION.
+  return 2;
+}
+
 - (void)dismissModals {
+  [self.contextMenuCoordinator stop];
+}
+
+#pragma mark - Recently closed tab helpers
+
+- (void)refreshRecentlyClosedTabs {
+  [self.tableView reloadData];
+}
+
+- (void)setTabRestoreService:(sessions::TabRestoreService*)tabRestoreService {
+  _tabRestoreService = tabRestoreService;
+}
+
+- (NSInteger)numberOfCellsInRecentlyClosedTabsSection {
+  // + 2 because of the section header, and the "Show full history" cell.
+  return [self numberOfRecentlyClosedTabs] + 2;
+}
+
+- (NSInteger)numberOfRecentlyClosedTabs {
+  if (!self.tabRestoreService)
+    return 0;
+  return static_cast<NSInteger>(self.tabRestoreService->entries().size());
+}
+
+- (const sessions::TabRestoreService::Entry*)tabRestoreEntryAtIndex:
+    (NSIndexPath*)indexPath {
+  DCHECK_EQ([self sectionType:indexPath.section], CLOSED_TAB_SECTION);
+  // "- 1" because of the section header.
+  NSInteger index = indexPath.row - 1;
+  DCHECK_LE(index, [self numberOfRecentlyClosedTabs]);
+  if (!self.tabRestoreService)
+    return nullptr;
+
+  // Advance the entry iterator to the correct index.
+  // Note that std:list<> can only be accessed sequentially, which is
+  // suboptimal when using Cocoa table APIs. This list doesn't appear
+  // to get very long, so it probably won't matter for perf.
+  sessions::TabRestoreService::Entries::const_iterator iter =
+      self.tabRestoreService->entries().begin();
+  std::advance(iter, index);
+  CHECK(*iter);
+  return iter->get();
+}
+
+#pragma mark - Helpers to open tabs, or show the full history view.
+
+- (void)dismissRecentTabsModal {
+  [self.handsetCommandHandler dismissRecentTabsWithCompletion:nil];
+}
+
+- (void)openTabWithContentOfDistantTab:
+    (synced_sessions::DistantTab const*)distantTab {
+  sync_sessions::OpenTabsUIDelegate* openTabs =
+      IOSChromeProfileSyncServiceFactory::GetForBrowserState(self.browserState)
+          ->GetOpenTabsUIDelegate();
+  const sessions::SessionTab* toLoad = nullptr;
+  [self dismissRecentTabsModal];
+  if (openTabs->GetForeignTab(distantTab->session_tag, distantTab->tab_id,
+                              &toLoad)) {
+    base::RecordAction(base::UserMetricsAction(
+        "MobileRecentTabManagerTabFromOtherDeviceOpened"));
+    new_tab_page_uma::RecordAction(
+        self.browserState, new_tab_page_uma::ACTION_OPENED_FOREIGN_SESSION);
+    [self.loader loadSessionTab:toLoad];
+  }
+}
+
+- (void)openTabWithTabRestoreEntry:
+    (const sessions::TabRestoreService::Entry*)entry {
+  DCHECK(entry);
+  if (!entry)
+    return;
+  // We only handle the TAB type.
+  if (entry->type != sessions::TabRestoreService::TAB)
+    return;
+  TabRestoreServiceDelegateImplIOS* delegate =
+      TabRestoreServiceDelegateImplIOSFactory::GetForBrowserState(
+          self.browserState);
+  [self dismissRecentTabsModal];
+  base::RecordAction(
+      base::UserMetricsAction("MobileRecentTabManagerRecentTabOpened"));
+  new_tab_page_uma::RecordAction(
+      self.browserState, new_tab_page_uma::ACTION_OPENED_RECENTLY_CLOSED_ENTRY);
+  self.tabRestoreService->RestoreEntryById(delegate, entry->id,
+                                           WindowOpenDisposition::CURRENT_TAB);
+}
+
+- (void)openTabWithURL:(const GURL&)url {
+  if (url.is_valid()) {
+    [self dismissRecentTabsModal];
+    [self.loader loadURL:url
+                 referrer:web::Referrer()
+               transition:ui::PAGE_TRANSITION_TYPED
+        rendererInitiated:NO];
+  }
+}
+
+- (void)showFullHistory {
+  __weak RecentTabsTableViewController* weakSelf = self;
+  ProceduralBlock openHistory = ^{
+    [weakSelf.dispatcher showHistory];
+  };
+  DCHECK(self.handsetCommandHandler);
+  [self.handsetCommandHandler dismissRecentTabsWithCompletion:openHistory];
+}
+
+#pragma mark - Handling of the collapsed sections.
+
+- (void)toggleExpansionOfSection:(NSInteger)sectionIndex {
+  NSString* sectionCollapseKey = nil;
+  int cellCount = 0;
+
+  SectionType section = [self sectionType:sectionIndex];
+
+  switch (section) {
+    case CLOSED_TAB_SECTION:
+      sectionCollapseKey = kRecentlyClosedCollapsedKey;
+      // - 1 because the header does not count.
+      cellCount = [self numberOfCellsInRecentlyClosedTabsSection] - 1;
+      break;
+    case SEPARATOR_SECTION:
+      NOTREACHED();
+      return;
+    case OTHER_DEVICES_SECTION:
+      cellCount = 1;
+      sectionCollapseKey = kOtherDeviceCollapsedKey;
+      break;
+    case SESSION_SECTION: {
+      size_t indexOfSession =
+          sectionIndex -
+          [self numberOfSectionsBeforeSessionOrOtherDevicesSections];
+      DCHECK_LT(indexOfSession, _syncedSessions->GetSessionCount());
+      synced_sessions::DistantSession const* distantSession =
+          _syncedSessions->GetSession(indexOfSession);
+      cellCount = distantSession->tabs.size();
+      sectionCollapseKey = [self keyForDistantSession:distantSession];
+      break;
+    }
+  }
+  DCHECK(sectionCollapseKey);
+  BOOL collapsed = ![self sectionIsCollapsed:sectionCollapseKey];
+  [self setSection:sectionCollapseKey collapsed:collapsed];
+
+  // Builds an array indexing all the cells needing to be removed or inserted to
+  // collapse/expand the section.
+  NSMutableArray* cellIndexPathsToDeleteOrInsert = [NSMutableArray array];
+  for (int i = 1; i <= cellCount; i++) {
+    NSIndexPath* tabIndexPath =
+        [NSIndexPath indexPathForRow:i inSection:sectionIndex];
+    [cellIndexPathsToDeleteOrInsert addObject:tabIndexPath];
+  }
+
+  // Update the table view.
+  [self.tableView beginUpdates];
+  if (collapsed) {
+    [self.tableView deleteRowsAtIndexPaths:cellIndexPathsToDeleteOrInsert
+                          withRowAnimation:UITableViewRowAnimationFade];
+  } else {
+    [self.tableView insertRowsAtIndexPaths:cellIndexPathsToDeleteOrInsert
+                          withRowAnimation:UITableViewRowAnimationFade];
+  }
+  [self.tableView endUpdates];
+
+  // Rotate disclosure icon.
+  NSIndexPath* sectionCellIndexPath =
+      [NSIndexPath indexPathForRow:0 inSection:sectionIndex];
+  UITableViewCell* sectionCell =
+      [self.tableView cellForRowAtIndexPath:sectionCellIndexPath];
+  UIView* subview = [sectionCell viewWithTag:kSectionHeader];
+  DCHECK([subview
+      conformsToProtocol:@protocol(HeaderOfCollapsableSectionProtocol)]);
+  id<HeaderOfCollapsableSectionProtocol> headerView =
+      static_cast<id<HeaderOfCollapsableSectionProtocol>>(subview);
+  [headerView setSectionIsCollapsed:collapsed animated:YES];
+}
+
+- (NSString*)keyForDistantSession:
+    (synced_sessions::DistantSession const*)distantSession {
+  return base::SysUTF8ToNSString(distantSession->tag);
+}
+
+- (void)setSection:(NSString*)sectionKey collapsed:(BOOL)collapsed {
+  // TODO(crbug.com/419346): Store in the browser state preference instead of
+  // NSUserDefaults.
+  NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
+  NSDictionary* collapsedSections =
+      [defaults dictionaryForKey:kCollapsedSectionsKey];
+  NSMutableDictionary* newCollapsedSessions =
+      [NSMutableDictionary dictionaryWithDictionary:collapsedSections];
+  NSNumber* value = [NSNumber numberWithBool:collapsed];
+  [newCollapsedSessions setValue:value forKey:sectionKey];
+  [defaults setObject:newCollapsedSessions forKey:kCollapsedSectionsKey];
+}
+
+- (BOOL)sectionIsCollapsed:(NSString*)sectionKey {
+  // TODO(crbug.com/419346): Store in the profile's preference instead of the
+  // NSUserDefaults.
+  DCHECK(sectionKey);
+  NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
+  NSDictionary* collapsedSessions =
+      [defaults dictionaryForKey:kCollapsedSectionsKey];
+  NSNumber* value = (NSNumber*)[collapsedSessions valueForKey:sectionKey];
+  return [value boolValue];
+}
+
+#pragma mark - Distant Sessions helpers
+
+- (void)refreshUserState:(SessionsSyncUserState)newSessionState {
+  if ((newSessionState == self.sessionState &&
+       self.sessionState !=
+           SessionsSyncUserState::USER_SIGNED_IN_SYNC_ON_WITH_SESSIONS) ||
+      self.signinPromoViewMediator.isSigninInProgress) {
+    // No need to refresh the sections.
+    return;
+  }
+
+  [self.tableView beginUpdates];
+  NSIndexSet* indexesToBeDeleted = [self sessionOrOtherDevicesSectionsIndexes];
+  [self.tableView deleteSections:indexesToBeDeleted
+                withRowAnimation:UITableViewRowAnimationFade];
+  syncer::SyncService* syncService =
+      IOSChromeProfileSyncServiceFactory::GetForBrowserState(self.browserState);
+  _syncedSessions.reset(new synced_sessions::SyncedSessions(syncService));
+  self.sessionState = newSessionState;
+
+  if (self.sessionState ==
+      SessionsSyncUserState::USER_SIGNED_IN_SYNC_IN_PROGRESS) {
+    // Expand the "Other Device" section once sync is finished.
+    [self setSection:kOtherDeviceCollapsedKey collapsed:NO];
+  }
+
+  NSIndexSet* indexesToBeInserted = [self sessionOrOtherDevicesSectionsIndexes];
+  [self.tableView insertSections:indexesToBeInserted
+                withRowAnimation:UITableViewRowAnimationFade];
+  [self.tableView endUpdates];
+
+  if (self.sessionState != SessionsSyncUserState::USER_SIGNED_OUT) {
+    [self.signinPromoViewMediator signinPromoViewRemoved];
+    self.signinPromoViewMediator = nil;
+  }
+}
+
+- (NSInteger)numberOfSessionSections {
+  DCHECK(self.sessionState ==
+         SessionsSyncUserState::USER_SIGNED_IN_SYNC_ON_WITH_SESSIONS);
+  return _syncedSessions->GetSessionCount();
+}
+
+- (NSIndexSet*)sessionOrOtherDevicesSectionsIndexes {
+  NSInteger sectionCount = 0;
+  switch (self.sessionState) {
+    case SessionsSyncUserState::USER_SIGNED_IN_SYNC_ON_WITH_SESSIONS:
+      sectionCount = [self numberOfSessionSections];
+      break;
+    case SessionsSyncUserState::USER_SIGNED_IN_SYNC_OFF:
+    case SessionsSyncUserState::USER_SIGNED_IN_SYNC_ON_NO_SESSIONS:
+    case SessionsSyncUserState::USER_SIGNED_OUT:
+    case SessionsSyncUserState::USER_SIGNED_IN_SYNC_IN_PROGRESS:
+      sectionCount = 1;
+      break;
+  }
+  NSRange rangeOfSessionSections = NSMakeRange(
+      [self numberOfSectionsBeforeSessionOrOtherDevicesSections], sectionCount);
+  NSIndexSet* sessionSectionsIndexes =
+      [NSIndexSet indexSetWithIndexesInRange:rangeOfSessionSections];
+  return sessionSectionsIndexes;
+}
+
+- (size_t)indexOfSessionAtIndexPath:(NSIndexPath*)indexPath {
+  DCHECK_EQ([self sectionType:indexPath.section], SESSION_SECTION);
+  size_t indexOfSession =
+      indexPath.section -
+      [self numberOfSectionsBeforeSessionOrOtherDevicesSections];
+  DCHECK_LT(indexOfSession, _syncedSessions->GetSessionCount());
+  return indexOfSession;
+}
+
+- (synced_sessions::DistantSession const*)sessionAtIndexPath:
+    (NSIndexPath*)indexPath {
+  return _syncedSessions->GetSession(
+      [self indexOfSessionAtIndexPath:indexPath]);
+}
+
+- (synced_sessions::DistantTab const*)distantTabAtIndex:
+    (NSIndexPath*)indexPath {
+  DCHECK_EQ([self sectionType:indexPath.section], SESSION_SECTION);
+  // "- 1" because of the section header.
+  size_t indexOfDistantTab = indexPath.row - 1;
+  synced_sessions::DistantSession const* session =
+      [self sessionAtIndexPath:indexPath];
+  DCHECK_LT(indexOfDistantTab, session->tabs.size());
+  return session->tabs[indexOfDistantTab].get();
+}
+
+#pragma mark - Long press and context menus
+
+- (void)handleLongPress:(UILongPressGestureRecognizer*)longPressGesture {
+  DCHECK_EQ(self.tableView, longPressGesture.view);
+  if (longPressGesture.state == UIGestureRecognizerStateBegan) {
+    CGPoint point = [longPressGesture locationInView:self.tableView];
+    NSIndexPath* indexPath = [self.tableView indexPathForRowAtPoint:point];
+    if (!indexPath)
+      return;
+    DCHECK_LE(indexPath.section,
+              [self numberOfSectionsInTableView:self.tableView]);
+
+    CellType cellType = [self cellType:indexPath];
+    if (cellType != CELL_SESSION_SECTION_HEADER) {
+      NOTREACHED();
+      return;
+    }
+
+    web::ContextMenuParams params;
+    // Get view coordinates in local space.
+    CGPoint viewCoordinate = [longPressGesture locationInView:self.tableView];
+    params.location = viewCoordinate;
+    params.view = self.tableView;
+
+    // Present sheet/popover using controller that is added to view hierarchy.
+    // TODO(crbug.com/754642): Remove TopPresentedViewController().
+    UIViewController* topController =
+        top_view_controller::TopPresentedViewController();
+
+    self.contextMenuCoordinator =
+        [[ContextMenuCoordinator alloc] initWithBaseViewController:topController
+                                                            params:params];
+
+    // Fill the sheet/popover with buttons.
+    __weak RecentTabsTableViewController* weakSelf = self;
+
+    // "Open all tabs" button.
+    NSString* openAllButtonLabel =
+        l10n_util::GetNSString(IDS_IOS_RECENT_TABS_OPEN_ALL_MENU_OPTION);
+    [self.contextMenuCoordinator
+        addItemWithTitle:openAllButtonLabel
+                  action:^{
+                    [weakSelf openTabsFromSessionAtIndexPath:indexPath];
+                  }];
+
+    // "Hide for now" button.
+    NSString* hideButtonLabel =
+        l10n_util::GetNSString(IDS_IOS_RECENT_TABS_HIDE_MENU_OPTION);
+    [self.contextMenuCoordinator
+        addItemWithTitle:hideButtonLabel
+                  action:^{
+                    [weakSelf removeSessionAtIndexPath:indexPath];
+                  }];
+
+    [self.contextMenuCoordinator start];
+  }
+}
+
+- (void)openTabsFromSessionAtIndexPath:(NSIndexPath*)indexPath {
+  synced_sessions::DistantSession const* session =
+      [self sessionAtIndexPath:indexPath];
+  [self dismissRecentTabsModal];
+  for (auto const& tab : session->tabs) {
+    [self.loader webPageOrderedOpen:tab->virtual_url
+                           referrer:web::Referrer()
+                       inBackground:YES
+                           appendTo:kLastTab];
+  }
+}
+
+- (void)removeSessionAtIndexPath:(NSIndexPath*)indexPath {
+  DCHECK_EQ([self cellType:indexPath], CELL_SESSION_SECTION_HEADER);
+  synced_sessions::DistantSession const* session =
+      [self sessionAtIndexPath:indexPath];
+  std::string sessionTagCopy = session->tag;
+  syncer::SyncService* syncService =
+      IOSChromeProfileSyncServiceFactory::GetForBrowserState(self.browserState);
+  sync_sessions::OpenTabsUIDelegate* openTabs =
+      syncService->GetOpenTabsUIDelegate();
+  _syncedSessions->EraseSession([self indexOfSessionAtIndexPath:indexPath]);
+  [self.tableView
+        deleteSections:[NSIndexSet indexSetWithIndex:indexPath.section]
+      withRowAnimation:UITableViewRowAnimationLeft];
+  // Use dispatch_async to give the action sheet a chance to cleanup before
+  // replacing its parent view.
+  dispatch_async(dispatch_get_main_queue(), ^{
+    openTabs->DeleteForeignSession(sessionTagCopy);
+  });
+}
+
+#pragma mark - UIGestureRecognizerDelegate
+
+- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer*)gestureRecognizer {
+  CGPoint point = [gestureRecognizer locationInView:self.tableView];
+  NSIndexPath* indexPath = [self.tableView indexPathForRowAtPoint:point];
+  if (!indexPath)
+    return NO;
+  CellType cellType = [self cellType:indexPath];
+  // Context menus can be opened on a section header for tabs.
+  return cellType == CELL_SESSION_SECTION_HEADER;
+}
+
+#pragma mark - UITableViewDataSource
+
+- (NSInteger)numberOfSectionsInTableView:(UITableView*)tableView {
+  switch (self.sessionState) {
+    case SessionsSyncUserState::USER_SIGNED_IN_SYNC_ON_WITH_SESSIONS:
+      return [self numberOfSectionsBeforeSessionOrOtherDevicesSections] +
+             [self numberOfSessionSections];
+    case SessionsSyncUserState::USER_SIGNED_IN_SYNC_OFF:
+    case SessionsSyncUserState::USER_SIGNED_IN_SYNC_ON_NO_SESSIONS:
+    case SessionsSyncUserState::USER_SIGNED_OUT:
+    case SessionsSyncUserState::USER_SIGNED_IN_SYNC_IN_PROGRESS:
+      return [self numberOfSectionsBeforeSessionOrOtherDevicesSections] + 1;
+  }
+}
+
+- (NSInteger)tableView:(UITableView*)tableView
+    numberOfRowsInSection:(NSInteger)section {
+  switch ([self sectionType:section]) {
+    case CLOSED_TAB_SECTION:
+      if ([self sectionIsCollapsed:kRecentlyClosedCollapsedKey])
+        return 1;
+      else
+        return [self numberOfCellsInRecentlyClosedTabsSection];
+    case SEPARATOR_SECTION:
+      return 1;
+    case OTHER_DEVICES_SECTION:
+      if (self.sessionState ==
+          SessionsSyncUserState::USER_SIGNED_IN_SYNC_IN_PROGRESS)
+        return 1;
+      if ([self sectionIsCollapsed:kOtherDeviceCollapsedKey])
+        return 1;
+      else
+        return 2;
+    case SESSION_SECTION: {
+      DCHECK(self.sessionState ==
+             SessionsSyncUserState::USER_SIGNED_IN_SYNC_ON_WITH_SESSIONS);
+      size_t sessionIndex =
+          section - [self numberOfSectionsBeforeSessionOrOtherDevicesSections];
+      DCHECK_LT(sessionIndex, _syncedSessions->GetSessionCount());
+      synced_sessions::DistantSession const* distantSession =
+          _syncedSessions->GetSession(sessionIndex);
+      NSString* key = [self keyForDistantSession:distantSession];
+      if ([self sectionIsCollapsed:key])
+        return 1;
+      else
+        return distantSession->tabs.size() + 1;
+    }
+  }
+}
+
+- (UITableViewCell*)tableView:(UITableView*)tableView
+        cellForRowAtIndexPath:(NSIndexPath*)indexPath {
+  UITableViewCell* cell =
+      [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
+                             reuseIdentifier:nil];
+  UIView* contentView = cell.contentView;
+  CGFloat contentViewTopMargin = 0;
+
+  UIView* subview;
+  CellType cellType = [self cellType:indexPath];
+  switch (cellType) {
+    case CELL_CLOSED_TAB_SECTION_HEADER: {
+      BOOL collapsed = [self sectionIsCollapsed:kRecentlyClosedCollapsedKey];
+      subview = [[GenericSectionHeaderView alloc]
+                initWithType:recent_tabs::RECENTLY_CLOSED_TABS_SECTION_HEADER
+          sectionIsCollapsed:collapsed];
+      [subview setTag:kSectionHeader];
+      break;
+    }
+    case CELL_CLOSED_TAB_DATA: {
+      SessionTabDataView* genericTabData =
+          [[SessionTabDataView alloc] initWithFrame:CGRectZero];
+      [genericTabData
+          updateWithTabRestoreEntry:[self tabRestoreEntryAtIndex:indexPath]
+                       browserState:self.browserState];
+      subview = genericTabData;
+      break;
+    }
+    case CELL_SHOW_FULL_HISTORY:
+      subview = [[ShowFullHistoryView alloc] initWithFrame:CGRectZero];
+      break;
+    case CELL_SEPARATOR:
+      subview = [[RecentlyClosedSectionFooter alloc] initWithFrame:CGRectZero];
+      [cell setSelectionStyle:UITableViewCellSelectionStyleNone];
+      break;
+    case CELL_OTHER_DEVICES_SECTION_HEADER: {
+      BOOL collapsed = [self sectionIsCollapsed:kOtherDeviceCollapsedKey];
+      subview = [[GenericSectionHeaderView alloc]
+                initWithType:recent_tabs::OTHER_DEVICES_SECTION_HEADER
+          sectionIsCollapsed:collapsed];
+      [subview setTag:kSectionHeader];
+      break;
+    }
+    case CELL_OTHER_DEVICES_SIGNED_IN_SYNC_OFF:
+      subview = [[SignedInSyncOffView alloc] initWithFrame:CGRectZero
+                                              browserState:self.browserState
+                                                 presenter:self];
+      [cell setSelectionStyle:UITableViewCellSelectionStyleNone];
+      break;
+    case CELL_OTHER_DEVICES_SIGNED_IN_SYNC_ON_NO_SESSIONS:
+      subview = [[SignedInSyncOnNoSessionsView alloc] initWithFrame:CGRectZero];
+      [cell setSelectionStyle:UITableViewCellSelectionStyleNone];
+      break;
+    case CELL_OTHER_DEVICES_SIGNIN_PROMO: {
+      if (!self.signinPromoViewMediator) {
+        self.signinPromoViewMediator = [[SigninPromoViewMediator alloc]
+            initWithBrowserState:self.browserState
+                     accessPoint:signin_metrics::AccessPoint::
+                                     ACCESS_POINT_RECENT_TABS
+                       presenter:self /* id<SigninPresenter> */];
+        self.signinPromoViewMediator.consumer = self;
+      }
+      contentViewTopMargin = kSigninPromoViewTopMargin;
+      SigninPromoView* signinPromoView =
+          [[SigninPromoView alloc] initWithFrame:CGRectZero];
+      signinPromoView.delegate = self.signinPromoViewMediator;
+      signinPromoView.textLabel.text =
+          l10n_util::GetNSString(IDS_IOS_SIGNIN_PROMO_RECENT_TABS);
+      signinPromoView.textLabel.preferredMaxLayoutWidth =
+          CGRectGetWidth(self.tableView.bounds) -
+          2 * signinPromoView.horizontalPadding;
+      SigninPromoViewConfigurator* configurator =
+          [self.signinPromoViewMediator createConfigurator];
+      [configurator configureSigninPromoView:signinPromoView];
+      subview = signinPromoView;
+      [cell setSelectionStyle:UITableViewCellSelectionStyleNone];
+      [self.signinPromoViewMediator signinPromoViewVisible];
+      break;
+    }
+    case CELL_OTHER_DEVICES_SYNC_IN_PROGRESS:
+      subview = [[SignedInSyncInProgressView alloc] initWithFrame:CGRectZero];
+      [cell setSelectionStyle:UITableViewCellSelectionStyleNone];
+      break;
+    case CELL_SESSION_SECTION_HEADER: {
+      synced_sessions::DistantSession const* distantSession =
+          [self sessionAtIndexPath:indexPath];
+      NSString* key = [self keyForDistantSession:distantSession];
+      BOOL collapsed = [self sectionIsCollapsed:key];
+      SessionSectionHeaderView* sessionSectionHeader =
+          [[SessionSectionHeaderView alloc] initWithFrame:CGRectZero
+                                       sectionIsCollapsed:collapsed];
+      [sessionSectionHeader updateWithSession:distantSession];
+      subview = sessionSectionHeader;
+      [subview setTag:kSectionHeader];
+      break;
+    }
+    case CELL_SESSION_TAB_DATA: {
+      SessionTabDataView* genericTabData =
+          [[SessionTabDataView alloc] initWithFrame:CGRectZero];
+      [genericTabData updateWithDistantTab:[self distantTabAtIndex:indexPath]
+                              browserState:self.browserState];
+      subview = genericTabData;
+      break;
+    }
+  }
+
+  DCHECK(subview);
+  [contentView addSubview:subview];
+
+  // Sets constraints on the subview.
+  [subview setTranslatesAutoresizingMaskIntoConstraints:NO];
+
+  NSDictionary* viewsDictionary = @{@"view" : subview};
+  // This set of constraints should match the constraints set on the
+  // RecentlyClosedSectionFooter.
+  // clang-format off
+  NSArray* constraints = @[
+                           @"V:|-(TopMargin)-[view]-0-|",
+                           @"H:|-(>=0)-[view(<=548)]-(>=0)-|",
+                           @"H:[view(==548@500)]"
+                           ];
+  // clang-format on
+  [contentView addConstraint:[NSLayoutConstraint
+                                 constraintWithItem:subview
+                                          attribute:NSLayoutAttributeCenterX
+                                          relatedBy:NSLayoutRelationEqual
+                                             toItem:contentView
+                                          attribute:NSLayoutAttributeCenterX
+                                         multiplier:1
+                                           constant:0]];
+  NSDictionary* metrics = @{ @"TopMargin" : @(contentViewTopMargin) };
+  ApplyVisualConstraintsWithMetrics(constraints, viewsDictionary, metrics);
+  return cell;
+}
+
+#pragma mark - UITableViewDelegate
+
+- (NSIndexPath*)tableView:(UITableView*)tableView
+    willSelectRowAtIndexPath:(NSIndexPath*)indexPath {
+  DCHECK_EQ(tableView, self.tableView);
+  CellType cellType = [self cellType:indexPath];
+  switch (cellType) {
+    case CELL_CLOSED_TAB_SECTION_HEADER:
+    case CELL_OTHER_DEVICES_SECTION_HEADER:
+    case CELL_SESSION_SECTION_HEADER:
+    case CELL_CLOSED_TAB_DATA:
+    case CELL_SESSION_TAB_DATA:
+    case CELL_SHOW_FULL_HISTORY:
+      return indexPath;
+    case CELL_SEPARATOR:
+    case CELL_OTHER_DEVICES_SIGNED_IN_SYNC_OFF:
+    case CELL_OTHER_DEVICES_SIGNED_IN_SYNC_ON_NO_SESSIONS:
+    case CELL_OTHER_DEVICES_SIGNIN_PROMO:
+    case CELL_OTHER_DEVICES_SYNC_IN_PROGRESS:
+      return nil;
+  }
+}
+
+- (void)tableView:(UITableView*)tableView
+    didSelectRowAtIndexPath:(NSIndexPath*)indexPath {
+  DCHECK_EQ(tableView, self.tableView);
+  CellType cellType = [self cellType:indexPath];
+  switch (cellType) {
+    case CELL_CLOSED_TAB_SECTION_HEADER:
+    case CELL_OTHER_DEVICES_SECTION_HEADER:
+    case CELL_SESSION_SECTION_HEADER:
+      // Collapse or uncollapse section.
+      [tableView deselectRowAtIndexPath:indexPath animated:NO];
+      [self toggleExpansionOfSection:indexPath.section];
+      break;
+    case CELL_CLOSED_TAB_DATA:
+      // Open new tab.
+      [self openTabWithTabRestoreEntry:[self tabRestoreEntryAtIndex:indexPath]];
+      break;
+    case CELL_SESSION_TAB_DATA:
+      // Open new tab.
+      [self openTabWithContentOfDistantTab:[self distantTabAtIndex:indexPath]];
+      break;
+    case CELL_SHOW_FULL_HISTORY:
+      [tableView deselectRowAtIndexPath:indexPath animated:NO];
+      [self showFullHistory];
+      break;
+    case CELL_SEPARATOR:
+    case CELL_OTHER_DEVICES_SIGNED_IN_SYNC_OFF:
+    case CELL_OTHER_DEVICES_SIGNED_IN_SYNC_ON_NO_SESSIONS:
+    case CELL_OTHER_DEVICES_SIGNIN_PROMO:
+    case CELL_OTHER_DEVICES_SYNC_IN_PROGRESS:
+      NOTREACHED();
+      break;
+  }
+}
+
+- (CGFloat)tableView:(UITableView*)tableView
+    heightForRowAtIndexPath:(NSIndexPath*)indexPath {
+  DCHECK_EQ(self.tableView, tableView);
+  CellType cellType = [self cellType:indexPath];
+  switch (cellType) {
+    case CELL_SHOW_FULL_HISTORY:
+      return [ShowFullHistoryView desiredHeightInUITableViewCell];
+    case CELL_SEPARATOR:
+      return [RecentlyClosedSectionFooter desiredHeightInUITableViewCell];
+    case CELL_OTHER_DEVICES_SIGNED_IN_SYNC_OFF:
+      return [SignedInSyncOffView desiredHeightInUITableViewCell];
+    case CELL_OTHER_DEVICES_SIGNED_IN_SYNC_ON_NO_SESSIONS:
+      return [SignedInSyncOnNoSessionsView desiredHeightInUITableViewCell];
+    case CELL_OTHER_DEVICES_SIGNIN_PROMO:
+      return UITableViewAutomaticDimension;
+    case CELL_SESSION_SECTION_HEADER:
+      return [SessionSectionHeaderView desiredHeightInUITableViewCell];
+    case CELL_CLOSED_TAB_DATA:
+    case CELL_SESSION_TAB_DATA:
+      return [SessionTabDataView desiredHeightInUITableViewCell];
+    case CELL_CLOSED_TAB_SECTION_HEADER:
+    case CELL_OTHER_DEVICES_SECTION_HEADER:
+      return [GenericSectionHeaderView desiredHeightInUITableViewCell];
+    case CELL_OTHER_DEVICES_SYNC_IN_PROGRESS:
+      return [SignedInSyncInProgressView desiredHeightInUITableViewCell];
+  }
+}
+
+- (UIView*)tableView:(UITableView*)tableView
+    viewForHeaderInSection:(NSInteger)section {
+  if ([self sectionType:section] == CLOSED_TAB_SECTION) {
+    return [[RecentlyTabsTopSpacingHeader alloc] initWithFrame:CGRectZero];
+  }
+  return nil;
+}
+
+- (CGFloat)tableView:(UITableView*)tableView
+    heightForHeaderInSection:(NSInteger)section {
+  if ([self sectionType:section] == CLOSED_TAB_SECTION) {
+    return [RecentlyTabsTopSpacingHeader desiredHeightInUITableViewCell];
+  }
+  return 0;
+}
+
+#pragma mark - SigninPromoViewConsumer
+
+- (void)configureSigninPromoWithConfigurator:
+            (SigninPromoViewConfigurator*)configurator
+                             identityChanged:(BOOL)identityChanged {
+  DCHECK(self.signinPromoViewMediator);
+  if ([self sectionIsCollapsed:kOtherDeviceCollapsedKey])
+    return;
+  NSInteger sectionIndex =
+      [self sectionIndexForSectionType:OTHER_DEVICES_SECTION];
+  DCHECK(sectionIndex != NSNotFound);
+  NSIndexPath* indexPath =
+      [NSIndexPath indexPathForRow:1 inSection:sectionIndex];
+  if (identityChanged) {
+    [self.tableView reloadRowsAtIndexPaths:@[ indexPath ]
+                          withRowAnimation:UITableViewRowAnimationNone];
+    return;
+  }
+  UITableViewCell* cell = [self.tableView cellForRowAtIndexPath:indexPath];
+  NSArray<UIView*>* contentViews = cell.contentView.subviews;
+  DCHECK(contentViews.count == 1);
+  UIView* subview = contentViews[0];
+  DCHECK([subview isKindOfClass:[SigninPromoView class]]);
+  SigninPromoView* signinPromoView = (SigninPromoView*)subview;
+  [configurator configureSigninPromoView:signinPromoView];
+}
+
+- (void)signinDidFinish {
+  [self.delegate refreshSessionsView];
+}
+
+#pragma mark - SyncPresenter
+
+- (void)showReauthenticateSignin {
+  [self.dispatcher
+              showSignin:
+                  [[ShowSigninCommand alloc]
+                      initWithOperation:AUTHENTICATION_OPERATION_REAUTHENTICATE
+                            accessPoint:signin_metrics::AccessPoint::
+                                            ACCESS_POINT_UNKNOWN]
+      baseViewController:self];
+}
+
+- (void)showSyncSettings {
+  [self.dispatcher showSyncSettingsFromViewController:self];
+}
+
+- (void)showSyncPassphraseSettings {
+  [self.dispatcher showSyncPassphraseSettingsFromViewController:self];
+}
+
+#pragma mark - SigninPresenter
+
+- (void)showSignin:(ShowSigninCommand*)command {
+  [self.dispatcher showSignin:command baseViewController:self];
 }
 
 @end
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.mm b/ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.mm
index c5bdcd0a..db2665d 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.mm
+++ b/ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.mm
@@ -537,6 +537,14 @@
   return [self layoutRightViewForBounds:bounds];
 }
 
+#pragma mark - UITextInput
+
+- (void)beginFloatingCursorAtPoint:(CGPoint)point {
+  // Exit preedit because it blocks the view of the textfield.
+  [self exitPreEditState];
+  [super beginFloatingCursorAtPoint:point];
+}
+
 #pragma mark - UIView
 
 - (void)layoutSubviews {
diff --git a/ios/chrome/browser/ui/tab_grid/BUILD.gn b/ios/chrome/browser/ui/tab_grid/BUILD.gn
index 0d24b23..57c0e97b 100644
--- a/ios/chrome/browser/ui/tab_grid/BUILD.gn
+++ b/ios/chrome/browser/ui/tab_grid/BUILD.gn
@@ -20,6 +20,7 @@
     ":tab_grid_ui",
     "//base",
     "//components/favicon/ios",
+    "//ios/chrome/browser",
     "//ios/chrome/browser/snapshots",
     "//ios/chrome/browser/tabs",
     "//ios/chrome/browser/ui/commands",
@@ -49,6 +50,7 @@
     "grid_view_controller.mm",
     "tab_grid_bottom_toolbar.h",
     "tab_grid_bottom_toolbar.mm",
+    "tab_grid_paging.h",
     "tab_grid_top_toolbar.h",
     "tab_grid_top_toolbar.mm",
     "tab_grid_transition_handler.h",
@@ -95,3 +97,38 @@
     "//third_party/ocmock",
   ]
 }
+
+source_set("eg_tests") {
+  configs += [ "//build/config/compiler:enable_arc" ]
+  testonly = true
+  sources = [
+    "tab_grid_egtest.mm",
+  ]
+
+  deps = [
+    ":tab_grid_ui",
+    "//base",
+    "//components/strings",
+    "//ios/chrome/app:app_internal",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser/ui:ui_util",
+    "//ios/chrome/browser/ui/util",
+    "//ios/chrome/test/app:test_support",
+    "//ios/chrome/test/earl_grey:test_support",
+    "//ios/testing/earl_grey:earl_grey_support",
+    "//ios/web:earl_grey_test_support",
+    "//ui/base",
+  ]
+  libs = [ "XCTest.framework" ]
+}
+
+source_set("hooks") {
+  configs += [ "//build/config/compiler:enable_arc" ]
+  testonly = true
+  sources = [
+    "tab_grid_egtests_hook.mm",
+  ]
+  deps = [
+    "//ios/chrome/app:tests_hook",
+  ]
+}
diff --git a/ios/chrome/browser/ui/tab_grid/tab_grid_adaptor.h b/ios/chrome/browser/ui/tab_grid/tab_grid_adaptor.h
index f55dc12..ea8765f9 100644
--- a/ios/chrome/browser/ui/tab_grid/tab_grid_adaptor.h
+++ b/ios/chrome/browser/ui/tab_grid/tab_grid_adaptor.h
@@ -10,6 +10,8 @@
 #import "ios/chrome/browser/ui/tab_grid/tab_grid_mediator.h"
 #import "ios/chrome/browser/ui/tab_switcher/tab_switcher.h"
 
+@protocol TabGridPaging;
+
 // An opque adaptor for the TabSwitcher protocol into the TabGrid.
 // Consuming objects should be passed instances of this object as an
 // id<TabSwitcher>.
@@ -22,6 +24,8 @@
 @property(nonatomic, weak)
     id<ApplicationCommands, BrowserCommands, OmniboxFocuser, ToolbarCommands>
         adaptedDispatcher;
+// Object that can set the current page of the tab grid.
+@property(nonatomic, weak) id<TabGridPaging> tabGridPager;
 // The mediator for the incognito grid.
 @property(nonatomic, weak) TabGridMediator* incognitoMediator;
 @end
diff --git a/ios/chrome/browser/ui/tab_grid/tab_grid_adaptor.mm b/ios/chrome/browser/ui/tab_grid/tab_grid_adaptor.mm
index 2aa1a431..3cea4bb 100644
--- a/ios/chrome/browser/ui/tab_grid/tab_grid_adaptor.mm
+++ b/ios/chrome/browser/ui/tab_grid/tab_grid_adaptor.mm
@@ -6,6 +6,8 @@
 
 #import "ios/chrome/browser/tabs/tab_model.h"
 #import "ios/chrome/browser/ui/main/view_controller_swapping.h"
+#import "ios/chrome/browser/ui/tab_grid/tab_grid_paging.h"
+
 #import "ios/web/public/navigation_manager.h"
 
 #import "base/logging.h"
@@ -21,6 +23,7 @@
 // Public properties
 @synthesize tabGridViewController = _tabGridViewController;
 @synthesize adaptedDispatcher = _adaptedDispatcher;
+@synthesize tabGridPager = _tabGridPager;
 @synthesize incognitoMediator = _incognitoMediator;
 
 #pragma mark - TabSwitcher
@@ -41,7 +44,13 @@
 - (void)restoreInternalStateWithMainTabModel:(TabModel*)mainModel
                                  otrTabModel:(TabModel*)otrModel
                               activeTabModel:(TabModel*)activeModel {
-  // This is a no-op, but it will be called frequently.
+  // The only action here is to signal to the tab grid which panel should be
+  // active.
+  if (activeModel == otrModel) {
+    self.tabGridPager.currentPage = TabGridPageIncognitoTabs;
+  } else {
+    self.tabGridPager.currentPage = TabGridPageRegularTabs;
+  }
 }
 
 - (void)prepareForDisplayAtSize:(CGSize)size {
diff --git a/ios/chrome/browser/ui/tab_grid/tab_grid_coordinator.mm b/ios/chrome/browser/ui/tab_grid/tab_grid_coordinator.mm
index 7a962ad..36125dc 100644
--- a/ios/chrome/browser/ui/tab_grid/tab_grid_coordinator.mm
+++ b/ios/chrome/browser/ui/tab_grid/tab_grid_coordinator.mm
@@ -4,6 +4,7 @@
 
 #import "ios/chrome/browser/ui/tab_grid/tab_grid_coordinator.h"
 
+#include "ios/chrome/browser/chrome_url_constants.h"
 #import "ios/chrome/browser/tabs/tab_model.h"
 #import "ios/chrome/browser/ui/commands/browser_commands.h"
 #import "ios/chrome/browser/ui/commands/command_dispatcher.h"
@@ -93,6 +94,7 @@
   self.adaptor.adaptedDispatcher =
       static_cast<id<ApplicationCommands, BrowserCommands, OmniboxFocuser,
                      ToolbarCommands>>(self.dispatcher);
+  self.adaptor.tabGridPager = mainViewController;
 
   self.regularTabsMediator = [[TabGridMediator alloc]
       initWithConsumer:mainViewController.regularTabsConsumer];
@@ -204,6 +206,15 @@
 #pragma mark - BrowserCommands
 
 - (void)openNewTab:(OpenNewTabCommand*)command {
+  TabModel* activeTabModel =
+      command.incognito ? self.incognitoTabModel : self.regularTabModel;
+  // TODO(crbug.com/804587) : It is better to use the mediator to insert a
+  // webState and show the active tab.
+  [self.tabSwitcher
+      dismissWithNewTabAnimationToModel:activeTabModel
+                                withURL:GURL(kChromeUINewTabURL)
+                                atIndex:NSNotFound
+                             transition:ui::PAGE_TRANSITION_TYPED];
 }
 
 - (void)closeAllTabs {
diff --git a/ios/chrome/browser/ui/tab_grid/tab_grid_egtest.mm b/ios/chrome/browser/ui/tab_grid/tab_grid_egtest.mm
new file mode 100644
index 0000000..2488df3
--- /dev/null
+++ b/ios/chrome/browser/ui/tab_grid/tab_grid_egtest.mm
@@ -0,0 +1,37 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/ui/tab_grid/tab_grid_view_controller.h"
+#import "ios/chrome/test/app/chrome_test_util.h"
+#import "ios/chrome/test/earl_grey/chrome_earl_grey.h"
+#import "ios/chrome/test/earl_grey/chrome_earl_grey_ui.h"
+#import "ios/chrome/test/earl_grey/chrome_matchers.h"
+#import "ios/chrome/test/earl_grey/chrome_test_case.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace {
+// Matcher for done button in tab grid.
+id<GREYMatcher> TabGridDoneButton() {
+  return grey_allOf(grey_accessibilityID(kTabGridDoneButtonAccessibilityID),
+                    grey_sufficientlyVisible(), nil);
+}
+}  // namespace
+
+@interface TabGridTestCase : ChromeTestCase
+@end
+
+@implementation TabGridTestCase
+
+// Tests entering and leaving the tab grid.
+- (void)testEnteringAndLeavingTabGrid {
+  [[EarlGrey selectElementWithMatcher:chrome_test_util::ShowTabsButton()]
+      performAction:grey_tap()];
+  [[EarlGrey selectElementWithMatcher:TabGridDoneButton()]
+      performAction:grey_tap()];
+}
+
+@end
diff --git a/ios/chrome/browser/ui/tab_grid/tab_grid_egtests_hook.mm b/ios/chrome/browser/ui/tab_grid/tab_grid_egtests_hook.mm
new file mode 100644
index 0000000..681321c
--- /dev/null
+++ b/ios/chrome/browser/ui/tab_grid/tab_grid_egtests_hook.mm
@@ -0,0 +1,54 @@
+// 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 "ios/chrome/app/tests_hook.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace tests_hook {
+
+bool DisableContentSuggestions() {
+  return true;
+}
+
+bool DisableContextualSearch() {
+  return true;
+}
+
+bool DisableFirstRun() {
+  return true;
+}
+
+bool DisableGeolocation() {
+  return true;
+}
+
+bool DisableSigninRecallPromo() {
+  return true;
+}
+
+bool DisableUpdateService() {
+  return true;
+}
+
+bool ForceUIRefreshPhase1() {
+  return true;
+}
+
+// TODO(crbug.com/818560) : Remove this hook.
+bool ForceTabSwitcherTabGrid() {
+  return true;
+}
+
+void SetUpTestsIfPresent() {
+  // No-op for Earl Grey.
+}
+
+void RunTestsIfPresent() {
+  // No-op for Earl Grey.
+}
+
+}  // namespace tests_hook
diff --git a/ios/chrome/browser/ui/tab_grid/tab_grid_paging.h b/ios/chrome/browser/ui/tab_grid/tab_grid_paging.h
new file mode 100644
index 0000000..c1dbea7
--- /dev/null
+++ b/ios/chrome/browser/ui/tab_grid/tab_grid_paging.h
@@ -0,0 +1,22 @@
+// 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 IOS_CHROME_BROWSER_UI_TAB_GRID_TAB_GRID_PAGING_H_
+#define IOS_CHROME_BROWSER_UI_TAB_GRID_TAB_GRID_PAGING_H_
+
+// Page enumerates the kinds of grouped tabs.
+typedef NS_ENUM(NSUInteger, TabGridPage) {
+  TabGridPageIncognitoTabs = 0,
+  TabGridPageRegularTabs = 1,
+  TabGridPageRemoteTabs = 2,
+};
+
+// An object implementing this protocol can change the active "page" of the tab
+// grid.
+@protocol TabGridPaging<NSObject>
+// Current visible page of the tab grid.
+@property(nonatomic, assign) TabGridPage currentPage;
+@end
+
+#endif  // IOS_CHROME_BROWSER_UI_TAB_GRID_TAB_GRID_PAGING_H_
diff --git a/ios/chrome/browser/ui/tab_grid/tab_grid_view_controller.h b/ios/chrome/browser/ui/tab_grid/tab_grid_view_controller.h
index b94a268..0f9882f7 100644
--- a/ios/chrome/browser/ui/tab_grid/tab_grid_view_controller.h
+++ b/ios/chrome/browser/ui/tab_grid/tab_grid_view_controller.h
@@ -7,18 +7,16 @@
 
 #import <UIKit/UIKit.h>
 
+#import "ios/chrome/browser/ui/tab_grid/tab_grid_paging.h"
 #import "ios/chrome/browser/ui/tab_grid/tab_grid_transition_state_provider.h"
 
 @protocol GridConsumer;
 @protocol GridCommands;
 @protocol GridImageDataSource;
 
-// Page enumerates the kinds of grouped tabs.
-typedef NS_ENUM(NSUInteger, TabGridPage) {
-  TabGridPageIncognitoTabs = 0,
-  TabGridPageRegularTabs = 1,
-  TabGridPageRemoteTabs = 2,
-};
+// TODO(crbug.com/818198) : Move to constants file.
+// The accessibility label for the done button for use in test automation.
+extern NSString* const kTabGridDoneButtonAccessibilityID;
 
 // Delegate protocol for an object that can handle presenting ("opening") tabs
 // from the tab grid.
@@ -30,7 +28,7 @@
 // View controller representing a tab switcher.  The tab switcher has an
 // incognito tab grid, regular tab grid, and remote tabs.
 @interface TabGridViewController
-    : UIViewController<TabGridTransitionStateProvider>
+    : UIViewController<TabGridPaging, TabGridTransitionStateProvider>
 
 // Delegate for this view controller to handle presenting tab UI.
 @property(nonatomic, weak) id<TabPresentationDelegate> tabPresentationDelegate;
@@ -47,9 +45,6 @@
 @property(nonatomic, weak) id<GridImageDataSource> regularTabsImageDataSource;
 @property(nonatomic, weak) id<GridImageDataSource> incognitoTabsImageDataSource;
 
-// Current visible page.
-@property(nonatomic, assign) TabGridPage currentPage;
-
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_TAB_GRID_TAB_GRID_VIEW_CONTROLLER_H_
diff --git a/ios/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm b/ios/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm
index be2bc89..6e0d026 100644
--- a/ios/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm
+++ b/ios/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm
@@ -16,6 +16,10 @@
 #error "This file requires ARC support."
 #endif
 
+// The accessibility label for the done button for use in test automation.
+NSString* const kTabGridDoneButtonAccessibilityID =
+    @"TabGridDoneButtonAccessibilityID";
+
 namespace {
 // Temporary alert used while building this feature.
 UIAlertController* NotImplementedAlert() {
@@ -53,6 +57,7 @@
 @synthesize incognitoTabsDelegate = _incognitoTabsDelegate;
 @synthesize regularTabsImageDataSource = _regularTabsImageDataSource;
 @synthesize incognitoTabsImageDataSource = _incognitoTabsImageDataSource;
+// TabGridPaging property.
 @synthesize currentPage = _currentPage;
 // Private properties.
 @synthesize regularTabsViewController = _regularTabsViewController;
@@ -89,6 +94,13 @@
   [self setupBottomToolbarButtons];
 }
 
+- (void)viewWillAppear:(BOOL)animated {
+  // Call the current page setter to sync the scroll view offset to the current
+  // page value.
+  self.currentPage = _currentPage;
+  [super viewWillAppear:animated];
+}
+
 - (void)viewWillLayoutSubviews {
   [super viewWillLayoutSubviews];
   // The content inset of the tab grids must be modified so that the toolbars
@@ -121,7 +133,7 @@
   CGFloat pageWidth = scrollView.frame.size.width;
   float fractionalPage = scrollView.contentOffset.x / pageWidth;
   NSUInteger page = lround(fractionalPage);
-  self.currentPage = static_cast<TabGridPage>(page);
+  _currentPage = static_cast<TabGridPage>(page);
 }
 
 #pragma mark - UIScrollViewAccessibilityDelegate
@@ -168,6 +180,31 @@
   _incognitoTabsImageDataSource = incognitoTabsImageDataSource;
 }
 
+#pragma mark - TabGridPaging
+
+- (void)setCurrentPage:(TabGridPage)currentPage {
+  // This method should never early return if |currentPage| == |_currentPage|;
+  // the ivar may have been set before the scroll view could be updated. Calling
+  // this method should always update the scroll view's offset if possible.
+
+  // If the view isn't loaded yet, just do bookkeeping on _currentPage.
+  if (!self.viewLoaded) {
+    _currentPage = currentPage;
+    return;
+  }
+  CGFloat pageWidth = self.scrollView.frame.size.width;
+  NSUInteger page = static_cast<NSUInteger>(currentPage);
+  CGPoint offset = CGPointMake(page * pageWidth, 0);
+  // If the view is visible, animate the change. Otherwise don't.
+  if (self.view.window == nil) {
+    self.scrollView.contentOffset = offset;
+    _currentPage = currentPage;
+  } else {
+    [self.scrollView setContentOffset:offset animated:YES];
+    // _currentPage is set in scrollViewDidEndDecelerating:
+  }
+}
+
 #pragma mark - Private
 
 // Adds the scroll view and sets constraints.
@@ -356,6 +393,7 @@
 - (void)setupTopToolbarButtons {
   self.doneButton = self.topToolbar.leadingButton;
   self.closeAllButton = self.topToolbar.trailingButton;
+  self.doneButton.accessibilityIdentifier = kTabGridDoneButtonAccessibilityID;
   // TODO(crbug.com/818699) : Localize strings.
   [self.doneButton setTitle:@"Done" forState:UIControlStateNormal];
   [self.closeAllButton setTitle:@"Close All" forState:UIControlStateNormal];
diff --git a/ios/chrome/browser/ui/toolbar/adaptive/adaptive_toolbar_eg_tests_hook.mm b/ios/chrome/browser/ui/toolbar/adaptive/adaptive_toolbar_eg_tests_hook.mm
index 7fa1b5b..15a705f 100644
--- a/ios/chrome/browser/ui/toolbar/adaptive/adaptive_toolbar_eg_tests_hook.mm
+++ b/ios/chrome/browser/ui/toolbar/adaptive/adaptive_toolbar_eg_tests_hook.mm
@@ -38,6 +38,11 @@
   return true;
 }
 
+// TODO(crbug.com/818560) : Remove this hook.
+bool ForceTabSwitcherTabGrid() {
+  return false;
+}
+
 void SetUpTestsIfPresent() {
   // No-op for Earl Grey.
 }
diff --git a/ios/chrome/browser/ui/toolbar/adaptive/adaptive_toolbar_egtest.mm b/ios/chrome/browser/ui/toolbar/adaptive/adaptive_toolbar_egtest.mm
index 0609fd70..d02f3d45 100644
--- a/ios/chrome/browser/ui/toolbar/adaptive/adaptive_toolbar_egtest.mm
+++ b/ios/chrome/browser/ui/toolbar/adaptive/adaptive_toolbar_egtest.mm
@@ -128,24 +128,20 @@
     // Split toolbar.
 
     // Test the visibility of the primary toolbar buttons.
-    [[EarlGrey selectElementWithMatcher:chrome_test_util::BackButton()]
-        assertWithMatcher:VisibleInPrimaryToolbar()];
-    [[EarlGrey selectElementWithMatcher:chrome_test_util::ForwardButton()]
-        assertWithMatcher:VisibleInPrimaryToolbar()];
     [[EarlGrey selectElementWithMatcher:chrome_test_util::Omnibox()]
         assertWithMatcher:VisibleInPrimaryToolbar()];
 
     // Test the visibility of the secondary toolbar buttons.
-    [[EarlGrey selectElementWithMatcher:chrome_test_util::
-                                            ButtonWithAccessibilityLabelId(
-                                                IDS_IOS_TOOLBAR_SHOW_TABS)]
+    [[EarlGrey selectElementWithMatcher:chrome_test_util::BackButton()]
         assertWithMatcher:VisibleInSecondaryToolbar()];
-    [[EarlGrey selectElementWithMatcher:ShareButton()]
+    [[EarlGrey selectElementWithMatcher:chrome_test_util::ForwardButton()]
         assertWithMatcher:VisibleInSecondaryToolbar()];
     [[EarlGrey selectElementWithMatcher:grey_accessibilityID(
                                             kToolbarOmniboxButtonIdentifier)]
         assertWithMatcher:VisibleInSecondaryToolbar()];
-    [[EarlGrey selectElementWithMatcher:BookmarkButton()]
+    [[EarlGrey selectElementWithMatcher:chrome_test_util::
+                                            ButtonWithAccessibilityLabelId(
+                                                IDS_IOS_TOOLBAR_SHOW_TABS)]
         assertWithMatcher:VisibleInSecondaryToolbar()];
     [[EarlGrey selectElementWithMatcher:chrome_test_util::
                                             ButtonWithAccessibilityLabelId(
@@ -203,14 +199,8 @@
                                   IDS_CANCEL),
                               VisibleInPrimaryToolbar(), nil)]
         assertWithMatcher:grey_notNil()];
-
-    // Check that controls are faded out.
-    [[EarlGrey selectElementWithMatcher:chrome_test_util::ForwardButton()]
-        assertWithMatcher:grey_not(grey_sufficientlyVisible())];
-    [[EarlGrey selectElementWithMatcher:chrome_test_util::BackButton()]
-        assertWithMatcher:grey_not(grey_sufficientlyVisible())];
   } else {
-    // Check that the cancel button is shown.
+    // Check that the cancel button is hidden.
     [[EarlGrey
         selectElementWithMatcher:
             grey_allOf(
@@ -236,6 +226,12 @@
 
 // Tests that bookmarks button is selected for the bookmarked pages.
 - (void)testBookmarkButton {
+  if (!IsIPadIdiom()) {
+    // If this test is run on an iPhone, rotate it to have the unsplit toolbar.
+    [EarlGrey rotateDeviceToOrientation:UIDeviceOrientationLandscapeLeft
+                             errorOrNil:nil];
+  }
+
   // Setup the bookmarks.
   [ChromeEarlGrey waitForBookmarksToFinishLoading];
   GREYAssert(chrome_test_util::ClearBookmarks(),
@@ -270,6 +266,12 @@
   // Clean the bookmarks
   GREYAssert(chrome_test_util::ClearBookmarks(),
              @"Not all bookmarks were removed.");
+
+  if (!IsIPadIdiom()) {
+    // Cancel rotation.
+    [EarlGrey rotateDeviceToOrientation:UIDeviceOrientationPortrait
+                             errorOrNil:nil];
+  }
 }
 
 // Tests that tapping a button cancels the focus on the omnibox.
@@ -469,20 +471,28 @@
 
 // Tests share button is enabled only on pages that can be shared.
 - (void)testShareButton {
+  if (!IsIPadIdiom()) {
+    // If this test is run on an iPhone, rotate it to have the unsplit toolbar.
+    [EarlGrey rotateDeviceToOrientation:UIDeviceOrientationLandscapeLeft
+                             errorOrNil:nil];
+  }
+
   // Setup the server.
   self.testServer->RegisterRequestHandler(
       base::BindRepeating(&StandardResponse));
   GREYAssertTrue(self.testServer->Start(), @"Test server failed to start.");
   const GURL pageURL = self.testServer->GetURL(kPageURL);
 
-  // The button is disabled on the NTP.
-  [[EarlGrey selectElementWithMatcher:ShareButton()]
-      assertWithMatcher:grey_not(grey_enabled())];
-
   // Navigate to another page and check that the share button is enabled.
   [ChromeEarlGrey loadURL:pageURL];
   [[EarlGrey selectElementWithMatcher:ShareButton()]
       assertWithMatcher:grey_interactable()];
+
+  if (!IsIPadIdiom()) {
+    // Cancel rotation.
+    [EarlGrey rotateDeviceToOrientation:UIDeviceOrientationPortrait
+                             errorOrNil:nil];
+  }
 }
 
 // Verifies the existence and state of toolbar UI elements.
diff --git a/ios/chrome/browser/ui/toolbar/adaptive/adaptive_toolbar_view.h b/ios/chrome/browser/ui/toolbar/adaptive/adaptive_toolbar_view.h
index aed7ce9f..e772597 100644
--- a/ios/chrome/browser/ui/toolbar/adaptive/adaptive_toolbar_view.h
+++ b/ios/chrome/browser/ui/toolbar/adaptive/adaptive_toolbar_view.h
@@ -24,6 +24,8 @@
 
 // Button to navigate back.
 @property(nonatomic, strong, readonly) ToolbarButton* backButton;
+// Buttons to navigate forward.
+@property(nonatomic, strong, readonly) ToolbarButton* forwardButton;
 // Button to display the TabGrid.
 @property(nonatomic, strong, readonly) ToolbarTabGridButton* tabGridButton;
 // Button to stop the loading of the page.
@@ -39,15 +41,6 @@
 // Button to display the tools menu.
 @property(nonatomic, strong, readonly) ToolbarButton* omniboxButton;
 
-// The following 2 properties are for the two buttons to navigate forward that
-// are visible in various mutually exclusive configurations of the toolbar.
-// Forward button when it's positioned on the leading side of the toolbar
-// (relatively to the omnibox) | ← → [omnibox] ㉈ â‹® |.
-@property(nonatomic, strong, readonly) ToolbarButton* forwardLeadingButton;
-// Forward button when it's positioned on the trailing side of the toolbar
-// (relatively to the omnibox) | ← [omnibox] → |.
-@property(nonatomic, strong, readonly) ToolbarButton* forwardTrailingButton;
-
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_TOOLBAR_ADAPTIVE_ADAPTIVE_TOOLBAR_VIEW_H_
diff --git a/ios/chrome/browser/ui/toolbar/adaptive/adaptive_toolbar_view_controller.mm b/ios/chrome/browser/ui/toolbar/adaptive/adaptive_toolbar_view_controller.mm
index e007aaf..bae75e8 100644
--- a/ios/chrome/browser/ui/toolbar/adaptive/adaptive_toolbar_view_controller.mm
+++ b/ios/chrome/browser/ui/toolbar/adaptive/adaptive_toolbar_view_controller.mm
@@ -73,8 +73,7 @@
 #pragma mark - ToolbarConsumer
 
 - (void)setCanGoForward:(BOOL)canGoForward {
-  self.view.forwardLeadingButton.enabled = canGoForward;
-  self.view.forwardTrailingButton.enabled = canGoForward;
+  self.view.forwardButton.enabled = canGoForward;
 }
 
 - (void)setCanGoBack:(BOOL)canGoBack {
@@ -179,10 +178,12 @@
 
 // Records the use of a button.
 - (IBAction)recordUserMetrics:(id)sender {
+  if (!sender)
+    return;
+
   if (sender == self.view.backButton) {
     base::RecordAction(base::UserMetricsAction("MobileToolbarBack"));
-  } else if (sender == self.view.forwardLeadingButton ||
-             sender == self.view.forwardTrailingButton) {
+  } else if (sender == self.view.forwardButton) {
     base::RecordAction(base::UserMetricsAction("MobileToolbarForward"));
   } else if (sender == self.view.reloadButton) {
     base::RecordAction(base::UserMetricsAction("MobileToolbarReload"));
diff --git a/ios/chrome/browser/ui/toolbar/adaptive/primary_toolbar_view.h b/ios/chrome/browser/ui/toolbar/adaptive/primary_toolbar_view.h
index a58f569..6f8d9e9 100644
--- a/ios/chrome/browser/ui/toolbar/adaptive/primary_toolbar_view.h
+++ b/ios/chrome/browser/ui/toolbar/adaptive/primary_toolbar_view.h
@@ -46,12 +46,18 @@
 // Button to cancel the edit of the location bar.
 @property(nonatomic, strong, readonly) UIButton* cancelButton;
 
-// Constraints to be activated when the location bar is focused.
+// Constraints to be activated when the location bar is expanded and positioned
+// relatively to the cancel button.
 @property(nonatomic, strong, readonly)
-    NSMutableArray<NSLayoutConstraint*>* focusedConstraints;
-// Constraints to be activated when the location bar is unfocused.
+    NSMutableArray<NSLayoutConstraint*>* expandedConstraints;
+// Constraints to be activated when the location bar is contracted with large
+// padding between the location bar and the controls.
 @property(nonatomic, strong, readonly)
-    NSMutableArray<NSLayoutConstraint*>* unfocusedConstraints;
+    NSMutableArray<NSLayoutConstraint*>* contractedConstraints;
+// Constraints to be activated when the location bar is expanded without cancel
+// button.
+@property(nonatomic, strong, readonly)
+    NSMutableArray<NSLayoutConstraint*>* contractedNoMarginConstraints;
 
 // Constraint for the bottom of the location bar.
 @property(nonatomic, strong, readwrite)
diff --git a/ios/chrome/browser/ui/toolbar/adaptive/primary_toolbar_view.mm b/ios/chrome/browser/ui/toolbar/adaptive/primary_toolbar_view.mm
index 7a72d46e..0510cedd 100644
--- a/ios/chrome/browser/ui/toolbar/adaptive/primary_toolbar_view.mm
+++ b/ios/chrome/browser/ui/toolbar/adaptive/primary_toolbar_view.mm
@@ -48,8 +48,8 @@
 #pragma mark** Buttons in the leading stack view. **
 // Button to navigate back, redefined as readwrite.
 @property(nonatomic, strong, readwrite) ToolbarButton* backButton;
-// Button to navigate forward, leading position, redefined as readwrite.
-@property(nonatomic, strong, readwrite) ToolbarButton* forwardLeadingButton;
+// Button to navigate forward, redefined as readwrite.
+@property(nonatomic, strong, readwrite) ToolbarButton* forwardButton;
 // Button to display the TabGrid, redefined as readwrite.
 @property(nonatomic, strong, readwrite) ToolbarTabGridButton* tabGridButton;
 // Button to stop the loading of the page, redefined as readwrite.
@@ -58,8 +58,6 @@
 @property(nonatomic, strong, readwrite) ToolbarButton* reloadButton;
 
 #pragma mark** Buttons in the trailing stack view. **
-// Button to navigate forward, trailing position, redefined as readwrite.
-@property(nonatomic, strong, readwrite) ToolbarButton* forwardTrailingButton;
 // Button to display the share menu, redefined as readwrite.
 @property(nonatomic, strong, readwrite) ToolbarButton* shareButton;
 // Button to manage the bookmarks of this page, redefined as readwrite.
@@ -70,14 +68,13 @@
 // Button to cancel the edit of the location bar, redefined as readwrite.
 @property(nonatomic, strong, readwrite) UIButton* cancelButton;
 
-// Constraints to be activated when the location bar is focused, redefined as
-// readwrite.
+// Constraints for the location bar, redefined as readwrite.
 @property(nonatomic, strong, readwrite)
-    NSMutableArray<NSLayoutConstraint*>* focusedConstraints;
-// Constraints to be activated when the location bar is unfocused, redefined as
-// readwrite.
+    NSMutableArray<NSLayoutConstraint*>* expandedConstraints;
 @property(nonatomic, strong, readwrite)
-    NSMutableArray<NSLayoutConstraint*>* unfocusedConstraints;
+    NSMutableArray<NSLayoutConstraint*>* contractedConstraints;
+@property(nonatomic, strong, readwrite)
+    NSMutableArray<NSLayoutConstraint*>* contractedNoMarginConstraints;
 
 @end
 
@@ -92,20 +89,20 @@
 @synthesize leadingStackView = _leadingStackView;
 @synthesize leadingStackViewButtons = _leadingStackViewButtons;
 @synthesize backButton = _backButton;
-@synthesize forwardLeadingButton = _forwardLeadingButton;
+@synthesize forwardButton = _forwardButton;
 @synthesize tabGridButton = _tabGridButton;
 @synthesize stopButton = _stopButton;
 @synthesize reloadButton = _reloadButton;
 @synthesize locationBarContainer = _locationBarContainer;
 @synthesize trailingStackView = _trailingStackView;
 @synthesize trailingStackViewButtons = _trailingStackViewButtons;
-@synthesize forwardTrailingButton = _forwardTrailingButton;
 @synthesize shareButton = _shareButton;
 @synthesize bookmarkButton = _bookmarkButton;
 @synthesize toolsMenuButton = _toolsMenuButton;
 @synthesize cancelButton = _cancelButton;
-@synthesize focusedConstraints = _focusedConstraints;
-@synthesize unfocusedConstraints = _unfocusedConstraints;
+@synthesize expandedConstraints = _expandedConstraints;
+@synthesize contractedConstraints = _contractedConstraints;
+@synthesize contractedNoMarginConstraints = _contractedNoMarginConstraints;
 @synthesize blur = _blur;
 @synthesize contentView = _contentView;
 
@@ -175,7 +172,7 @@
 - (void)setUpCancelButton {
   self.cancelButton = [self.buttonFactory cancelButton];
   self.cancelButton.translatesAutoresizingMaskIntoConstraints = NO;
-  [self.contentView addSubview:self.cancelButton];
+  [self addSubview:self.cancelButton];
 }
 
 // Sets the location bar container and its view if present.
@@ -202,38 +199,43 @@
 // Sets the leading stack view.
 - (void)setUpLeadingStackView {
   self.backButton = [self.buttonFactory backButton];
-  self.forwardLeadingButton = [self.buttonFactory leadingForwardButton];
+  self.forwardButton = [self.buttonFactory forwardButton];
   self.tabGridButton = [self.buttonFactory tabGridButton];
   self.stopButton = [self.buttonFactory stopButton];
   self.stopButton.hiddenInCurrentState = YES;
   self.reloadButton = [self.buttonFactory reloadButton];
 
   self.leadingStackViewButtons = @[
-    self.backButton, self.forwardLeadingButton, self.tabGridButton,
-    self.stopButton, self.reloadButton
+    self.backButton, self.forwardButton, self.tabGridButton, self.stopButton,
+    self.reloadButton
   ];
   self.leadingStackView = [[UIStackView alloc]
       initWithArrangedSubviews:self.leadingStackViewButtons];
   self.leadingStackView.translatesAutoresizingMaskIntoConstraints = NO;
   self.leadingStackView.spacing = kAdaptiveToolbarStackViewSpacing;
+  [self.leadingStackView
+      setContentHuggingPriority:UILayoutPriorityDefaultHigh
+                        forAxis:UILayoutConstraintAxisHorizontal];
+
   [self.contentView addSubview:self.leadingStackView];
 }
 
 // Sets the trailing stack view.
 - (void)setUpTrailingStackView {
-  self.forwardTrailingButton = [self.buttonFactory trailingForwardButton];
   self.shareButton = [self.buttonFactory shareButton];
   self.bookmarkButton = [self.buttonFactory bookmarkButton];
   self.toolsMenuButton = [self.buttonFactory toolsMenuButton];
 
-  self.trailingStackViewButtons = @[
-    self.forwardTrailingButton, self.shareButton, self.bookmarkButton,
-    self.toolsMenuButton
-  ];
+  self.trailingStackViewButtons =
+      @[ self.shareButton, self.bookmarkButton, self.toolsMenuButton ];
   self.trailingStackView = [[UIStackView alloc]
       initWithArrangedSubviews:self.trailingStackViewButtons];
   self.trailingStackView.translatesAutoresizingMaskIntoConstraints = NO;
   self.trailingStackView.spacing = kAdaptiveToolbarStackViewSpacing;
+  [self.trailingStackView
+      setContentHuggingPriority:UILayoutPriorityDefaultHigh
+                        forAxis:UILayoutConstraintAxisHorizontal];
+
   [self.contentView addSubview:self.trailingStackView];
 }
 
@@ -248,8 +250,9 @@
 // Sets the constraints up.
 - (void)setUpConstraints {
   id<LayoutGuideProvider> safeArea = SafeAreaLayoutGuideForView(self);
-  self.focusedConstraints = [NSMutableArray array];
-  self.unfocusedConstraints = [NSMutableArray array];
+  self.expandedConstraints = [NSMutableArray array];
+  self.contractedConstraints = [NSMutableArray array];
+  self.contractedNoMarginConstraints = [NSMutableArray array];
 
   // Leading StackView constraints
   [NSLayoutConstraint activateConstraints:@[
@@ -274,7 +277,7 @@
     self.locationBarBottomConstraint,
     self.locationBarHeight,
   ]];
-  [self.unfocusedConstraints addObjectsFromArray:@[
+  [self.contractedConstraints addObjectsFromArray:@[
     [self.locationBarContainer.trailingAnchor
         constraintEqualToAnchor:self.trailingStackView.leadingAnchor
                        constant:-kContractedLocationBarHorizontalMargin],
@@ -282,7 +285,15 @@
         constraintEqualToAnchor:self.leadingStackView.trailingAnchor
                        constant:kContractedLocationBarHorizontalMargin],
   ]];
-  [self.focusedConstraints addObjectsFromArray:@[
+  [self.contractedNoMarginConstraints addObjectsFromArray:@[
+    [self.locationBarContainer.leadingAnchor
+        constraintEqualToAnchor:safeArea.leadingAnchor
+                       constant:kExpandedLocationBarHorizontalMargin],
+    [self.locationBarContainer.trailingAnchor
+        constraintEqualToAnchor:safeArea.trailingAnchor
+                       constant:-kExpandedLocationBarHorizontalMargin]
+  ]];
+  [self.expandedConstraints addObjectsFromArray:@[
     [self.locationBarContainer.trailingAnchor
         constraintEqualToAnchor:self.cancelButton.leadingAnchor],
     [self.locationBarContainer.leadingAnchor
@@ -304,7 +315,13 @@
 
   // locationBarView constraints, if present.
   if (self.locationBarView) {
-    AddSameConstraints(self.locationBarContainer, self.locationBarView);
+    AddSameConstraintsToSides(
+        self.locationBarView, self.locationBarContainer,
+        LayoutSides::kTop | LayoutSides::kBottom | LayoutSides::kLeading);
+    [self.locationBarContainer.trailingAnchor
+        constraintGreaterThanOrEqualToAnchor:self.locationBarView
+                                                 .trailingAnchor]
+        .active = YES;
   }
 
   // Cancel button constraints.
@@ -314,13 +331,14 @@
     [self.cancelButton.bottomAnchor
         constraintEqualToAnchor:self.trailingStackView.bottomAnchor],
   ]];
-  NSLayoutConstraint* focusedTrailing = [self.cancelButton.trailingAnchor
+  NSLayoutConstraint* visibleCancel = [self.cancelButton.trailingAnchor
       constraintEqualToAnchor:safeArea.trailingAnchor
                      constant:-kExpandedLocationBarHorizontalMargin];
-  [self.focusedConstraints addObject:focusedTrailing];
-  [self.unfocusedConstraints
-      addObject:[self.cancelButton.leadingAnchor
-                    constraintEqualToAnchor:self.trailingAnchor]];
+  NSLayoutConstraint* hiddenCancel = [self.cancelButton.leadingAnchor
+      constraintEqualToAnchor:self.trailingAnchor];
+  [self.expandedConstraints addObject:visibleCancel];
+  [self.contractedConstraints addObject:hiddenCancel];
+  [self.contractedNoMarginConstraints addObject:hiddenCancel];
 
   // ProgressBar constraints.
   [NSLayoutConstraint activateConstraints:@[
@@ -331,8 +349,6 @@
     [self.progressBar.heightAnchor
         constraintEqualToConstant:kProgressBarHeight],
   ]];
-
-  [NSLayoutConstraint activateConstraints:self.unfocusedConstraints];
 }
 
 #pragma mark - Property accessors
@@ -352,7 +368,12 @@
     return;
 
   [self.locationBarContainer addSubview:locationBarView];
-  AddSameConstraints(self.locationBarContainer, locationBarView);
+  AddSameConstraintsToSides(
+      self.locationBarView, self.locationBarContainer,
+      LayoutSides::kTop | LayoutSides::kBottom | LayoutSides::kLeading);
+  [self.locationBarContainer.trailingAnchor
+      constraintGreaterThanOrEqualToAnchor:self.locationBarView.trailingAnchor]
+      .active = YES;
 }
 
 - (NSArray<ToolbarButton*>*)allButtons {
diff --git a/ios/chrome/browser/ui/toolbar/adaptive/primary_toolbar_view_controller.mm b/ios/chrome/browser/ui/toolbar/adaptive/primary_toolbar_view_controller.mm
index e64229f..0d592aac 100644
--- a/ios/chrome/browser/ui/toolbar/adaptive/primary_toolbar_view_controller.mm
+++ b/ios/chrome/browser/ui/toolbar/adaptive/primary_toolbar_view_controller.mm
@@ -19,7 +19,8 @@
 #import "ios/chrome/browser/ui/toolbar/buttons/toolbar_configuration.h"
 #import "ios/chrome/browser/ui/toolbar/buttons/toolbar_constants.h"
 #import "ios/chrome/browser/ui/toolbar/buttons/toolbar_tools_menu_button.h"
-#include "ios/chrome/browser/ui/ui_util.h"
+#import "ios/chrome/browser/ui/ui_util.h"
+#import "ios/chrome/browser/ui/uikit_ui_util.h"
 #import "ios/chrome/browser/ui/util/named_guide.h"
 #import "ios/third_party/material_components_ios/src/components/ProgressView/src/MaterialProgressView.h"
 
@@ -75,7 +76,6 @@
 
 - (void)setScrollProgressForTabletOmnibox:(CGFloat)progress {
   [super setScrollProgressForTabletOmnibox:progress];
-  DCHECK(IsIPadIdiom());
   self.view.locationBarBottomConstraint.constant =
       -kLocationBarVerticalMargin * progress;
   self.view.locationBarContainer.alpha = progress;
@@ -98,14 +98,12 @@
 
   // Adds the layout guide to the buttons.
   self.view.toolsMenuButton.guideName = kTabSwitcherGuide;
-  self.view.forwardLeadingButton.guideName = kForwardButtonGuide;
-  self.view.forwardTrailingButton.guideName = kForwardButtonGuide;
+  self.view.forwardButton.guideName = kForwardButtonGuide;
   self.view.backButton.guideName = kBackButtonGuide;
 
   // Add navigation popup menu triggers.
   [self addLongPressGestureToView:self.view.backButton];
-  [self addLongPressGestureToView:self.view.forwardLeadingButton];
-  [self addLongPressGestureToView:self.view.forwardTrailingButton];
+  [self addLongPressGestureToView:self.view.forwardButton];
 }
 
 - (void)didMoveToParentViewController:(UIViewController*)parent {
@@ -148,15 +146,13 @@
   if (buttonType == ToolbarButtonTypeBack) {
     self.view.backButton.selected = YES;
   } else {
-    self.view.forwardLeadingButton.selected = YES;
-    self.view.forwardTrailingButton.selected = YES;
+    self.view.forwardButton.selected = YES;
   }
 }
 
 - (void)updateUIForTabHistoryWasDismissed {
   self.view.backButton.selected = NO;
-  self.view.forwardLeadingButton.selected = NO;
-  self.view.forwardTrailingButton.selected = NO;
+  self.view.forwardButton.selected = NO;
 }
 
 #pragma mark - FullscreenUIElement
@@ -207,14 +203,19 @@
 #pragma mark - ToolbarAnimatee
 
 - (void)expandLocationBar {
-  [NSLayoutConstraint deactivateConstraints:self.view.unfocusedConstraints];
-  [NSLayoutConstraint activateConstraints:self.view.focusedConstraints];
+  [self deactivateViewLocationBarConstraints];
+  [NSLayoutConstraint activateConstraints:self.view.expandedConstraints];
   [self.view layoutIfNeeded];
 }
 
 - (void)contractLocationBar {
-  [NSLayoutConstraint deactivateConstraints:self.view.focusedConstraints];
-  [NSLayoutConstraint activateConstraints:self.view.unfocusedConstraints];
+  [self deactivateViewLocationBarConstraints];
+  if (IsSplitToolbarMode(self)) {
+    [NSLayoutConstraint
+        activateConstraints:self.view.contractedNoMarginConstraints];
+  } else {
+    [NSLayoutConstraint activateConstraints:self.view.contractedConstraints];
+  }
   [self.view layoutIfNeeded];
 }
 
@@ -240,6 +241,14 @@
 
 #pragma mark - Private
 
+// Deactivates the constraints on the location bar positioning.
+- (void)deactivateViewLocationBarConstraints {
+  [NSLayoutConstraint deactivateConstraints:self.view.contractedConstraints];
+  [NSLayoutConstraint
+      deactivateConstraints:self.view.contractedNoMarginConstraints];
+  [NSLayoutConstraint deactivateConstraints:self.view.expandedConstraints];
+}
+
 // Adds a LongPressGesture to the |view|, with target on -|handleLongPress:|.
 - (void)addLongPressGestureToView:(UIView*)view {
   UILongPressGestureRecognizer* navigationHistoryLongPress =
@@ -256,8 +265,7 @@
 
   if (gesture.view == self.view.backButton) {
     [self.dispatcher showTabHistoryPopupForBackwardHistory];
-  } else if (gesture.view == self.view.forwardLeadingButton ||
-             gesture.view == self.view.forwardTrailingButton) {
+  } else if (gesture.view == self.view.forwardButton) {
     [self.dispatcher showTabHistoryPopupForForwardHistory];
   }
 }
diff --git a/ios/chrome/browser/ui/toolbar/adaptive/secondary_toolbar_view.mm b/ios/chrome/browser/ui/toolbar/adaptive/secondary_toolbar_view.mm
index e8fe3744..2926bc0 100644
--- a/ios/chrome/browser/ui/toolbar/adaptive/secondary_toolbar_view.mm
+++ b/ios/chrome/browser/ui/toolbar/adaptive/secondary_toolbar_view.mm
@@ -26,16 +26,16 @@
 // The stack view containing the buttons.
 @property(nonatomic, strong) UIStackView* stackView;
 
+// Button to navigate back, redefined as readwrite.
+@property(nonatomic, strong, readwrite) ToolbarButton* backButton;
+// Buttons to navigate forward, redefined as readwrite.
+@property(nonatomic, strong, readwrite) ToolbarButton* forwardButton;
 // Button to display the tools menu, redefined as readwrite.
 @property(nonatomic, strong, readwrite) ToolbarToolsMenuButton* toolsMenuButton;
 // Button to display the tab grid, redefined as readwrite.
 @property(nonatomic, strong, readwrite) ToolbarTabGridButton* tabGridButton;
-// Button to display the share menu, redefined as readwrite.
-@property(nonatomic, strong, readwrite) ToolbarButton* shareButton;
 // Button to focus the omnibox, redefined as readwrite.
 @property(nonatomic, strong, readwrite) ToolbarButton* omniboxButton;
-// Button to manage the bookmarks of this page, defined as readwrite.
-@property(nonatomic, strong, readwrite) ToolbarButton* bookmarkButton;
 
 @end
 
@@ -44,10 +44,10 @@
 @synthesize allButtons = _allButtons;
 @synthesize buttonFactory = _buttonFactory;
 @synthesize stackView = _stackView;
+@synthesize backButton = _backButton;
+@synthesize forwardButton = _forwardButton;
 @synthesize toolsMenuButton = _toolsMenuButton;
-@synthesize shareButton = _shareButton;
 @synthesize omniboxButton = _omniboxButton;
-@synthesize bookmarkButton = _bookmarkButton;
 @synthesize tabGridButton = _tabGridButton;
 
 #pragma mark - Public
@@ -101,15 +101,15 @@
     contentView = vibrancyView.contentView;
   }
 
-  self.tabGridButton = [self.buttonFactory tabGridButton];
-  self.shareButton = [self.buttonFactory shareButton];
+  self.backButton = [self.buttonFactory backButton];
+  self.forwardButton = [self.buttonFactory forwardButton];
   self.omniboxButton = [self.buttonFactory omniboxButton];
-  self.bookmarkButton = [self.buttonFactory bookmarkButton];
+  self.tabGridButton = [self.buttonFactory tabGridButton];
   self.toolsMenuButton = [self.buttonFactory toolsMenuButton];
 
   self.allButtons = @[
-    self.tabGridButton, self.shareButton, self.omniboxButton,
-    self.bookmarkButton, self.toolsMenuButton
+    self.backButton, self.forwardButton, self.omniboxButton, self.tabGridButton,
+    self.toolsMenuButton
   ];
 
   self.stackView =
@@ -135,18 +135,6 @@
 
 #pragma mark - AdaptiveToolbarView
 
-- (ToolbarButton*)backButton {
-  return nil;
-}
-
-- (ToolbarButton*)forwardLeadingButton {
-  return nil;
-}
-
-- (ToolbarButton*)forwardTrailingButton {
-  return nil;
-}
-
 - (ToolbarButton*)stopButton {
   return nil;
 }
@@ -159,4 +147,12 @@
   return nil;
 }
 
+- (ToolbarButton*)bookmarkButton {
+  return nil;
+}
+
+- (ToolbarButton*)shareButton {
+  return nil;
+}
+
 @end
diff --git a/ios/chrome/browser/ui/toolbar/buttons/toolbar_button_factory.h b/ios/chrome/browser/ui/toolbar/buttons/toolbar_button_factory.h
index 9404daa5..a00cf6f 100644
--- a/ios/chrome/browser/ui/toolbar/buttons/toolbar_button_factory.h
+++ b/ios/chrome/browser/ui/toolbar/buttons/toolbar_button_factory.h
@@ -41,10 +41,8 @@
 
 // Back ToolbarButton.
 - (ToolbarButton*)backButton;
-// Forward ToolbarButton to be displayed on the leading side of the toolbar.
-- (ToolbarButton*)leadingForwardButton;
-// Forward ToolbarButton to be displayed on the trailing side of the toolbar.
-- (ToolbarButton*)trailingForwardButton;
+// Forward ToolbarButton.
+- (ToolbarButton*)forwardButton;
 // Tab Grid ToolbarButton.
 - (ToolbarTabGridButton*)tabGridButton;
 // Tab Switcher Strip ToolbarButton.
diff --git a/ios/chrome/browser/ui/toolbar/buttons/toolbar_button_factory.mm b/ios/chrome/browser/ui/toolbar/buttons/toolbar_button_factory.mm
index c7e61ea..a106ae4 100644
--- a/ios/chrome/browser/ui/toolbar/buttons/toolbar_button_factory.mm
+++ b/ios/chrome/browser/ui/toolbar/buttons/toolbar_button_factory.mm
@@ -98,17 +98,44 @@
   return backButton;
 }
 
-- (ToolbarButton*)leadingForwardButton {
-  ToolbarButton* forwardButton = self.forwardButton;
+// Returns a forward button without visibility mask configured.
+- (ToolbarButton*)forwardButton {
+  int forwardButtonImages[styleCount][TOOLBAR_STATE_COUNT] =
+      TOOLBAR_IDR_THREE_STATE(FORWARD);
+  ToolbarButton* forwardButton = nil;
+  if (IsUIRefreshPhase1Enabled()) {
+    forwardButton = [ToolbarButton
+        toolbarButtonWithImage:[[UIImage imageNamed:@"toolbar_forward"]
+                                   imageFlippedForRightToLeftLayoutDirection]];
+    [self configureButton:forwardButton width:kAdaptiveToolbarButtonWidth];
+  } else {
+    forwardButton = [ToolbarButton
+        toolbarButtonWithImageForNormalState:NativeReversableImage(
+                                                 forwardButtonImages[self.style]
+                                                                    [DEFAULT],
+                                                 YES)
+                    imageForHighlightedState:NativeReversableImage(
+                                                 forwardButtonImages[self.style]
+                                                                    [PRESSED],
+                                                 YES)
+                       imageForDisabledState:NativeReversableImage(
+                                                 forwardButtonImages[self.style]
+                                                                    [DISABLED],
+                                                 YES)];
+    [self configureButton:forwardButton width:kToolbarButtonWidth];
+    if (!IsIPadIdiom()) {
+      forwardButton.imageEdgeInsets =
+          UIEdgeInsetsMakeDirected(0, kForwardButtonImageInset, 0, 0);
+    }
+  }
   forwardButton.visibilityMask =
-      self.visibilityConfiguration.leadingForwardButtonVisibility;
-  return forwardButton;
-}
-
-- (ToolbarButton*)trailingForwardButton {
-  ToolbarButton* forwardButton = self.forwardButton;
-  forwardButton.visibilityMask =
-      self.visibilityConfiguration.trailingForwardButtonVisibility;
+      self.visibilityConfiguration.forwardButtonVisibility;
+  DCHECK(forwardButton);
+  forwardButton.accessibilityLabel =
+      l10n_util::GetNSString(IDS_ACCNAME_FORWARD);
+  [forwardButton addTarget:self.dispatcher
+                    action:@selector(goForward)
+          forControlEvents:UIControlEventTouchUpInside];
   return forwardButton;
 }
 
@@ -464,43 +491,5 @@
                                    nil];
 }
 
-// Returns a forward button without visibility mask configured.
-- (ToolbarButton*)forwardButton {
-  int forwardButtonImages[styleCount][TOOLBAR_STATE_COUNT] =
-      TOOLBAR_IDR_THREE_STATE(FORWARD);
-  ToolbarButton* forwardButton = nil;
-  if (IsUIRefreshPhase1Enabled()) {
-    forwardButton = [ToolbarButton
-        toolbarButtonWithImage:[[UIImage imageNamed:@"toolbar_forward"]
-                                   imageFlippedForRightToLeftLayoutDirection]];
-    [self configureButton:forwardButton width:kAdaptiveToolbarButtonWidth];
-  } else {
-    forwardButton = [ToolbarButton
-        toolbarButtonWithImageForNormalState:NativeReversableImage(
-                                                 forwardButtonImages[self.style]
-                                                                    [DEFAULT],
-                                                 YES)
-                    imageForHighlightedState:NativeReversableImage(
-                                                 forwardButtonImages[self.style]
-                                                                    [PRESSED],
-                                                 YES)
-                       imageForDisabledState:NativeReversableImage(
-                                                 forwardButtonImages[self.style]
-                                                                    [DISABLED],
-                                                 YES)];
-    [self configureButton:forwardButton width:kToolbarButtonWidth];
-    if (!IsIPadIdiom()) {
-      forwardButton.imageEdgeInsets =
-          UIEdgeInsetsMakeDirected(0, kForwardButtonImageInset, 0, 0);
-    }
-  }
-  DCHECK(forwardButton);
-  forwardButton.accessibilityLabel =
-      l10n_util::GetNSString(IDS_ACCNAME_FORWARD);
-  [forwardButton addTarget:self.dispatcher
-                    action:@selector(goForward)
-          forControlEvents:UIControlEventTouchUpInside];
-  return forwardButton;
-}
 
 @end
diff --git a/ios/chrome/browser/ui/toolbar/buttons/toolbar_button_visibility_configuration.h b/ios/chrome/browser/ui/toolbar/buttons/toolbar_button_visibility_configuration.h
index cebf50f..a2a8207c 100644
--- a/ios/chrome/browser/ui/toolbar/buttons/toolbar_button_visibility_configuration.h
+++ b/ios/chrome/browser/ui/toolbar/buttons/toolbar_button_visibility_configuration.h
@@ -26,9 +26,7 @@
 // Configuration for the forward button displayed in the leading part of the
 // toolbar.
 @property(nonatomic, readonly)
-    ToolbarComponentVisibility leadingForwardButtonVisibility;
-@property(nonatomic, readonly)
-    ToolbarComponentVisibility trailingForwardButtonVisibility;
+    ToolbarComponentVisibility forwardButtonVisibility;
 @property(nonatomic, readonly)
     ToolbarComponentVisibility tabGridButtonVisibility;
 @property(nonatomic, readonly)
diff --git a/ios/chrome/browser/ui/toolbar/buttons/toolbar_button_visibility_configuration.mm b/ios/chrome/browser/ui/toolbar/buttons/toolbar_button_visibility_configuration.mm
index 0401486..3f2f632 100644
--- a/ios/chrome/browser/ui/toolbar/buttons/toolbar_button_visibility_configuration.mm
+++ b/ios/chrome/browser/ui/toolbar/buttons/toolbar_button_visibility_configuration.mm
@@ -23,38 +23,28 @@
 - (ToolbarComponentVisibility)backButtonVisibility {
   switch (self.type) {
     case PRIMARY:
-      return ToolbarComponentVisibilityAlways;
+      return ToolbarComponentVisibilityAlways &
+             ~ToolbarComponentVisibilitySplit;
     case SECONDARY:
-      return ToolbarComponentVisibilityNone;
+      return ToolbarComponentVisibilitySplit;
     case LEGACY:
       return ToolbarComponentVisibilityAlways;
   }
 }
 
-- (ToolbarComponentVisibility)leadingForwardButtonVisibility {
+- (ToolbarComponentVisibility)forwardButtonVisibility {
   switch (self.type) {
     case PRIMARY:
       return ToolbarComponentVisibilityAlways &
-             ~self.trailingForwardButtonVisibility;
+             ~ToolbarComponentVisibilitySplit;
     case SECONDARY:
-      return ToolbarComponentVisibilityNone;
+      return ToolbarComponentVisibilitySplit;
     case LEGACY:
       return ToolbarComponentVisibilityOnlyWhenEnabled |
              ToolbarComponentVisibilityRegularWidthRegularHeight;
   }
 }
 
-- (ToolbarComponentVisibility)trailingForwardButtonVisibility {
-  switch (self.type) {
-    case PRIMARY:
-      return ToolbarComponentVisibilityCompactWidthRegularHeight;
-    case SECONDARY:
-      return ToolbarComponentVisibilityNone;
-    case LEGACY:
-      return ToolbarComponentVisibilityNone;
-  }
-}
-
 - (ToolbarComponentVisibility)tabGridButtonVisibility {
   switch (self.type) {
     case PRIMARY:
@@ -85,7 +75,7 @@
       return ToolbarComponentVisibilityAlways &
              ~ToolbarComponentVisibilityCompactWidthRegularHeight;
     case SECONDARY:
-      return ToolbarComponentVisibilitySplit;
+      return ToolbarComponentVisibilityNone;
     case LEGACY:
       return ToolbarComponentVisibilityRegularWidthRegularHeight;
   }
@@ -119,7 +109,7 @@
       return ToolbarComponentVisibilityAlways &
              ~ToolbarComponentVisibilityCompactWidthRegularHeight;
     case SECONDARY:
-      return ToolbarComponentVisibilitySplit;
+      return ToolbarComponentVisibilityNone;
     case LEGACY:
       return ToolbarComponentVisibilityRegularWidthCompactHeight |
              ToolbarComponentVisibilityRegularWidthRegularHeight;
diff --git a/ios/chrome/browser/ui/toolbar/clean/toolbar_view.mm b/ios/chrome/browser/ui/toolbar/clean/toolbar_view.mm
index 4b7f63b..4e46f2cd6 100644
--- a/ios/chrome/browser/ui/toolbar/clean/toolbar_view.mm
+++ b/ios/chrome/browser/ui/toolbar/clean/toolbar_view.mm
@@ -131,7 +131,7 @@
 
 - (void)setUpToolbarButtons {
   self.backButton = [self.buttonFactory backButton];
-  self.forwardButton = [self.buttonFactory leadingForwardButton];
+  self.forwardButton = [self.buttonFactory forwardButton];
   self.tabSwitchStripButton = [self.buttonFactory tabSwitcherStripButton];
   self.toolsMenuButton = [self.buttonFactory toolsMenuButton];
   self.shareButton = [self.buttonFactory shareButton];
diff --git a/ios/chrome/browser/ui/ui_util.mm b/ios/chrome/browser/ui/ui_util.mm
index 5f0432f..9e68e25 100644
--- a/ios/chrome/browser/ui/ui_util.mm
+++ b/ios/chrome/browser/ui/ui_util.mm
@@ -63,7 +63,10 @@
   return base::FeatureList::IsEnabled(kUIRefreshPhase1);
 }
 
+// TODO(crbug.com/818560) : Remove this flag.
 bool IsTabSwitcherTabGridEnabled() {
+  if (tests_hook::ForceTabSwitcherTabGrid())
+    return true;
   return base::FeatureList::IsEnabled(kTabSwitcherTabGrid);
 }
 
diff --git a/ios/chrome/test/app/chrome_test_util.mm b/ios/chrome/test/app/chrome_test_util.mm
index c1ffaf9a..0008ad6b 100644
--- a/ios/chrome/test/app/chrome_test_util.mm
+++ b/ios/chrome/test/app/chrome_test_util.mm
@@ -114,9 +114,19 @@
 UIViewController* GetActiveViewController() {
   UIWindow* main_window = [[UIApplication sharedApplication] keyWindow];
   DCHECK([main_window isKindOfClass:[ChromeOverlayWindow class]]);
-  id<ViewControllerSwapping> main_view_controller =
-      static_cast<id<ViewControllerSwapping>>([main_window rootViewController]);
-  return main_view_controller.activeViewController;
+  UIViewController* main_view_controller = main_window.rootViewController;
+  if ([main_view_controller
+          conformsToProtocol:@protocol(ViewControllerSwapping)]) {
+    // This is either the stack_view or the iPad tab_switcher, in which case it
+    // is best to call |-activeViewController|.
+    return [static_cast<id<ViewControllerSwapping>>(main_view_controller)
+        activeViewController];
+  }
+  // The active view controller is either the TabGridViewController or its
+  // presented BVC.
+  return main_view_controller.presentedViewController
+             ? main_view_controller.presentedViewController
+             : main_view_controller;
 }
 
 id<ApplicationCommands, BrowserCommands> DispatcherForActiveViewController() {
@@ -125,10 +135,15 @@
   if (bvc)
     return bvc.dispatcher;
   if ([vc conformsToProtocol:@protocol(TabSwitcher)]) {
+    // In stack_view and the iPad tab switcher, the view controller has a
+    // dispatcher.
     id<TabSwitcher> tabSwitcher = static_cast<id<TabSwitcher>>(vc);
     return tabSwitcher.dispatcher;
   }
-  return nil;
+  // In tab grid, the TabSwitcher object is not in the view hierarchy so it must
+  // be gotten through the MainController.
+  return static_cast<id<ApplicationCommands, BrowserCommands>>(
+      GetMainController().tabSwitcher.dispatcher);
 }
 
 void RemoveAllInfoBars() {
diff --git a/ios/chrome/test/earl_grey/BUILD.gn b/ios/chrome/test/earl_grey/BUILD.gn
index 969b4409..7fca231 100644
--- a/ios/chrome/test/earl_grey/BUILD.gn
+++ b/ios/chrome/test/earl_grey/BUILD.gn
@@ -19,6 +19,7 @@
     ":ios_chrome_reading_list_egtests",
     ":ios_chrome_settings_egtests",
     ":ios_chrome_smoke_egtests",
+    ":ios_chrome_tab_grid_egtests",
     ":ios_chrome_ui_egtests",
     ":ios_chrome_web_egtests",
   ]
@@ -74,6 +75,14 @@
   ]
 }
 
+chrome_ios_eg_test("ios_chrome_tab_grid_egtests") {
+  deps = [
+    ":test_support",
+    "//ios/chrome/browser/ui/tab_grid:eg_tests",
+  ]
+  hooks_target = "//ios/chrome/browser/ui/tab_grid:hooks"
+}
+
 chrome_ios_eg_test("ios_chrome_ui_egtests") {
   deps = [
     "//ios/chrome/browser/ui:eg_tests",
diff --git a/ios/chrome/test/earl_grey/eg_tests_hook.mm b/ios/chrome/test/earl_grey/eg_tests_hook.mm
index f1f1ada..05154c2 100644
--- a/ios/chrome/test/earl_grey/eg_tests_hook.mm
+++ b/ios/chrome/test/earl_grey/eg_tests_hook.mm
@@ -38,6 +38,11 @@
   return false;
 }
 
+// TODO(crbug.com/818560) : Remove this hook.
+bool ForceTabSwitcherTabGrid() {
+  return false;
+}
+
 void SetUpTestsIfPresent() {
   // No-op for Earl Grey.
 }
diff --git a/net/BUILD.gn b/net/BUILD.gn
index db2c8a9..ee97a615 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -2191,6 +2191,7 @@
         "websockets/websocket_handshake_request_info.h",
         "websockets/websocket_handshake_response_info.cc",
         "websockets/websocket_handshake_response_info.h",
+        "websockets/websocket_handshake_stream_base.cc",
         "websockets/websocket_handshake_stream_base.h",
         "websockets/websocket_handshake_stream_create_helper.cc",
         "websockets/websocket_handshake_stream_create_helper.h",
@@ -2648,6 +2649,8 @@
     "test/keychain_test_util_mac.h",
     "test/net_test_suite.cc",
     "test/net_test_suite.h",
+    "test/quic_simple_test_server.cc",
+    "test/quic_simple_test_server.h",
     "test/scoped_disable_exit_on_dfatal.cc",
     "test/scoped_disable_exit_on_dfatal.h",
     "test/tcp_socket_proxy.cc",
@@ -2687,6 +2690,7 @@
   ]
 
   deps = [
+    ":simple_quic_tools",
     "//third_party/zlib",
   ]
 
diff --git a/net/cookies/cookie_monster.cc b/net/cookies/cookie_monster.cc
index ce09270f..58a8b86 100644
--- a/net/cookies/cookie_monster.cc
+++ b/net/cookies/cookie_monster.cc
@@ -97,8 +97,8 @@
 
 namespace {
 
-void MayeRunDeleteCallback(base::WeakPtr<net::CookieMonster> cookie_monster,
-                           base::OnceClosure callback) {
+void MaybeRunDeleteCallback(base::WeakPtr<net::CookieMonster> cookie_monster,
+                            base::OnceClosure callback) {
   if (cookie_monster && callback)
     std::move(callback).Run();
 }
@@ -652,7 +652,7 @@
   }
 
   FlushStore(
-      base::BindOnce(&MayeRunDeleteCallback, weak_ptr_factory_.GetWeakPtr(),
+      base::BindOnce(&MaybeRunDeleteCallback, weak_ptr_factory_.GetWeakPtr(),
                      callback ? base::BindOnce(std::move(callback), num_deleted)
                               : base::OnceClosure()));
 }
@@ -680,7 +680,7 @@
   }
 
   FlushStore(
-      base::BindOnce(&MayeRunDeleteCallback, weak_ptr_factory_.GetWeakPtr(),
+      base::BindOnce(&MaybeRunDeleteCallback, weak_ptr_factory_.GetWeakPtr(),
                      callback ? base::BindOnce(std::move(callback), num_deleted)
                               : base::OnceClosure()));
 }
@@ -749,7 +749,7 @@
     }
   }
 
-  FlushStore(base::BindOnce(&MayeRunDeleteCallback,
+  FlushStore(base::BindOnce(&MaybeRunDeleteCallback,
                             weak_ptr_factory_.GetWeakPtr(),
                             // No callback null check needed as BindOnce
                             // is not being called and MaybeRunDeleteCallback
@@ -772,7 +772,7 @@
     }
   }
   FlushStore(
-      base::BindOnce(&MayeRunDeleteCallback, weak_ptr_factory_.GetWeakPtr(),
+      base::BindOnce(&MaybeRunDeleteCallback, weak_ptr_factory_.GetWeakPtr(),
                      callback ? base::BindOnce(std::move(callback), result)
                               : base::OnceClosure()));
 }
@@ -794,7 +794,7 @@
   }
 
   FlushStore(
-      base::BindOnce(&MayeRunDeleteCallback, weak_ptr_factory_.GetWeakPtr(),
+      base::BindOnce(&MaybeRunDeleteCallback, weak_ptr_factory_.GetWeakPtr(),
                      callback ? base::BindOnce(std::move(callback), num_deleted)
                               : base::OnceClosure()));
 }
diff --git a/components/grpc_support/test/quic_test_server.cc b/net/test/quic_simple_test_server.cc
similarity index 64%
rename from components/grpc_support/test/quic_test_server.cc
rename to net/test/quic_simple_test_server.cc
index 2d286fd..0f11650 100644
--- a/components/grpc_support/test/quic_test_server.cc
+++ b/net/test/quic_simple_test_server.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/grpc_support/test/quic_test_server.h"
+#include "net/test/quic_simple_test_server.h"
 
 #include <memory>
 #include <utility>
@@ -12,6 +12,7 @@
 #include "base/files/file_util.h"
 #include "base/message_loop/message_loop.h"
 #include "base/path_service.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/threading/thread.h"
@@ -24,12 +25,11 @@
 #include "net/tools/quic/quic_http_response_cache.h"
 #include "net/tools/quic/quic_simple_server.h"
 
-namespace grpc_support {
+namespace {
 
 const char kTestServerDomain[] = "example.com";
 // This must match the certificate used (quic-chain.pem and quic-leaf-cert.key).
 const char kTestServerHost[] = "test.example.com";
-const char kTestServerUrl[] = "https://test.example.com/hello.txt";
 
 const char kStatusHeader[] = ":status";
 
@@ -43,7 +43,6 @@
 const char kHelloTrailerName[] = "hello_trailer";
 const char kHelloTrailerValue[] = "hello trailer value";
 
-const char kTestServerSimpleUrl[] = "https://test.example.com/simple.txt";
 const char kSimplePath[] = "/simple.txt";
 const char kSimpleBodyValue[] = "Simple Hello from QUIC Server";
 const char kSimpleStatus[] = "200";
@@ -56,16 +55,92 @@
 net::QuicSimpleServer* g_quic_server = nullptr;
 int g_quic_server_port = 0;
 
+}  // namespace
+
+namespace net {
+
+const std::string QuicSimpleTestServer::GetDomain() {
+  return kTestServerDomain;
+}
+
+const std::string QuicSimpleTestServer::GetHost() {
+  return kTestServerHost;
+}
+
+GURL QuicSimpleTestServer::GetFileURL(const std::string& file_path) {
+  return GURL("https://test.example.com:" + base::NumberToString(GetPort()))
+      .Resolve(file_path);
+}
+
+GURL QuicSimpleTestServer::GetHelloURL() {
+  // Don't include |port| into Hello URL as it is mapped differently.
+  return GURL("https://test.example.com").Resolve(kHelloPath);
+}
+
+const std::string QuicSimpleTestServer::GetStatusHeaderName() {
+  return kStatusHeader;
+}
+
+// Hello Url returns response with HTTP/2 headers and trailers.
+const std::string QuicSimpleTestServer::GetHelloPath() {
+  return kHelloPath;
+}
+
+const std::string QuicSimpleTestServer::GetHelloBodyValue() {
+  return kHelloBodyValue;
+}
+const std::string QuicSimpleTestServer::GetHelloStatus() {
+  return kHelloStatus;
+}
+
+const std::string QuicSimpleTestServer::GetHelloHeaderName() {
+  return kHelloHeaderName;
+}
+
+const std::string QuicSimpleTestServer::GetHelloHeaderValue() {
+  return kHelloHeaderValue;
+}
+
+const std::string QuicSimpleTestServer::GetHelloTrailerName() {
+  return kHelloTrailerName;
+}
+
+const std::string QuicSimpleTestServer::GetHelloTrailerValue() {
+  return kHelloTrailerValue;
+}
+
+// Simple Url returns response without HTTP/2 trailers.
+GURL QuicSimpleTestServer::GetSimpleURL() {
+  // Don't include |port| into Simple URL as it is mapped differently.
+  return GURL("https://test.example.com").Resolve(kSimplePath);
+}
+
+const std::string QuicSimpleTestServer::GetSimpleBodyValue() {
+  return kSimpleBodyValue;
+}
+
+const std::string QuicSimpleTestServer::GetSimpleStatus() {
+  return kSimpleStatus;
+}
+
+const std::string QuicSimpleTestServer::GetSimpleHeaderName() {
+  return kSimpleHeaderName;
+}
+
+const std::string QuicSimpleTestServer::GetSimpleHeaderValue() {
+  return kSimpleHeaderValue;
+}
+
 void SetupQuicHttpResponseCache() {
-  net::SpdyHeaderBlock headers;
+  SpdyHeaderBlock headers;
   headers[kHelloHeaderName] = kHelloHeaderValue;
-  headers[kStatusHeader] =  kHelloStatus;
-  net::SpdyHeaderBlock trailers;
+  headers[kStatusHeader] = kHelloStatus;
+  SpdyHeaderBlock trailers;
   trailers[kHelloTrailerName] = kHelloTrailerValue;
-  g_quic_response_cache = new net::QuicHttpResponseCache();
+  g_quic_response_cache = new QuicHttpResponseCache();
   g_quic_response_cache->AddResponse(base::StringPrintf("%s", kTestServerHost),
-                                      kHelloPath, std::move(headers),
-                                      kHelloBodyValue, std::move(trailers));
+                                     kHelloPath, std::move(headers),
+                                     kHelloBodyValue, std::move(trailers));
   headers[kSimpleHeaderName] = kSimpleHeaderValue;
   headers[kStatusHeader] = kSimpleStatus;
   g_quic_response_cache->AddResponse(base::StringPrintf("%s", kTestServerHost),
@@ -78,25 +153,22 @@
   DCHECK(g_quic_server_thread->task_runner()->BelongsToCurrentThread());
   DCHECK(!g_quic_server);
 
-  net::QuicConfig config;
+  QuicConfig config;
   // Set up server certs.
   base::FilePath directory;
   directory = test_files_root;
-  std::unique_ptr<net::ProofSourceChromium> proof_source(
-      new net::ProofSourceChromium());
+  std::unique_ptr<ProofSourceChromium> proof_source(new ProofSourceChromium());
   CHECK(proof_source->Initialize(directory.AppendASCII("quic-chain.pem"),
                                  directory.AppendASCII("quic-leaf-cert.key"),
                                  base::FilePath()));
   SetupQuicHttpResponseCache();
 
-  g_quic_server = new net::QuicSimpleServer(
-      std::move(proof_source), config,
-      net::QuicCryptoServerConfig::ConfigOptions(), net::AllSupportedVersions(),
-      g_quic_response_cache);
+  g_quic_server = new QuicSimpleServer(
+      std::move(proof_source), config, QuicCryptoServerConfig::ConfigOptions(),
+      AllSupportedVersions(), g_quic_response_cache);
 
   // Start listening on an unbound port.
-  int rv = g_quic_server->Listen(
-      net::IPEndPoint(net::IPAddress::IPv4AllZeros(), 0));
+  int rv = g_quic_server->Listen(IPEndPoint(IPAddress::IPv4AllZeros(), 0));
   CHECK_GE(rv, 0) << "Quic server fails to start";
   g_quic_server_port = g_quic_server->server_address().port();
   server_started_event->Signal();
@@ -119,7 +191,7 @@
   dispatcher_stopped_event->Signal();
 }
 
-bool StartQuicTestServer() {
+bool QuicSimpleTestServer::Start() {
   DVLOG(3) << g_quic_server_thread;
   DCHECK(!g_quic_server_thread);
   g_quic_server_thread = new base::Thread("quic server thread");
@@ -127,7 +199,7 @@
   thread_options.message_loop_type = base::MessageLoop::TYPE_IO;
   bool started = g_quic_server_thread->StartWithOptions(thread_options);
   DCHECK(started);
-  base::FilePath test_files_root = net::GetTestCertsDirectory();
+  base::FilePath test_files_root = GetTestCertsDirectory();
 
   base::WaitableEvent server_started_event(
       base::WaitableEvent::ResetPolicy::MANUAL,
@@ -140,7 +212,7 @@
 }
 
 // Shut down the server dispatcher, and the stream should error out.
-void ShutdownQuicTestServerDispatcher() {
+void QuicSimpleTestServer::ShutdownDispatcherForTesting() {
   if (!g_quic_server)
     return;
   DCHECK(!g_quic_server_thread->task_runner()->BelongsToCurrentThread());
@@ -153,7 +225,7 @@
   dispatcher_stopped_event.Wait();
 }
 
-void ShutdownQuicTestServer() {
+void QuicSimpleTestServer::Shutdown() {
   if (!g_quic_server)
     return;
   DCHECK(!g_quic_server_thread->task_runner()->BelongsToCurrentThread());
@@ -168,8 +240,8 @@
   g_quic_server_thread = nullptr;
 }
 
-int GetQuicTestServerPort() {
+int QuicSimpleTestServer::GetPort() {
   return g_quic_server_port;
 }
 
-}  // namespace grpc_support
+}  // namespace net
diff --git a/net/test/quic_simple_test_server.h b/net/test/quic_simple_test_server.h
new file mode 100644
index 0000000..03ed5b7
--- /dev/null
+++ b/net/test/quic_simple_test_server.h
@@ -0,0 +1,60 @@
+// 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_TEST_QUIC_SIMPLE_TEST_SERVER_H_
+#define NET_TEST_QUIC_SIMPLE_TEST_SERVER_H_
+
+#include <string>
+
+#include "url/gurl.h"
+
+namespace net {
+
+class QuicSimpleTestServer {
+ public:
+  static bool Start();
+  static void Shutdown();
+
+  // Shuts down the server dispatcher, which results in sending ConnectionClose
+  // frames to all connected clients.
+  static void ShutdownDispatcherForTesting();
+
+  // Returns example.com
+  static const std::string GetDomain();
+  // Returns test.example.com
+  static const std::string GetHost();
+  // Returns port number of the server.
+  static int GetPort();
+  // Returns test.example.com:port
+  static const std::string GetHostPort();
+
+  // Returns URL with host, port and file path, for example
+  // https://test.example.com:12345/{file_path}
+  static GURL GetFileURL(const std::string& file_path);
+
+  static const std::string GetStatusHeaderName();
+
+  // Server returns response with HTTP/2 headers and trailers. Does not include
+  // |port| as it is resolved differently: https://test.example.com/hello.txt
+  static GURL GetHelloURL();
+  static const std::string GetHelloPath();
+  static const std::string GetHelloBodyValue();
+  static const std::string GetHelloStatus();
+  static const std::string GetHelloHeaderName();
+  static const std::string GetHelloHeaderValue();
+  static const std::string GetHelloTrailerName();
+  static const std::string GetHelloTrailerValue();
+
+  // Server returns response without HTTP/2 trailers.
+  // https://test.example.com/simple.txt
+  static GURL GetSimpleURL();
+  static const std::string GetSimpleBodyValue();
+  static const std::string GetSimpleStatus();
+  static const std::string GetSimpleHeaderName();
+  static const std::string GetSimpleHeaderValue();
+};
+
+}  // namespace net
+
+#endif  // NET_TEST_QUIC_SIMPLE_TEST_SERVER_H_
diff --git a/net/websockets/websocket_basic_handshake_stream.cc b/net/websockets/websocket_basic_handshake_stream.cc
index 189b72a0..f8a3565 100644
--- a/net/websockets/websocket_basic_handshake_stream.cc
+++ b/net/websockets/websocket_basic_handshake_stream.cc
@@ -9,7 +9,6 @@
 #include <iterator>
 #include <set>
 #include <string>
-#include <unordered_set>
 #include <utility>
 #include <vector>
 
@@ -42,7 +41,6 @@
 #include "net/websockets/websocket_deflate_predictor_impl.h"
 #include "net/websockets/websocket_deflate_stream.h"
 #include "net/websockets/websocket_deflater.h"
-#include "net/websockets/websocket_extension_parser.h"
 #include "net/websockets/websocket_handshake_challenge.h"
 #include "net/websockets/websocket_handshake_constants.h"
 #include "net/websockets/websocket_handshake_request_info.h"
@@ -57,13 +55,6 @@
 
 }  // namespace
 
-// TODO(ricea): If more extensions are added, replace this with a more general
-// mechanism.
-struct WebSocketExtensionParams {
-  bool deflate_enabled = false;
-  WebSocketDeflateParameters deflate_parameters;
-};
-
 namespace {
 
 enum GetHeaderResult {
@@ -76,13 +67,6 @@
   return std::string("'") + header_name + "' header is missing";
 }
 
-std::string MultipleHeaderValuesMessage(const std::string& header_name) {
-  return
-      std::string("'") +
-      header_name +
-      "' header must not appear more than once in a response";
-}
-
 std::string GenerateHandshakeChallenge() {
   std::string raw_challenge(websockets::kRawChallengeLength, '\0');
   crypto::RandBytes(base::string_as_array(&raw_challenge),
@@ -92,14 +76,6 @@
   return encoded_challenge;
 }
 
-void AddVectorHeaderIfNonEmpty(const char* name,
-                               const std::vector<std::string>& value,
-                               HttpRequestHeaders* headers) {
-  if (value.empty())
-    return;
-  headers->SetHeader(name, base::JoinString(value, ", "));
-}
-
 GetHeaderResult GetSingleHeaderValue(const HttpResponseHeaders* headers,
                                      const base::StringPiece& name,
                                      std::string* value) {
@@ -122,7 +98,8 @@
     return false;
   }
   if (result == GET_HEADER_MULTIPLE) {
-    *failure_message = MultipleHeaderValuesMessage(header_name);
+    *failure_message =
+        WebSocketHandshakeStreamBase::MultipleHeaderValuesMessage(header_name);
     return false;
   }
   DCHECK_EQ(result, GET_HEADER_OK);
@@ -182,111 +159,6 @@
   return true;
 }
 
-bool ValidateSubProtocol(
-    const HttpResponseHeaders* headers,
-    const std::vector<std::string>& requested_sub_protocols,
-    std::string* sub_protocol,
-    std::string* failure_message) {
-  size_t iter = 0;
-  std::string value;
-  std::unordered_set<std::string> requested_set(requested_sub_protocols.begin(),
-                                                requested_sub_protocols.end());
-  int count = 0;
-  bool has_multiple_protocols = false;
-  bool has_invalid_protocol = false;
-
-  while (!has_invalid_protocol || !has_multiple_protocols) {
-    std::string temp_value;
-    if (!headers->EnumerateHeader(&iter, websockets::kSecWebSocketProtocol,
-                                  &temp_value))
-      break;
-    value = temp_value;
-    if (requested_set.count(value) == 0)
-      has_invalid_protocol = true;
-    if (++count > 1)
-      has_multiple_protocols = true;
-  }
-
-  if (has_multiple_protocols) {
-    *failure_message =
-        MultipleHeaderValuesMessage(websockets::kSecWebSocketProtocol);
-    return false;
-  } else if (count > 0 && requested_sub_protocols.size() == 0) {
-    *failure_message =
-        std::string("Response must not include 'Sec-WebSocket-Protocol' "
-                    "header if not present in request: ")
-        + value;
-    return false;
-  } else if (has_invalid_protocol) {
-    *failure_message =
-        "'Sec-WebSocket-Protocol' header value '" +
-        value +
-        "' in response does not match any of sent values";
-    return false;
-  } else if (requested_sub_protocols.size() > 0 && count == 0) {
-    *failure_message =
-        "Sent non-empty 'Sec-WebSocket-Protocol' header "
-        "but no response was received";
-    return false;
-  }
-  *sub_protocol = value;
-  return true;
-}
-
-bool ValidateExtensions(const HttpResponseHeaders* headers,
-                        std::string* accepted_extensions_descriptor,
-                        std::string* failure_message,
-                        WebSocketExtensionParams* params) {
-  size_t iter = 0;
-  std::string header_value;
-  std::vector<std::string> header_values;
-  // TODO(ricea): If adding support for additional extensions, generalise this
-  // code.
-  bool seen_permessage_deflate = false;
-  while (headers->EnumerateHeader(&iter, websockets::kSecWebSocketExtensions,
-                                  &header_value)) {
-    WebSocketExtensionParser parser;
-    if (!parser.Parse(header_value)) {
-      // TODO(yhirano) Set appropriate failure message.
-      *failure_message =
-          "'Sec-WebSocket-Extensions' header value is "
-          "rejected by the parser: " +
-          header_value;
-      return false;
-    }
-
-    const std::vector<WebSocketExtension>& extensions = parser.extensions();
-    for (const auto& extension : extensions) {
-      if (extension.name() == "permessage-deflate") {
-        if (seen_permessage_deflate) {
-          *failure_message = "Received duplicate permessage-deflate response";
-          return false;
-        }
-        seen_permessage_deflate = true;
-        auto& deflate_parameters = params->deflate_parameters;
-        if (!deflate_parameters.Initialize(extension, failure_message) ||
-            !deflate_parameters.IsValidAsResponse(failure_message)) {
-          *failure_message = "Error in permessage-deflate: " + *failure_message;
-          return false;
-        }
-        // Note that we don't have to check the request-response compatibility
-        // here because we send a request compatible with any valid responses.
-        // TODO(yhirano): Place a DCHECK here.
-
-        header_values.push_back(header_value);
-      } else {
-        *failure_message = "Found an unsupported extension '" +
-                           extension.name() +
-                           "' in 'Sec-WebSocket-Extensions' header";
-        return false;
-      }
-    }
-  }
-  *accepted_extensions_descriptor = base::JoinString(header_values, ", ");
-  params->deflate_enabled = seen_permessage_deflate;
-  return true;
-}
-
 }  // namespace
 
 WebSocketBasicHandshakeStream::WebSocketBasicHandshakeStream(
diff --git a/net/websockets/websocket_handshake_constants.cc b/net/websockets/websocket_handshake_constants.cc
index ce9bb62..4bd4bd1 100644
--- a/net/websockets/websocket_handshake_constants.cc
+++ b/net/websockets/websocket_handshake_constants.cc
@@ -22,8 +22,6 @@
 const char kUpgrade[] = "Upgrade";
 const char kWebSocketGuid[] = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
 
-const char kSecWebSocketProtocolLowercase[] = "sec-websocket-protocol";
-const char kSecWebSocketExtensionsLowercase[] = "sec-websocket-extensions";
 const char kWebSocketLowercase[] = "websocket";
 
 }  // namespace websockets
diff --git a/net/websockets/websocket_handshake_constants.h b/net/websockets/websocket_handshake_constants.h
index 8fb5fc5..3794d3ff 100644
--- a/net/websockets/websocket_handshake_constants.h
+++ b/net/websockets/websocket_handshake_constants.h
@@ -56,14 +56,6 @@
 // RFC6455.
 extern const char NET_EXPORT kWebSocketGuid[];
 
-// Some parts of the code require lowercase versions of the header names in
-// order to do case-insensitive comparisons, or because of HTTP/2.
-// "sec-websocket-protocol"
-extern const char kSecWebSocketProtocolLowercase[];
-
-// "sec-websocket-extensions"
-extern const char kSecWebSocketExtensionsLowercase[];
-
 // "websocket", as used in the "Upgrade:" header. This is always lowercase
 // (except in obsolete versions of the protocol).
 extern const char kWebSocketLowercase[];
diff --git a/net/websockets/websocket_handshake_stream_base.cc b/net/websockets/websocket_handshake_stream_base.cc
new file mode 100644
index 0000000..a90a896a
--- /dev/null
+++ b/net/websockets/websocket_handshake_stream_base.cc
@@ -0,0 +1,141 @@
+// 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 "net/websockets/websocket_handshake_stream_base.h"
+
+#include <unordered_set>
+
+#include "base/strings/string_util.h"
+#include "net/http/http_request_headers.h"
+#include "net/http/http_response_headers.h"
+#include "net/websockets/websocket_extension.h"
+#include "net/websockets/websocket_extension_parser.h"
+#include "net/websockets/websocket_handshake_constants.h"
+
+namespace net {
+
+// static
+std::string WebSocketHandshakeStreamBase::MultipleHeaderValuesMessage(
+    const std::string& header_name) {
+  return std::string("'") + header_name +
+         "' header must not appear more than once in a response";
+}
+
+// static
+void WebSocketHandshakeStreamBase::AddVectorHeaderIfNonEmpty(
+    const char* name,
+    const std::vector<std::string>& value,
+    HttpRequestHeaders* headers) {
+  if (value.empty())
+    return;
+  headers->SetHeader(name, base::JoinString(value, ", "));
+}
+
+// static
+bool WebSocketHandshakeStreamBase::ValidateSubProtocol(
+    const HttpResponseHeaders* headers,
+    const std::vector<std::string>& requested_sub_protocols,
+    std::string* sub_protocol,
+    std::string* failure_message) {
+  size_t iter = 0;
+  std::string value;
+  std::unordered_set<std::string> requested_set(requested_sub_protocols.begin(),
+                                                requested_sub_protocols.end());
+  int count = 0;
+  bool has_multiple_protocols = false;
+  bool has_invalid_protocol = false;
+
+  while (!has_invalid_protocol || !has_multiple_protocols) {
+    std::string temp_value;
+    if (!headers->EnumerateHeader(&iter, websockets::kSecWebSocketProtocol,
+                                  &temp_value))
+      break;
+    value = temp_value;
+    if (requested_set.count(value) == 0)
+      has_invalid_protocol = true;
+    if (++count > 1)
+      has_multiple_protocols = true;
+  }
+
+  if (has_multiple_protocols) {
+    *failure_message =
+        MultipleHeaderValuesMessage(websockets::kSecWebSocketProtocol);
+    return false;
+  } else if (count > 0 && requested_sub_protocols.size() == 0) {
+    *failure_message = std::string(
+                           "Response must not include 'Sec-WebSocket-Protocol' "
+                           "header if not present in request: ") +
+                       value;
+    return false;
+  } else if (has_invalid_protocol) {
+    *failure_message = "'Sec-WebSocket-Protocol' header value '" + value +
+                       "' in response does not match any of sent values";
+    return false;
+  } else if (requested_sub_protocols.size() > 0 && count == 0) {
+    *failure_message =
+        "Sent non-empty 'Sec-WebSocket-Protocol' header "
+        "but no response was received";
+    return false;
+  }
+  *sub_protocol = value;
+  return true;
+}
+
+// static
+bool WebSocketHandshakeStreamBase::ValidateExtensions(
+    const HttpResponseHeaders* headers,
+    std::string* accepted_extensions_descriptor,
+    std::string* failure_message,
+    WebSocketExtensionParams* params) {
+  size_t iter = 0;
+  std::string header_value;
+  std::vector<std::string> header_values;
+  // TODO(ricea): If adding support for additional extensions, generalise this
+  // code.
+  bool seen_permessage_deflate = false;
+  while (headers->EnumerateHeader(&iter, websockets::kSecWebSocketExtensions,
+                                  &header_value)) {
+    WebSocketExtensionParser parser;
+    if (!parser.Parse(header_value)) {
+      // TODO(yhirano) Set appropriate failure message.
+      *failure_message =
+          "'Sec-WebSocket-Extensions' header value is "
+          "rejected by the parser: " +
+          header_value;
+      return false;
+    }
+
+    const std::vector<WebSocketExtension>& extensions = parser.extensions();
+    for (const auto& extension : extensions) {
+      if (extension.name() == "permessage-deflate") {
+        if (seen_permessage_deflate) {
+          *failure_message = "Received duplicate permessage-deflate response";
+          return false;
+        }
+        seen_permessage_deflate = true;
+        auto& deflate_parameters = params->deflate_parameters;
+        if (!deflate_parameters.Initialize(extension, failure_message) ||
+            !deflate_parameters.IsValidAsResponse(failure_message)) {
+          *failure_message = "Error in permessage-deflate: " + *failure_message;
+          return false;
+        }
+        // Note that we don't have to check the request-response compatibility
+        // here because we send a request compatible with any valid responses.
+        // TODO(yhirano): Place a DCHECK here.
+
+        header_values.push_back(header_value);
+      } else {
+        *failure_message = "Found an unsupported extension '" +
+                           extension.name() +
+                           "' in 'Sec-WebSocket-Extensions' header";
+        return false;
+      }
+    }
+  }
+  *accepted_extensions_descriptor = base::JoinString(header_values, ", ");
+  params->deflate_enabled = seen_permessage_deflate;
+  return true;
+}
+
+}  // namespace net
diff --git a/net/websockets/websocket_handshake_stream_base.h b/net/websockets/websocket_handshake_stream_base.h
index feb12a38..d8abbc4 100644
--- a/net/websockets/websocket_handshake_stream_base.h
+++ b/net/websockets/websocket_handshake_stream_base.h
@@ -11,6 +11,7 @@
 
 #include <memory>
 #include <string>
+#include <vector>
 
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
@@ -18,12 +19,15 @@
 #include "net/base/net_export.h"
 #include "net/http/http_stream.h"
 #include "net/url_request/websocket_handshake_userdata_key.h"
+#include "net/websockets/websocket_deflate_parameters.h"
 #include "net/websockets/websocket_stream.h"
 
 namespace net {
 
 class ClientSocketHandle;
 class SpdySession;
+class HttpRequestHeaders;
+class HttpResponseHeaders;
 
 // WebSocketHandshakeStreamBase is the base class of
 // WebSocketBasicHandshakeStream.  net/http code uses this interface to handle
@@ -31,6 +35,9 @@
 // HttpStreamBase.
 class NET_EXPORT WebSocketHandshakeStreamBase : public HttpStream {
  public:
+  WebSocketHandshakeStreamBase() = default;
+  ~WebSocketHandshakeStreamBase() override = default;
+
   // An object that stores data needed for the creation of a
   // WebSocketBasicHandshakeStream object. A new CreateHelper is used for each
   // WebSocket connection.
@@ -58,10 +65,6 @@
         base::WeakPtr<SpdySession> session) = 0;
   };
 
-  // This has to have an inline implementation so that the net/url_request/
-  // tests do not fail on iOS.
-  ~WebSocketHandshakeStreamBase() override {}
-
   // After the handshake has completed, this method creates a WebSocketStream
   // (of the appropriate type) from the WebSocketHandshakeStreamBase object.
   // The WebSocketHandshakeStreamBase object is unusable after Upgrade() has
@@ -70,9 +73,31 @@
 
   void SetRequestHeadersCallback(RequestHeadersCallback callback) override {}
 
+  static std::string MultipleHeaderValuesMessage(
+      const std::string& header_name);
+
  protected:
-  // As with the destructor, this must be inline.
-  WebSocketHandshakeStreamBase() {}
+  // TODO(ricea): If more extensions are added, replace this with a more general
+  // mechanism.
+  struct WebSocketExtensionParams {
+    bool deflate_enabled = false;
+    WebSocketDeflateParameters deflate_parameters;
+  };
+
+  static void AddVectorHeaderIfNonEmpty(const char* name,
+                                        const std::vector<std::string>& value,
+                                        HttpRequestHeaders* headers);
+
+  static bool ValidateSubProtocol(
+      const HttpResponseHeaders* headers,
+      const std::vector<std::string>& requested_sub_protocols,
+      std::string* sub_protocol,
+      std::string* failure_message);
+
+  static bool ValidateExtensions(const HttpResponseHeaders* headers,
+                                 std::string* accepted_extensions_descriptor,
+                                 std::string* failure_message,
+                                 WebSocketExtensionParams* params);
 
  private:
   DISALLOW_COPY_AND_ASSIGN(WebSocketHandshakeStreamBase);
diff --git a/net/websockets/websocket_http2_handshake_stream.cc b/net/websockets/websocket_http2_handshake_stream.cc
index 987f38b..beb332e8 100644
--- a/net/websockets/websocket_http2_handshake_stream.cc
+++ b/net/websockets/websocket_http2_handshake_stream.cc
@@ -5,13 +5,11 @@
 #include "net/websockets/websocket_http2_handshake_stream.h"
 
 #include <cstddef>
-#include <unordered_set>
 #include <utility>
 
 #include "base/bind.h"
 #include "base/logging.h"
 #include "base/metrics/histogram_macros.h"
-#include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/time/time.h"
 #include "net/http/http_request_headers.h"
@@ -26,141 +24,17 @@
 #include "net/websockets/websocket_deflate_predictor_impl.h"
 #include "net/websockets/websocket_deflate_stream.h"
 #include "net/websockets/websocket_deflater.h"
-#include "net/websockets/websocket_extension_parser.h"
 #include "net/websockets/websocket_handshake_constants.h"
 #include "net/websockets/websocket_handshake_request_info.h"
 
 namespace net {
 
-// TODO(ricea): If more extensions are added, replace this with a more general
-// mechanism.
-struct WebSocketExtensionParams {
-  bool deflate_enabled = false;
-  WebSocketDeflateParameters deflate_parameters;
-};
-
 namespace {
 
-void AddVectorHeaderIfNonEmpty(const char* name,
-                               const std::vector<std::string>& value,
-                               HttpRequestHeaders* headers) {
-  if (value.empty())
-    return;
-  headers->SetHeader(name, base::JoinString(value, ", "));
-}
-
-std::string MultipleHeaderValuesMessage(const std::string& header_name) {
-  return std::string("'") + header_name +
-         "' header must not appear more than once in a response";
-}
-
 bool ValidateStatus(const HttpResponseHeaders* headers) {
   return headers->GetStatusLine() == "HTTP/1.1 200";
 }
 
-bool ValidateSubProtocol(
-    const HttpResponseHeaders* headers,
-    const std::vector<std::string>& requested_sub_protocols,
-    std::string* sub_protocol,
-    std::string* failure_message) {
-  size_t iter = 0;
-  std::string value;
-  std::unordered_set<std::string> requested_set(requested_sub_protocols.begin(),
-                                                requested_sub_protocols.end());
-  int count = 0;
-  bool has_multiple_protocols = false;
-  bool has_invalid_protocol = false;
-
-  while (!has_invalid_protocol || !has_multiple_protocols) {
-    std::string temp_value;
-    if (!headers->EnumerateHeader(
-            &iter, websockets::kSecWebSocketProtocolLowercase, &temp_value))
-      break;
-    value = temp_value;
-    if (requested_set.count(value) == 0)
-      has_invalid_protocol = true;
-    if (++count > 1)
-      has_multiple_protocols = true;
-  }
-
-  if (has_multiple_protocols) {
-    *failure_message =
-        MultipleHeaderValuesMessage(websockets::kSecWebSocketProtocolLowercase);
-    return false;
-  } else if (count > 0 && requested_sub_protocols.size() == 0) {
-    *failure_message = std::string(
-                           "Response must not include 'Sec-WebSocket-Protocol' "
-                           "header if not present in request: ") +
-                       value;
-    return false;
-  } else if (has_invalid_protocol) {
-    *failure_message = "'Sec-WebSocket-Protocol' header value '" + value +
-                       "' in response does not match any of sent values";
-    return false;
-  } else if (requested_sub_protocols.size() > 0 && count == 0) {
-    *failure_message =
-        "Sent non-empty 'Sec-WebSocket-Protocol' header "
-        "but no response was received";
-    return false;
-  }
-  *sub_protocol = value;
-  return true;
-}
-
-bool ValidateExtensions(const HttpResponseHeaders* headers,
-                        std::string* accepted_extensions_descriptor,
-                        std::string* failure_message,
-                        WebSocketExtensionParams* params) {
-  size_t iter = 0;
-  std::string header_value;
-  std::vector<std::string> header_values;
-  // TODO(ricea): If adding support for additional extensions, generalise this
-  // code.
-  bool seen_permessage_deflate = false;
-  while (headers->EnumerateHeader(
-      &iter, websockets::kSecWebSocketExtensionsLowercase, &header_value)) {
-    WebSocketExtensionParser parser;
-    if (!parser.Parse(header_value)) {
-      // TODO(yhirano) Set appropriate failure message.
-      *failure_message =
-          "'Sec-WebSocket-Extensions' header value is "
-          "rejected by the parser: " +
-          header_value;
-      return false;
-    }
-
-    const std::vector<WebSocketExtension>& extensions = parser.extensions();
-    for (const auto& extension : extensions) {
-      if (extension.name() == "permessage-deflate") {
-        if (seen_permessage_deflate) {
-          *failure_message = "Received duplicate permessage-deflate response";
-          return false;
-        }
-        seen_permessage_deflate = true;
-        auto& deflate_parameters = params->deflate_parameters;
-        if (!deflate_parameters.Initialize(extension, failure_message) ||
-            !deflate_parameters.IsValidAsResponse(failure_message)) {
-          *failure_message = "Error in permessage-deflate: " + *failure_message;
-          return false;
-        }
-        // Note that we don't have to check the request-response compatibility
-        // here because we send a request compatible with any valid responses.
-        // TODO(yhirano): Place a DCHECK here.
-
-        header_values.push_back(header_value);
-      } else {
-        *failure_message = "Found an unsupported extension '" +
-                           extension.name() +
-                           "' in 'Sec-WebSocket-Extensions' header";
-        return false;
-      }
-    }
-  }
-  *accepted_extensions_descriptor = base::JoinString(header_values, ", ");
-  params->deflate_enabled = seen_permessage_deflate;
-  return true;
-}
-
 }  // namespace
 
 WebSocketHttp2HandshakeStream::WebSocketHttp2HandshakeStream(
diff --git a/net/websockets/websocket_stream_test.cc b/net/websockets/websocket_stream_test.cc
index 05e76eec..65139b14 100644
--- a/net/websockets/websocket_stream_test.cc
+++ b/net/websockets/websocket_stream_test.cc
@@ -90,7 +90,10 @@
 class WebSocketStreamCreateTest : public TestWithParam<HandshakeStreamType>,
                                   public WebSocketStreamCreateTestBase {
  protected:
-  WebSocketStreamCreateTest() : stream_type_(GetParam()), sequence_number_(0) {}
+  WebSocketStreamCreateTest()
+      : stream_type_(GetParam()),
+        http2_response_status_("200"),
+        sequence_number_(0) {}
   ~WebSocketStreamCreateTest() override {
     // Permit any endpoint locks to be released.
     stream_request_.reset();
@@ -108,6 +111,18 @@
     url_request_context_host_.AddSSLSocketDataProvider(std::move(ssl_data));
   }
 
+  void SetTimer(std::unique_ptr<base::Timer> timer) {
+    timer_ = std::move(timer);
+  }
+
+  void SetAdditionalResponseData(std::string additional_data) {
+    additional_data_ = std::move(additional_data);
+  }
+
+  void SetHttp2ResponseStatus(const char* const http2_response_status) {
+    http2_response_status_ = http2_response_status;
+  }
+
   // Set up mock data and start websockets request, either for WebSocket
   // upgraded from an HTTP/1 connection, or for a WebSocket request over HTTP/2.
   void CreateAndConnectStandard(
@@ -119,9 +134,7 @@
       const GURL& site_for_cookies,
       const WebSocketExtraHeaders& send_additional_request_headers,
       const WebSocketExtraHeaders& extra_request_headers,
-      const WebSocketExtraHeaders& extra_response_headers,
-      std::unique_ptr<base::Timer> timer = {},
-      const std::string& additional_data = {}) {
+      const WebSocketExtraHeaders& extra_response_headers) {
     if (stream_type_ == BASIC_HANDSHAKE_STREAM) {
       url_request_context_host_.SetExpectations(
           WebSocketStandardRequest(
@@ -130,11 +143,11 @@
               WebSocketExtraHeadersToString(extra_request_headers)),
           WebSocketStandardResponse(
               WebSocketExtraHeadersToString(extra_response_headers)) +
-              additional_data);
+              additional_data_);
       CreateAndConnectStream(
           GURL(socket_url), sub_protocols, origin, site_for_cookies,
           WebSocketExtraHeadersToString(send_additional_request_headers),
-          std::move(timer));
+          std::move(timer_));
       return;
     }
 
@@ -221,15 +234,15 @@
       // Save a pointer to the original header value provided by the caller.
       extra_response_headers_vector.push_back(extra_header.second.c_str());
     }
-    frames_.push_back(spdy_util_.ConstructSpdyGetReply(
-        extra_response_headers_vector.data(),
+    frames_.push_back(spdy_util_.ConstructSpdyReplyError(
+        http2_response_status_, extra_response_headers_vector.data(),
         extra_response_headers_vector.size() / 2, 3));
     AddRead(&frames_.back());
 
     // WebSocket data received.
-    if (!additional_data.empty()) {
+    if (!additional_data_.empty()) {
       frames_.push_back(
-          spdy_util_.ConstructSpdyDataFrame(3, additional_data, true));
+          spdy_util_.ConstructSpdyDataFrame(3, additional_data_, true));
       AddRead(&frames_.back());
     }
 
@@ -261,7 +274,7 @@
     CreateAndConnectStream(
         GURL(socket_url), sub_protocols, origin, site_for_cookies,
         WebSocketExtraHeadersToString(send_additional_request_headers),
-        std::move(timer));
+        std::move(timer_));
   }
 
   // Like CreateAndConnectStandard(), but allow for arbitrary response body.
@@ -317,14 +330,13 @@
       const url::Origin& origin,
       const GURL& site_for_cookies,
       const std::string& send_additional_request_headers,
-      std::unique_ptr<SequencedSocketData> socket_data,
-      std::unique_ptr<base::Timer> timer = std::unique_ptr<base::Timer>()) {
+      std::unique_ptr<SequencedSocketData> socket_data) {
     ASSERT_EQ(BASIC_HANDSHAKE_STREAM, stream_type_);
 
     url_request_context_host_.AddRawExpectations(std::move(socket_data));
     CreateAndConnectStream(GURL(socket_url), sub_protocols, origin,
                            site_for_cookies, send_additional_request_headers,
-                           std::move(timer));
+                           std::move(timer_));
   }
 
  private:
@@ -342,6 +354,9 @@
   const HandshakeStreamType stream_type_;
 
  private:
+  std::unique_ptr<base::Timer> timer_;
+  std::string additional_data_;
+  const char* http2_response_status_;
   SpdyTestUtil spdy_util_;
   NetLogWithSource log_;
 
@@ -535,7 +550,7 @@
 
 INSTANTIATE_TEST_CASE_P(,
                         WebSocketStreamCreateUMATest,
-                        Values(BASIC_HANDSHAKE_STREAM));
+                        Values(BASIC_HANDSHAKE_STREAM, HTTP2_HANDSHAKE_STREAM));
 
 // Confirm that the basic case works as expected.
 TEST_P(WebSocketMultiProtocolStreamCreateTest, SimpleSuccess) {
@@ -728,20 +743,11 @@
   WaitUntilConnectDone();
   EXPECT_FALSE(stream_);
   EXPECT_TRUE(has_failed());
-  if (stream_type_ == BASIC_HANDSHAKE_STREAM) {
-    EXPECT_EQ(
-        "Error during WebSocket handshake: "
-        "'Sec-WebSocket-Protocol' header must not appear "
-        "more than once in a response",
-        failure_message());
-  } else {
-    DCHECK_EQ(HTTP2_HANDSHAKE_STREAM, stream_type_);
-    EXPECT_EQ(
-        "Error during WebSocket handshake: "
-        "'sec-websocket-protocol' header must not appear "
-        "more than once in a response",
-        failure_message());
-  }
+  EXPECT_EQ(
+      "Error during WebSocket handshake: "
+      "'Sec-WebSocket-Protocol' header must not appear "
+      "more than once in a response",
+      failure_message());
 }
 
 // Unmatched sub-protocol should be rejected.
@@ -786,15 +792,14 @@
 // permessage-deflate enabled.
 TEST_P(WebSocketStreamCreateExtensionTest, PerMessageDeflateInflates) {
   AddSSLData();
+  SetAdditionalResponseData(std::string(
+      "\xc1\x07"  // WebSocket header (FIN + RSV1, Text payload 7 bytes)
+      "\xf2\x48\xcd\xc9\xc9\x07\x00",  // "Hello" DEFLATE compressed
+      9));
   CreateAndConnectStandard(
       "wss://www.example.org/testing_path", "www.example.org", "/testing_path",
       NoSubProtocols(), Origin(), Url(), {}, {},
-      {{"Sec-WebSocket-Extensions", "permessage-deflate"}},
-      std::unique_ptr<base::Timer>(),
-      std::string(
-          "\xc1\x07"  // WebSocket header (FIN + RSV1, Text payload 7 bytes)
-          "\xf2\x48\xcd\xc9\xc9\x07\x00",  // "Hello" DEFLATE compressed
-          9));
+      {{"Sec-WebSocket-Extensions", "permessage-deflate"}});
   WaitUntilConnectDone();
 
   ASSERT_TRUE(stream_);
@@ -895,19 +900,28 @@
 
 // Redirects are not followed (according to the WHATWG WebSocket API, which
 // overrides RFC6455 for browser applications).
-TEST_P(WebSocketStreamCreateTest, RedirectsRejected) {
-  static const char kRedirectResponse[] =
-      "HTTP/1.1 302 Moved Temporarily\r\n"
-      "Content-Type: text/html\r\n"
-      "Content-Length: 34\r\n"
-      "Connection: keep-alive\r\n"
-      "Location: wss://www.example.org/other\r\n"
-      "\r\n"
-      "<title>Moved</title><h1>Moved</h1>";
-  CreateAndConnectCustomResponse("ws://www.example.org/", "www.example.org",
-                                 "/", NoSubProtocols(), Origin(), Url(), {}, {},
-                                 kRedirectResponse);
+TEST_P(WebSocketMultiProtocolStreamCreateTest, RedirectsRejected) {
+  AddSSLData();
+  if (stream_type_ == BASIC_HANDSHAKE_STREAM) {
+    static const char kRedirectResponse[] =
+        "HTTP/1.1 302 Moved Temporarily\r\n"
+        "Content-Type: text/html\r\n"
+        "Content-Length: 34\r\n"
+        "Connection: keep-alive\r\n"
+        "Location: wss://www.example.org/other\r\n"
+        "\r\n"
+        "<title>Moved</title><h1>Moved</h1>";
+    CreateAndConnectCustomResponse("wss://www.example.org/", "www.example.org",
+                                   "/", NoSubProtocols(), Origin(), Url(), {},
+                                   {}, kRedirectResponse);
+  } else {
+    DCHECK_EQ(stream_type_, HTTP2_HANDSHAKE_STREAM);
+    SetHttp2ResponseStatus("302");
+    CreateAndConnectStandard("wss://www.example.org/", "www.example.org", "/",
+                             NoSubProtocols(), Origin(), Url(), {}, {}, {});
+  }
   WaitUntilConnectDone();
+
   EXPECT_TRUE(has_failed());
   EXPECT_EQ("Error during WebSocket handshake: Unexpected response code: 302",
             failure_message());
@@ -1113,9 +1127,9 @@
   socket_data->set_connect_data(MockConnect(SYNCHRONOUS, ERR_IO_PENDING));
   auto timer = std::make_unique<MockWeakTimer>(false, false);
   base::WeakPtr<MockWeakTimer> weak_timer = timer->AsWeakPtr();
+  SetTimer(std::move(timer));
   CreateAndConnectRawExpectations("ws://www.example.org/", NoSubProtocols(),
-                                  Origin(), Url(), "", std::move(socket_data),
-                                  std::move(timer));
+                                  Origin(), Url(), "", std::move(socket_data));
   EXPECT_FALSE(has_failed());
   ASSERT_TRUE(weak_timer.get());
   EXPECT_TRUE(weak_timer->IsRunning());
@@ -1134,9 +1148,9 @@
   auto timer = std::make_unique<MockWeakTimer>(false, false);
   base::WeakPtr<MockWeakTimer> weak_timer = timer->AsWeakPtr();
 
+  SetTimer(std::move(timer));
   CreateAndConnectStandard("ws://www.example.org/", "www.example.org", "/",
-                           NoSubProtocols(), Origin(), Url(), {}, {}, {},
-                           std::move(timer));
+                           NoSubProtocols(), Origin(), Url(), {}, {}, {});
   ASSERT_TRUE(weak_timer);
   EXPECT_TRUE(weak_timer->IsRunning());
 
@@ -1154,9 +1168,9 @@
       MockConnect(SYNCHRONOUS, ERR_CONNECTION_REFUSED));
   auto timer = std::make_unique<MockWeakTimer>(false, false);
   base::WeakPtr<MockWeakTimer> weak_timer = timer->AsWeakPtr();
+  SetTimer(std::move(timer));
   CreateAndConnectRawExpectations("ws://www.example.org/", NoSubProtocols(),
-                                  Origin(), Url(), "", std::move(socket_data),
-                                  std::move(timer));
+                                  Origin(), Url(), "", std::move(socket_data));
   ASSERT_TRUE(weak_timer.get());
   EXPECT_TRUE(weak_timer->IsRunning());
 
@@ -1363,7 +1377,8 @@
 TEST_P(WebSocketStreamCreateUMATest, Incomplete) {
   base::HistogramTester histogram_tester;
 
-  CreateAndConnectStandard("ws://www.example.org/", "www.example.org", "/",
+  AddSSLData();
+  CreateAndConnectStandard("wss://www.example.org/", "www.example.org", "/",
                            NoSubProtocols(), Origin(), Url(), {}, {}, {});
   stream_request_.reset();
 
@@ -1377,7 +1392,8 @@
 TEST_P(WebSocketStreamCreateUMATest, Connected) {
   base::HistogramTester histogram_tester;
 
-  CreateAndConnectStandard("ws://www.example.org/", "www.example.org", "/",
+  AddSSLData();
+  CreateAndConnectStandard("wss://www.example.org/", "www.example.org", "/",
                            NoSubProtocols(), Origin(), Url(), {}, {}, {});
   WaitUntilConnectDone();
   stream_request_.reset();
@@ -1392,17 +1408,28 @@
 TEST_P(WebSocketStreamCreateUMATest, Failed) {
   base::HistogramTester histogram_tester;
 
-  static const char kInvalidStatusCodeResponse[] =
-      "HTTP/1.1 200 OK\r\n"
-      "Upgrade: websocket\r\n"
-      "Connection: Upgrade\r\n"
-      "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
-      "\r\n";
-  CreateAndConnectCustomResponse("ws://www.example.org/", "www.example.org",
-                                 "/", NoSubProtocols(), Origin(), Url(), {}, {},
-                                 kInvalidStatusCodeResponse);
-  WaitUntilConnectDone();
-  stream_request_.reset();
+  if (stream_type_ == BASIC_HANDSHAKE_STREAM) {
+    AddSSLData();
+    static const char kInvalidStatusCodeResponse[] =
+        "HTTP/1.1 200 OK\r\n"
+        "Upgrade: websocket\r\n"
+        "Connection: Upgrade\r\n"
+        "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
+        "\r\n";
+    CreateAndConnectCustomResponse("wss://www.example.org/", "www.example.org",
+                                   "/", NoSubProtocols(), Origin(), Url(), {},
+                                   {}, kInvalidStatusCodeResponse);
+    WaitUntilConnectDone();
+    stream_request_.reset();
+  } else {
+    DCHECK_EQ(stream_type_, HTTP2_HANDSHAKE_STREAM);
+    AddSSLData();
+    SetHttp2ResponseStatus("404");
+    CreateAndConnectStandard("wss://www.example.org/", "www.example.org", "/",
+                             NoSubProtocols(), Origin(), Url(), {}, {}, {});
+    WaitUntilConnectDone();
+    stream_request_.reset();
+  }
 
   auto samples = histogram_tester.GetHistogramSamplesSinceCreation(
       "Net.WebSocket.HandshakeResult");
diff --git a/services/tracing/coordinator.cc b/services/tracing/coordinator.cc
index 795abd0..351a66d8 100644
--- a/services/tracing/coordinator.cc
+++ b/services/tracing/coordinator.cc
@@ -347,7 +347,7 @@
                      weak_ptr_factory_.GetWeakPtr(),
                      base::Unretained(agent_entry), false));
   agent_entry->agent()->StartTracing(
-      config_, base::TimeTicks::Now(),
+      config_, TRACE_TIME_TICKS_NOW(),
       base::BindRepeating(&Coordinator::OnTracingStarted,
                           weak_ptr_factory_.GetWeakPtr(),
                           base::Unretained(agent_entry)));
diff --git a/services/tracing/public/cpp/chrome_trace_event_agent.cc b/services/tracing/public/cpp/chrome_trace_event_agent.cc
index 0def62c..135105eb 100644
--- a/services/tracing/public/cpp/chrome_trace_event_agent.cc
+++ b/services/tracing/public/cpp/chrome_trace_event_agent.cc
@@ -65,7 +65,7 @@
   // NaCl and system times are offset by a bit, so subtract some time from
   // the captured timestamps. The value might be off by a bit due to messaging
   // latency.
-  base::TimeDelta time_offset = base::TimeTicks::Now() - coordinator_time;
+  base::TimeDelta time_offset = TRACE_TIME_TICKS_NOW() - coordinator_time;
   TraceLog::GetInstance()->SetTimeOffset(time_offset);
 #endif
   enabled_tracing_modes_ = base::trace_event::TraceLog::RECORDING_MODE;
diff --git a/services/viz/public/cpp/compositing/copy_output_result_struct_traits.cc b/services/viz/public/cpp/compositing/copy_output_result_struct_traits.cc
index 0b952bd..c0fd8a8 100644
--- a/services/viz/public/cpp/compositing/copy_output_result_struct_traits.cc
+++ b/services/viz/public/cpp/compositing/copy_output_result_struct_traits.cc
@@ -40,6 +40,92 @@
 namespace mojo {
 
 // static
+viz::mojom::CopyOutputResultFormat
+EnumTraits<viz::mojom::CopyOutputResultFormat, viz::CopyOutputResult::Format>::
+    ToMojom(viz::CopyOutputResult::Format format) {
+  switch (format) {
+    case viz::CopyOutputResult::Format::RGBA_BITMAP:
+      return viz::mojom::CopyOutputResultFormat::RGBA_BITMAP;
+    case viz::CopyOutputResult::Format::RGBA_TEXTURE:
+      return viz::mojom::CopyOutputResultFormat::RGBA_TEXTURE;
+    case viz::CopyOutputResult::Format::I420_PLANES:
+      break;  // Not intended for transport across service boundaries.
+  }
+  NOTREACHED();
+  return viz::mojom::CopyOutputResultFormat::RGBA_BITMAP;
+}
+
+// static
+bool EnumTraits<viz::mojom::CopyOutputResultFormat,
+                viz::CopyOutputResult::Format>::
+    FromMojom(viz::mojom::CopyOutputResultFormat input,
+              viz::CopyOutputResult::Format* out) {
+  switch (input) {
+    case viz::mojom::CopyOutputResultFormat::RGBA_BITMAP:
+      *out = viz::CopyOutputResult::Format::RGBA_BITMAP;
+      return true;
+    case viz::mojom::CopyOutputResultFormat::RGBA_TEXTURE:
+      *out = viz::CopyOutputResult::Format::RGBA_TEXTURE;
+      return true;
+  }
+  return false;
+}
+
+// static
+viz::CopyOutputResult::Format
+StructTraits<viz::mojom::CopyOutputResultDataView,
+             std::unique_ptr<viz::CopyOutputResult>>::
+    format(const std::unique_ptr<viz::CopyOutputResult>& result) {
+  return result->format();
+}
+
+// static
+const gfx::Rect& StructTraits<viz::mojom::CopyOutputResultDataView,
+                              std::unique_ptr<viz::CopyOutputResult>>::
+    rect(const std::unique_ptr<viz::CopyOutputResult>& result) {
+  return result->rect();
+}
+
+// static
+const SkBitmap& StructTraits<viz::mojom::CopyOutputResultDataView,
+                             std::unique_ptr<viz::CopyOutputResult>>::
+    bitmap(const std::unique_ptr<viz::CopyOutputResult>& result) {
+  // This will return a non-drawable bitmap if the result was not
+  // RGBA_BITMAP or if the result is empty.
+  return result->AsSkBitmap();
+}
+
+// static
+base::Optional<gpu::Mailbox>
+StructTraits<viz::mojom::CopyOutputResultDataView,
+             std::unique_ptr<viz::CopyOutputResult>>::
+    mailbox(const std::unique_ptr<viz::CopyOutputResult>& result) {
+  if (result->format() != viz::CopyOutputResult::Format::RGBA_TEXTURE)
+    return base::nullopt;
+  return result->GetTextureResult()->mailbox;
+}
+
+// static
+base::Optional<gpu::SyncToken>
+StructTraits<viz::mojom::CopyOutputResultDataView,
+             std::unique_ptr<viz::CopyOutputResult>>::
+    sync_token(const std::unique_ptr<viz::CopyOutputResult>& result) {
+  if (result->format() != viz::CopyOutputResult::Format::RGBA_TEXTURE)
+    return base::nullopt;
+  return result->GetTextureResult()->sync_token;
+}
+
+// static
+base::Optional<gfx::ColorSpace>
+StructTraits<viz::mojom::CopyOutputResultDataView,
+             std::unique_ptr<viz::CopyOutputResult>>::
+    color_space(const std::unique_ptr<viz::CopyOutputResult>& result) {
+  if (result->format() != viz::CopyOutputResult::Format::RGBA_TEXTURE)
+    return base::nullopt;
+  return result->GetTextureResult()->color_space;
+}
+
+// static
 viz::mojom::TextureReleaserPtr
 StructTraits<viz::mojom::CopyOutputResultDataView,
              std::unique_ptr<viz::CopyOutputResult>>::
diff --git a/services/viz/public/cpp/compositing/copy_output_result_struct_traits.h b/services/viz/public/cpp/compositing/copy_output_result_struct_traits.h
index 2fdcfc2e..60900bd 100644
--- a/services/viz/public/cpp/compositing/copy_output_result_struct_traits.h
+++ b/services/viz/public/cpp/compositing/copy_output_result_struct_traits.h
@@ -20,73 +20,32 @@
 struct EnumTraits<viz::mojom::CopyOutputResultFormat,
                   viz::CopyOutputResult::Format> {
   static viz::mojom::CopyOutputResultFormat ToMojom(
-      viz::CopyOutputResult::Format format) {
-    switch (format) {
-      case viz::CopyOutputResult::Format::RGBA_BITMAP:
-        return viz::mojom::CopyOutputResultFormat::RGBA_BITMAP;
-      case viz::CopyOutputResult::Format::RGBA_TEXTURE:
-        return viz::mojom::CopyOutputResultFormat::RGBA_TEXTURE;
-      case viz::CopyOutputResult::Format::I420_PLANES:
-        break;  // Not intended for transport across service boundaries.
-    }
-    NOTREACHED();
-    return viz::mojom::CopyOutputResultFormat::RGBA_BITMAP;
-  }
+      viz::CopyOutputResult::Format format);
 
   static bool FromMojom(viz::mojom::CopyOutputResultFormat input,
-                        viz::CopyOutputResult::Format* out) {
-    switch (input) {
-      case viz::mojom::CopyOutputResultFormat::RGBA_BITMAP:
-        *out = viz::CopyOutputResult::Format::RGBA_BITMAP;
-        return true;
-      case viz::mojom::CopyOutputResultFormat::RGBA_TEXTURE:
-        *out = viz::CopyOutputResult::Format::RGBA_TEXTURE;
-        return true;
-    }
-    return false;
-  }
+                        viz::CopyOutputResult::Format* out);
 };
 
 template <>
 struct StructTraits<viz::mojom::CopyOutputResultDataView,
                     std::unique_ptr<viz::CopyOutputResult>> {
   static viz::CopyOutputResult::Format format(
-      const std::unique_ptr<viz::CopyOutputResult>& result) {
-    return result->format();
-  }
+      const std::unique_ptr<viz::CopyOutputResult>& result);
 
   static const gfx::Rect& rect(
-      const std::unique_ptr<viz::CopyOutputResult>& result) {
-    return result->rect();
-  }
+      const std::unique_ptr<viz::CopyOutputResult>& result);
 
   static const SkBitmap& bitmap(
-      const std::unique_ptr<viz::CopyOutputResult>& result) {
-    // This will return a non-drawable bitmap if the result was not
-    // RGBA_BITMAP or if the result is empty.
-    return result->AsSkBitmap();
-  }
+      const std::unique_ptr<viz::CopyOutputResult>& result);
 
   static base::Optional<gpu::Mailbox> mailbox(
-      const std::unique_ptr<viz::CopyOutputResult>& result) {
-    if (result->format() != viz::CopyOutputResult::Format::RGBA_TEXTURE)
-      return base::nullopt;
-    return result->GetTextureResult()->mailbox;
-  }
+      const std::unique_ptr<viz::CopyOutputResult>& result);
 
   static base::Optional<gpu::SyncToken> sync_token(
-      const std::unique_ptr<viz::CopyOutputResult>& result) {
-    if (result->format() != viz::CopyOutputResult::Format::RGBA_TEXTURE)
-      return base::nullopt;
-    return result->GetTextureResult()->sync_token;
-  }
+      const std::unique_ptr<viz::CopyOutputResult>& result);
 
   static base::Optional<gfx::ColorSpace> color_space(
-      const std::unique_ptr<viz::CopyOutputResult>& result) {
-    if (result->format() != viz::CopyOutputResult::Format::RGBA_TEXTURE)
-      return base::nullopt;
-    return result->GetTextureResult()->color_space;
-  }
+      const std::unique_ptr<viz::CopyOutputResult>& result);
 
   static viz::mojom::TextureReleaserPtr releaser(
       const std::unique_ptr<viz::CopyOutputResult>& result);
diff --git a/services/viz/public/cpp/compositing/paint_filter.typemap b/services/viz/public/cpp/compositing/paint_filter.typemap
index 8dc59bd4..610e620b 100644
--- a/services/viz/public/cpp/compositing/paint_filter.typemap
+++ b/services/viz/public/cpp/compositing/paint_filter.typemap
@@ -9,4 +9,7 @@
 deps = [
   "//cc/paint",
 ]
+sources = [
+  "//services/viz/public/cpp/compositing/paint_filter_struct_traits.cc",
+]
 type_mappings = [ "viz.mojom.PaintFilter=sk_sp<cc::PaintFilter>" ]
diff --git a/services/viz/public/cpp/compositing/paint_filter_struct_traits.cc b/services/viz/public/cpp/compositing/paint_filter_struct_traits.cc
new file mode 100644
index 0000000..2e5757bd
--- /dev/null
+++ b/services/viz/public/cpp/compositing/paint_filter_struct_traits.cc
@@ -0,0 +1,62 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/viz/public/cpp/compositing/paint_filter_struct_traits.h"
+
+#include "cc/paint/paint_filter.h"
+
+namespace mojo {
+
+// static
+base::Optional<std::vector<uint8_t>>
+StructTraits<viz::mojom::PaintFilterDataView, sk_sp<cc::PaintFilter>>::data(
+    const sk_sp<cc::PaintFilter>& filter) {
+  std::vector<uint8_t> memory;
+  memory.resize(cc::PaintOpWriter::HeaderBytes() +
+                cc::PaintFilter::GetFilterSize(filter.get()));
+  cc::PaintOpWriter writer(memory.data(), memory.size(), nullptr, nullptr,
+                           true /* enable_security_constraints */);
+  writer.Write(filter.get());
+
+  if (writer.size() == 0)
+    return base::nullopt;
+
+  memory.resize(writer.size());
+  return memory;
+}
+
+// static
+bool StructTraits<viz::mojom::PaintFilterDataView, sk_sp<cc::PaintFilter>>::
+    Read(viz::mojom::PaintFilterDataView data, sk_sp<cc::PaintFilter>* out) {
+  base::Optional<std::vector<uint8_t>> buffer;
+  if (!data.ReadData(&buffer))
+    return false;
+
+  if (!buffer) {
+    // We may fail to serialize the filter if it doesn't fit in kBufferSize
+    // above, use an empty filter instead of rejecting the message.
+    *out = nullptr;
+    return true;
+  }
+
+  cc::PaintOpReader reader(buffer->data(), buffer->size(), nullptr,
+                           true /* enable_security_constraints */);
+  sk_sp<cc::PaintFilter> filter;
+  reader.Read(&filter);
+  if (!reader.valid()) {
+    *out = nullptr;
+    return false;
+  }
+
+  // We must have consumed all bytes writen when reading this filter.
+  if (reader.remaining_bytes() != 0u) {
+    *out = nullptr;
+    return false;
+  }
+
+  *out = std::move(filter);
+  return true;
+}
+
+}  // namespace mojo
diff --git a/services/viz/public/cpp/compositing/paint_filter_struct_traits.h b/services/viz/public/cpp/compositing/paint_filter_struct_traits.h
index a6df351..de2e8bd 100644
--- a/services/viz/public/cpp/compositing/paint_filter_struct_traits.h
+++ b/services/viz/public/cpp/compositing/paint_filter_struct_traits.h
@@ -7,62 +7,23 @@
 
 #include <vector>
 
-#include "cc/paint/paint_filter.h"
 #include "cc/paint/paint_op_reader.h"
 #include "cc/paint/paint_op_writer.h"
 #include "services/viz/public/interfaces/compositing/paint_filter.mojom-shared.h"
 
+namespace cc {
+class PaintFilter;
+}
+
 namespace mojo {
 
 template <>
 struct StructTraits<viz::mojom::PaintFilterDataView, sk_sp<cc::PaintFilter>> {
   static base::Optional<std::vector<uint8_t>> data(
-      const sk_sp<cc::PaintFilter>& filter) {
-    std::vector<uint8_t> memory;
-    memory.resize(cc::PaintOpWriter::HeaderBytes() +
-                  cc::PaintFilter::GetFilterSize(filter.get()));
-    cc::PaintOpWriter writer(memory.data(), memory.size(), nullptr, nullptr,
-                             true /* enable_security_constraints */);
-    writer.Write(filter.get());
-
-    if (writer.size() == 0)
-      return base::nullopt;
-
-    memory.resize(writer.size());
-    return memory;
-  }
+      const sk_sp<cc::PaintFilter>& filter);
 
   static bool Read(viz::mojom::PaintFilterDataView data,
-                   sk_sp<cc::PaintFilter>* out) {
-    base::Optional<std::vector<uint8_t>> buffer;
-    if (!data.ReadData(&buffer))
-      return false;
-
-    if (!buffer) {
-      // We may fail to serialize the filter if it doesn't fit in kBufferSize
-      // above, use an empty filter instead of rejecting the message.
-      *out = nullptr;
-      return true;
-    }
-
-    cc::PaintOpReader reader(buffer->data(), buffer->size(), nullptr,
-                             true /* enable_security_constraints */);
-    sk_sp<cc::PaintFilter> filter;
-    reader.Read(&filter);
-    if (!reader.valid()) {
-      *out = nullptr;
-      return false;
-    }
-
-    // We must have consumed all bytes writen when reading this filter.
-    if (reader.remaining_bytes() != 0u) {
-      *out = nullptr;
-      return false;
-    }
-
-    *out = std::move(filter);
-    return true;
-  }
+                   sk_sp<cc::PaintFilter>* out);
 };
 
 }  // namespace mojo
diff --git a/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter b/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter
index 4490cff..055ae80 100644
--- a/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter
+++ b/testing/buildbot/filters/mojo.fyi.network_browser_tests.filter
@@ -211,14 +211,6 @@
 # Remove streams concept from code and replace with data pipe passing.
 -MimeHandlerViewTests/MimeHandlerViewTest.Abort/0
 -MimeHandlerViewTests/MimeHandlerViewTest.Abort/1
--MimeHandlerViewTests/MimeHandlerViewTest.DataUrl/0
--MimeHandlerViewTests/MimeHandlerViewTest.DataUrl/1
--MimeHandlerViewTests/MimeHandlerViewTest.EmbeddedDataUrlEmbed/0
--MimeHandlerViewTests/MimeHandlerViewTest.EmbeddedDataUrlEmbed/1
--MimeHandlerViewTests/MimeHandlerViewTest.EmbeddedDataUrlLong/0
--MimeHandlerViewTests/MimeHandlerViewTest.EmbeddedDataUrlLong/1
--MimeHandlerViewTests/MimeHandlerViewTest.EmbeddedDataUrlObject/0
--MimeHandlerViewTests/MimeHandlerViewTest.EmbeddedDataUrlObject/1
 -MimeHandlerViewTests/MimeHandlerViewTest.SingleRequest/0
 -MimeHandlerViewTests/MimeHandlerViewTest.SingleRequest/1
 -PrerenderBrowserTestWithExtensions.StreamsTest
@@ -334,16 +326,6 @@
 -ContentFaviconDriverTest.ReloadBypassingCache
 -ContentFaviconDriverTest.MixedContentSecureFaviconAllowed
 
-
-# Failing NoStatePrefetch tests
-# https://crbug.com/792776
-#
-# Crashing.
--NoStatePrefetchBrowserTest/NoStatePrefetchBrowserTest.PrefetchCookie/1
--NoStatePrefetchBrowserTest/NoStatePrefetchBrowserTest.PrefetchCookie/0
--NoStatePrefetchBrowserTest/NoStatePrefetchBrowserTest.PrefetchCookieCrossDomain/0
--NoStatePrefetchBrowserTest/NoStatePrefetchBrowserTest.PrefetchCookieCrossDomain/1
-
 # Add support of download_to_file for URLLoader.
 # http://crbug.com/791702
 -OutOfProcessPPAPITest.FileRef1
diff --git a/third_party/WebKit/LayoutTests/ASANExpectations b/third_party/WebKit/LayoutTests/ASANExpectations
index 4a25f084..537d6434 100644
--- a/third_party/WebKit/LayoutTests/ASANExpectations
+++ b/third_party/WebKit/LayoutTests/ASANExpectations
@@ -70,3 +70,6 @@
 crbug.com/803276 virtual/sampling-heap-profiler/inspector-protocol/memory/sampling-native-profile.js [ Skip ]
 crbug.com/803276 virtual/sampling-heap-profiler/inspector-protocol/memory/sampling-native-snapshot.js [ Skip ]
 
+# Tests timing out sometimes on WebKit Linux Trusty ASAN/MSAN
+crbug.com/681919 [ Linux ] http/tests/media/media-src-suspend-after-have-metadata.html [ Timeout Pass ]
+crbug.com/681919 [ Linux ] http/tests/media/media-src-suspend-before-have-metadata.html [ Timeout Pass ]
diff --git a/third_party/WebKit/LayoutTests/MSANExpectations b/third_party/WebKit/LayoutTests/MSANExpectations
index f322677..659f5ae 100644
--- a/third_party/WebKit/LayoutTests/MSANExpectations
+++ b/third_party/WebKit/LayoutTests/MSANExpectations
@@ -93,3 +93,6 @@
 crbug.com/803276 virtual/sampling-heap-profiler/inspector-protocol/memory/sampling-native-profile.js [ Skip ]
 crbug.com/803276 virtual/sampling-heap-profiler/inspector-protocol/memory/sampling-native-snapshot.js [ Skip ]
 
+# Tests timing out sometimes on WebKit Linux Trusty ASAN/MSAN
+crbug.com/681919 [ Linux ] http/tests/media/media-src-suspend-after-have-metadata.html [ Timeout Pass ]
+crbug.com/681919 [ Linux ] http/tests/media/media-src-suspend-before-have-metadata.html [ Timeout Pass ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 873c8d73..5c2bd039 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -883,10 +883,8 @@
 crbug.com/441840 external/wpt/css/css-shapes/shape-outside/values/shape-outside-polygon-004.html [ Failure ]
 crbug.com/441840 [ Linux Win ] external/wpt/css/css-shapes/shape-outside/values/shape-outside-shape-arguments-000.html [ Failure ]
 
-crbug.com/817804 [ Linux ] external/wpt/css/css-text/i18n/css3-text-line-break-opclns-004.html [ Failure ]
 crbug.com/817781 external/wpt/css/css-text/i18n/css3-text-line-break-opclns-013.html [ Failure ]
 crbug.com/817781 external/wpt/css/css-text/i18n/css3-text-line-break-opclns-048.html [ Failure ]
-crbug.com/817804 [ Linux ] external/wpt/css/css-text/i18n/css3-text-line-break-opclns-111.html [ Failure ]
 crbug.com/817778 external/wpt/css/css-text/i18n/css3-text-line-break-opclns-118.html [ Failure ]
 crbug.com/817778 external/wpt/css/css-text/i18n/css3-text-line-break-opclns-154.html [ Failure ]
 crbug.com/817778 external/wpt/css/css-text/i18n/css3-text-line-break-opclns-216.html [ Failure ]
@@ -1669,6 +1667,7 @@
 crbug.com/805463 external/wpt/acid/acid3/numbered-tests.html [ Skip ]
 
 # ====== New tests from wpt-importer added here ======
+crbug.com/626703 external/wpt/css/css-writing-modes/available-size-019.html [ Failure ]
 crbug.com/626703 external/wpt/payment-request/change-shipping-option-select-last-manual.https.html [ Skip ]
 crbug.com/626703 [ Mac10.13 ] external/wpt/css/css-text/word-break/word-break-break-all-004.html [ Failure ]
 crbug.com/626703 [ Android ] external/wpt/bluetooth/requestDevice/canonicalizeFilter/no-arguments.https.html [ Crash ]
@@ -3357,11 +3356,15 @@
 crbug.com/811977 virtual/new-remote-playback-pipeline/media/controls/picture-in-picture-interstitial.html [ Skip ]
 
 # Sheriff 2018-02-26
-crbug.com/816475 [ Win7 ] external/wpt/webrtc/RTCDTMFSender-ontonechange.https.html [ Failure Pass ]
+# NOT FIXED - must be commented out to let temp disable below be committed: crbug.com/816475 [ Win7 ] external/wpt/webrtc/RTCDTMFSender-ontonechange.https.html [ Failure Pass ]
 crbug.com/816914 [ Mac ] fast/canvas/canvas-drawImage-live-video.html [ Failure Pass ]
 crbug.com/816766 [ Mac ] fast/dom/Window/window-focus-self.html [ Failure Pass ]
 crbug.com/817167 http/tests/devtools/oopif/oopif-cookies-refresh.js [ Failure Timeout Pass ]
 
+# Temporary disable to allow webrtc bugfix to land
+crbug.com/819118 external/wpt/webrtc/RTCDTMFSender-ontonechange.https.html [ Skip ]
+crbug.com/819118 external/wpt/webrtc/RTCDTMFSender-insertDTMF.https.html [ Skip ]
+
 # Sheriff 2018-03-01
 crbug.com/817678 [ Win ] http/tests/devtools/console/console-group-similar.js [ Failure Pass ]
 
@@ -3395,3 +3398,7 @@
 
 # Sheriff 2018-03-05
 crbug.com/818650 [ Linux ] fast/speech/scripted/speechrecognition-restart-onend.html [ Crash Pass ]
+
+# Sheriff 2018-03-06
+crbug.com/681919 [ Linux Debug ] http/tests/media/media-src-suspend-after-have-metadata.html [ Timeout Pass ]
+crbug.com/681919 [ Linux Debug ] http/tests/media/media-src-suspend-before-have-metadata.html [ Timeout Pass ]
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/column-count-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/column-count-interpolation.html
new file mode 100644
index 0000000..608b9c7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/column-count-interpolation.html
@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<body>
+<style>
+.parent {
+  column-count: 30;
+}
+.target {
+  column-count: 10;
+}
+</style>
+<script src="resources/interpolation-test.js"></script>
+<script>
+assertInterpolation({
+  property: 'column-count',
+  from: neutralKeyframe,
+  to: '20',
+}, [
+  {at: -0.5, is: '5'},
+  {at: 0, is: '10'},
+  {at: 0.3, is: '13'},
+  {at: 0.7, is: '17'},
+  {at: 1, is: '20'},
+  {at: 1.5, is: '25'},
+]);
+
+assertNoInterpolation({
+  property: 'column-count',
+  from: 'auto',
+  to: '20',
+});
+
+assertInterpolation({
+  property: 'column-count',
+  from: 'inherit',
+  to: '20',
+}, [
+  {at: -0.5, is: '35'},
+  {at: 0, is: '30'},
+  {at: 0.3, is: '27'},
+  {at: 0.7, is: '23'},
+  {at: 1, is: '20'},
+  {at: 1.5, is: '15'},
+]);
+
+assertInterpolation({
+  property: 'column-count',
+  from: '10',
+  to: '1'
+}, [
+  {at: -0.5, is: '15'},
+  {at: 0, is: '10'},
+  {at: 0.3, is: '7'},
+  {at: 0.7, is: '4'},
+  // Only positive integers are valid
+  {at: 1, is: '1'},
+  {at: 1.5, is: '1'}
+]);
+</script>
diff --git a/third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-columnCount.html b/third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-columnCount.html
new file mode 100644
index 0000000..cda651cf
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-columnCount.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<div id='container'>
+    <div id='element'></div>
+</div>
+<script>
+
+var container = document.getElementById('container');
+var element = document.getElementById('element');
+
+test(function() {
+    var keyframes = [
+        {columnCount: 'inherit'},
+        {columnCount: '6'}
+    ];
+
+    container.style.columnCount = 'auto';
+    var player = element.animate(keyframes, 20);
+
+    player.pause();
+    player.currentTime = 5;
+    assert_equals(getComputedStyle(element).columnCount, 'auto');
+
+    container.style.columnCount = '2';
+    assert_equals(getComputedStyle(element).columnCount, '3');
+
+    player.currentTime = 10;
+    container.style.columnCount = '8';
+    assert_equals(getComputedStyle(element).columnCount, '7');
+}, 'column-count responsive to inherited column-count changes');
+</script>
diff --git a/third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-font-size-adjust.html b/third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-font-size-adjust.html
new file mode 100644
index 0000000..447c6378
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/animations/responsive/animations-responsive-font-size-adjust.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<div id='container'>
+    <div id='element'></div>
+</div>
+<script>
+
+var container = document.getElementById('container');
+var element = document.getElementById('element');
+
+test(function() {
+    var keyframes = [
+        {fontSizeAdjust: 'inherit'},
+        {fontSizeAdjust: '6'}
+    ];
+
+    container.style.fontSizeAdjust = 'none';
+    var player = element.animate(keyframes, 20);
+
+    player.pause();
+    player.currentTime = 5;
+    assert_equals(getComputedStyle(element).fontSizeAdjust, 'none');
+
+    container.style.fontSizeAdjust = '2';
+    assert_equals(getComputedStyle(element).fontSizeAdjust, '3');
+
+    player.currentTime = 10;
+    container.style.fontSizeAdjust = '8';
+    assert_equals(getComputedStyle(element).fontSizeAdjust, '7');
+}, 'font-size-adjust responsive to inherited font-size-adjust changes');
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
index ae78a8f..c59f07b 100644
--- a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
+++ b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
@@ -74741,6 +74741,18 @@
      {}
     ]
    ],
+   "css/css-writing-modes/available-size-019.html": [
+    [
+     "/css/css-writing-modes/available-size-019.html",
+     [
+      [
+       "/css/css-writing-modes/reference/available-size-002-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-writing-modes/background-position-vrl-018.xht": [
     [
      "/css/css-writing-modes/background-position-vrl-018.xht",
@@ -146550,6 +146562,11 @@
      {}
     ]
    ],
+   "html/semantics/forms/textfieldselection/selection-start-end-extra-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "html/semantics/forms/the-button-element/.gitkeep": [
     [
      {}
@@ -177591,6 +177608,12 @@
      {}
     ]
    ],
+   "css/css-display/display-contents-parsing-001.html": [
+    [
+     "/css/css-display/display-contents-parsing-001.html",
+     {}
+    ]
+   ],
    "css/css-display/display-contents-svg-anchor-child.html": [
     [
      "/css/css-display/display-contents-svg-anchor-child.html",
@@ -178017,6 +178040,12 @@
      {}
     ]
    ],
+   "css/css-flexbox/getcomputedstyle/flexbox_computedstyle_min-auto-size.html": [
+    [
+     "/css/css-flexbox/getcomputedstyle/flexbox_computedstyle_min-auto-size.html",
+     {}
+    ]
+   ],
    "css/css-flexbox/getcomputedstyle/flexbox_computedstyle_min-height-auto.html": [
     [
      "/css/css-flexbox/getcomputedstyle/flexbox_computedstyle_min-height-auto.html",
@@ -179295,6 +179324,12 @@
      {}
     ]
    ],
+   "css/css-grid/grid-items/grid-item-min-auto-size-001.html": [
+    [
+     "/css/css-grid/grid-items/grid-item-min-auto-size-001.html",
+     {}
+    ]
+   ],
    "css/css-grid/grid-items/grid-minimum-size-grid-items-021.html": [
     [
      "/css/css-grid/grid-items/grid-minimum-size-grid-items-021.html",
@@ -180759,6 +180794,12 @@
      {}
     ]
    ],
+   "css/css-tables/width-distribution/td-with-subpixel-padding.html": [
+    [
+     "/css/css-tables/width-distribution/td-with-subpixel-padding.html",
+     {}
+    ]
+   ],
    "css/css-text-decor/text-decoration-serialization.tentative.html": [
     [
      "/css/css-text-decor/text-decoration-serialization.tentative.html",
@@ -197553,6 +197594,12 @@
      {}
     ]
    ],
+   "html/semantics/forms/textfieldselection/selection-start-end-extra.html": [
+    [
+     "/html/semantics/forms/textfieldselection/selection-start-end-extra.html",
+     {}
+    ]
+   ],
    "html/semantics/forms/textfieldselection/selection-start-end.html": [
     [
      "/html/semantics/forms/textfieldselection/selection-start-end.html",
@@ -271914,6 +271961,10 @@
    "a0114c40f3919ed615525495b8504925dbbc6cc7",
    "reftest"
   ],
+  "css/css-display/display-contents-parsing-001.html": [
+   "a058037193f51ef4cfdf6870d5e09e24901cbe9c",
+   "testharness"
+  ],
   "css/css-display/display-contents-pass-green-no-red-ref.html": [
    "6c4a6b62d0ea48e8a7778ea20b1d2a26ff8e68aa",
    "support"
@@ -274458,6 +274509,10 @@
    "0b598a59d971769ea6e6243652493ac12206e374",
    "testharness"
   ],
+  "css/css-flexbox/getcomputedstyle/flexbox_computedstyle_min-auto-size.html": [
+   "6a91427df77eb29fa9b04568abd30c96c218b69e",
+   "testharness"
+  ],
   "css/css-flexbox/getcomputedstyle/flexbox_computedstyle_min-height-auto.html": [
    "0ba6f6efc0a0663dc822f2795aad3b322dfd7e9c",
    "testharness"
@@ -283898,6 +283953,10 @@
    "21d5aae1010b398e29175baa05eeca7fef76d8c0",
    "reftest"
   ],
+  "css/css-grid/grid-items/grid-item-min-auto-size-001.html": [
+   "ec33f67361be5b5f13334788b998c1f6676343e6",
+   "testharness"
+  ],
   "css/css-grid/grid-items/grid-items-001.html": [
    "9d1066bf6e7051f36c7750b1cd22ad2c23ef2ae4",
    "reftest"
@@ -289222,6 +289281,10 @@
    "9eeb49d2d78c3f81825de0d9e24de2a097275175",
    "testharness"
   ],
+  "css/css-tables/width-distribution/td-with-subpixel-padding.html": [
+   "3f7a5f9c45ea9a664220ddaa45f7bc671810f9e6",
+   "testharness"
+  ],
   "css/css-tables/zero-rowspan-001-ref.html": [
    "b7886acdf8a380f85ebbcab0ded1e927fd509600",
    "support"
@@ -301295,7 +301358,7 @@
    "testharness"
   ],
   "css/css-typed-om/the-stylepropertymap/declared/append.tentative.html": [
-   "b7e04deeef9b7f7c71534973425a87435727706b",
+   "51933be93dabfa2cd0e57224d9a53733d6e20809",
    "testharness"
   ],
   "css/css-typed-om/the-stylepropertymap/declared/clear.html": [
@@ -301351,11 +301414,11 @@
    "testharness"
   ],
   "css/css-typed-om/the-stylepropertymap/declared/set.tentative.html": [
-   "23c875b8bb41344e9c4ffc0753f8f8fb36171d8b",
+   "6ae0c80287da3f5053a1fbe79893fcffed48524f",
    "testharness"
   ],
   "css/css-typed-om/the-stylepropertymap/inline/append.tentative.html": [
-   "d8d853cb1ac33b5668f42a6f8cb53fbac1e43936",
+   "198863e1d89a6408aad8768f11e0f7f7d3de0899",
    "testharness"
   ],
   "css/css-typed-om/the-stylepropertymap/inline/clear.html": [
@@ -301407,7 +301470,7 @@
    "testharness"
   ],
   "css/css-typed-om/the-stylepropertymap/inline/set.tentative.html": [
-   "68095148a2ede91974f5df04d29a64bcad3ab2f6",
+   "65c9c20da930fd46136d4dd5706524ae05118807",
    "testharness"
   ],
   "css/css-typed-om/the-stylepropertymap/interface-expected.txt": [
@@ -305855,7 +305918,7 @@
    "reftest"
   ],
   "css/css-writing-modes/available-size-008.html": [
-   "b422cebb5c5839abfa11a049395702cda52a1459",
+   "ca5b879b261068dbf49246d1f1c9c602d5908236",
    "reftest"
   ],
   "css/css-writing-modes/available-size-009.html": [
@@ -305898,6 +305961,10 @@
    "ce16806681745f6904483d09d1954152605bf39b",
    "reftest"
   ],
+  "css/css-writing-modes/available-size-019.html": [
+   "3cd3d22d4c43b8e577901f50647080802f007a03",
+   "reftest"
+  ],
   "css/css-writing-modes/background-position-vlr-003.xht": [
    "c56c42d17b140be6868cc6f413f545dd6a5180e8",
    "manual"
@@ -338126,6 +338193,14 @@
    "db63d0d1eedec810d4c7e1b38789be457e06e985",
    "testharness"
   ],
+  "html/semantics/forms/textfieldselection/selection-start-end-extra-expected.txt": [
+   "80487b2ab10598fcb4326963a5d47b7ab90354b3",
+   "support"
+  ],
+  "html/semantics/forms/textfieldselection/selection-start-end-extra.html": [
+   "d50596ef2b907db30e6121ba7a5d98c887cdc2b2",
+   "testharness"
+  ],
   "html/semantics/forms/textfieldselection/selection-start-end.html": [
    "6bef6943accb6677e9f466df6cc5ad267b01680f",
    "testharness"
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-text/i18n/css3-text-line-break-opclns-004.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-text/i18n/css3-text-line-break-opclns-004.html
index 4708ae59..96b3539 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-text/i18n/css3-text-line-break-opclns-004.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-text/i18n/css3-text-line-break-opclns-004.html
@@ -10,12 +10,10 @@
 <meta name="assert" content="Because it has OP Opening Punctuation property, the browser will not leave 0F3A TIBETAN MARK GUG RTAGS GYON at the end of a line.">
 <style type='text/css'>
 @font-face {
-	font-family: 'mplus-1p-regular';
-	src: url('support/mplus-1p-regular.woff') format('woff');
-	/* filesize: 803K */
+	font-family: CSSFW;
+	src: url('../../fonts/adobe-fonts/CSSFWOrientationTest.otf');
 	}
-.test, .ref { font-size: 30px; font-family: mplus-1p-regular, sans-serif; width: 95px; padding: 0; border: 1px solid orange; line-height: 1em; }
-.test, .ref { width: 115px; }
+.test, .ref { font-size: 30px; font-family: CSSFW, sans-serif; width: 3em; padding: 0; border: 1px solid orange; line-height: 1em; }
 </style>
 </head>
 <body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-text/i18n/css3-text-line-break-opclns-111.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-text/i18n/css3-text-line-break-opclns-111.html
index 6b5dea8..4afbcfb 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-text/i18n/css3-text-line-break-opclns-111.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-text/i18n/css3-text-line-break-opclns-111.html
@@ -10,12 +10,10 @@
 <meta name="assert" content="Because it has a CL Closing Punctuation property, the browser will not leave 0F3B TIBETAN MARK GUG RTAGS GYAS at the beginning of a line.">
 <style type='text/css'>
 @font-face {
-	font-family: 'mplus-1p-regular';
-	src: url('support/mplus-1p-regular.woff') format('woff');
-	/* filesize: 803K */
+	font-family: CSSFW;
+	src: url('../../fonts/adobe-fonts/CSSFWOrientationTest.otf');
 	}
-.test, .ref { font-size: 30px; font-family: mplus-1p-regular, sans-serif; width: 95px; padding: 0; border: 1px solid orange; line-height: 1em; }
-.test, .ref { width: 115px; }
+.test, .ref { font-size: 30px; font-family: CSSFW, sans-serif; width: 3em; padding: 0; border: 1px solid orange; line-height: 1em; }
 </style>
 </head>
 <body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-text/i18n/reference/css3-text-line-break-opclns-004-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-text/i18n/reference/css3-text-line-break-opclns-004-ref.html
index ebc6850..06ee93c 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-text/i18n/reference/css3-text-line-break-opclns-004-ref.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-text/i18n/reference/css3-text-line-break-opclns-004-ref.html
@@ -7,12 +7,10 @@
 <meta name='flags' content=''>
 <style type='text/css'>
 @font-face {
-	font-family: 'mplus-1p-regular';
-	src: url('support/mplus-1p-regular.woff') format('woff');
-	/* filesize: 803K */
+	font-family: CSSFW;
+	src: url('../../../fonts/adobe-fonts/CSSFWOrientationTest.otf');
 	}
-.test, .ref { font-size: 30px; font-family: mplus-1p-regular, sans-serif; width: 95px; padding: 0; border: 1px solid orange; line-height: 1em; }
-.test, .ref { width: 115px; }
+.test, .ref { font-size: 30px; font-family: CSSFW, sans-serif; width: 3em; padding: 0; border: 1px solid orange; line-height: 1em; }
 </style>
 </head>
 <body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-text/i18n/reference/css3-text-line-break-opclns-111-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-text/i18n/reference/css3-text-line-break-opclns-111-ref.html
index 030567e0..013ff06a 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-text/i18n/reference/css3-text-line-break-opclns-111-ref.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-text/i18n/reference/css3-text-line-break-opclns-111-ref.html
@@ -7,12 +7,10 @@
 <meta name='flags' content=''>
 <style type='text/css'>
 @font-face {
-	font-family: 'mplus-1p-regular';
-	src: url('support/mplus-1p-regular.woff') format('woff');
-	/* filesize: 803K */
+	font-family: CSSFW;
+	src: url('../../../fonts/adobe-fonts/CSSFWOrientationTest.otf');
 	}
-.test, .ref { font-size: 30px; font-family: mplus-1p-regular, sans-serif; width: 95px; padding: 0; border: 1px solid orange; line-height: 1em; }
-.test, .ref { width: 115px; }
+.test, .ref { font-size: 30px; font-family: CSSFW, sans-serif; padding: 0; width: 3em; border: 1px solid orange; line-height: 1em; }
 </style>
 </head>
 <body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes/available-size-008.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes/available-size-008.html
index 2fcfbac..d38c9cb 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes/available-size-008.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes/available-size-008.html
@@ -8,7 +8,7 @@
 <meta name="flags" content="">
 <style>
 body { margin-top: 0; margin-bottom: 0; } /* Shouldn't matter, but in some browsers does. -007 tests this aspect specifically. */
-div {
+div div {
   writing-mode: vertical-rl;
   font-family: monospace;
   font-size: 20px;
@@ -46,5 +46,7 @@
 <p>Test passes if there is a <strong>green rectangle</strong> below and <strong>no red</strong>.
 
 <section>
+<div>
 <div><aside id="red">0</aside><aside class="spacer"></aside><aside class="spacer"></aside><aside class="spacer"></aside><aside class="spacer"></aside><aside class="spacer"></aside> <span>0</span></div>
+</div>
 </section>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes/available-size-019.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes/available-size-019.html
new file mode 100644
index 0000000..a25a2f6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes/available-size-019.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Testing Available Space in Orthogonal Flows / ICB / tall max-height parent</title>
+<link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net/">
+<link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-auto">
+<link rel="match" href="reference/available-size-002-ref.html">
+<meta name="assert" content="When an orthogonal flow's parent doesn't have a definite block size, but has a max-height, but that max-height is than the ICB, use the ICB instead.">
+<meta name="flags" content="">
+<style>
+body { margin-top: 0; margin-bottom: 0; } /* Shouldn't matter, but in some browsers does. -007 tests this aspect specifically. */
+div {
+  writing-mode: vertical-rl;
+  font-family: monospace;
+  font-size: 20px;
+  position: relative; /* to be a container for #red*/
+}
+.spacer { /* using 5 spacers of 20vh each instead of a single large one, so
+             that the line would wrap between spacers if it ends up being
+             shorter thatn 100vh*/
+  display: inline-block;
+  height: calc(20vh - 0.1px); /*Using this instead of 20vh, to account for accumulation of rounding errors, that might make 5*20vh taller than 100vh in some browsers*/
+}
+
+span {
+  background: green;
+  display: inline-block; /* This should not change it's size or position, but makes the size of the background predictable*/
+  color: transparent;
+}
+
+#red { /* Not necessary when when comparing to the reference, but makes human judgement easier */
+  position: absolute;
+  background: red;
+  writing-mode: vertical-rl;
+  z-index: -1;
+  font-family: monospace;
+  font-size: 20px;
+  left: 0; top: 0;
+}
+
+section {
+  max-height: 120vh;
+}
+</style>
+
+<p>Test passes if there is a <strong>green rectangle</strong> below and <strong>no red</strong>.
+
+<section>
+<div><aside id="red">0</aside><aside class="spacer"></aside><aside class="spacer"></aside><aside class="spacer"></aside><aside class="spacer"></aside><aside class="spacer"></aside> <span>0</span></div>
+</section>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/fetch/api/basic/integrity-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/fetch/api/basic/integrity-expected.txt
deleted file mode 100644
index c91ba4a7..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/fetch/api/basic/integrity-expected.txt
+++ /dev/null
@@ -1,18 +0,0 @@
-This is a testharness.js-based test.
-PASS Empty string integrity
-PASS SHA-256 integrity
-PASS SHA-384 integrity
-PASS SHA-512 integrity
-PASS Invalid integrity
-PASS Multiple integrities: valid stronger than invalid
-PASS Multiple integrities: invalid stronger than valid
-PASS Multiple integrities: invalid as strong as valid
-PASS Multiple integrities: both are valid
-PASS Multiple integrities: both are invalid
-PASS CORS empty integrity
-PASS CORS SHA-512 integrity
-PASS CORS invalid integrity
-PASS Empty string integrity for opaque response
-FAIL SHA-* integrity for opaque response assert_unreached: Should have rejected: undefined Reached unreachable code
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/fetch/api/basic/integrity-sharedworker-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/fetch/api/basic/integrity-sharedworker-expected.txt
deleted file mode 100644
index c91ba4a7..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/fetch/api/basic/integrity-sharedworker-expected.txt
+++ /dev/null
@@ -1,18 +0,0 @@
-This is a testharness.js-based test.
-PASS Empty string integrity
-PASS SHA-256 integrity
-PASS SHA-384 integrity
-PASS SHA-512 integrity
-PASS Invalid integrity
-PASS Multiple integrities: valid stronger than invalid
-PASS Multiple integrities: invalid stronger than valid
-PASS Multiple integrities: invalid as strong as valid
-PASS Multiple integrities: both are valid
-PASS Multiple integrities: both are invalid
-PASS CORS empty integrity
-PASS CORS SHA-512 integrity
-PASS CORS invalid integrity
-PASS Empty string integrity for opaque response
-FAIL SHA-* integrity for opaque response assert_unreached: Should have rejected: undefined Reached unreachable code
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/fetch/api/basic/integrity-worker-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/fetch/api/basic/integrity-worker-expected.txt
deleted file mode 100644
index c91ba4a7..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/fetch/api/basic/integrity-worker-expected.txt
+++ /dev/null
@@ -1,18 +0,0 @@
-This is a testharness.js-based test.
-PASS Empty string integrity
-PASS SHA-256 integrity
-PASS SHA-384 integrity
-PASS SHA-512 integrity
-PASS Invalid integrity
-PASS Multiple integrities: valid stronger than invalid
-PASS Multiple integrities: invalid stronger than valid
-PASS Multiple integrities: invalid as strong as valid
-PASS Multiple integrities: both are valid
-PASS Multiple integrities: both are invalid
-PASS CORS empty integrity
-PASS CORS SHA-512 integrity
-PASS CORS invalid integrity
-PASS Empty string integrity for opaque response
-FAIL SHA-* integrity for opaque response assert_unreached: Should have rejected: undefined Reached unreachable code
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/textfieldselection/selection-start-end-extra-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/textfieldselection/selection-start-end-extra-expected.txt
new file mode 100644
index 0000000..b2174bf8
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/textfieldselection/selection-start-end-extra-expected.txt
@@ -0,0 +1,13 @@
+This is a testharness.js-based test.
+PASS Setting defaultValue in a textarea should move the cursor to the end
+PASS Setting defaultValue in a textarea with a value should NOT make any difference
+PASS Setting textContent in a textarea should move selection{Start,End} to the end
+PASS Adding children to a textarea should move selection{Start,End} to the end
+PASS Removing children from a textarea should update selection{Start,End}
+FAIL Setting the same value (with different newlines) in a textarea should NOT update selection{Start,End} assert_equals: expected 3 but got 14
+PASS Setting value to a shorter string than defaultValue should correct the cursor position
+PASS Shortening value by turning the input type into 'url' should correct selection{Start,End}
+FAIL Shortening value by turning the input type into 'color' and back to 'text' should correct selection{Start,End} assert_equals: expected 7 but got 9
+PASS Resetting a value to a shorter string than defaultValue should correct the cursor position
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/textfieldselection/selection-start-end-extra.html b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/textfieldselection/selection-start-end-extra.html
new file mode 100644
index 0000000..af51354
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/semantics/forms/textfieldselection/selection-start-end-extra.html
@@ -0,0 +1,123 @@
+<!doctype html>
+<meta charset=utf-8>
+<title></title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<div id=log></div>
+<form id="form"><input id="form-input" type="text" value="abc" /></form>
+<script>
+  // * Should we test setting the dirty flag in any way that isn't
+  //   setting the value?
+  // * How to simulate users typing?
+
+  test(function() {
+    var el = document.createElement("textarea");
+    assert_equals(el.selectionStart, 0);
+    assert_equals(el.selectionEnd, 0);
+    el.defaultValue = "123";
+    assert_equals(el.value.length, 3);
+    assert_equals(el.selectionStart, 3);
+    assert_equals(el.selectionEnd, 3);
+  }, "Setting defaultValue in a textarea should move the cursor to the end");
+
+  test(function() {
+    var el = document.createElement("textarea");
+    el.value = "abcdef";
+    assert_equals(el.selectionStart, 6);
+    assert_equals(el.selectionEnd, 6);
+    el.defaultValue = "123";
+    assert_equals(el.value.length, 6);
+    assert_equals(el.selectionStart, 6);
+    assert_equals(el.selectionEnd, 6);
+  }, "Setting defaultValue in a textarea with a value should NOT make any difference");
+
+  test(function() {
+    var el = document.createElement("textarea");
+    el.appendChild(document.createTextNode("abcdef"));
+    assert_equals(el.selectionStart, 6);
+    assert_equals(el.selectionEnd, 6);
+    el.textContent = "abcdef123456";
+    assert_equals(el.selectionStart, 12);
+    assert_equals(el.selectionEnd, 12);
+  }, "Setting textContent in a textarea should move selection{Start,End} to the end");
+
+  test(function() {
+    var el = document.createElement("textarea");
+    el.appendChild(document.createTextNode("abcdef"));
+    assert_equals(el.selectionStart, 6);
+    assert_equals(el.selectionEnd, 6);
+    el.appendChild(document.createTextNode("123456"));
+    assert_equals(el.selectionStart, 12);
+    assert_equals(el.selectionEnd, 12);
+  }, "Adding children to a textarea should move selection{Start,End} to the end");
+
+  test(function() {
+    var el = document.createElement("textarea");
+    el.appendChild(document.createTextNode("abcdef"));
+    el.appendChild(document.createTextNode("123"));
+    assert_equals(el.selectionStart, 9);
+    assert_equals(el.selectionEnd, 9);
+
+    el.removeChild(el.firstChild);
+    assert_equals(el.selectionStart, 3);
+    assert_equals(el.selectionEnd, 3);
+  }, "Removing children from a textarea should update selection{Start,End}");
+
+  test(function() {
+    var el = document.createElement("textarea");
+    el.textContent = "abcdef\nwhatevs";
+    el.selectionStart = 3;
+    el.selectionEnd = 5;
+
+    el.textContent = "abcdef\r\nwhatevs";
+    assert_equals(el.selectionStart, 3);
+    assert_equals(el.selectionEnd, 5);
+  }, "Setting the same value (with different newlines) in a textarea should NOT update selection{Start,End}");
+
+  test(function() {
+    var el = document.createElement("textarea");
+    el.defaultValue = "123";
+    assert_equals(el.value.length, 3);
+    assert_equals(el.selectionStart, 3);
+    assert_equals(el.selectionEnd, 3);
+    el.value = "12";
+    assert_equals(el.value.length, 2);
+    assert_equals(el.selectionStart, 2);
+    assert_equals(el.selectionEnd, 2);
+  }, "Setting value to a shorter string than defaultValue should correct the cursor position");
+
+  test(function() {
+    var el = document.createElement("input");
+    el.type = "text";
+    el.value = "http://example.com   ";
+    assert_equals(el.selectionStart, 21);
+    assert_equals(el.selectionEnd, 21);
+    el.type = "url";
+    assert_equals(el.selectionStart, 18);
+    assert_equals(el.selectionEnd, 18);
+  }, "Shortening value by turning the input type into 'url' should correct selection{Start,End}");
+
+  test(function() {
+    var el = document.createElement("input");
+    el.type = "text";
+    el.value = "#123456xx";
+    assert_equals(el.selectionStart, 9);
+    assert_equals(el.selectionEnd, 9);
+    el.type = "color";
+    el.type = "text";
+    assert_equals(el.selectionStart, 7);
+    assert_equals(el.selectionEnd, 7);
+  }, "Shortening value by turning the input type into 'color' and back to 'text' should correct selection{Start,End}");
+
+  test(function() {
+    var form = document.getElementById("form");
+    var el = document.getElementById("form-input");
+
+    el.value = "abcde";
+    assert_equals(el.value.length, 5);
+    form.reset();
+    assert_equals(el.value.length, 3);
+    assert_equals(el.selectionStart, 3);
+    assert_equals(el.selectionEnd, 3);
+  }, "Resetting a value to a shorter string than defaultValue should correct the cursor position");
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/fetch/chromium/signal-gc.html b/third_party/WebKit/LayoutTests/http/tests/fetch/chromium/signal-gc.html
new file mode 100644
index 0000000..b02c46e8
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/fetch/chromium/signal-gc.html
@@ -0,0 +1,37 @@
+<!doctype html>
+<script src = "/resources/testharness.js"></script>
+<script src = "/resources/testharnessreport.js"></script>
+<script>
+// This test verifies that chains of AbortSignal objects do not lose abort
+// events due to collection of objects in the middle of the chain. It uses
+// Request objects to perform the chaining, as they are currently the only place
+// that the https://dom.spec.whatwg.org/#abortsignal-follow operation is used in
+// Blink.
+//
+// This test is Blink-specific because it requires access to garbage collection.
+promise_test(async () => {
+  assert_not_equals(typeof GCController, undefined,
+         'this test requires garbage collection to be exposed');
+  // |controller| will have a strong reference to controller.signal.
+  const controller = new AbortController();
+  // |controller.signal| will hold a weak reference to |signal|.
+  let signal = new Request('/', { signal: controller.signal }).signal;
+  // |signal| will hold a weak reference to |request.signal|.
+  const request = new Request('/', { signal: signal });
+
+  // Allow |signal| to be collected.
+  signal = undefined;
+
+  // Experimantely two collections is the right number for collection to
+  // reliably happen. If this test starts to flake, try increasing the number.
+  for (let i = 0; i < 2; ++i) {
+    GCController.collect();
+    // Allow the Oilpan GC to run with an empty stack.
+    await new Promise(resolve => setTimeout(resolve, 0));
+  }
+
+  // Abort should still abort the request.
+  controller.abort();
+  assert_true(request.signal.aborted, 'aborted should be true');
+}, 'aborts should not be lost due to garbage collection');
+</script>
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptWrappableMarkingVisitorTest.cpp b/third_party/WebKit/Source/bindings/core/v8/ScriptWrappableMarkingVisitorTest.cpp
index 1bd9a08..78da3da9 100644
--- a/third_party/WebKit/Source/bindings/core/v8/ScriptWrappableMarkingVisitorTest.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/ScriptWrappableMarkingVisitorTest.cpp
@@ -501,6 +501,7 @@
       DeathAwareScriptWrappable::Create();
   Base* base = Base::Create(base_wrapper, mixin_wrapper);
   Mixin* mixin = static_cast<Mixin*>(base);
+
   HeapObjectHeader* base_header = HeapObjectHeader::FromPayload(base);
   EXPECT_FALSE(base_header->IsWrapperHeaderMarked());
 
@@ -515,7 +516,7 @@
   TraceWrapperMember<Mixin> mixin_handle = mixin;
   EXPECT_TRUE(base_header->IsWrapperHeaderMarked());
   EXPECT_FALSE(visitor->MarkingDeque()->IsEmpty());
-  EXPECT_TRUE(visitor->MarkingDequeContains(base));
+  EXPECT_TRUE(visitor->MarkingDequeContains(mixin));
 
   visitor->AdvanceTracing(
       0, v8::EmbedderHeapTracer::AdvanceTracingActions(
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8EmbedderGraphBuilder.cpp b/third_party/WebKit/Source/bindings/core/v8/V8EmbedderGraphBuilder.cpp
index dfd1eb7..ecf0a5a 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V8EmbedderGraphBuilder.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/V8EmbedderGraphBuilder.cpp
@@ -64,7 +64,7 @@
     const WrapperDescriptor& wrapper_descriptor) const {
   // Add an edge from the current parent to this object.
   // Also push the object to the worklist in order to process its members.
-  const void* traceable = wrapper_descriptor.base_object_payload;
+  const void* traceable = wrapper_descriptor.traceable;
   Graph::Node* graph_node =
       GraphNode(traceable, wrapper_descriptor.name_callback(traceable));
   graph_->AddEdge(current_parent_, graph_node);
@@ -113,7 +113,7 @@
 V8EmbedderGraphBuilder::WorklistItem V8EmbedderGraphBuilder::ToWorklistItem(
     Graph::Node* node,
     const WrapperDescriptor& wrapper_descriptor) const {
-  return {node, wrapper_descriptor.base_object_payload,
+  return {node, wrapper_descriptor.traceable,
           wrapper_descriptor.trace_wrappers_callback};
 }
 
@@ -123,7 +123,7 @@
     auto item = worklist_.back();
     worklist_.pop_back();
     ParentScope parent(this, item.node);
-    item.trace_wrappers_callback(this, const_cast<void*>(item.traceable));
+    item.trace_wrappers_callback(this, item.traceable);
   }
 }
 
diff --git a/third_party/WebKit/Source/core/animation/CSSNumberInterpolationType.cpp b/third_party/WebKit/Source/core/animation/CSSNumberInterpolationType.cpp
index f20844dc..a0955681 100644
--- a/third_party/WebKit/Source/core/animation/CSSNumberInterpolationType.cpp
+++ b/third_party/WebKit/Source/core/animation/CSSNumberInterpolationType.cpp
@@ -8,6 +8,7 @@
 #include "core/animation/NumberPropertyFunctions.h"
 #include "core/css/resolver/StyleBuilder.h"
 #include "core/css/resolver/StyleResolverState.h"
+#include "platform/wtf/Optional.h"
 #include "platform/wtf/PtrUtil.h"
 
 namespace blink {
@@ -17,25 +18,23 @@
  public:
   static std::unique_ptr<InheritedNumberChecker> Create(
       const CSSProperty& property,
-      double number) {
+      Optional<double> number) {
     return WTF::WrapUnique(new InheritedNumberChecker(property, number));
   }
 
  private:
-  InheritedNumberChecker(const CSSProperty& property, double number)
+  InheritedNumberChecker(const CSSProperty& property, Optional<double> number)
       : property_(property), number_(number) {}
 
   bool IsValid(const StyleResolverState& state,
                const InterpolationValue& underlying) const final {
-    double parent_number;
-    if (!NumberPropertyFunctions::GetNumber(property_, *state.ParentStyle(),
-                                            parent_number))
-      return false;
-    return parent_number == number_;
+    Optional<double> parent_number =
+        NumberPropertyFunctions::GetNumber(property_, *state.ParentStyle());
+    return number_ == parent_number;
   }
 
   const CSSProperty& property_;
-  const double number_;
+  const Optional<double> number_;
 };
 
 const CSSValue* CSSNumberInterpolationType::CreateCSSValue(
@@ -61,10 +60,11 @@
 InterpolationValue CSSNumberInterpolationType::MaybeConvertInitial(
     const StyleResolverState&,
     ConversionCheckers& conversion_checkers) const {
-  double initial_number;
-  if (!NumberPropertyFunctions::GetInitialNumber(CssProperty(), initial_number))
+  Optional<double> initial_number =
+      NumberPropertyFunctions::GetInitialNumber(CssProperty());
+  if (!initial_number)
     return nullptr;
-  return CreateNumberValue(initial_number);
+  return CreateNumberValue(*initial_number);
 }
 
 InterpolationValue CSSNumberInterpolationType::MaybeConvertInherit(
@@ -72,13 +72,13 @@
     ConversionCheckers& conversion_checkers) const {
   if (!state.ParentStyle())
     return nullptr;
-  double inherited_number;
-  if (!NumberPropertyFunctions::GetNumber(CssProperty(), *state.ParentStyle(),
-                                          inherited_number))
-    return nullptr;
+  Optional<double> inherited =
+      NumberPropertyFunctions::GetNumber(CssProperty(), *state.ParentStyle());
   conversion_checkers.push_back(
-      InheritedNumberChecker::Create(CssProperty(), inherited_number));
-  return CreateNumberValue(inherited_number);
+      InheritedNumberChecker::Create(CssProperty(), inherited));
+  if (!inherited)
+    return nullptr;
+  return CreateNumberValue(*inherited);
 }
 
 InterpolationValue CSSNumberInterpolationType::MaybeConvertValue(
@@ -93,11 +93,11 @@
 InterpolationValue
 CSSNumberInterpolationType::MaybeConvertStandardPropertyUnderlyingValue(
     const ComputedStyle& style) const {
-  double underlying_number;
-  if (!NumberPropertyFunctions::GetNumber(CssProperty(), style,
-                                          underlying_number))
+  Optional<double> underlying_number =
+      NumberPropertyFunctions::GetNumber(CssProperty(), style);
+  if (!underlying_number)
     return nullptr;
-  return CreateNumberValue(underlying_number);
+  return CreateNumberValue(*underlying_number);
 }
 
 void CSSNumberInterpolationType::ApplyStandardPropertyValue(
diff --git a/third_party/WebKit/Source/core/animation/NumberPropertyFunctions.cpp b/third_party/WebKit/Source/core/animation/NumberPropertyFunctions.cpp
index d087f5b2..96162580 100644
--- a/third_party/WebKit/Source/core/animation/NumberPropertyFunctions.cpp
+++ b/third_party/WebKit/Source/core/animation/NumberPropertyFunctions.cpp
@@ -8,83 +8,67 @@
 
 namespace blink {
 
-bool NumberPropertyFunctions::GetInitialNumber(const CSSProperty& property,
-                                               double& result) {
-  return GetNumber(property, ComputedStyle::InitialStyle(), result);
+Optional<double> NumberPropertyFunctions::GetInitialNumber(
+    const CSSProperty& property) {
+  return GetNumber(property, ComputedStyle::InitialStyle());
 }
 
-bool NumberPropertyFunctions::GetNumber(const CSSProperty& property,
-                                        const ComputedStyle& style,
-                                        double& result) {
+Optional<double> NumberPropertyFunctions::GetNumber(
+    const CSSProperty& property,
+    const ComputedStyle& style) {
   switch (property.PropertyID()) {
     case CSSPropertyFillOpacity:
-      result = style.FillOpacity();
-      return true;
+      return style.FillOpacity();
     case CSSPropertyFlexGrow:
-      result = style.FlexGrow();
-      return true;
+      return style.FlexGrow();
     case CSSPropertyFlexShrink:
-      result = style.FlexShrink();
-      return true;
+      return style.FlexShrink();
     case CSSPropertyFloodOpacity:
-      result = style.FloodOpacity();
-      return true;
+      return style.FloodOpacity();
     case CSSPropertyOpacity:
-      result = style.Opacity();
-      return true;
+      return style.Opacity();
     case CSSPropertyOrder:
-      result = style.Order();
-      return true;
+      return style.Order();
     case CSSPropertyOrphans:
-      result = style.Orphans();
-      return true;
+      return style.Orphans();
     case CSSPropertyShapeImageThreshold:
-      result = style.ShapeImageThreshold();
-      return true;
+      return style.ShapeImageThreshold();
     case CSSPropertyStopOpacity:
-      result = style.StopOpacity();
-      return true;
+      return style.StopOpacity();
     case CSSPropertyStrokeMiterlimit:
-      result = style.StrokeMiterLimit();
-      return true;
+      return style.StrokeMiterLimit();
     case CSSPropertyStrokeOpacity:
-      result = style.StrokeOpacity();
-      return true;
+      return style.StrokeOpacity();
     case CSSPropertyWidows:
-      result = style.Widows();
-      return true;
+      return style.Widows();
 
     case CSSPropertyFontSizeAdjust:
       if (!style.HasFontSizeAdjust())
-        return false;
-      result = style.FontSizeAdjust();
-      return true;
+        return Optional<double>();
+      return style.FontSizeAdjust();
     case CSSPropertyColumnCount:
       if (style.HasAutoColumnCount())
-        return false;
-      result = style.ColumnCount();
-      return true;
+        return Optional<double>();
+      return style.ColumnCount();
     case CSSPropertyZIndex:
       if (style.HasAutoZIndex())
-        return false;
-      result = style.ZIndex();
-      return true;
+        return Optional<double>();
+      return style.ZIndex();
 
     case CSSPropertyLineHeight: {
       const Length& length = style.SpecifiedLineHeight();
       // Numbers are represented by percentages.
       if (length.GetType() != kPercent)
-        return false;
+        return Optional<double>();
       double value = length.Value();
       // -100% represents the keyword "normal".
       if (value == -100)
-        return false;
-      result = value / 100;
-      return true;
+        return Optional<double>();
+      return value / 100;
     }
 
     default:
-      return false;
+      return Optional<double>();
   }
 }
 
diff --git a/third_party/WebKit/Source/core/animation/NumberPropertyFunctions.h b/third_party/WebKit/Source/core/animation/NumberPropertyFunctions.h
index 136af7ff..0ba9a8a9 100644
--- a/third_party/WebKit/Source/core/animation/NumberPropertyFunctions.h
+++ b/third_party/WebKit/Source/core/animation/NumberPropertyFunctions.h
@@ -6,6 +6,7 @@
 #define NumberPropertyFunctions_h
 
 #include "core/CSSPropertyNames.h"
+#include "platform/wtf/Optional.h"
 
 namespace blink {
 
@@ -14,10 +15,8 @@
 
 class NumberPropertyFunctions {
  public:
-  static bool GetInitialNumber(const CSSProperty&, double& result);
-  static bool GetNumber(const CSSProperty&,
-                        const ComputedStyle&,
-                        double& result);
+  static Optional<double> GetInitialNumber(const CSSProperty&);
+  static Optional<double> GetNumber(const CSSProperty&, const ComputedStyle&);
   static double ClampNumber(const CSSProperty&, double);
   static bool SetNumber(const CSSProperty&, ComputedStyle&, double);
 };
diff --git a/third_party/WebKit/Source/core/dom/AbortSignal.cpp b/third_party/WebKit/Source/core/dom/AbortSignal.cpp
index 24fdb7c..eb39b3ca 100644
--- a/third_party/WebKit/Source/core/dom/AbortSignal.cpp
+++ b/third_party/WebKit/Source/core/dom/AbortSignal.cpp
@@ -44,6 +44,28 @@
   DispatchEvent(Event::Create(EventTypeNames::abort));
 }
 
+void AbortSignal::Follow(AbortSignal* parentSignal) {
+  if (aborted_flag_)
+    return;
+  if (parentSignal->aborted_flag_)
+    SignalAbort();
+
+  // Unlike the usual practice for AddAlgorithm(), we don't use a weak pointer
+  // here. To see why, consider the following object graph:
+  //
+  // controller --owns--> signal1 -?-> signal2 -?-> signal3 <--owns-- request
+  //
+  // It's easy to create chained signals like this using the Request
+  // constructor. If the -?-> pointers were weak, then |signal2| could be
+  // collected even though |controller| and |request| were still
+  // referenced. This would prevent controller.abort() from working. So the
+  // pointers need to be strong. This won't artificially extend the lifetime of
+  // |request|, because the pointer to it in the closure held by |signal3| is
+  // still weak.
+  parentSignal->AddAlgorithm(
+      WTF::Bind(&AbortSignal::SignalAbort, WrapPersistent(this)));
+}
+
 void AbortSignal::Trace(Visitor* visitor) {
   visitor->Trace(execution_context_);
   EventTargetWithInlineData::Trace(visitor);
diff --git a/third_party/WebKit/Source/core/dom/AbortSignal.h b/third_party/WebKit/Source/core/dom/AbortSignal.h
index 89258f9..0bd48e2 100644
--- a/third_party/WebKit/Source/core/dom/AbortSignal.h
+++ b/third_party/WebKit/Source/core/dom/AbortSignal.h
@@ -54,6 +54,11 @@
   // event. Does nothing if called more than once.
   void SignalAbort();
 
+  // The "follow" algorithm from the standard:
+  // https://dom.spec.whatwg.org/#abortsignal-follow
+  // |this| is the followingSignal described in the standard.
+  void Follow(AbortSignal* parentSignal);
+
   virtual void Trace(Visitor*);
 
  private:
diff --git a/third_party/WebKit/Source/core/editing/Editor.h b/third_party/WebKit/Source/core/editing/Editor.h
index 08564611..be7167cb 100644
--- a/third_party/WebKit/Source/core/editing/Editor.h
+++ b/third_party/WebKit/Source/core/editing/Editor.h
@@ -61,8 +61,7 @@
 enum class InsertMode { kSimple, kSmart };
 enum class DragSourceType { kHTMLSource, kPlainTextSource };
 enum class EditorParagraphSeparator { kIsDiv, kIsP };
-
-enum EditorCommandSource { kCommandFromMenuOrKeyBinding, kCommandFromDOM };
+enum class EditorCommandSource { kMenuOrKeyBinding, kDOM };
 
 class CORE_EXPORT Editor final : public GarbageCollectedFinalized<Editor> {
  public:
diff --git a/third_party/WebKit/Source/core/editing/FrameCaret.cpp b/third_party/WebKit/Source/core/editing/FrameCaret.cpp
index c5067f7e..d5fb6be 100644
--- a/third_party/WebKit/Source/core/editing/FrameCaret.cpp
+++ b/third_party/WebKit/Source/core/editing/FrameCaret.cpp
@@ -160,15 +160,6 @@
   display_item_client_->InvalidatePaint(block, context);
 }
 
-bool FrameCaret::CaretPositionIsValidForDocument(
-    const Document& document) const {
-  if (!IsActive())
-    return true;
-
-  return CaretPosition().GetDocument() == document &&
-         !CaretPosition().IsOrphan();
-}
-
 static IntRect AbsoluteBoundsForLocalRect(Node* node, const LayoutRect& rect) {
   LayoutBlock* caret_painter = CaretDisplayItemClient::CaretLayoutBlock(node);
   if (!caret_painter)
diff --git a/third_party/WebKit/Source/core/editing/FrameCaret.h b/third_party/WebKit/Source/core/editing/FrameCaret.h
index fcc98f8..572b917 100644
--- a/third_party/WebKit/Source/core/editing/FrameCaret.h
+++ b/third_party/WebKit/Source/core/editing/FrameCaret.h
@@ -39,7 +39,6 @@
 
 class CaretDisplayItemClient;
 class DisplayItemClient;
-class Document;
 class FrameCaret;
 class GraphicsContext;
 class LayoutBlock;
@@ -99,7 +98,6 @@
 
   bool ShouldBlinkCaret() const;
   void CaretBlinkTimerFired(TimerBase*);
-  bool CaretPositionIsValidForDocument(const Document&) const;
   void UpdateAppearance();
 
   const Member<const SelectionEditor> selection_editor_;
diff --git a/third_party/WebKit/Source/core/editing/commands/DocumentExecCommand.cpp b/third_party/WebKit/Source/core/editing/commands/DocumentExecCommand.cpp
index c4f330b..8a18dde 100644
--- a/third_party/WebKit/Source/core/editing/commands/DocumentExecCommand.cpp
+++ b/third_party/WebKit/Source/core/editing/commands/DocumentExecCommand.cpp
@@ -50,7 +50,8 @@
     return Editor::Command();
 
   document->UpdateStyleAndLayoutTree();
-  return frame->GetEditor().CreateCommand(command_name, kCommandFromDOM);
+  return frame->GetEditor().CreateCommand(command_name,
+                                          EditorCommandSource::kDOM);
 }
 
 }  // namespace
diff --git a/third_party/WebKit/Source/core/editing/commands/EditorCommand.cpp b/third_party/WebKit/Source/core/editing/commands/EditorCommand.cpp
index ed6bbf1d0..c4decde5 100644
--- a/third_party/WebKit/Source/core/editing/commands/EditorCommand.cpp
+++ b/third_party/WebKit/Source/core/editing/commands/EditorCommand.cpp
@@ -316,10 +316,10 @@
   // FIXME: We don't call shouldApplyStyle when the source is DOM; is there a
   // good reason for that?
   switch (source) {
-    case kCommandFromMenuOrKeyBinding:
+    case EditorCommandSource::kMenuOrKeyBinding:
       ApplyStyleToSelection(frame, style, input_type);
       return true;
-    case kCommandFromDOM:
+    case EditorCommandSource::kDOM:
       ApplyStyle(frame, style, input_type);
       return true;
   }
@@ -443,10 +443,10 @@
   // FIXME: We don't call shouldApplyStyle when the source is DOM; is there a
   // good reason for that?
   switch (source) {
-    case kCommandFromMenuOrKeyBinding:
+    case EditorCommandSource::kMenuOrKeyBinding:
       frame.GetEditor().ApplyParagraphStyleToSelection(style, input_type);
       return true;
-    case kCommandFromDOM:
+    case EditorCommandSource::kDOM:
       frame.GetEditor().ApplyParagraphStyle(style, input_type);
       return true;
   }
@@ -739,7 +739,7 @@
 }
 
 static bool CanWriteClipboard(LocalFrame& frame, EditorCommandSource source) {
-  if (source == kCommandFromMenuOrKeyBinding)
+  if (source == EditorCommandSource::kMenuOrKeyBinding)
     return true;
   Settings* settings = frame.GetSettings();
   bool default_value =
@@ -756,7 +756,8 @@
   //  "Set target to be the element that contains the start of the selection in
   //   document order, or the body element if there is no selection or cursor."
   // We treat hidden selections as "no selection or cursor".
-  if (source == kCommandFromMenuOrKeyBinding && frame.Selection().IsHidden())
+  if (source == EditorCommandSource::kMenuOrKeyBinding &&
+      frame.Selection().IsHidden())
     return frame.Selection().GetDocument().body();
 
   return FindEventTargetFrom(
@@ -838,7 +839,8 @@
   // Since copy is a read-only operation it succeeds anytime a selection
   // is *visible*. In contrast to cut or paste, the selection does not
   // need to be focused - being visible is enough.
-  if (source == kCommandFromMenuOrKeyBinding && frame.Selection().IsHidden())
+  if (source == EditorCommandSource::kMenuOrKeyBinding &&
+      frame.Selection().IsHidden())
     return true;
 
   // TODO(editing-dev): The use of UpdateStyleAndLayoutIgnorePendingStylesheets
@@ -911,7 +913,7 @@
   // before we obtain the selection.
   frame.GetDocument()->UpdateStyleAndLayoutIgnorePendingStylesheets();
 
-  if (source == kCommandFromMenuOrKeyBinding &&
+  if (source == EditorCommandSource::kMenuOrKeyBinding &&
       !frame.Selection().SelectionHasFocus())
     return true;
 
@@ -928,7 +930,7 @@
     WriteSelectionToPasteboard(frame);
   }
 
-  if (source == kCommandFromMenuOrKeyBinding) {
+  if (source == EditorCommandSource::kMenuOrKeyBinding) {
     if (DispatchBeforeInputDataTransfer(
             FindEventTargetForClipboardEvent(frame, source),
             InputEvent::InputType::kDeleteByCut,
@@ -987,12 +989,12 @@
                           EditorCommandSource source,
                           const String&) {
   switch (source) {
-    case kCommandFromMenuOrKeyBinding: {
+    case EditorCommandSource::kMenuOrKeyBinding: {
       // Doesn't modify the text if the current selection isn't a range.
       PerformDelete(frame);
       return true;
     }
-    case kCommandFromDOM:
+    case EditorCommandSource::kDOM:
       // If the current selection is a caret, delete the preceding character. IE
       // performs forwardDelete, but we currently side with Firefox. Doesn't
       // scroll to make the selection visible, or modify the kill ring (this
@@ -1251,11 +1253,11 @@
                                  const String&) {
   EditingState editing_state;
   switch (source) {
-    case kCommandFromMenuOrKeyBinding:
+    case EditorCommandSource::kMenuOrKeyBinding:
       DeleteWithDirection(frame, DeleteDirection::kForward,
                           TextGranularity::kCharacter, false, true);
       return true;
-    case kCommandFromDOM:
+    case EditorCommandSource::kDOM:
       // Doesn't scroll to make the selection visible, or modify the kill ring.
       // ForwardDelete is not implemented in IE or Firefox, so this behavior is
       // only needed for backward compatibility with ourselves, and for
@@ -1334,11 +1336,11 @@
                                    EditorCommandSource source,
                                    const String&) {
   switch (source) {
-    case kCommandFromMenuOrKeyBinding:
+    case EditorCommandSource::kMenuOrKeyBinding:
       return TargetFrame(frame, event)
           ->GetEventHandler()
           .HandleTextInputEvent("\n", event, kTextEventInputLineBreak);
-    case kCommandFromDOM:
+    case EditorCommandSource::kDOM:
       // Doesn't scroll to make the selection visible, or modify the kill ring.
       // InsertLineBreak is not implemented in IE or Firefox, so this behavior
       // is only needed for backward compatibility with ourselves, and for
@@ -2025,7 +2027,7 @@
 }
 
 static bool CanReadClipboard(LocalFrame& frame, EditorCommandSource source) {
-  if (source == kCommandFromMenuOrKeyBinding)
+  if (source == EditorCommandSource::kMenuOrKeyBinding)
     return true;
   Settings* settings = frame.GetSettings();
   bool default_value = settings &&
@@ -2130,7 +2132,7 @@
   // before we obtain the selection.
   frame.GetDocument()->UpdateStyleAndLayoutIgnorePendingStylesheets();
 
-  if (source == kCommandFromMenuOrKeyBinding &&
+  if (source == EditorCommandSource::kMenuOrKeyBinding &&
       !frame.Selection().SelectionHasFocus())
     return;
 
@@ -2140,7 +2142,7 @@
   const PasteMode paste_mode =
       frame.GetEditor().CanEditRichly() ? kAllMimeTypes : kPlainTextOnly;
 
-  if (source == kCommandFromMenuOrKeyBinding) {
+  if (source == EditorCommandSource::kMenuOrKeyBinding) {
     DataTransfer* data_transfer =
         DataTransfer::Create(DataTransfer::kCopyAndPaste, kDataTransferReadable,
                              DataObject::CreateFromPasteboard(paste_mode));
@@ -2191,7 +2193,7 @@
     return false;
   if (!frame.GetEditor().Behavior().SupportsGlobalSelection())
     return false;
-  DCHECK_EQ(source, kCommandFromMenuOrKeyBinding);
+  DCHECK_EQ(source, EditorCommandSource::kMenuOrKeyBinding);
 
   bool old_selection_mode = Pasteboard::GeneralPasteboard()->IsSelectionMode();
   Pasteboard::GeneralPasteboard()->SetSelectionMode(true);
@@ -2215,7 +2217,7 @@
   // before we obtain the selection.
   frame.GetDocument()->UpdateStyleAndLayoutIgnorePendingStylesheets();
 
-  if (source == kCommandFromMenuOrKeyBinding &&
+  if (source == EditorCommandSource::kMenuOrKeyBinding &&
       !frame.Selection().SelectionHasFocus())
     return false;
 
@@ -2304,9 +2306,10 @@
                              Event*,
                              EditorCommandSource source,
                              const String&) {
-  const SetSelectionBy set_selection_by = source == kCommandFromMenuOrKeyBinding
-                                              ? SetSelectionBy::kUser
-                                              : SetSelectionBy::kSystem;
+  const SetSelectionBy set_selection_by =
+      source == EditorCommandSource::kMenuOrKeyBinding
+          ? SetSelectionBy::kUser
+          : SetSelectionBy::kSystem;
   frame.Selection().SelectAll(set_selection_by);
   return true;
 }
@@ -2635,7 +2638,7 @@
                                     EditorCommandSource source) {
   frame.GetDocument()->UpdateStyleAndLayoutIgnorePendingStylesheets();
 
-  if (source == kCommandFromMenuOrKeyBinding &&
+  if (source == EditorCommandSource::kMenuOrKeyBinding &&
       !frame.Selection().SelectionHasFocus())
     return false;
 
@@ -2652,7 +2655,7 @@
                                            EditorCommandSource source) {
   frame.GetDocument()->UpdateStyleAndLayoutIgnorePendingStylesheets();
 
-  if (source == kCommandFromMenuOrKeyBinding &&
+  if (source == EditorCommandSource::kMenuOrKeyBinding &&
       !frame.Selection().SelectionHasFocus())
     return false;
 
@@ -2668,7 +2671,7 @@
                                       EditorCommandSource source) {
   frame.GetDocument()->UpdateStyleAndLayoutIgnorePendingStylesheets();
 
-  if (source == kCommandFromMenuOrKeyBinding &&
+  if (source == EditorCommandSource::kMenuOrKeyBinding &&
       !frame.Selection().SelectionHasFocus())
     return false;
   const VisibleSelection& selection =
@@ -2692,7 +2695,7 @@
 static bool EnabledCut(LocalFrame& frame, Event*, EditorCommandSource source) {
   if (!CanWriteClipboard(frame, source))
     return false;
-  if (source == kCommandFromMenuOrKeyBinding &&
+  if (source == EditorCommandSource::kMenuOrKeyBinding &&
       !frame.Selection().SelectionHasFocus())
     return false;
   return !DispatchCopyOrCutEvent(frame, source, EventTypeNames::beforecut) ||
@@ -2703,7 +2706,7 @@
                                   Event* event,
                                   EditorCommandSource source) {
   frame.GetDocument()->UpdateStyleAndLayoutIgnorePendingStylesheets();
-  if (source == kCommandFromMenuOrKeyBinding &&
+  if (source == EditorCommandSource::kMenuOrKeyBinding &&
       !frame.Selection().SelectionHasFocus())
     return false;
   const SelectionInDOMTree selection =
@@ -2716,10 +2719,10 @@
                           Event* event,
                           EditorCommandSource source) {
   switch (source) {
-    case kCommandFromMenuOrKeyBinding:
+    case EditorCommandSource::kMenuOrKeyBinding:
       return frame.Selection().SelectionHasFocus() &&
              frame.GetEditor().CanDelete();
-    case kCommandFromDOM:
+    case EditorCommandSource::kDOM:
       // "Delete" from DOM is like delete/backspace keypress, affects selected
       // range if non-empty, otherwise removes a character
       return EnabledInEditableText(frame, event, source);
@@ -2732,7 +2735,7 @@
                                         Event*,
                                         EditorCommandSource source) {
   frame.GetDocument()->UpdateStyleAndLayoutIgnorePendingStylesheets();
-  if (source == kCommandFromMenuOrKeyBinding &&
+  if (source == EditorCommandSource::kMenuOrKeyBinding &&
       !frame.Selection().SelectionHasFocus())
     return false;
   const VisibleSelection& selection =
@@ -2746,7 +2749,7 @@
                          EditorCommandSource source) {
   if (!CanReadClipboard(frame, source))
     return false;
-  if (source == kCommandFromMenuOrKeyBinding &&
+  if (source == EditorCommandSource::kMenuOrKeyBinding &&
       !frame.Selection().SelectionHasFocus())
     return false;
   return frame.GetEditor().CanPaste();
@@ -2756,7 +2759,7 @@
                                        Event*,
                                        EditorCommandSource source) {
   frame.GetDocument()->UpdateStyleAndLayoutIgnorePendingStylesheets();
-  if (source == kCommandFromMenuOrKeyBinding &&
+  if (source == EditorCommandSource::kMenuOrKeyBinding &&
       !frame.Selection().SelectionHasFocus())
     return false;
   return frame.Selection()
@@ -2771,7 +2774,7 @@
                                              Event*,
                                              EditorCommandSource source) {
   frame.GetDocument()->UpdateStyleAndLayoutIgnorePendingStylesheets();
-  if (source == kCommandFromMenuOrKeyBinding &&
+  if (source == EditorCommandSource::kMenuOrKeyBinding &&
       !frame.Selection().SelectionHasFocus())
     return false;
   const VisibleSelection& selection =
@@ -2812,7 +2815,8 @@
     return true;
   // Hidden selection appears as no selection to users, in which case user-
   // triggered SelectAll should be enabled and act as if there is no selection.
-  if (source == kCommandFromMenuOrKeyBinding && frame.Selection().IsHidden())
+  if (source == EditorCommandSource::kMenuOrKeyBinding &&
+      frame.Selection().IsHidden())
     return true;
   if (Node* root = HighestEditableRoot(selection.Start())) {
     if (!root->hasChildren())
@@ -3471,8 +3475,8 @@
 }
 
 Editor::Command Editor::CreateCommand(const String& command_name) {
-  return Command(InternalCommand(command_name), kCommandFromMenuOrKeyBinding,
-                 frame_);
+  return Command(InternalCommand(command_name),
+                 EditorCommandSource::kMenuOrKeyBinding, frame_);
 }
 
 Editor::Command Editor::CreateCommand(const String& command_name,
@@ -3569,7 +3573,7 @@
       return false;
   }
 
-  if (source_ == kCommandFromMenuOrKeyBinding) {
+  if (source_ == EditorCommandSource::kMenuOrKeyBinding) {
     InputEvent::InputType input_type =
         InputTypeFromCommandType(command_->command_type, *frame_);
     if (input_type != InputEvent::InputType::kNone) {
@@ -3598,9 +3602,9 @@
   if (!command_)
     return false;
   switch (source_) {
-    case kCommandFromMenuOrKeyBinding:
+    case EditorCommandSource::kMenuOrKeyBinding:
       return true;
-    case kCommandFromDOM:
+    case EditorCommandSource::kDOM:
       return command_->is_supported_from_dom(frame_.Get());
   }
   NOTREACHED();
diff --git a/third_party/WebKit/Source/core/events/PointerEventFactory.cpp b/third_party/WebKit/Source/core/events/PointerEventFactory.cpp
index 079816a..8258bb3 100644
--- a/third_party/WebKit/Source/core/events/PointerEventFactory.cpp
+++ b/third_party/WebKit/Source/core/events/PointerEventFactory.cpp
@@ -241,9 +241,7 @@
   if (type == EventTypeNames::pointermove) {
     HeapVector<Member<PointerEvent>> coalesced_pointer_events;
     for (const auto& coalesced_event : coalesced_events) {
-      // TODO(crbug.com/733774): Disabled the DCHECK on the id of the events
-      // because it failed on some versions of Mac OS.
-      // DCHECK_EQ(web_pointer_event.id, coalesced_event.id);
+      DCHECK_EQ(web_pointer_event.id, coalesced_event.id);
       DCHECK_EQ(web_pointer_event.GetType(), coalesced_event.GetType());
       DCHECK_EQ(web_pointer_event.pointer_type, coalesced_event.pointer_type);
 
diff --git a/third_party/WebKit/Source/core/fetch/FetchManager.cpp b/third_party/WebKit/Source/core/fetch/FetchManager.cpp
index 0cce3d0..da44386 100644
--- a/third_party/WebKit/Source/core/fetch/FetchManager.cpp
+++ b/third_party/WebKit/Source/core/fetch/FetchManager.cpp
@@ -200,6 +200,7 @@
                 FetchManager::Loader* loader,
                 String integrity_metadata,
                 const KURL& url,
+                network::mojom::FetchResponseType response_type,
                 scoped_refptr<base::SingleThreadTaskRunner> task_runner)
         : handle_(std::move(handle)),
           updater_(updater),
@@ -207,6 +208,7 @@
           loader_(loader),
           integrity_metadata_(integrity_metadata),
           url_(url),
+          response_type_(response_type),
           finished_(false) {
       reader_ = handle_->ObtainReader(this, std::move(task_runner));
     }
@@ -239,11 +241,23 @@
       finished_ = true;
       if (r == WebDataConsumerHandle::kDone) {
         SubresourceIntegrity::ReportInfo report_info;
-        bool check_result = SubresourceIntegrity::CheckSubresourceIntegrity(
-            integrity_metadata_,
-            SubresourceIntegrityHelper::GetFeatures(
-                loader_->GetExecutionContext()),
-            buffer_.data(), buffer_.size(), url_, report_info);
+        bool check_result = true;
+        if (response_type_ != network::mojom::FetchResponseType::kBasic &&
+            response_type_ != network::mojom::FetchResponseType::kCORS &&
+            response_type_ != network::mojom::FetchResponseType::kDefault) {
+          report_info.AddConsoleErrorMessage(
+              "Subresource Integrity: The resource '" + url_.ElidedString() +
+              "' has an integrity attribute, but the response is not "
+              "eligible for integrity validation.");
+          check_result = false;
+        }
+        if (check_result) {
+          check_result = SubresourceIntegrity::CheckSubresourceIntegrity(
+              integrity_metadata_,
+              SubresourceIntegrityHelper::GetFeatures(
+                  loader_->GetExecutionContext()),
+              buffer_.data(), buffer_.size(), url_, report_info);
+        }
         SubresourceIntegrityHelper::DoReport(*loader_->GetExecutionContext(),
                                              report_info);
         if (check_result) {
@@ -284,6 +298,7 @@
     Member<FetchManager::Loader> loader_;
     String integrity_metadata_;
     KURL url_;
+    const network::mojom::FetchResponseType response_type_;
     std::unique_ptr<WebDataConsumerHandle::Reader> reader_;
     Vector<char> buffer_;
     bool finished_;
@@ -521,7 +536,7 @@
     DCHECK(!integrity_verifier_);
     integrity_verifier_ = new SRIVerifier(
         std::move(handle), sri_consumer, r, this, request_->Integrity(),
-        response.Url(),
+        response.Url(), r->GetResponse()->GetType(),
         resolver_->GetExecutionContext()->GetTaskRunner(TaskType::kNetworking));
   }
 }
diff --git a/third_party/WebKit/Source/core/fetch/Request.cpp b/third_party/WebKit/Source/core/fetch/Request.cpp
index b9f8b89..db3820d 100644
--- a/third_party/WebKit/Source/core/fetch/Request.cpp
+++ b/third_party/WebKit/Source/core/fetch/Request.cpp
@@ -13,7 +13,6 @@
 #include "core/fileapi/PublicURLManager.h"
 #include "core/loader/ThreadableLoader.h"
 #include "platform/bindings/V8PrivateProperty.h"
-#include "platform/heap/Persistent.h"
 #include "platform/loader/cors/CORS.h"
 #include "platform/loader/fetch/FetchUtils.h"
 #include "platform/loader/fetch/ResourceLoaderOptions.h"
@@ -23,7 +22,6 @@
 #include "platform/runtime_enabled_features.h"
 #include "platform/weborigin/OriginAccessEntry.h"
 #include "platform/weborigin/Referrer.h"
-#include "platform/wtf/Functional.h"
 #include "public/platform/WebURLRequest.h"
 #include "public/platform/modules/serviceworker/WebServiceWorkerRequest.h"
 
@@ -375,17 +373,9 @@
     // "Set |r|'s Headers object's guard to "request-no-cors"."
     r->getHeaders()->SetGuard(Headers::kRequestNoCORSGuard);
   }
-  // "If |signal| is not null, then add the following abort steps to signal:
-  //   1. Signal abort on r’s signal."
-  // TODO(ricea): Use the new "followingSignal ... is made to follow" algorithm
-  // that has been added to the DOM standard.
+  // "If |signal| is not null, then make |r|’s signal follow |signal|."
   if (signal) {
-    if (signal->aborted()) {
-      r->signal_->SignalAbort();
-    } else {
-      signal->AddAlgorithm(WTF::Bind(&AbortSignal::SignalAbort,
-                                     WrapWeakPersistent(r->signal_.Get())));
-    }
+    r->signal_->Follow(signal);
   }
   // "Fill |r|'s Headers object with |headers|. Rethrow any exceptions."
   if (!init.GetHeaders().IsNull()) {
@@ -746,12 +736,7 @@
   Headers* headers = Headers::Create(request->HeaderList());
   headers->SetGuard(headers_->GetGuard());
   auto* signal = new AbortSignal(ExecutionContext::From(script_state));
-  if (signal_->aborted()) {
-    signal->SignalAbort();
-  } else {
-    signal_->AddAlgorithm(
-        WTF::Bind(&AbortSignal::SignalAbort, WrapWeakPersistent(signal)));
-  }
+  signal->Follow(signal_);
   return new Request(script_state, request, headers, signal);
 }
 
diff --git a/third_party/WebKit/Source/core/frame/LocalFrameView.cpp b/third_party/WebKit/Source/core/frame/LocalFrameView.cpp
index 96321ed..d38674fb 100644
--- a/third_party/WebKit/Source/core/frame/LocalFrameView.cpp
+++ b/third_party/WebKit/Source/core/frame/LocalFrameView.cpp
@@ -5459,6 +5459,8 @@
   if (frame_->FrameScheduler()) {
     frame_->FrameScheduler()->SetFrameVisible(!hidden_for_throttling_);
     frame_->FrameScheduler()->SetCrossOrigin(frame_->IsCrossOriginSubframe());
+    frame_->FrameScheduler()->TraceUrlChange(
+        frame_->GetDocument()->Url().GetString());
   }
 
 #if DCHECK_IS_ON()
diff --git a/third_party/WebKit/Source/core/html/canvas/CanvasContextCreationAttributesCore.cpp b/third_party/WebKit/Source/core/html/canvas/CanvasContextCreationAttributesCore.cpp
index 51827a4..b87d129 100644
--- a/third_party/WebKit/Source/core/html/canvas/CanvasContextCreationAttributesCore.cpp
+++ b/third_party/WebKit/Source/core/html/canvas/CanvasContextCreationAttributesCore.cpp
@@ -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 "CanvasContextCreationAttributesCore.h"
+#include "core/html/canvas/CanvasContextCreationAttributesCore.h"
 
 namespace blink {
 
diff --git a/third_party/WebKit/Source/core/loader/EmptyClients.cpp b/third_party/WebKit/Source/core/loader/EmptyClients.cpp
index f4a685d..f7efa11 100644
--- a/third_party/WebKit/Source/core/loader/EmptyClients.cpp
+++ b/third_party/WebKit/Source/core/loader/EmptyClients.cpp
@@ -80,6 +80,7 @@
   void SetPaused(bool) override {}
   void SetCrossOrigin(bool) override {}
   bool IsCrossOrigin() const override { return false; }
+  void TraceUrlChange(const String&) override {}
   WebFrameScheduler::FrameType GetFrameType() const override {
     return WebFrameScheduler::FrameType::kSubframe;
   }
diff --git a/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinatorContext.cpp b/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinatorContext.cpp
index 16ba650a..5e40697 100644
--- a/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinatorContext.cpp
+++ b/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinatorContext.cpp
@@ -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 "ScrollingCoordinatorContext.h"
+#include "core/page/scrolling/ScrollingCoordinatorContext.h"
 
 #include "core/paint/PaintLayer.h"
 
diff --git a/third_party/WebKit/Source/platform/WebFrameScheduler.h b/third_party/WebKit/Source/platform/WebFrameScheduler.h
index b56a1a7..bd6cc93e 100644
--- a/third_party/WebKit/Source/platform/WebFrameScheduler.h
+++ b/third_party/WebKit/Source/platform/WebFrameScheduler.h
@@ -7,6 +7,7 @@
 
 #include "base/memory/scoped_refptr.h"
 #include "base/single_thread_task_runner.h"
+#include "platform/wtf/text/WTFString.h"
 #include "public/platform/TaskType.h"
 #include "public/platform/WebScopedVirtualTimePauser.h"
 
@@ -94,6 +95,7 @@
   // frames.
   virtual void SetCrossOrigin(bool) = 0;
   virtual bool IsCrossOrigin() const = 0;
+  virtual void TraceUrlChange(const String&) = 0;
 
   // Returns the frame type, which currently determines whether this frame is
   // the top level frame, i.e. a main frame.
diff --git a/third_party/WebKit/Source/platform/bindings/ScriptWrappableMarkingVisitor.cpp b/third_party/WebKit/Source/platform/bindings/ScriptWrappableMarkingVisitor.cpp
index df42b6c..e27a426 100644
--- a/third_party/WebKit/Source/platform/bindings/ScriptWrappableMarkingVisitor.cpp
+++ b/third_party/WebKit/Source/platform/bindings/ScriptWrappableMarkingVisitor.cpp
@@ -254,8 +254,8 @@
 
 void ScriptWrappableMarkingVisitor::Visit(
     const WrapperDescriptor& wrapper_descriptor) const {
-  HeapObjectHeader* header =
-      HeapObjectHeader::FromPayload(wrapper_descriptor.base_object_payload);
+  HeapObjectHeader* header = wrapper_descriptor.heap_object_header_callback(
+      wrapper_descriptor.traceable);
   if (header->IsWrapperHeaderMarked())
     return;
   MarkWrapperHeader(header);
diff --git a/third_party/WebKit/Source/platform/bindings/ScriptWrappableMarkingVisitor.h b/third_party/WebKit/Source/platform/bindings/ScriptWrappableMarkingVisitor.h
index 5f5b2293..fe437fc6 100644
--- a/third_party/WebKit/Source/platform/bindings/ScriptWrappableMarkingVisitor.h
+++ b/third_party/WebKit/Source/platform/bindings/ScriptWrappableMarkingVisitor.h
@@ -66,8 +66,7 @@
       return;
 
     // If the wrapper is already marked we can bail out here.
-    if (TraceTrait<T>::GetHeapObjectHeader(const_cast<T*>(dst_object))
-            ->IsWrapperHeaderMarked())
+    if (TraceTrait<T>::GetHeapObjectHeader(dst_object)->IsWrapperHeaderMarked())
       return;
 
     CurrentVisitor(thread_state->GetIsolate())
@@ -110,17 +109,19 @@
   class MarkingDequeItem {
    public:
     explicit MarkingDequeItem(const WrapperDescriptor& wrapper_descriptor)
-        : raw_object_pointer_(wrapper_descriptor.base_object_payload),
-          trace_wrappers_callback_(wrapper_descriptor.trace_wrappers_callback) {
-      DCHECK(raw_object_pointer_);
+        : trace_wrappers_callback_(wrapper_descriptor.trace_wrappers_callback),
+          heap_object_header_callback_(
+              wrapper_descriptor.heap_object_header_callback),
+          raw_object_pointer_(wrapper_descriptor.traceable) {
       DCHECK(trace_wrappers_callback_);
+      DCHECK(heap_object_header_callback_);
+      DCHECK(raw_object_pointer_);
     }
 
     // Traces wrappers if the underlying object has not yet been invalidated.
     inline void TraceWrappers(ScriptWrappableVisitor* visitor) const {
       if (raw_object_pointer_) {
-        trace_wrappers_callback_(visitor,
-                                 const_cast<void*>(raw_object_pointer_));
+        trace_wrappers_callback_(visitor, raw_object_pointer_);
       }
     }
 
@@ -138,11 +139,13 @@
 
    private:
     inline const HeapObjectHeader* GetHeapObjectHeader() {
-      return HeapObjectHeader::FromPayload(raw_object_pointer_);
+      DCHECK(raw_object_pointer_);
+      return heap_object_header_callback_(raw_object_pointer_);
     }
 
-    const void* raw_object_pointer_;
     TraceWrappersCallback trace_wrappers_callback_;
+    HeapObjectHeaderCallback heap_object_header_callback_;
+    const void* raw_object_pointer_;
   };
 
   void MarkWrapperHeader(HeapObjectHeader*) const;
diff --git a/third_party/WebKit/Source/platform/bindings/ScriptWrappableVisitor.h b/third_party/WebKit/Source/platform/bindings/ScriptWrappableVisitor.h
index 8a736a1..6335b21 100644
--- a/third_party/WebKit/Source/platform/bindings/ScriptWrappableVisitor.h
+++ b/third_party/WebKit/Source/platform/bindings/ScriptWrappableVisitor.h
@@ -17,6 +17,7 @@
 
 template <typename T>
 class DOMWrapperMap;
+class HeapObjectHeader;
 class ScriptWrappable;
 class ScriptWrappableVisitor;
 template <typename T>
@@ -26,17 +27,18 @@
 template <typename T>
 class TraceWrapperV8Reference;
 
+using HeapObjectHeaderCallback = HeapObjectHeader* (*)(const void*);
 using MissedWriteBarrierCallback = void (*)();
+using TraceWrappersCallback = void (*)(const ScriptWrappableVisitor*,
+                                       const void* self);
 using NameCallback = const char* (*)(const void* self);
 
-#define DEFINE_TRAIT_FOR_TRACE_WRAPPERS(ClassName)                            \
-  template <>                                                                 \
-  inline void TraceTrait<ClassName>::TraceWrappers(                           \
-      ScriptWrappableVisitor* visitor, void* t) {                             \
-    static_assert(sizeof(ClassName), "type needs to be defined");             \
-    static_assert(IsGarbageCollectedType<ClassName>::value,                   \
-                  "only objects deriving from GarbageCollected can be used"); \
-    static_cast<ClassName*>(t)->TraceWrappers(visitor);                       \
+#define DEFINE_TRAIT_FOR_TRACE_WRAPPERS(ClassName)                   \
+  template <>                                                        \
+  inline void TraceTrait<ClassName>::TraceMarkedWrapper(             \
+      const ScriptWrappableVisitor* visitor, const void* t) {        \
+    const ClassName* traceable = ToWrapperTracingType(t);            \
+    traceable->TraceWrappers(visitor);                               \
   }
 
 // WrapperDescriptor contains enough information to visit a
@@ -44,8 +46,9 @@
 // It is passed to ScriptWrappableVisitor::Visit method.
 struct WrapperDescriptor {
   STACK_ALLOCATED();
-  const void* base_object_payload;
+  const void* traceable;
   TraceWrappersCallback trace_wrappers_callback;
+  HeapObjectHeaderCallback heap_object_header_callback;
   MissedWriteBarrierCallback missed_write_barrier_callback;
   NameCallback name_callback;
 };
@@ -122,9 +125,8 @@
 
   template <typename T>
   static WrapperDescriptor WrapperDescriptorFor(const T* traceable) {
-    TraceWrapperDescriptor desc =
-        TraceTrait<T>::GetTraceWrapperDescriptor(const_cast<T*>(traceable));
-    return {desc.base_object_payload, desc.callback,
+    return {traceable, TraceTrait<T>::TraceMarkedWrapper,
+            TraceTrait<T>::GetHeapObjectHeader,
             ScriptWrappableVisitor::MissedWriteBarrier<T>,
             ScriptWrappableVisitor::NameCallback<T>};
   }
@@ -146,7 +148,6 @@
 
   template <typename T>
   static const char* NameCallback(const void* traceable) {
-    // Mixns never inherit from TraceWrapperBase.
     return NameInHeapSnapshot(static_cast<const T*>(traceable));
   }
 
diff --git a/third_party/WebKit/Source/platform/bindings/ScriptWrappableVisitorVerifier.h b/third_party/WebKit/Source/platform/bindings/ScriptWrappableVisitorVerifier.h
index 05d926f..5d198a41 100644
--- a/third_party/WebKit/Source/platform/bindings/ScriptWrappableVisitorVerifier.h
+++ b/third_party/WebKit/Source/platform/bindings/ScriptWrappableVisitorVerifier.h
@@ -16,8 +16,9 @@
  protected:
   void Visit(const TraceWrapperV8Reference<v8::Value>&) const final {}
   void Visit(const WrapperDescriptor& wrapper_descriptor) const final {
-    if (!HeapObjectHeader::FromPayload(wrapper_descriptor.base_object_payload)
-             ->IsWrapperHeaderMarked()) {
+    HeapObjectHeader* header = wrapper_descriptor.heap_object_header_callback(
+        wrapper_descriptor.traceable);
+    if (!header->IsWrapperHeaderMarked()) {
       // If this branch is hit, it means that a white (not discovered by
       // traceWrappers) object was assigned as a member to a black object
       // (already processed by traceWrappers). Black object will not be
diff --git a/third_party/WebKit/Source/platform/blob/BlobBytesProviderTest.cpp b/third_party/WebKit/Source/platform/blob/BlobBytesProviderTest.cpp
index e369c77..2b811090 100644
--- a/third_party/WebKit/Source/platform/blob/BlobBytesProviderTest.cpp
+++ b/third_party/WebKit/Source/platform/blob/BlobBytesProviderTest.cpp
@@ -78,9 +78,9 @@
   auto provider = std::make_unique<BlobBytesProvider>(test_data1_);
   Vector<uint8_t> received_bytes;
   provider->RequestAsReply(
-      base::Bind([](Vector<uint8_t>* bytes_out,
-                    const Vector<uint8_t>& bytes) { *bytes_out = bytes; },
-                 &received_bytes));
+      base::BindOnce([](Vector<uint8_t>* bytes_out,
+                        const Vector<uint8_t>& bytes) { *bytes_out = bytes; },
+                     &received_bytes));
   EXPECT_EQ(test_bytes1_, received_bytes);
 
   received_bytes.clear();
@@ -88,9 +88,9 @@
   provider->AppendData(test_data2_);
   provider->AppendData(test_data3_);
   provider->RequestAsReply(
-      base::Bind([](Vector<uint8_t>* bytes_out,
-                    const Vector<uint8_t>& bytes) { *bytes_out = bytes; },
-                 &received_bytes));
+      base::BindOnce([](Vector<uint8_t>* bytes_out,
+                        const Vector<uint8_t>& bytes) { *bytes_out = bytes; },
+                     &received_bytes));
   EXPECT_EQ(combined_bytes_, received_bytes);
 }
 
@@ -129,7 +129,7 @@
         source_offset, source_length,
         base::File(path, base::File::FLAG_OPEN | base::File::FLAG_WRITE),
         file_offset,
-        base::Bind(
+        base::BindOnce(
             [](WTF::Optional<WTF::Time>* received_modified,
                WTF::Optional<WTF::Time> modified) {
               *received_modified = modified;
@@ -206,7 +206,7 @@
   test_provider_->RequestAsFile(
       test.offset, test.size,
       base::File(path, base::File::FLAG_OPEN | base::File::FLAG_WRITE),
-      file_offset, base::Bind([](WTF::Optional<WTF::Time> last_modified) {
+      file_offset, base::BindOnce([](WTF::Optional<WTF::Time> last_modified) {
         EXPECT_TRUE(last_modified);
       }));
 
@@ -252,7 +252,7 @@
     provider->RequestAsFile(
         i, 16, base::File(path, base::File::FLAG_OPEN | base::File::FLAG_WRITE),
         combined_bytes_.size() - i - 16,
-        base::Bind([](WTF::Optional<WTF::Time> last_modified) {
+        base::BindOnce([](WTF::Optional<WTF::Time> last_modified) {
           EXPECT_TRUE(last_modified);
         }));
     expected_data.insert(0, combined_bytes_.data() + i, 16);
@@ -276,7 +276,7 @@
 
   provider->RequestAsFile(
       0, 16, base::File(), 0,
-      base::Bind([](WTF::Optional<WTF::Time> last_modified) {
+      base::BindOnce([](WTF::Optional<WTF::Time> last_modified) {
         EXPECT_FALSE(last_modified);
       }));
 }
@@ -288,7 +288,7 @@
   base::CreateTemporaryFile(&path);
   provider->RequestAsFile(
       0, 16, base::File(path, base::File::FLAG_OPEN | base::File::FLAG_READ), 0,
-      base::Bind([](WTF::Optional<WTF::Time> last_modified) {
+      base::BindOnce([](WTF::Optional<WTF::Time> last_modified) {
         EXPECT_FALSE(last_modified);
       }));
 
@@ -313,7 +313,7 @@
                               mojo::SimpleWatcher::ArmingPolicy::AUTOMATIC);
   watcher.Watch(
       pipe.consumer_handle.get(), MOJO_HANDLE_SIGNAL_READABLE,
-      base::Bind(
+      base::BindRepeating(
           [](mojo::DataPipeConsumerHandle pipe, base::Closure quit_closure,
              Vector<uint8_t>* bytes_out, MojoResult result) {
             if (result == MOJO_RESULT_CANCELLED ||
diff --git a/third_party/WebKit/Source/platform/blob/BlobDataTest.cpp b/third_party/WebKit/Source/platform/blob/BlobDataTest.cpp
index a0ce583..3c6e24a 100644
--- a/third_party/WebKit/Source/platform/blob/BlobDataTest.cpp
+++ b/third_party/WebKit/Source/platform/blob/BlobDataTest.cpp
@@ -159,7 +159,7 @@
         Vector<uint8_t> received_bytes;
         mojom::blink::BytesProviderPtr data(
             std::move(actual->get_bytes()->data));
-        data->RequestAsReply(base::Bind(
+        data->RequestAsReply(base::BindOnce(
             [](base::Closure quit_closure, Vector<uint8_t>* bytes_out,
                const Vector<uint8_t>& bytes) {
               *bytes_out = bytes;
@@ -196,7 +196,7 @@
         base::RunLoop loop;
         String received_uuid;
         mojom::blink::BlobPtr blob(std::move(actual->get_blob()->blob));
-        blob->GetInternalUUID(base::Bind(
+        blob->GetInternalUUID(base::BindOnce(
             [](base::Closure quit_closure, String* uuid_out,
                const String& uuid) {
               *uuid_out = uuid;
diff --git a/third_party/WebKit/Source/platform/fonts/FontMetrics.cpp b/third_party/WebKit/Source/platform/fonts/FontMetrics.cpp
index 3b94970e..cd202ee 100644
--- a/third_party/WebKit/Source/platform/fonts/FontMetrics.cpp
+++ b/third_party/WebKit/Source/platform/fonts/FontMetrics.cpp
@@ -27,7 +27,7 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include "FontMetrics.h"
+#include "platform/fonts/FontMetrics.h"
 
 #include "build/build_config.h"
 #include "platform/fonts/FontPlatformData.h"
diff --git a/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp b/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp
index 9048e5d..8c9e85a1 100644
--- a/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp
+++ b/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp
@@ -193,8 +193,8 @@
   // does not scroll.
   scroll_layer->SetBounds(bounds);
   scroll_layer->set_did_scroll_callback(
-      base::Bind(&blink::WebLayerScrollClient::DidScroll,
-                 base::Unretained(&scroll_client_)));
+      base::BindRepeating(&blink::WebLayerScrollClient::DidScroll,
+                          base::Unretained(&scroll_client_)));
   return scroll_layer;
 }
 
diff --git a/third_party/WebKit/Source/platform/graphics/paint/PaintPropertyNode.cpp b/third_party/WebKit/Source/platform/graphics/paint/PaintPropertyNode.cpp
index 26be6ae..4347e22d 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/PaintPropertyNode.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/PaintPropertyNode.cpp
@@ -13,11 +13,17 @@
 
 namespace {
 
+// Returns -1 if |maybe_ancestor| is found in the ancestor chain, or returns
+// the depth of the node from the root.
 template <typename NodeType>
-unsigned NodeDepth(const NodeType& node) {
-  unsigned depth = 0;
-  for (const NodeType* n = &node; n; n = n->Parent())
+int NodeDepthOrFoundAncestor(const NodeType& node,
+                             const NodeType& maybe_ancestor) {
+  int depth = 0;
+  for (const NodeType* n = &node; n; n = n->Parent()) {
+    if (n == &maybe_ancestor)
+      return -1;
     depth++;
+  }
   return depth;
 }
 
@@ -25,8 +31,12 @@
 const NodeType& LowestCommonAncestorTemplate(const NodeType& a,
                                              const NodeType& b) {
   // Measure both depths.
-  unsigned depth_a = NodeDepth(a);
-  unsigned depth_b = NodeDepth(b);
+  auto depth_a = NodeDepthOrFoundAncestor(a, b);
+  if (depth_a == -1)
+    return b;
+  auto depth_b = NodeDepthOrFoundAncestor(b, a);
+  if (depth_b == -1)
+    return a;
 
   const auto* a_ptr = &a;
   const auto* b_ptr = &b;
@@ -56,25 +66,25 @@
 
 }  // namespace
 
-const TransformPaintPropertyNode& LowestCommonAncestor(
+const TransformPaintPropertyNode& LowestCommonAncestorInternal(
     const TransformPaintPropertyNode& a,
     const TransformPaintPropertyNode& b) {
   return LowestCommonAncestorTemplate(a, b);
 }
 
-const ClipPaintPropertyNode& LowestCommonAncestor(
+const ClipPaintPropertyNode& LowestCommonAncestorInternal(
     const ClipPaintPropertyNode& a,
     const ClipPaintPropertyNode& b) {
   return LowestCommonAncestorTemplate(a, b);
 }
 
-const EffectPaintPropertyNode& LowestCommonAncestor(
+const EffectPaintPropertyNode& LowestCommonAncestorInternal(
     const EffectPaintPropertyNode& a,
     const EffectPaintPropertyNode& b) {
   return LowestCommonAncestorTemplate(a, b);
 }
 
-const ScrollPaintPropertyNode& LowestCommonAncestor(
+const ScrollPaintPropertyNode& LowestCommonAncestorInternal(
     const ScrollPaintPropertyNode& a,
     const ScrollPaintPropertyNode& b) {
   return LowestCommonAncestorTemplate(a, b);
diff --git a/third_party/WebKit/Source/platform/graphics/paint/PaintPropertyNode.h b/third_party/WebKit/Source/platform/graphics/paint/PaintPropertyNode.h
index 9c0fd65a..1d04571 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/PaintPropertyNode.h
+++ b/third_party/WebKit/Source/platform/graphics/paint/PaintPropertyNode.h
@@ -24,16 +24,31 @@
 class TransformPaintPropertyNode;
 
 // Returns the lowest common ancestor in the paint property tree.
-PLATFORM_EXPORT const ClipPaintPropertyNode& LowestCommonAncestor(
+template <typename NodeType>
+const NodeType& LowestCommonAncestor(const NodeType& a, const NodeType& b) {
+  // Fast path of common cases.
+  if (&a == &b || !a.Parent() || b.Parent() == &a) {
+    DCHECK(a.IsAncestorOf(b));
+    return a;
+  }
+  if (!b.Parent() || a.Parent() == &b) {
+    DCHECK(b.IsAncestorOf(a));
+    return b;
+  }
+
+  return LowestCommonAncestorInternal(a, b);
+}
+
+PLATFORM_EXPORT const ClipPaintPropertyNode& LowestCommonAncestorInternal(
     const ClipPaintPropertyNode&,
     const ClipPaintPropertyNode&);
-PLATFORM_EXPORT const EffectPaintPropertyNode& LowestCommonAncestor(
+PLATFORM_EXPORT const EffectPaintPropertyNode& LowestCommonAncestorInternal(
     const EffectPaintPropertyNode&,
     const EffectPaintPropertyNode&);
-PLATFORM_EXPORT const ScrollPaintPropertyNode& LowestCommonAncestor(
+PLATFORM_EXPORT const ScrollPaintPropertyNode& LowestCommonAncestorInternal(
     const ScrollPaintPropertyNode&,
     const ScrollPaintPropertyNode&);
-PLATFORM_EXPORT const TransformPaintPropertyNode& LowestCommonAncestor(
+PLATFORM_EXPORT const TransformPaintPropertyNode& LowestCommonAncestorInternal(
     const TransformPaintPropertyNode&,
     const TransformPaintPropertyNode&);
 
diff --git a/third_party/WebKit/Source/platform/heap/BlinkGC.h b/third_party/WebKit/Source/platform/heap/BlinkGC.h
index 3034a01..cee5c09b3 100644
--- a/third_party/WebKit/Source/platform/heap/BlinkGC.h
+++ b/third_party/WebKit/Source/platform/heap/BlinkGC.h
@@ -16,7 +16,6 @@
 
 class MarkingVisitor;
 class Visitor;
-class ScriptWrappableVisitor;
 
 using Address = uint8_t*;
 
@@ -24,7 +23,6 @@
 using VisitorCallback = void (*)(Visitor*, void*);
 using MarkingVisitorCallback = void (*)(MarkingVisitor*, void*);
 using TraceCallback = VisitorCallback;
-using TraceWrappersCallback = void (*)(ScriptWrappableVisitor*, void*);
 using WeakCallback = VisitorCallback;
 using EphemeronCallback = VisitorCallback;
 
diff --git a/third_party/WebKit/Source/platform/heap/GarbageCollected.h b/third_party/WebKit/Source/platform/heap/GarbageCollected.h
index 6dc9902..21fcf87 100644
--- a/third_party/WebKit/Source/platform/heap/GarbageCollected.h
+++ b/third_party/WebKit/Source/platform/heap/GarbageCollected.h
@@ -16,6 +16,7 @@
 template <typename T>
 class GarbageCollected;
 class HeapObjectHeader;
+class ScriptWrappableVisitor;
 
 // GC_PLUGIN_IGNORE is used to make the plugin ignore a particular class or
 // field when checking for proper usage.  When using GC_PLUGIN_IGNORE
@@ -53,11 +54,6 @@
   bool can_trace_eagerly;
 };
 
-struct TraceWrapperDescriptor {
-  void* base_object_payload;
-  TraceWrappersCallback callback;
-};
-
 // The GarbageCollectedMixin interface and helper macro
 // USING_GARBAGE_COLLECTED_MIXIN can be used to automatically define
 // TraceTrait/ObjectAliveTrait on non-leftmost deriving classes
@@ -75,39 +71,43 @@
 // };
 //
 // With the helper, as long as we are using Member<B>, TypeTrait<B> will
-// dispatch dynamically to retrieve the necessary tracing and header methods.
+// dispatch adjustAndMark dynamically to find collect addr of the object header.
 // Note that this is only enabled for Member<B>. For Member<A> which we can
-// compute the necessary methods and pointers statically and this dynamic
-// dispatch is not used.
+// compute the object header addr statically, this dynamic dispatch is not used.
+//
 class PLATFORM_EXPORT GarbageCollectedMixin {
  public:
   typedef int IsGarbageCollectedMixinMarker;
   virtual void Trace(Visitor*) {}
-  virtual HeapObjectHeader* GetHeapObjectHeader() const = 0;
   virtual TraceDescriptor GetTraceDescriptor() const = 0;
-  virtual TraceWrapperDescriptor GetTraceWrapperDescriptor() const = 0;
+  virtual HeapObjectHeader* GetHeapObjectHeader() const = 0;
+  virtual void AdjustAndTraceMarkedWrapper(
+      const ScriptWrappableVisitor*) const = 0;
 };
 
-#define DEFINE_GARBAGE_COLLECTED_MIXIN_METHODS(TYPE)                         \
- public:                                                                     \
-  HeapObjectHeader* GetHeapObjectHeader() const override {                   \
-    static_assert(                                                           \
-        WTF::IsSubclassOfTemplate<typename std::remove_const<TYPE>::type,    \
-                                  blink::GarbageCollected>::value,           \
-        "only garbage collected objects can have garbage collected mixins"); \
-    return HeapObjectHeader::FromPayload(static_cast<const TYPE*>(this));    \
-  }                                                                          \
-                                                                             \
-  TraceDescriptor GetTraceDescriptor() const override {                      \
-    return {const_cast<TYPE*>(static_cast<const TYPE*>(this)),               \
-            TraceTrait<TYPE>::Trace, TraceEagerlyTrait<TYPE>::value};        \
-  }                                                                          \
-                                                                             \
-  TraceWrapperDescriptor GetTraceWrapperDescriptor() const override {        \
-    return {const_cast<TYPE*>(static_cast<const TYPE*>(this)),               \
-            TraceTrait<TYPE>::TraceWrappers};                                \
-  }                                                                          \
-                                                                             \
+#define DEFINE_GARBAGE_COLLECTED_MIXIN_METHODS(TYPE)                          \
+ public:                                                                      \
+  TraceDescriptor GetTraceDescriptor() const override {                       \
+    typedef WTF::IsSubclassOfTemplate<typename std::remove_const<TYPE>::type, \
+                                      blink::GarbageCollected>                \
+        IsSubclassOfGarbageCollected;                                         \
+    static_assert(                                                            \
+        IsSubclassOfGarbageCollected::value,                                  \
+        "only garbage collected objects can have garbage collected mixins");  \
+    return {const_cast<TYPE*>(static_cast<const TYPE*>(this)),                \
+            TraceTrait<TYPE>::Trace, TraceEagerlyTrait<TYPE>::value};         \
+  }                                                                           \
+                                                                              \
+  void AdjustAndTraceMarkedWrapper(const ScriptWrappableVisitor* visitor)     \
+      const override {                                                        \
+    const TYPE* base = static_cast<const TYPE*>(this);                        \
+    TraceTrait<TYPE>::TraceMarkedWrapper(visitor, base);                      \
+  }                                                                           \
+                                                                              \
+  HeapObjectHeader* GetHeapObjectHeader() const override {                    \
+    return HeapObjectHeader::FromPayload(static_cast<const TYPE*>(this));     \
+  }                                                                           \
+                                                                              \
  private:
 
 // A C++ object's vptr will be initialized to its leftmost base's vtable after
@@ -212,13 +212,14 @@
 //    // ambiguous. USING_GARBAGE_COLLECTED_MIXIN(TYPE) overrides them later
 //    // and provides the implementations.
 //  };
-#define MERGE_GARBAGE_COLLECTED_MIXINS()                                 \
- public:                                                                 \
-  HeapObjectHeader* GetHeapObjectHeader() const override = 0;            \
-  TraceDescriptor GetTraceDescriptor() const override = 0;               \
-  TraceWrapperDescriptor GetTraceWrapperDescriptor() const override = 0; \
-                                                                         \
- private:                                                                \
+#define MERGE_GARBAGE_COLLECTED_MIXINS()                          \
+ public:                                                          \
+  TraceDescriptor GetTraceDescriptor() const override = 0;        \
+  HeapObjectHeader* GetHeapObjectHeader() const override = 0;     \
+  void AdjustAndTraceMarkedWrapper(const ScriptWrappableVisitor*) \
+      const override = 0;                                         \
+                                                                  \
+ private:                                                         \
   using merge_garbage_collected_mixins_requires_semicolon = void
 
 // Base class for objects allocated in the Blink garbage-collected heap.
diff --git a/third_party/WebKit/Source/platform/heap/HeapAllocator.h b/third_party/WebKit/Source/platform/heap/HeapAllocator.h
index 85b3488..1467adb 100644
--- a/third_party/WebKit/Source/platform/heap/HeapAllocator.h
+++ b/third_party/WebKit/Source/platform/heap/HeapAllocator.h
@@ -181,12 +181,6 @@
   }
 
   template <typename VisitorDispatcher>
-  static void RegisterDelayedMarkNoTracing(VisitorDispatcher visitor,
-                                           const void* object) {
-    visitor->RegisterDelayedMarkNoTracing(object);
-  }
-
-  template <typename VisitorDispatcher>
   static void RegisterWeakMembers(VisitorDispatcher visitor,
                                   const void* closure,
                                   WeakCallback callback) {
@@ -211,12 +205,6 @@
 #endif
 
   template <typename T, typename VisitorDispatcher>
-  static void RegisterBackingStoreReference(VisitorDispatcher visitor,
-                                            T** slot) {
-    visitor->RegisterBackingStoreReference(slot);
-  }
-
-  template <typename T, typename VisitorDispatcher>
   static void RegisterBackingStoreCallback(VisitorDispatcher visitor,
                                            T* backing_store,
                                            MovingObjectCallback callback,
@@ -282,22 +270,31 @@
 #endif  // BUILDFLAG(BLINK_HEAP_INCREMENTAL_MARKING)
   }
 
-  template <typename T, typename VisitorDispatcher>
-  static void TraceVectorBacking(VisitorDispatcher visitor,
+  template <typename T>
+  static void TraceVectorBacking(Visitor* visitor,
                                  T* backing,
                                  T** backing_slot) {
-    HeapVectorBacking<T>* vector_backing =
-        reinterpret_cast<HeapVectorBacking<T>*>(backing);
-    visitor->RegisterBackingStoreReference(backing_slot);
-    visitor->Trace(vector_backing);
+    visitor->TraceBackingStoreStrongly(
+        reinterpret_cast<HeapVectorBacking<T>*>(backing),
+        reinterpret_cast<HeapVectorBacking<T>**>(backing_slot));
   }
 
-  template <typename T, typename HashTable, typename VisitorDispatcher>
-  static void TraceHashTableBacking(VisitorDispatcher visitor, T* backing) {
-    HeapHashTableBacking<HashTable>* hashtable_backing =
-        reinterpret_cast<HeapHashTableBacking<HashTable>*>(backing);
-    // Backing store reference is registered by the caller.
-    visitor->Trace(hashtable_backing);
+  template <typename T, typename HashTable>
+  static void TraceHashTableBackingStrongly(Visitor* visitor,
+                                            T* backing,
+                                            T** backing_slot) {
+    visitor->TraceBackingStoreStrongly(
+        reinterpret_cast<HeapHashTableBacking<HashTable>*>(backing),
+        reinterpret_cast<HeapHashTableBacking<HashTable>**>(backing_slot));
+  }
+
+  template <typename T, typename HashTable>
+  static void TraceHashTableBackingWeakly(Visitor* visitor,
+                                          T* backing,
+                                          T** backing_slot) {
+    visitor->TraceBackingStoreWeakly(
+        reinterpret_cast<HeapHashTableBacking<HashTable>*>(backing),
+        reinterpret_cast<HeapHashTableBacking<HashTable>**>(backing_slot));
   }
 
  private:
diff --git a/third_party/WebKit/Source/platform/heap/MarkingVerifier.h b/third_party/WebKit/Source/platform/heap/MarkingVerifier.h
index 25a43e2..1c20563 100644
--- a/third_party/WebKit/Source/platform/heap/MarkingVerifier.h
+++ b/third_party/WebKit/Source/platform/heap/MarkingVerifier.h
@@ -49,11 +49,15 @@
   }
 
   // Unused overrides.
-  void RegisterBackingStoreReference(void* slot) final {}
+  void VisitBackingStoreStrongly(void* object,
+                                 void** object_slot,
+                                 TraceDescriptor desc) final {}
+  void VisitBackingStoreWeakly(void* object,
+                               void** object_slot,
+                               TraceDescriptor desc) final {}
   void RegisterBackingStoreCallback(void* backing_store,
                                     MovingObjectCallback,
                                     void* callback_data) final {}
-  void RegisterDelayedMarkNoTracing(const void* pointer) final {}
   void RegisterWeakCallback(void* closure, WeakCallback) final {}
 
  private:
diff --git a/third_party/WebKit/Source/platform/heap/MarkingVisitor.h b/third_party/WebKit/Source/platform/heap/MarkingVisitor.h
index 9c07fe7..7d2b146 100644
--- a/third_party/WebKit/Source/platform/heap/MarkingVisitor.h
+++ b/third_party/WebKit/Source/platform/heap/MarkingVisitor.h
@@ -96,11 +96,30 @@
     Mark(desc.base_object_payload, desc.callback);
   }
 
-  void RegisterBackingStoreReference(void* slot) final;
+  void VisitBackingStoreStrongly(void* object,
+                                 void** object_slot,
+                                 TraceDescriptor desc) final {
+    RegisterBackingStoreReference(object_slot);
+    Visit(object, desc);
+  }
+
+  // Used to delay the marking of objects until the usual marking including
+  // ephemeron iteration is done. This is used to delay the marking of
+  // collection backing stores until we know if they are reachable from
+  // locations other than the collection front object. If collection backings
+  // are reachable from other locations we strongify them to avoid issues with
+  // iterators and weak processing.
+  void VisitBackingStoreWeakly(void* object,
+                               void** object_slot,
+                               TraceDescriptor desc) final {
+    DCHECK(GetMarkingMode() != kWeakProcessing);
+    RegisterBackingStoreReference(object_slot);
+    Heap().PushPostMarkingCallback(object, &MarkNoTracingCallback);
+  }
+
   void RegisterBackingStoreCallback(void* backing_store,
                                     MovingObjectCallback,
                                     void* callback_data) final;
-  void RegisterDelayedMarkNoTracing(const void* pointer) final;
   bool RegisterWeakTable(const void* closure,
                          EphemeronCallback iteration_callback,
                          EphemeronCallback iteration_done_callback) final;
@@ -112,6 +131,8 @@
  private:
   static void MarkNoTracingCallback(Visitor*, void*);
 
+  void RegisterBackingStoreReference(void* slot);
+
   const MarkingMode marking_mode_;
 };
 
@@ -148,13 +169,6 @@
   MarkHeader(header, reinterpret_cast<TraceCallback>(0));
 }
 
-inline void MarkingVisitor::RegisterDelayedMarkNoTracing(
-    const void* object_pointer) {
-  DCHECK(GetMarkingMode() != kWeakProcessing);
-  Heap().PushPostMarkingCallback(const_cast<void*>(object_pointer),
-                                 &MarkNoTracingCallback);
-}
-
 inline bool MarkingVisitor::EnsureMarked(const void* object_pointer) {
   if (!object_pointer)
     return false;
diff --git a/third_party/WebKit/Source/platform/heap/TraceTraits.h b/third_party/WebKit/Source/platform/heap/TraceTraits.h
index 10ab493..85590c9 100644
--- a/third_party/WebKit/Source/platform/heap/TraceTraits.h
+++ b/third_party/WebKit/Source/platform/heap/TraceTraits.h
@@ -54,16 +54,20 @@
     return {self, TraceTrait<T>::Trace, TraceEagerlyTrait<T>::value};
   }
 
-  static TraceWrapperDescriptor GetTraceWrapperDescriptor(void* self) {
-    return {self, TraceTrait<T>::TraceWrappers};
-  }
-
-  static HeapObjectHeader* GetHeapObjectHeader(void* self) {
+  static HeapObjectHeader* GetHeapObjectHeader(const T* self) {
 #if DCHECK_IS_ON()
     HeapObjectHeader::CheckFromPayload(self);
 #endif
     return HeapObjectHeader::FromPayload(self);
   }
+
+  static void TraceMarkedWrapper(const ScriptWrappableVisitor* visitor,
+                                 const T* self) {
+    // The term *mark* is misleading here as we effectively trace through the
+    // API boundary, i.e., tell V8 that an object is alive. Actual marking
+    // will be done in V8.
+    visitor->DispatchTraceWrappers(self);
+  }
 };
 
 template <typename T>
@@ -71,19 +75,18 @@
   STATIC_ONLY(AdjustAndMarkTrait);
 
  public:
-  static TraceDescriptor GetTraceDescriptor(const T* self) {
+  static HeapObjectHeader* GetHeapObjectHeader(const T* self) {
+    return self->GetHeapObjectHeader();
+  }
+
+  static TraceDescriptor GetTraceDescriptor(T* self) {
     DCHECK(self);
     return self->GetTraceDescriptor();
   }
 
-  static TraceWrapperDescriptor GetTraceWrapperDescriptor(const T* self) {
-    DCHECK(self);
-    return self->GetTraceWrapperDescriptor();
-  }
-
-  static HeapObjectHeader* GetHeapObjectHeader(const T* self) {
-    DCHECK(self);
-    return self->GetHeapObjectHeader();
+  static void TraceMarkedWrapper(const ScriptWrappableVisitor* visitor,
+                                 const T* self) {
+    self->AdjustAndTraceMarkedWrapper(visitor);
   }
 };
 
@@ -170,11 +173,10 @@
   }
 };
 
-// The TraceTrait is used to specify how to trace and object for Oilpan and
-// wrapper tracing.
+// The TraceTrait is used to specify how to mark an object pointer and
+// how to trace all of the pointers in the object.
 //
-//
-// By default, the 'Trace' method implemented on an object itself is
+// By default, the 'trace' method implemented on an object itself is
 // used to trace the pointers to other heap objects inside the object.
 //
 // However, the TraceTrait can be specialized to use a different
@@ -191,17 +193,17 @@
     return AdjustAndMarkTrait<T>::GetTraceDescriptor(static_cast<T*>(self));
   }
 
-  static TraceWrapperDescriptor GetTraceWrapperDescriptor(void* self) {
-    return AdjustAndMarkTrait<T>::GetTraceWrapperDescriptor(
-        static_cast<T*>(self));
-  }
-
-  static HeapObjectHeader* GetHeapObjectHeader(void* self) {
-    return AdjustAndMarkTrait<T>::GetHeapObjectHeader(static_cast<T*>(self));
-  }
-
   static void Trace(Visitor*, void* self);
-  static void TraceWrappers(ScriptWrappableVisitor*, void*);
+  static void TraceMarkedWrapper(const ScriptWrappableVisitor*, const void*);
+  static HeapObjectHeader* GetHeapObjectHeader(const void*);
+
+ private:
+  static const T* ToWrapperTracingType(const void* t) {
+    static_assert(sizeof(T), "type needs to be defined");
+    static_assert(IsGarbageCollectedType<T>::value,
+                  "only objects deriving from GarbageCollected can be used");
+    return reinterpret_cast<const T*>(t);
+  }
 };
 
 template <typename T>
@@ -214,13 +216,16 @@
 }
 
 template <typename T>
-void TraceTrait<T>::TraceWrappers(ScriptWrappableVisitor* visitor, void* self) {
-  static_assert(sizeof(T), "type needs to be defined");
-  static_assert(IsGarbageCollectedType<T>::value,
-                "only objects deriving from GarbageCollected can be used");
-  visitor->DispatchTraceWrappers(static_cast<T*>(self));
+void TraceTrait<T>::TraceMarkedWrapper(const ScriptWrappableVisitor* visitor,
+                                       const void* t) {
+  const T* traceable = ToWrapperTracingType(t);
+  AdjustAndMarkTrait<T>::TraceMarkedWrapper(visitor, traceable);
 }
 
+template <typename T>
+HeapObjectHeader* TraceTrait<T>::GetHeapObjectHeader(const void* t) {
+  return AdjustAndMarkTrait<T>::GetHeapObjectHeader(ToWrapperTracingType(t));
+}
 
 template <typename T, typename Traits>
 struct TraceTrait<HeapVectorBacking<T, Traits>> {
diff --git a/third_party/WebKit/Source/platform/heap/Visitor.h b/third_party/WebKit/Source/platform/heap/Visitor.h
index 5e21119a..79e1d81 100644
--- a/third_party/WebKit/Source/platform/heap/Visitor.h
+++ b/third_party/WebKit/Source/platform/heap/Visitor.h
@@ -113,6 +113,34 @@
               const_cast<void*>(reinterpret_cast<const void*>(t))));
   }
 
+  template <typename T>
+  void TraceBackingStoreStrongly(T* backing_store, T** backing_store_slot) {
+    static_assert(sizeof(T), "T must be fully defined");
+    static_assert(IsGarbageCollectedType<T>::value,
+                  "T needs to be a garbage collected object");
+
+    if (!backing_store)
+      return;
+    VisitBackingStoreStrongly(reinterpret_cast<void*>(backing_store),
+                              reinterpret_cast<void**>(backing_store_slot),
+                              TraceTrait<T>::GetTraceDescriptor(
+                                  reinterpret_cast<void*>(backing_store)));
+  }
+
+  template <typename T>
+  void TraceBackingStoreWeakly(T* backing_store, T** backing_store_slot) {
+    static_assert(sizeof(T), "T must be fully defined");
+    static_assert(IsGarbageCollectedType<T>::value,
+                  "T needs to be a garbage collected object");
+
+    if (!backing_store)
+      return;
+    VisitBackingStoreWeakly(reinterpret_cast<void*>(backing_store),
+                            reinterpret_cast<void**>(backing_store_slot),
+                            TraceTrait<T>::GetTraceDescriptor(
+                                reinterpret_cast<void*>(backing_store)));
+  }
+
   // WeakMember version of the templated trace method. It doesn't keep
   // the traced thing alive, but will write null to the WeakMember later
   // if the pointed-to object is dead. It's lying for this to be const,
@@ -174,21 +202,16 @@
   // Visits an object through a strong reference.
   virtual void Visit(void*, TraceDescriptor) = 0;
 
+  // Visitors for collection backing stores.
+  virtual void VisitBackingStoreStrongly(void*, void**, TraceDescriptor) = 0;
+  virtual void VisitBackingStoreWeakly(void*, void**, TraceDescriptor) = 0;
+
   // Registers backing store pointers so that they can be moved and properly
   // updated.
-  virtual void RegisterBackingStoreReference(void* slot) = 0;
   virtual void RegisterBackingStoreCallback(void* backing_store,
                                             MovingObjectCallback,
                                             void* callback_data) = 0;
 
-  // Used to delay the marking of objects until the usual marking including
-  // ephemeron iteration is done. This is used to delay the marking of
-  // collection backing stores until we know if they are reachable from
-  // locations other than the collection front object. If collection backings
-  // are reachable from other locations we strongify them to avoid issues with
-  // iterators and weak processing.
-  virtual void RegisterDelayedMarkNoTracing(const void* pointer) = 0;
-
   // Used to register ephemeron callbacks.
   virtual bool RegisterWeakTable(const void* closure,
                                  EphemeronCallback iteration_callback,
diff --git a/third_party/WebKit/Source/platform/loader/SubresourceIntegrity.h b/third_party/WebKit/Source/platform/loader/SubresourceIntegrity.h
index 044bba4..bff877d0 100644
--- a/third_party/WebKit/Source/platform/loader/SubresourceIntegrity.h
+++ b/third_party/WebKit/Source/platform/loader/SubresourceIntegrity.h
@@ -21,7 +21,7 @@
   STATIC_ONLY(SubresourceIntegrity);
 
  public:
-  class ReportInfo final {
+  class PLATFORM_EXPORT ReportInfo final {
    public:
     enum class UseCounterFeature {
       kSRIElementWithMatchingIntegrityAttribute,
diff --git a/third_party/WebKit/Source/platform/loader/fetch/BufferingDataPipeWriter.cpp b/third_party/WebKit/Source/platform/loader/fetch/BufferingDataPipeWriter.cpp
index 85a3773a..11fca26 100644
--- a/third_party/WebKit/Source/platform/loader/fetch/BufferingDataPipeWriter.cpp
+++ b/third_party/WebKit/Source/platform/loader/fetch/BufferingDataPipeWriter.cpp
@@ -19,10 +19,10 @@
     base::SingleThreadTaskRunner* runner)
     : handle_(std::move(handle)),
       watcher_(FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::MANUAL, runner) {
-  watcher_.Watch(
-      handle_.get(), MOJO_HANDLE_SIGNAL_WRITABLE,
-      MOJO_WATCH_CONDITION_SATISFIED,
-      base::Bind(&BufferingDataPipeWriter::OnWritable, base::Unretained(this)));
+  watcher_.Watch(handle_.get(), MOJO_HANDLE_SIGNAL_WRITABLE,
+                 MOJO_WATCH_CONDITION_SATISFIED,
+                 base::BindRepeating(&BufferingDataPipeWriter::OnWritable,
+                                     base::Unretained(this)));
 }
 
 bool BufferingDataPipeWriter::Write(const char* buffer, uint32_t num_bytes) {
diff --git a/third_party/WebKit/Source/platform/runtime_enabled_features.json5 b/third_party/WebKit/Source/platform/runtime_enabled_features.json5
index 4e20e9d..7b3ff5f 100644
--- a/third_party/WebKit/Source/platform/runtime_enabled_features.json5
+++ b/third_party/WebKit/Source/platform/runtime_enabled_features.json5
@@ -292,6 +292,10 @@
       status: "experimental",
     },
     {
+      name: "CSSPartPseudoElement",
+      status: "test",
+    },
+    {
       name: "CSSScrollSnapPoints",
       status: "experimental",
     },
diff --git a/third_party/WebKit/Source/platform/scheduler/BUILD.gn b/third_party/WebKit/Source/platform/scheduler/BUILD.gn
index 5ac1b18d..1199be55 100644
--- a/third_party/WebKit/Source/platform/scheduler/BUILD.gn
+++ b/third_party/WebKit/Source/platform/scheduler/BUILD.gn
@@ -17,7 +17,7 @@
     "base/moveable_auto_lock.h",
     "base/real_time_domain.cc",
     "base/real_time_domain.h",
-    "base/sequence.h",
+    "base/sequenced_task_source.h",
     "base/task_queue.cc",
     "base/task_queue.h",
     "base/task_queue_impl.cc",
diff --git a/third_party/WebKit/Source/platform/scheduler/base/sequence.h b/third_party/WebKit/Source/platform/scheduler/base/sequenced_task_source.h
similarity index 92%
rename from third_party/WebKit/Source/platform/scheduler/base/sequence.h
rename to third_party/WebKit/Source/platform/scheduler/base/sequenced_task_source.h
index afe219d..c41bfb1 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/sequence.h
+++ b/third_party/WebKit/Source/platform/scheduler/base/sequenced_task_source.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_SEQUENCE_H_
-#define THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_SEQUENCE_H_
+#ifndef THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_SEQUENCED_TASK_SOURCE_H_
+#define THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_SEQUENCED_TASK_SOURCE_H_
 
 #include "base/optional.h"
 #include "base/pending_task.h"
@@ -16,8 +16,7 @@
 
 // This is temporary interface for ThreadController to be able to run tasks
 // from TaskQueueManager.
-// TODO(alexclarke): Rename to SequencedTaskSource.
-class Sequence {
+class SequencedTaskSource {
  public:
   // TODO(alexclarke): Move this enum elsewhere.
   enum class WorkType { kImmediate, kDelayed };
@@ -38,4 +37,4 @@
 }  // namespace scheduler
 }  // namespace blink
 
-#endif  // THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_SEQUENCE_H_
+#endif  // THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_SEQUENCED_TASK_SOURCE_H_
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue.cc b/third_party/WebKit/Source/platform/scheduler/base/task_queue.cc
index 1569c4a..22b0330 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/task_queue.cc
+++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue.cc
@@ -250,12 +250,12 @@
   if (observer) {
     // Observer is guaranteed to outlive TaskQueue and TaskQueueImpl lifecycle
     // is controlled by |this|.
-    impl_->SetOnNextWakeUpChangedCallback(
-        base::Bind(&TaskQueue::Observer::OnQueueNextWakeUpChanged,
-                   base::Unretained(observer), base::Unretained(this)));
+    impl_->SetOnNextWakeUpChangedCallback(base::BindRepeating(
+        &TaskQueue::Observer::OnQueueNextWakeUpChanged,
+        base::Unretained(observer), base::Unretained(this)));
   } else {
     impl_->SetOnNextWakeUpChangedCallback(
-        base::Callback<void(base::TimeTicks)>());
+        base::RepeatingCallback<void(base::TimeTicks)>());
   }
 }
 
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue_impl.cc b/third_party/WebKit/Source/platform/scheduler/base/task_queue_impl.cc
index 4dce8ad5..bbc3b55c 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/task_queue_impl.cc
+++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue_impl.cc
@@ -280,8 +280,8 @@
   // TODO(altimin): Add a copy method to Task to capture metadata here.
   PushOntoImmediateIncomingQueueLocked(
       Task(TaskQueue::PostedTask(
-               base::Bind(&TaskQueueImpl::ScheduleDelayedWorkTask,
-                          base::Unretained(this), base::Passed(&pending_task)),
+               base::BindOnce(&TaskQueueImpl::ScheduleDelayedWorkTask,
+                              base::Unretained(this), std::move(pending_task)),
                FROM_HERE, base::TimeDelta(), base::Nestable::kNonNestable,
                pending_task.task_type()),
            base::TimeTicks(), thread_hop_task_sequence_number,
@@ -904,13 +904,13 @@
 
 void TaskQueueImpl::RequeueDeferredNonNestableTask(
     TaskQueueImpl::Task&& task,
-    Sequence::WorkType work_type) {
+    SequencedTaskSource::WorkType work_type) {
   DCHECK(task.nestable == base::Nestable::kNonNestable);
   // The re-queued tasks have to be pushed onto the front because we'd otherwise
   // violate the strict monotonically increasing enqueue order within the
   // WorkQueue.  We can't assign them a new enqueue order here because that will
   // not behave correctly with fences and things will break (e.g Idle TQ).
-  if (work_type == Sequence::WorkType::kDelayed) {
+  if (work_type == SequencedTaskSource::WorkType::kDelayed) {
     main_thread_only().delayed_work_queue->PushNonNestableTaskToFront(
         std::move(task));
   } else {
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue_impl.h b/third_party/WebKit/Source/platform/scheduler/base/task_queue_impl.h
index b666025..1df5ad6 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/task_queue_impl.h
+++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue_impl.h
@@ -21,7 +21,7 @@
 #include "platform/scheduler/base/enqueue_order.h"
 #include "platform/scheduler/base/graceful_queue_shutdown_helper.h"
 #include "platform/scheduler/base/intrusive_heap.h"
-#include "platform/scheduler/base/sequence.h"
+#include "platform/scheduler/base/sequenced_task_source.h"
 #include "platform/scheduler/base/task_queue.h"
 #include "platform/wtf/Deque.h"
 
@@ -144,7 +144,8 @@
     TaskQueue::PostedTask task;
   };
 
-  using OnNextWakeUpChangedCallback = base::Callback<void(base::TimeTicks)>;
+  using OnNextWakeUpChangedCallback =
+      base::RepeatingCallback<void(base::TimeTicks)>;
   using OnTaskStartedHandler =
       base::RepeatingCallback<void(const TaskQueue::Task&, base::TimeTicks)>;
   using OnTaskCompletedHandler =
@@ -245,7 +246,7 @@
   // Pushes |task| onto the front of the specified work queue. Caution must be
   // taken with this API because you could easily starve out other work.
   void RequeueDeferredNonNestableTask(TaskQueueImpl::Task&& task,
-                                      Sequence::WorkType work_type);
+                                      SequencedTaskSource::WorkType work_type);
 
   void PushImmediateIncomingTaskForTest(TaskQueueImpl::Task&& task);
   EnqueueOrder GetFenceForTest() const;
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_impl.cc b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_impl.cc
index cfcc01de..f313fe91 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_impl.cc
+++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_impl.cc
@@ -72,7 +72,7 @@
 
   RegisterTimeDomain(main_thread_only().real_time_domain.get());
 
-  controller_->SetSequence(this);
+  controller_->SetSequencedTaskSource(this);
   controller_->AddNestingObserver(this);
 }
 
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_impl.h b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_impl.h
index e1cb8c4..18b6903 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_impl.h
+++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_impl.h
@@ -22,7 +22,7 @@
 #include "platform/scheduler/base/enqueue_order.h"
 #include "platform/scheduler/base/graceful_queue_shutdown_helper.h"
 #include "platform/scheduler/base/moveable_auto_lock.h"
-#include "platform/scheduler/base/sequence.h"
+#include "platform/scheduler/base/sequenced_task_source.h"
 #include "platform/scheduler/base/task_queue_impl.h"
 #include "platform/scheduler/base/task_queue_manager.h"
 #include "platform/scheduler/base/task_queue_selector.h"
@@ -69,7 +69,7 @@
 //
 class PLATFORM_EXPORT TaskQueueManagerImpl
     : public TaskQueueManager,
-      public internal::Sequence,
+      public internal::SequencedTaskSource,
       public internal::TaskQueueSelector::Observer,
       public base::RunLoop::NestingObserver {
  public:
@@ -109,7 +109,7 @@
   size_t GetNumberOfPendingTasks() const override;
   bool HasImmediateWorkForTesting() const override;
 
-  // Implementation of Sequence:
+  // Implementation of SequencedTaskSource:
   base::Optional<base::PendingTask> TakeTask() override;
   void DidRunTask() override;
   base::TimeDelta DelayTillNextTask(LazyNow* lazy_now) override;
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_impl_unittest.cc b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_impl_unittest.cc
index 09a5985..5c33e0fb 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_impl_unittest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_impl_unittest.cc
@@ -1055,8 +1055,8 @@
                        std::vector<EnqueueOrder>* out_result) {
   out_result->push_back(countdown);
   if (--countdown) {
-    runner->PostTask(FROM_HERE,
-                     Bind(&ReentrantTestTask, runner, countdown, out_result));
+    runner->PostTask(
+        FROM_HERE, BindOnce(&ReentrantTestTask, runner, countdown, out_result));
   }
 }
 
@@ -1066,8 +1066,8 @@
   Initialize(1u);
 
   std::vector<EnqueueOrder> run_order;
-  runners_[0]->PostTask(FROM_HERE,
-                        Bind(&ReentrantTestTask, runners_[0], 3, &run_order));
+  runners_[0]->PostTask(
+      FROM_HERE, BindOnce(&ReentrantTestTask, runners_[0], 3, &run_order));
 
   test_task_runner_->RunUntilIdle();
   EXPECT_THAT(run_order, ElementsAre(3, 2, 1));
@@ -1110,8 +1110,9 @@
 void RePostingTestTask(scoped_refptr<base::SingleThreadTaskRunner> runner,
                        int* run_count) {
   (*run_count)++;
-  runner->PostTask(FROM_HERE, Bind(&RePostingTestTask,
-                                   base::Unretained(runner.get()), run_count));
+  runner->PostTask(
+      FROM_HERE,
+      BindOnce(&RePostingTestTask, base::Unretained(runner.get()), run_count));
 }
 
 TEST_F(TaskQueueManagerTest, DoWorkCantPostItselfMultipleTimes) {
@@ -3430,19 +3431,17 @@
   manager_.reset();
 
   thread->task_runner()->PostTask(
-      FROM_HERE,
-      base::BindOnce(
-          [](scoped_refptr<base::SingleThreadTaskRunner> task_queue,
-             std::unique_ptr<PostTaskInDestructor> test_object,
-             base::WaitableEvent* test_executed) {
-            task_queue->PostTask(
-                FROM_HERE,
-                base::BindOnce(&PostTaskInDestructor::Do,
-                               base::Passed(std::move(test_object))));
-            test_executed->Signal();
-          },
-          main_tq, std::make_unique<PostTaskInDestructor>(main_tq),
-          &test_executed));
+      FROM_HERE, base::BindOnce(
+                     [](scoped_refptr<base::SingleThreadTaskRunner> task_queue,
+                        std::unique_ptr<PostTaskInDestructor> test_object,
+                        base::WaitableEvent* test_executed) {
+                       task_queue->PostTask(
+                           FROM_HERE, base::BindOnce(&PostTaskInDestructor::Do,
+                                                     std::move(test_object)));
+                       test_executed->Signal();
+                     },
+                     main_tq, std::make_unique<PostTaskInDestructor>(main_tq),
+                     &test_executed));
   test_executed.Wait();
 }
 
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_perftest.cc b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_perftest.cc
index d04c510a5..0b6e09d 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_perftest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager_perftest.cc
@@ -126,8 +126,9 @@
       unsigned int delay =
           num_tasks_to_post_ % 2 ? 1 : (10 + num_tasks_to_post_ % 10);
       queues_[queue]->PostDelayedTask(
-          FROM_HERE, base::Bind(&TaskQueueManagerPerfTest::TestDelayedTask,
-                                base::Unretained(this)),
+          FROM_HERE,
+          base::BindOnce(&TaskQueueManagerPerfTest::TestDelayedTask,
+                         base::Unretained(this)),
           base::TimeDelta::FromMilliseconds(delay));
       num_tasks_in_flight_++;
       num_tasks_to_post_--;
@@ -141,7 +142,8 @@
     TestDelayedTask();
   }
 
-  void Benchmark(const std::string& trace, const base::Closure& test_task) {
+  void Benchmark(const std::string& trace,
+                 const base::RepeatingClosure& test_task) {
     base::ThreadTicks start = base::ThreadTicks::Now();
     base::ThreadTicks now;
     unsigned long long num_iterations = 0;
@@ -180,8 +182,9 @@
 
   max_tasks_in_flight_ = 200;
   Benchmark("run 10000 delayed tasks with one queue",
-            base::Bind(&TaskQueueManagerPerfTest::ResetAndCallTestDelayedTask,
-                       base::Unretained(this), 10000));
+            base::BindRepeating(
+                &TaskQueueManagerPerfTest::ResetAndCallTestDelayedTask,
+                base::Unretained(this), 10000));
 }
 
 TEST_F(TaskQueueManagerPerfTest, RunTenThousandDelayedTasks_FourQueues) {
@@ -191,8 +194,9 @@
 
   max_tasks_in_flight_ = 200;
   Benchmark("run 10000 delayed tasks with four queues",
-            base::Bind(&TaskQueueManagerPerfTest::ResetAndCallTestDelayedTask,
-                       base::Unretained(this), 10000));
+            base::BindRepeating(
+                &TaskQueueManagerPerfTest::ResetAndCallTestDelayedTask,
+                base::Unretained(this), 10000));
 }
 
 TEST_F(TaskQueueManagerPerfTest, RunTenThousandDelayedTasks_EightQueues) {
@@ -202,8 +206,9 @@
 
   max_tasks_in_flight_ = 200;
   Benchmark("run 10000 delayed tasks with eight queues",
-            base::Bind(&TaskQueueManagerPerfTest::ResetAndCallTestDelayedTask,
-                       base::Unretained(this), 10000));
+            base::BindRepeating(
+                &TaskQueueManagerPerfTest::ResetAndCallTestDelayedTask,
+                base::Unretained(this), 10000));
 }
 
 TEST_F(TaskQueueManagerPerfTest, RunTenThousandDelayedTasks_ThirtyTwoQueues) {
@@ -213,8 +218,9 @@
 
   max_tasks_in_flight_ = 200;
   Benchmark("run 10000 delayed tasks with eight queues",
-            base::Bind(&TaskQueueManagerPerfTest::ResetAndCallTestDelayedTask,
-                       base::Unretained(this), 10000));
+            base::BindRepeating(
+                &TaskQueueManagerPerfTest::ResetAndCallTestDelayedTask,
+                base::Unretained(this), 10000));
 }
 
 // TODO(alexclarke): Add additional tests with different mixes of non-delayed vs
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue_selector_unittest.cc b/third_party/WebKit/Source/platform/scheduler/base/task_queue_selector_unittest.cc
index da76bff..ac997c7 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/task_queue_selector_unittest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue_selector_unittest.cc
@@ -48,7 +48,8 @@
 class TaskQueueSelectorTest : public ::testing::Test {
  public:
   TaskQueueSelectorTest()
-      : test_closure_(base::Bind(&TaskQueueSelectorTest::TestFunction)) {}
+      : test_closure_(
+            base::BindRepeating(&TaskQueueSelectorTest::TestFunction)) {}
   ~TaskQueueSelectorTest() override = default;
 
   TaskQueueSelectorForTest::PrioritizingSelector* prioritizing_selector() {
@@ -133,7 +134,7 @@
   }
 
   const size_t kTaskQueueCount = 5;
-  base::Closure test_closure_;
+  base::RepeatingClosure test_closure_;
   TaskQueueSelectorForTest selector_;
   std::unique_ptr<VirtualTimeDomain> virtual_time_domain_;
   std::vector<std::unique_ptr<TaskQueueImpl>> task_queues_;
diff --git a/third_party/WebKit/Source/platform/scheduler/base/thread_controller.h b/third_party/WebKit/Source/platform/scheduler/base/thread_controller.h
index da3e1274..36a832fa 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/thread_controller.h
+++ b/third_party/WebKit/Source/platform/scheduler/base/thread_controller.h
@@ -20,7 +20,7 @@
 namespace scheduler {
 namespace internal {
 
-class Sequence;
+class SequencedTaskSource;
 
 // Interface for TaskQueueManager to schedule work to be run.
 class PLATFORM_EXPORT ThreadController {
@@ -63,9 +63,10 @@
   // |run_time| and previously scheduled callbacks should be cancelled.
   virtual void CancelDelayedWork(base::TimeTicks run_time) = 0;
 
-  // Sets the sequence from which to take tasks after a Schedule*Work() call is
-  // made. Must be called before the first call to Schedule*Work().
-  virtual void SetSequence(Sequence*) = 0;
+  // Sets the sequenced task source from which to take tasks after
+  // a Schedule*Work() call is made.
+  // Must be called before the first call to Schedule*Work().
+  virtual void SetSequencedTaskSource(SequencedTaskSource*) = 0;
 
   // TODO(altimin): Get rid of the methods below.
   // These methods exist due to current integration of TaskQueueManager
diff --git a/third_party/WebKit/Source/platform/scheduler/base/thread_controller_impl.cc b/third_party/WebKit/Source/platform/scheduler/base/thread_controller_impl.cc
index f92326d..a400478 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/thread_controller_impl.cc
+++ b/third_party/WebKit/Source/platform/scheduler/base/thread_controller_impl.cc
@@ -11,7 +11,6 @@
 #include "base/time/tick_clock.h"
 #include "base/trace_event/trace_event.h"
 #include "platform/scheduler/base/lazy_now.h"
-#include "platform/scheduler/base/sequence.h"
 
 namespace blink {
 namespace scheduler {
@@ -29,10 +28,10 @@
       weak_factory_(this) {
   immediate_do_work_closure_ = base::BindRepeating(
       &ThreadControllerImpl::DoWork, weak_factory_.GetWeakPtr(),
-      Sequence::WorkType::kImmediate);
-  delayed_do_work_closure_ = base::BindRepeating(&ThreadControllerImpl::DoWork,
-                                                 weak_factory_.GetWeakPtr(),
-                                                 Sequence::WorkType::kDelayed);
+      SequencedTaskSource::WorkType::kImmediate);
+  delayed_do_work_closure_ = base::BindRepeating(
+      &ThreadControllerImpl::DoWork, weak_factory_.GetWeakPtr(),
+      SequencedTaskSource::WorkType::kDelayed);
 }
 
 ThreadControllerImpl::~ThreadControllerImpl() = default;
@@ -44,7 +43,8 @@
       message_loop, message_loop->task_runner(), time_source));
 }
 
-void ThreadControllerImpl::SetSequence(Sequence* sequence) {
+void ThreadControllerImpl::SetSequencedTaskSource(
+    SequencedTaskSource* sequence) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(sequence);
   DCHECK(!sequence_);
@@ -138,13 +138,13 @@
   task_annotator_.DidQueueTask("TaskQueueManager::PostTask", pending_task);
 }
 
-void ThreadControllerImpl::DoWork(Sequence::WorkType work_type) {
+void ThreadControllerImpl::DoWork(SequencedTaskSource::WorkType work_type) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(sequence_);
 
   {
     base::AutoLock lock(any_sequence_lock_);
-    if (work_type == Sequence::WorkType::kImmediate)
+    if (work_type == SequencedTaskSource::WorkType::kImmediate)
       any_sequence().immediate_do_work_posted = false;
     any_sequence().do_work_running_count++;
   }
diff --git a/third_party/WebKit/Source/platform/scheduler/base/thread_controller_impl.h b/third_party/WebKit/Source/platform/scheduler/base/thread_controller_impl.h
index 69b776ee..1227ef3 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/thread_controller_impl.h
+++ b/third_party/WebKit/Source/platform/scheduler/base/thread_controller_impl.h
@@ -15,7 +15,7 @@
 #include "base/sequence_checker.h"
 #include "base/single_thread_task_runner.h"
 #include "platform/PlatformExport.h"
-#include "platform/scheduler/base/sequence.h"
+#include "platform/scheduler/base/sequenced_task_source.h"
 
 namespace base {
 class MessageLoop;
@@ -43,7 +43,7 @@
   void ScheduleDelayedWork(base::TimeTicks now,
                            base::TimeTicks run_timy) override;
   void CancelDelayedWork(base::TimeTicks run_time) override;
-  void SetSequence(Sequence* sequence) override;
+  void SetSequencedTaskSource(SequencedTaskSource* sequence) override;
   bool RunsTasksInCurrentSequence() override;
   base::TickClock* GetClock() override;
   void SetDefaultTaskRunner(
@@ -69,7 +69,7 @@
   base::RunLoop::NestingObserver* nesting_observer_ = nullptr;
 
  private:
-  void DoWork(Sequence::WorkType work_type);
+  void DoWork(SequencedTaskSource::WorkType work_type);
 
   struct AnySequence {
     AnySequence() = default;
@@ -117,7 +117,7 @@
   base::RepeatingClosure immediate_do_work_closure_;
   base::RepeatingClosure delayed_do_work_closure_;
   base::CancelableClosure cancelable_delayed_do_work_closure_;
-  Sequence* sequence_ = nullptr;  // NOT OWNED
+  SequencedTaskSource* sequence_ = nullptr;  // NOT OWNED
   base::debug::TaskAnnotator task_annotator_;
 
   base::WeakPtrFactory<ThreadControllerImpl> weak_factory_;
diff --git a/third_party/WebKit/Source/platform/scheduler/base/work_queue.h b/third_party/WebKit/Source/platform/scheduler/base/work_queue.h
index d8a9d998..d6bbf632 100644
--- a/third_party/WebKit/Source/platform/scheduler/base/work_queue.h
+++ b/third_party/WebKit/Source/platform/scheduler/base/work_queue.h
@@ -13,7 +13,7 @@
 #include "base/trace_event/trace_event_argument.h"
 #include "platform/scheduler/base/enqueue_order.h"
 #include "platform/scheduler/base/intrusive_heap.h"
-#include "platform/scheduler/base/sequence.h"
+#include "platform/scheduler/base/sequenced_task_source.h"
 #include "platform/scheduler/base/task_queue_impl.h"
 
 namespace blink {
@@ -33,7 +33,7 @@
 // throttling mechanisms.
 class PLATFORM_EXPORT WorkQueue {
  public:
-  using QueueType = Sequence::WorkType;
+  using QueueType = SequencedTaskSource::WorkType;
 
   // Note |task_queue| can be null if queue_type is kNonNestable.
   WorkQueue(TaskQueueImpl* task_queue, const char* name, QueueType queue_type);
diff --git a/third_party/WebKit/Source/platform/scheduler/child/idle_canceled_delayed_task_sweeper.cc b/third_party/WebKit/Source/platform/scheduler/child/idle_canceled_delayed_task_sweeper.cc
index 78aa610f..1114072b 100644
--- a/third_party/WebKit/Source/platform/scheduler/child/idle_canceled_delayed_task_sweeper.cc
+++ b/third_party/WebKit/Source/platform/scheduler/child/idle_canceled_delayed_task_sweeper.cc
@@ -25,8 +25,8 @@
 void IdleCanceledDelayedTaskSweeper::PostIdleTask() {
   idle_task_runner_->PostDelayedIdleTask(
       FROM_HERE, base::TimeDelta::FromSeconds(kDelayedTaskSweepIntervalSeconds),
-      base::Bind(&IdleCanceledDelayedTaskSweeper::SweepIdleTask,
-                 weak_factory_.GetWeakPtr()));
+      base::BindOnce(&IdleCanceledDelayedTaskSweeper::SweepIdleTask,
+                     weak_factory_.GetWeakPtr()));
 }
 
 void IdleCanceledDelayedTaskSweeper::SweepIdleTask(base::TimeTicks deadline) {
diff --git a/third_party/WebKit/Source/platform/scheduler/child/idle_canceled_delayed_task_sweeper_unittest.cc b/third_party/WebKit/Source/platform/scheduler/child/idle_canceled_delayed_task_sweeper_unittest.cc
index dbb826c..50852a48 100644
--- a/third_party/WebKit/Source/platform/scheduler/child/idle_canceled_delayed_task_sweeper_unittest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/child/idle_canceled_delayed_task_sweeper_unittest.cc
@@ -90,28 +90,28 @@
   // Post one task we won't cancel.
   default_task_queue_->PostDelayedTask(
       FROM_HERE,
-      base::Bind(&TestClass::NopTask, class1.weak_factory_.GetWeakPtr()),
+      base::BindOnce(&TestClass::NopTask, class1.weak_factory_.GetWeakPtr()),
       base::TimeDelta::FromSeconds(100));
 
   // And a bunch we will.
   default_task_queue_->PostDelayedTask(
       FROM_HERE,
-      base::Bind(&TestClass::NopTask, class2.weak_factory_.GetWeakPtr()),
+      base::BindOnce(&TestClass::NopTask, class2.weak_factory_.GetWeakPtr()),
       base::TimeDelta::FromSeconds(101));
 
   default_task_queue_->PostDelayedTask(
       FROM_HERE,
-      base::Bind(&TestClass::NopTask, class2.weak_factory_.GetWeakPtr()),
+      base::BindOnce(&TestClass::NopTask, class2.weak_factory_.GetWeakPtr()),
       base::TimeDelta::FromSeconds(102));
 
   default_task_queue_->PostDelayedTask(
       FROM_HERE,
-      base::Bind(&TestClass::NopTask, class2.weak_factory_.GetWeakPtr()),
+      base::BindOnce(&TestClass::NopTask, class2.weak_factory_.GetWeakPtr()),
       base::TimeDelta::FromSeconds(103));
 
   default_task_queue_->PostDelayedTask(
       FROM_HERE,
-      base::Bind(&TestClass::NopTask, class2.weak_factory_.GetWeakPtr()),
+      base::BindOnce(&TestClass::NopTask, class2.weak_factory_.GetWeakPtr()),
       base::TimeDelta::FromSeconds(104));
 
   // Cancel the last four tasks.
diff --git a/third_party/WebKit/Source/platform/scheduler/child/idle_helper.cc b/third_party/WebKit/Source/platform/scheduler/child/idle_helper.cc
index d095066..3c5a19b 100644
--- a/third_party/WebKit/Source/platform/scheduler/child/idle_helper.cc
+++ b/third_party/WebKit/Source/platform/scheduler/child/idle_helper.cc
@@ -30,9 +30,9 @@
       is_shutdown_(false),
       weak_factory_(this) {
   weak_idle_helper_ptr_ = weak_factory_.GetWeakPtr();
-  enable_next_long_idle_period_closure_.Reset(
-      base::Bind(&IdleHelper::EnableLongIdlePeriod, weak_idle_helper_ptr_));
-  on_idle_task_posted_closure_.Reset(base::Bind(
+  enable_next_long_idle_period_closure_.Reset(base::BindRepeating(
+      &IdleHelper::EnableLongIdlePeriod, weak_idle_helper_ptr_));
+  on_idle_task_posted_closure_.Reset(base::BindRepeating(
       &IdleHelper::OnIdleTaskPostedOnMainThread, weak_idle_helper_ptr_));
 
   idle_task_runner_ =
diff --git a/third_party/WebKit/Source/platform/scheduler/child/idle_helper_unittest.cc b/third_party/WebKit/Source/platform/scheduler/child/idle_helper_unittest.cc
index 99e5d289..1d4535f 100644
--- a/third_party/WebKit/Source/platform/scheduler/child/idle_helper_unittest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/child/idle_helper_unittest.cc
@@ -56,10 +56,10 @@
                                  int max_reentrant_count) {
   vector->push_back((*reentrant_count)++);
   if (*reentrant_count < max_reentrant_count) {
-    task_runner->PostTask(
-        FROM_HERE,
-        base::Bind(AppendToVectorReentrantTask, base::Unretained(task_runner),
-                   vector, reentrant_count, max_reentrant_count));
+    task_runner->PostTask(FROM_HERE,
+                          base::BindOnce(AppendToVectorReentrantTask,
+                                         base::Unretained(task_runner), vector,
+                                         reentrant_count, max_reentrant_count));
   }
 }
 
@@ -78,9 +78,9 @@
                            base::TimeTicks deadline) {
   if ((*run_count + 1) < g_max_idle_task_reposts) {
     idle_task_runner->PostIdleTask(
-        FROM_HERE,
-        base::Bind(&RepostingIdleTestTask, base::Unretained(idle_task_runner),
-                   run_count, deadline_out));
+        FROM_HERE, base::BindOnce(&RepostingIdleTestTask,
+                                  base::Unretained(idle_task_runner), run_count,
+                                  deadline_out));
   }
   *deadline_out = deadline;
   (*run_count)++;
@@ -95,9 +95,9 @@
     base::TimeTicks deadline) {
   if ((*run_count + 1) < g_max_idle_task_reposts) {
     idle_task_runner->PostIdleTask(
-        FROM_HERE, base::Bind(&RepostingUpdateClockIdleTestTask,
-                              base::Unretained(idle_task_runner), run_count,
-                              clock, advance_time, deadlines));
+        FROM_HERE, base::BindOnce(&RepostingUpdateClockIdleTestTask,
+                                  base::Unretained(idle_task_runner), run_count,
+                                  clock, advance_time, deadlines));
   }
   deadlines->push_back(deadline);
   (*run_count)++;
@@ -109,8 +109,9 @@
                    base::TimeDelta delay) {
   if (num_repeats > 1) {
     task_runner->PostDelayedTask(
-        FROM_HERE, base::Bind(&RepeatingTask, base::Unretained(task_runner),
-                              num_repeats - 1, delay),
+        FROM_HERE,
+        base::BindOnce(&RepeatingTask, base::Unretained(task_runner),
+                       num_repeats - 1, delay),
         delay);
   }
 }
@@ -332,7 +333,7 @@
 
   clock_.Advance(base::TimeDelta::FromMilliseconds(100));
   idle_task_runner_->PostIdleTask(
-      FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task));
+      FROM_HERE, base::BindOnce(&IdleTestTask, &run_count, &deadline_in_task));
 
   RunUntilIdle();
   EXPECT_EQ(0, run_count);
@@ -350,7 +351,7 @@
 
   clock_.Advance(base::TimeDelta::FromMilliseconds(100));
   idle_task_runner_->PostIdleTask(
-      FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task));
+      FROM_HERE, base::BindOnce(&IdleTestTask, &run_count, &deadline_in_task));
 
   RunUntilIdle();
   EXPECT_EQ(0, run_count);
@@ -369,9 +370,9 @@
 
   g_max_idle_task_reposts = 2;
   idle_task_runner_->PostIdleTask(
-      FROM_HERE,
-      base::Bind(&RepostingIdleTestTask, base::RetainedRef(idle_task_runner_),
-                 &run_count, &actual_deadline));
+      FROM_HERE, base::BindOnce(&RepostingIdleTestTask,
+                                base::RetainedRef(idle_task_runner_),
+                                &run_count, &actual_deadline));
   idle_helper_->StartIdlePeriod(
       IdleHelper::IdlePeriodState::kInShortIdlePeriod, clock_.NowTicks(),
       clock_.NowTicks() + base::TimeDelta::FromMilliseconds(10));
@@ -395,10 +396,10 @@
   // Post two UpdateClockToDeadlineIdleTestTask tasks.
   idle_task_runner_->PostIdleTask(
       FROM_HERE,
-      base::Bind(&UpdateClockToDeadlineIdleTestTask, &clock_, &run_count));
+      base::BindOnce(&UpdateClockToDeadlineIdleTestTask, &clock_, &run_count));
   idle_task_runner_->PostIdleTask(
       FROM_HERE,
-      base::Bind(&UpdateClockToDeadlineIdleTestTask, &clock_, &run_count));
+      base::BindOnce(&UpdateClockToDeadlineIdleTestTask, &clock_, &run_count));
 
   idle_helper_->StartIdlePeriod(
       IdleHelper::IdlePeriodState::kInShortIdlePeriod, clock_.NowTicks(),
@@ -509,26 +510,28 @@
   std::vector<std::string> order;
   idle_task_runner_->PostIdleTask(
       FROM_HERE,
-      base::Bind(&AppendToVectorIdleTestTask, &order, std::string("1")));
+      base::BindOnce(&AppendToVectorIdleTestTask, &order, std::string("1")));
   idle_task_runner_->PostIdleTask(
       FROM_HERE,
-      base::Bind(&AppendToVectorIdleTestTask, &order, std::string("2")));
+      base::BindOnce(&AppendToVectorIdleTestTask, &order, std::string("2")));
 
   std::vector<std::pair<SingleThreadIdleTaskRunner::IdleTask, bool>>
       tasks_to_post_from_nested_loop;
   tasks_to_post_from_nested_loop.push_back(std::make_pair(
-      base::Bind(&AppendToVectorIdleTestTask, &order, std::string("3")),
+      base::BindOnce(&AppendToVectorIdleTestTask, &order, std::string("3")),
       false));
   tasks_to_post_from_nested_loop.push_back(std::make_pair(
-      base::Bind(&AppendToVectorIdleTestTask, &order, std::string("4")), true));
+      base::BindOnce(&AppendToVectorIdleTestTask, &order, std::string("4")),
+      true));
   tasks_to_post_from_nested_loop.push_back(std::make_pair(
-      base::Bind(&AppendToVectorIdleTestTask, &order, std::string("5")), true));
+      base::BindOnce(&AppendToVectorIdleTestTask, &order, std::string("5")),
+      true));
 
   default_task_runner_->PostTask(
       FROM_HERE,
-      base::Bind(&IdleHelperWithMessageLoopTest::PostFromNestedRunloop,
-                 base::Unretained(this),
-                 base::Unretained(&tasks_to_post_from_nested_loop)));
+      base::BindOnce(&IdleHelperWithMessageLoopTest::PostFromNestedRunloop,
+                     base::Unretained(this),
+                     base::Unretained(&tasks_to_post_from_nested_loop)));
 
   idle_helper_->StartIdlePeriod(
       IdleHelper::IdlePeriodState::kInShortIdlePeriod, clock_.NowTicks(),
@@ -547,7 +550,7 @@
   int run_count = 0;
 
   idle_task_runner_->PostIdleTask(
-      FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task));
+      FROM_HERE, base::BindOnce(&IdleTestTask, &run_count, &deadline_in_task));
 
   EXPECT_CALL(*idle_helper_, CanEnterLongIdlePeriod(_, _))
       .Times(1)
@@ -570,8 +573,8 @@
   int run_count = 0;
 
   idle_task_runner_->PostIdleTask(
-      FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task));
-  default_task_runner_->PostDelayedTask(FROM_HERE, base::Bind(&NullTask),
+      FROM_HERE, base::BindOnce(&IdleTestTask, &run_count, &deadline_in_task));
+  default_task_runner_->PostDelayedTask(FROM_HERE, base::BindOnce(&NullTask),
                                         pending_task_delay);
 
   idle_helper_->EnableLongIdlePeriod();
@@ -585,7 +588,7 @@
   base::TimeTicks deadline_in_task;
   int run_count = 0;
 
-  default_task_runner_->PostDelayedTask(FROM_HERE, base::Bind(&NullTask),
+  default_task_runner_->PostDelayedTask(FROM_HERE, base::BindOnce(&NullTask),
                                         pending_task_delay);
 
   // Advance clock until after delayed task was meant to be run.
@@ -594,7 +597,7 @@
   // Post an idle task and then EnableLongIdlePeriod. Since there is a late
   // pending delayed task this shouldn't actually start an idle period.
   idle_task_runner_->PostIdleTask(
-      FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task));
+      FROM_HERE, base::BindOnce(&IdleTestTask, &run_count, &deadline_in_task));
   idle_helper_->EnableLongIdlePeriod();
   RunUntilIdle();
   EXPECT_EQ(0, run_count);
@@ -619,9 +622,10 @@
   base::TimeTicks clock_before(clock_.NowTicks());
   base::TimeDelta idle_task_runtime(base::TimeDelta::FromMilliseconds(10));
   idle_task_runner_->PostIdleTask(
-      FROM_HERE, base::Bind(&RepostingUpdateClockIdleTestTask,
-                            base::RetainedRef(idle_task_runner_), &run_count,
-                            &clock_, idle_task_runtime, &actual_deadlines));
+      FROM_HERE,
+      base::BindOnce(&RepostingUpdateClockIdleTestTask,
+                     base::RetainedRef(idle_task_runner_), &run_count, &clock_,
+                     idle_task_runtime, &actual_deadlines));
 
   // Check each idle task runs in their own idle period.
   idle_helper_->EnableLongIdlePeriod();
@@ -635,12 +639,13 @@
 
   g_max_idle_task_reposts = 5;
   idle_task_runner_->PostIdleTask(
-      FROM_HERE, base::Bind(&RepostingUpdateClockIdleTestTask,
-                            base::RetainedRef(idle_task_runner_), &run_count,
-                            &clock_, idle_task_runtime, &actual_deadlines));
-  idle_task_runner_->PostIdleTask(
       FROM_HERE,
-      base::Bind(&EndIdlePeriodIdleTask, base::Unretained(idle_helper_.get())));
+      base::BindOnce(&RepostingUpdateClockIdleTestTask,
+                     base::RetainedRef(idle_task_runner_), &run_count, &clock_,
+                     idle_task_runtime, &actual_deadlines));
+  idle_task_runner_->PostIdleTask(
+      FROM_HERE, base::BindOnce(&EndIdlePeriodIdleTask,
+                                base::Unretained(idle_helper_.get())));
 
   // Ensure that reposting tasks stop after EndIdlePeriod is called.
   RunUntilIdle();
@@ -670,7 +675,7 @@
   EXPECT_CALL(*idle_helper_, OnIdlePeriodStarted()).Times(AnyNumber());
 
   idle_task_runner_->PostIdleTask(
-      FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task));
+      FROM_HERE, base::BindOnce(&IdleTestTask, &run_count, &deadline_in_task));
 
   // Make sure Idle tasks don't run until the delay has occurred.
   idle_helper_->EnableLongIdlePeriod();
@@ -701,9 +706,10 @@
   // they have max deadlines.
   g_max_idle_task_reposts = 2;
   idle_task_runner_->PostIdleTask(
-      FROM_HERE, base::Bind(&RepostingUpdateClockIdleTestTask,
-                            base::RetainedRef(idle_task_runner_), &run_count,
-                            &clock_, idle_task_runtime, &actual_deadlines));
+      FROM_HERE,
+      base::BindOnce(&RepostingUpdateClockIdleTestTask,
+                     base::RetainedRef(idle_task_runner_), &run_count, &clock_,
+                     idle_task_runtime, &actual_deadlines));
 
   idle_helper_->EnableLongIdlePeriod();
   RunUntilIdle();
@@ -725,14 +731,14 @@
                                     retry_enable_long_idle_period_delay());
 
   // Post delayed task to ensure idle period doesn't have a max deadline.
-  default_task_runner_->PostDelayedTask(FROM_HERE, base::Bind(&NullTask),
+  default_task_runner_->PostDelayedTask(FROM_HERE, base::BindOnce(&NullTask),
                                         pending_task_delay);
 
   g_max_idle_task_reposts = 2;
   idle_task_runner_->PostIdleTask(
-      FROM_HERE,
-      base::Bind(&RepostingIdleTestTask, base::RetainedRef(idle_task_runner_),
-                 &run_count, &actual_deadline));
+      FROM_HERE, base::BindOnce(&RepostingIdleTestTask,
+                                base::RetainedRef(idle_task_runner_),
+                                &run_count, &actual_deadline));
   idle_helper_->EnableLongIdlePeriod();
   RunUntilIdle();
   EXPECT_EQ(1, run_count);
@@ -772,9 +778,10 @@
   base::TimeTicks clock_before(clock_.NowTicks());
   base::TimeDelta idle_task_runtime(base::TimeDelta::FromMilliseconds(10));
   idle_task_runner_->PostIdleTask(
-      FROM_HERE, base::Bind(&RepostingUpdateClockIdleTestTask,
-                            base::RetainedRef(idle_task_runner_), &run_count,
-                            &clock_, idle_task_runtime, &actual_deadlines));
+      FROM_HERE,
+      base::BindOnce(&RepostingUpdateClockIdleTestTask,
+                     base::RetainedRef(idle_task_runner_), &run_count, &clock_,
+                     idle_task_runtime, &actual_deadlines));
   RunUntilIdle();
   EXPECT_EQ(2, run_count);
   EXPECT_THAT(actual_deadlines,
@@ -796,7 +803,7 @@
   int run_count = 0;
 
   idle_task_runner_->PostIdleTask(
-      FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task));
+      FROM_HERE, base::BindOnce(&IdleTestTask, &run_count, &deadline_in_task));
   idle_helper_->Shutdown();
 
   // We shouldn't be able to enter a long idle period when shutdown
@@ -824,9 +831,9 @@
 
   // Should return false for short idle periods.
   idle_task_runner_->PostIdleTask(
-      FROM_HERE,
-      base::Bind(&TestCanExceedIdleDeadlineIfRequiredTask, idle_helper_.get(),
-                 &can_exceed_idle_deadline, &run_count));
+      FROM_HERE, base::BindOnce(&TestCanExceedIdleDeadlineIfRequiredTask,
+                                idle_helper_.get(), &can_exceed_idle_deadline,
+                                &run_count));
   idle_helper_->StartIdlePeriod(
       IdleHelper::IdlePeriodState::kInShortIdlePeriod, clock_.NowTicks(),
       clock_.NowTicks() + base::TimeDelta::FromMilliseconds(10));
@@ -836,12 +843,12 @@
 
   // Should return false for a long idle period which is shortened due to a
   // pending delayed task.
-  default_task_runner_->PostDelayedTask(FROM_HERE, base::Bind(&NullTask),
+  default_task_runner_->PostDelayedTask(FROM_HERE, base::BindOnce(&NullTask),
                                         base::TimeDelta::FromMilliseconds(10));
   idle_task_runner_->PostIdleTask(
-      FROM_HERE,
-      base::Bind(&TestCanExceedIdleDeadlineIfRequiredTask, idle_helper_.get(),
-                 &can_exceed_idle_deadline, &run_count));
+      FROM_HERE, base::BindOnce(&TestCanExceedIdleDeadlineIfRequiredTask,
+                                idle_helper_.get(), &can_exceed_idle_deadline,
+                                &run_count));
   idle_helper_->EnableLongIdlePeriod();
   RunUntilIdle();
   EXPECT_EQ(2, run_count);
@@ -851,9 +858,9 @@
   // CanExceedIdleDeadlineIfRequired should return true.
   clock_.Advance(maximum_idle_period_duration());
   idle_task_runner_->PostIdleTask(
-      FROM_HERE,
-      base::Bind(&TestCanExceedIdleDeadlineIfRequiredTask, idle_helper_.get(),
-                 &can_exceed_idle_deadline, &run_count));
+      FROM_HERE, base::BindOnce(&TestCanExceedIdleDeadlineIfRequiredTask,
+                                idle_helper_.get(), &can_exceed_idle_deadline,
+                                &run_count));
   RunUntilIdle();
   EXPECT_EQ(3, run_count);
   EXPECT_TRUE(can_exceed_idle_deadline);
@@ -884,7 +891,7 @@
 
   void MakeNonQuiescent() {
     // Run an arbitrary task so we're deemed to be not quiescent.
-    default_task_runner_->PostTask(FROM_HERE, base::Bind(NullTask));
+    default_task_runner_->PostTask(FROM_HERE, base::BindOnce(NullTask));
     RunUntilIdle();
   }
 
@@ -916,9 +923,9 @@
   int run_count = 0;
   g_max_idle_task_reposts = 1;
   idle_task_runner_->PostIdleTask(
-      FROM_HERE,
-      base::Bind(&RepostingIdleTestTask, base::RetainedRef(idle_task_runner_),
-                 &run_count, &actual_deadline));
+      FROM_HERE, base::BindOnce(&RepostingIdleTestTask,
+                                base::RetainedRef(idle_task_runner_),
+                                &run_count, &actual_deadline));
 
   idle_helper_->EnableLongIdlePeriod();
   RunUntilIdle();
@@ -938,9 +945,9 @@
   int run_count = 0;
   g_max_idle_task_reposts = 1;
   idle_task_runner_->PostIdleTask(
-      FROM_HERE,
-      base::Bind(&RepostingIdleTestTask, base::RetainedRef(idle_task_runner_),
-                 &run_count, &actual_deadline));
+      FROM_HERE, base::BindOnce(&RepostingIdleTestTask,
+                                base::RetainedRef(idle_task_runner_),
+                                &run_count, &actual_deadline));
 
   idle_helper_->EnableLongIdlePeriod();
   RunUntilIdle();
@@ -957,9 +964,9 @@
 
   // Run a repeating task so we're deemed to be busy for the next 400ms.
   default_task_runner_->PostTask(
-      FROM_HERE,
-      base::Bind(&RepeatingTask, base::Unretained(default_task_runner_.get()),
-                 10, base::TimeDelta::FromMilliseconds(40)));
+      FROM_HERE, base::BindOnce(&RepeatingTask,
+                                base::Unretained(default_task_runner_.get()),
+                                10, base::TimeDelta::FromMilliseconds(40)));
 
   int run_count = 0;
   // In this scenario EnableLongIdlePeriod deems us not to be quiescent 5x in
@@ -969,7 +976,7 @@
                               5 * kQuiescenceDelayMs + kLongIdlePeriodMs);
   base::TimeTicks deadline_in_task;
   idle_task_runner_->PostIdleTask(
-      FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task));
+      FROM_HERE, base::BindOnce(&IdleTestTask, &run_count, &deadline_in_task));
 
   idle_helper_->EnableLongIdlePeriod();
   RunUntilIdle();
@@ -981,12 +988,12 @@
        QuescienceCheckedForAfterLongIdlePeriodEnds) {
   mock_task_runner_->SetAutoAdvanceNowToPendingTasks(true);
 
-  idle_task_runner_->PostIdleTask(FROM_HERE, base::Bind(&NullIdleTask));
+  idle_task_runner_->PostIdleTask(FROM_HERE, base::BindOnce(&NullIdleTask));
   idle_helper_->EnableLongIdlePeriod();
   RunUntilIdle();
 
   // Post a normal task to make the scheduler non-quiescent.
-  default_task_runner_->PostTask(FROM_HERE, base::Bind(&NullTask));
+  default_task_runner_->PostTask(FROM_HERE, base::BindOnce(&NullTask));
   RunUntilIdle();
 
   // Post an idle task. The idle task won't run initially because the system is
@@ -997,7 +1004,7 @@
       clock_.NowTicks() +
       base::TimeDelta::FromMilliseconds(kQuiescenceDelayMs + kLongIdlePeriodMs);
   idle_task_runner_->PostIdleTask(
-      FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task));
+      FROM_HERE, base::BindOnce(&IdleTestTask, &run_count, &deadline_in_task));
   idle_helper_->EnableLongIdlePeriod();
   RunUntilIdle();
 
@@ -1010,7 +1017,7 @@
   base::TimeTicks deadline_in_task;
 
   idle_task_runner_->PostIdleTask(
-      FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task));
+      FROM_HERE, base::BindOnce(&IdleTestTask, &run_count, &deadline_in_task));
 
   base::TimeDelta half_a_ms(base::TimeDelta::FromMicroseconds(50));
   base::TimeTicks less_than_min_deadline(
@@ -1040,8 +1047,8 @@
       minimum_idle_period_duration() + half_a_ms);
 
   idle_task_runner_->PostIdleTask(
-      FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task));
-  default_task_runner_->PostDelayedTask(FROM_HERE, base::Bind(&NullTask),
+      FROM_HERE, base::BindOnce(&IdleTestTask, &run_count, &deadline_in_task));
+  default_task_runner_->PostDelayedTask(FROM_HERE, base::BindOnce(&NullTask),
                                         less_than_min_deadline_duration);
 
   idle_helper_->EnableLongIdlePeriod();
@@ -1053,7 +1060,7 @@
   RunUntilIdle();
   EXPECT_EQ(0, run_count);
 
-  default_task_runner_->PostDelayedTask(FROM_HERE, base::Bind(&NullTask),
+  default_task_runner_->PostDelayedTask(FROM_HERE, base::BindOnce(&NullTask),
                                         more_than_min_deadline_duration);
   idle_helper_->EnableLongIdlePeriod();
   RunUntilIdle();
@@ -1069,10 +1076,10 @@
   base::TimeTicks deadline_in_task;
   idle_task_runner_->PostIdleTask(
       FROM_HERE,
-      base::Bind(&ShutdownIdleTask, base::Unretained(idle_helper_.get()),
-                 &shutdown_task_run));
+      base::BindOnce(&ShutdownIdleTask, base::Unretained(idle_helper_.get()),
+                     &shutdown_task_run));
   idle_task_runner_->PostIdleTask(
-      FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task));
+      FROM_HERE, base::BindOnce(&IdleTestTask, &run_count, &deadline_in_task));
 
   // Delayed call to IdleHelper::EnableLongIdlePeriod enables idle tasks.
   idle_helper_->EnableLongIdlePeriod();
@@ -1098,7 +1105,7 @@
   // task queue until the delay is up.
   idle_task_runner_->PostDelayedIdleTask(
       FROM_HERE, base::TimeDelta::FromMilliseconds(200),
-      base::Bind(&IdleTestTask, &run_count, &deadline_in_task));
+      base::BindOnce(&IdleTestTask, &run_count, &deadline_in_task));
   EXPECT_EQ(0u, idle_queue()->GetNumberOfPendingTasks());
 
   clock_.Advance(base::TimeDelta::FromMilliseconds(100));
@@ -1138,7 +1145,7 @@
 
   clock_.Advance(base::TimeDelta::FromMilliseconds(100));
   idle_task_runner_->PostIdleTask(
-      FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task));
+      FROM_HERE, base::BindOnce(&IdleTestTask, &run_count, &deadline_in_task));
 
   RunUntilIdle();
   EXPECT_EQ(0, run_count);
@@ -1169,9 +1176,9 @@
 
   clock_.Advance(base::TimeDelta::FromMilliseconds(100));
   idle_task_runner_->PostIdleTask(
-      FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task));
+      FROM_HERE, base::BindOnce(&IdleTestTask, &run_count, &deadline_in_task));
   idle_task_runner_->PostIdleTask(
-      FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task));
+      FROM_HERE, base::BindOnce(&IdleTestTask, &run_count, &deadline_in_task));
 
   RunUntilIdle();
   EXPECT_EQ(0, run_count);
diff --git a/third_party/WebKit/Source/platform/scheduler/child/scheduler_helper_unittest.cc b/third_party/WebKit/Source/platform/scheduler/child/scheduler_helper_unittest.cc
index afa91c0..e7916837 100644
--- a/third_party/WebKit/Source/platform/scheduler/child/scheduler_helper_unittest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/child/scheduler_helper_unittest.cc
@@ -39,10 +39,10 @@
                                  int max_reentrant_count) {
   vector->push_back((*reentrant_count)++);
   if (*reentrant_count < max_reentrant_count) {
-    task_runner->PostTask(
-        FROM_HERE,
-        base::Bind(AppendToVectorReentrantTask, base::Unretained(task_runner),
-                   vector, reentrant_count, max_reentrant_count));
+    task_runner->PostTask(FROM_HERE,
+                          base::BindOnce(AppendToVectorReentrantTask,
+                                         base::Unretained(task_runner), vector,
+                                         reentrant_count, max_reentrant_count));
   }
 }
 
@@ -93,13 +93,13 @@
 TEST_F(SchedulerHelperTest, TestPostDefaultTask) {
   std::vector<std::string> run_order;
   default_task_runner_->PostTask(
-      FROM_HERE, base::Bind(&AppendToVectorTestTask, &run_order, "D1"));
+      FROM_HERE, base::BindOnce(&AppendToVectorTestTask, &run_order, "D1"));
   default_task_runner_->PostTask(
-      FROM_HERE, base::Bind(&AppendToVectorTestTask, &run_order, "D2"));
+      FROM_HERE, base::BindOnce(&AppendToVectorTestTask, &run_order, "D2"));
   default_task_runner_->PostTask(
-      FROM_HERE, base::Bind(&AppendToVectorTestTask, &run_order, "D3"));
+      FROM_HERE, base::BindOnce(&AppendToVectorTestTask, &run_order, "D3"));
   default_task_runner_->PostTask(
-      FROM_HERE, base::Bind(&AppendToVectorTestTask, &run_order, "D4"));
+      FROM_HERE, base::BindOnce(&AppendToVectorTestTask, &run_order, "D4"));
 
   RunUntilIdle();
   EXPECT_THAT(run_order,
@@ -111,9 +111,9 @@
   int count = 0;
   std::vector<int> run_order;
   default_task_runner_->PostTask(
-      FROM_HERE, base::Bind(AppendToVectorReentrantTask,
-                            base::RetainedRef(default_task_runner_), &run_order,
-                            &count, 5));
+      FROM_HERE, base::BindOnce(AppendToVectorReentrantTask,
+                                base::RetainedRef(default_task_runner_),
+                                &run_order, &count, 5));
   RunUntilIdle();
 
   EXPECT_THAT(run_order, ::testing::ElementsAre(0, 1, 2, 3, 4));
@@ -129,11 +129,11 @@
 TEST_F(SchedulerHelperTest, GetNumberOfPendingTasks) {
   std::vector<std::string> run_order;
   scheduler_helper_->DefaultWorkerTaskQueue()->PostTask(
-      FROM_HERE, base::Bind(&AppendToVectorTestTask, &run_order, "D1"));
+      FROM_HERE, base::BindOnce(&AppendToVectorTestTask, &run_order, "D1"));
   scheduler_helper_->DefaultWorkerTaskQueue()->PostTask(
-      FROM_HERE, base::Bind(&AppendToVectorTestTask, &run_order, "D2"));
+      FROM_HERE, base::BindOnce(&AppendToVectorTestTask, &run_order, "D2"));
   scheduler_helper_->ControlWorkerTaskQueue()->PostTask(
-      FROM_HERE, base::Bind(&AppendToVectorTestTask, &run_order, "C1"));
+      FROM_HERE, base::BindOnce(&AppendToVectorTestTask, &run_order, "C1"));
   EXPECT_EQ(3U, scheduler_helper_->GetNumberOfPendingTasks());
   RunUntilIdle();
   EXPECT_EQ(0U, scheduler_helper_->GetNumberOfPendingTasks());
@@ -153,8 +153,8 @@
   MockTaskObserver observer;
   scheduler_helper_->AddTaskObserver(&observer);
 
-  scheduler_helper_->DefaultWorkerTaskQueue()->PostTask(FROM_HERE,
-                                                        base::Bind(&NopTask));
+  scheduler_helper_->DefaultWorkerTaskQueue()->PostTask(
+      FROM_HERE, base::BindOnce(&NopTask));
 
   EXPECT_CALL(observer, WillProcessTask(_)).Times(1);
   EXPECT_CALL(observer, DidProcessTask(_)).Times(1);
@@ -165,8 +165,8 @@
   MockTaskObserver observer;
   scheduler_helper_->AddTaskObserver(&observer);
 
-  scheduler_helper_->ControlWorkerTaskQueue()->PostTask(FROM_HERE,
-                                                        base::Bind(&NopTask));
+  scheduler_helper_->ControlWorkerTaskQueue()->PostTask(
+      FROM_HERE, base::BindOnce(&NopTask));
 
   EXPECT_CALL(observer, WillProcessTask(_)).Times(0);
   EXPECT_CALL(observer, DidProcessTask(_)).Times(0);
diff --git a/third_party/WebKit/Source/platform/scheduler/child/webthread_impl_for_worker_scheduler.cc b/third_party/WebKit/Source/platform/scheduler/child/webthread_impl_for_worker_scheduler.cc
index 71d2ffa..808b2b5 100644
--- a/third_party/WebKit/Source/platform/scheduler/child/webthread_impl_for_worker_scheduler.cc
+++ b/third_party/WebKit/Source/platform/scheduler/child/webthread_impl_for_worker_scheduler.cc
@@ -35,8 +35,8 @@
       base::WaitableEvent::ResetPolicy::AUTOMATIC,
       base::WaitableEvent::InitialState::NOT_SIGNALED);
   thread_task_runner_->PostTask(
-      FROM_HERE, base::Bind(&WebThreadImplForWorkerScheduler::InitOnThread,
-                            base::Unretained(this), &completion));
+      FROM_HERE, base::BindOnce(&WebThreadImplForWorkerScheduler::InitOnThread,
+                                base::Unretained(this), &completion));
   completion.Wait();
 }
 
@@ -49,8 +49,8 @@
         base::WaitableEvent::InitialState::NOT_SIGNALED);
     thread_task_runner_->PostTask(
         FROM_HERE,
-        base::Bind(&WebThreadImplForWorkerScheduler::ShutdownOnThread,
-                   base::Unretained(this), &completion));
+        base::BindOnce(&WebThreadImplForWorkerScheduler::ShutdownOnThread,
+                       base::Unretained(this), &completion));
     completion.Wait();
   }
   thread_->Stop();
diff --git a/third_party/WebKit/Source/platform/scheduler/child/webthread_impl_for_worker_scheduler_unittest.cc b/third_party/WebKit/Source/platform/scheduler/child/webthread_impl_for_worker_scheduler_unittest.cc
index 47c51e9..30b3927d8 100644
--- a/third_party/WebKit/Source/platform/scheduler/child/webthread_impl_for_worker_scheduler_unittest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/child/webthread_impl_for_worker_scheduler_unittest.cc
@@ -79,21 +79,22 @@
   }
 
   void RunOnWorkerThread(const base::Location& from_here,
-                         const base::Closure& task) {
+                         base::OnceClosure task) {
     base::WaitableEvent completion(
         base::WaitableEvent::ResetPolicy::AUTOMATIC,
         base::WaitableEvent::InitialState::NOT_SIGNALED);
     thread_->GetTaskRunner()->PostTask(
         from_here,
-        base::Bind(&WebThreadImplForWorkerSchedulerTest::RunOnWorkerThreadTask,
-                   base::Unretained(this), task, &completion));
+        base::BindOnce(
+            &WebThreadImplForWorkerSchedulerTest::RunOnWorkerThreadTask,
+            base::Unretained(this), std::move(task), &completion));
     completion.Wait();
   }
 
  protected:
-  void RunOnWorkerThreadTask(const base::Closure& task,
+  void RunOnWorkerThreadTask(base::OnceClosure task,
                              base::WaitableEvent* completion) {
-    task.Run();
+    std::move(task).Run();
     completion->Signal();
   }
 
@@ -163,12 +164,12 @@
   TestObserver observer(&calls);
 
   RunOnWorkerThread(FROM_HERE,
-                    base::Bind(&AddTaskObserver, thread_.get(), &observer));
+                    base::BindOnce(&AddTaskObserver, thread_.get(), &observer));
   PostCrossThreadTask(
       *thread_->GetTaskRunner(), FROM_HERE,
       CrossThreadBind(&RunTestTask, WTF::CrossThreadUnretained(&calls)));
-  RunOnWorkerThread(FROM_HERE,
-                    base::Bind(&RemoveTaskObserver, thread_.get(), &observer));
+  RunOnWorkerThread(
+      FROM_HERE, base::BindOnce(&RemoveTaskObserver, thread_.get(), &observer));
 
   // We need to be careful what we test here.  We want to make sure the
   // observers are un in the expected order before and after the task.
@@ -186,7 +187,8 @@
   EXPECT_CALL(task, Run()).Times(0);
   EXPECT_CALL(delayed_task, Run()).Times(0);
 
-  RunOnWorkerThread(FROM_HERE, base::Bind(&ShutdownOnThread, thread_.get()));
+  RunOnWorkerThread(FROM_HERE,
+                    base::BindOnce(&ShutdownOnThread, thread_.get()));
   PostCrossThreadTask(
       *thread_->GetTaskRunner(), FROM_HERE,
       CrossThreadBind(&MockTask::Run, WTF::CrossThreadUnretained(&task)));
diff --git a/third_party/WebKit/Source/platform/scheduler/child/worker_scheduler_impl.cc b/third_party/WebKit/Source/platform/scheduler/child/worker_scheduler_impl.cc
index 99e91f10..36e8e2f 100644
--- a/third_party/WebKit/Source/platform/scheduler/child/worker_scheduler_impl.cc
+++ b/third_party/WebKit/Source/platform/scheduler/child/worker_scheduler_impl.cc
@@ -59,7 +59,7 @@
       idle_canceled_delayed_task_sweeper_(helper_.get(),
                                           idle_helper_.IdleTaskRunner()),
       load_tracker_(helper_->NowTicks(),
-                    base::Bind(&ReportWorkerTaskLoad),
+                    base::BindRepeating(&ReportWorkerTaskLoad),
                     kUnspecifiedWorkerThreadLoadTrackerReportingInterval),
       throttling_state_(
           proxy ? proxy->throttling_state()
diff --git a/third_party/WebKit/Source/platform/scheduler/child/worker_scheduler_impl_unittest.cc b/third_party/WebKit/Source/platform/scheduler/child/worker_scheduler_impl_unittest.cc
index 8fd2bb0..064b7adc 100644
--- a/third_party/WebKit/Source/platform/scheduler/child/worker_scheduler_impl_unittest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/child/worker_scheduler_impl_unittest.cc
@@ -144,12 +144,13 @@
       switch (task[0]) {
         case 'D':
           default_task_runner_->PostTask(
-              FROM_HERE, base::Bind(&AppendToVectorTestTask, run_order, task));
+              FROM_HERE,
+              base::BindOnce(&AppendToVectorTestTask, run_order, task));
           break;
         case 'I':
           idle_task_runner_->PostIdleTask(
               FROM_HERE,
-              base::Bind(&AppendToVectorIdleTestTask, run_order, task));
+              base::BindOnce(&AppendToVectorIdleTestTask, run_order, task));
           break;
         default:
           NOTREACHED();
@@ -216,7 +217,7 @@
   PostTestTasks(&run_order, "I1 D2 D3 D4");
 
   default_task_runner_->PostDelayedTask(
-      FROM_HERE, base::Bind(&AppendToVectorTestTask, &run_order, "DELAYED"),
+      FROM_HERE, base::BindOnce(&AppendToVectorTestTask, &run_order, "DELAYED"),
       base::TimeDelta::FromMilliseconds(1000));
 
   RunUntilIdle();
@@ -234,13 +235,14 @@
   timeline.push_back("Post default task");
   // Post a delayed task timed to occur mid way during the long idle period.
   default_task_runner_->PostTask(
-      FROM_HERE, base::Bind(&RecordTimelineTask, base::Unretained(&timeline),
-                            base::Unretained(&clock_)));
+      FROM_HERE,
+      base::BindOnce(&RecordTimelineTask, base::Unretained(&timeline),
+                     base::Unretained(&clock_)));
   RunUntilIdle();
 
   timeline.push_back("Post idle task");
-  idle_task_runner_->PostIdleTask(FROM_HERE,
-                                  base::Bind(&TimelineIdleTestTask, &timeline));
+  idle_task_runner_->PostIdleTask(
+      FROM_HERE, base::BindOnce(&TimelineIdleTestTask, &timeline));
 
   RunUntilIdle();
 
@@ -264,11 +266,11 @@
   // Post a delayed task timed to occur mid way during the long idle period.
   default_task_runner_->PostDelayedTask(
       FROM_HERE,
-      base::Bind(&RecordTimelineTask, base::Unretained(&timeline),
-                 base::Unretained(&clock_)),
+      base::BindOnce(&RecordTimelineTask, base::Unretained(&timeline),
+                     base::Unretained(&clock_)),
       base::TimeDelta::FromMilliseconds(20));
-  idle_task_runner_->PostIdleTask(FROM_HERE,
-                                  base::Bind(&TimelineIdleTestTask, &timeline));
+  idle_task_runner_->PostIdleTask(
+      FROM_HERE, base::BindOnce(&TimelineIdleTestTask, &timeline));
 
   RunUntilIdle();
 
@@ -291,11 +293,11 @@
   // Post a delayed task timed to occur well after the long idle period.
   default_task_runner_->PostDelayedTask(
       FROM_HERE,
-      base::Bind(&RecordTimelineTask, base::Unretained(&timeline),
-                 base::Unretained(&clock_)),
+      base::BindOnce(&RecordTimelineTask, base::Unretained(&timeline),
+                     base::Unretained(&clock_)),
       base::TimeDelta::FromMilliseconds(500));
-  idle_task_runner_->PostIdleTask(FROM_HERE,
-                                  base::Bind(&TimelineIdleTestTask, &timeline));
+  idle_task_runner_->PostIdleTask(
+      FROM_HERE, base::BindOnce(&TimelineIdleTestTask, &timeline));
 
   RunUntilIdle();
 
@@ -312,7 +314,8 @@
   Init();
 
   default_task_runner_->PostDelayedTask(
-      FROM_HERE, base::Bind(&NopTask), base::TimeDelta::FromMilliseconds(1000));
+      FROM_HERE, base::BindOnce(&NopTask),
+      base::TimeDelta::FromMilliseconds(1000));
   RunUntilIdle();
 
   std::vector<std::string> run_order;
@@ -330,8 +333,8 @@
   timeline->push_back(base::StringPrintf("run PostIdleTask @ %d",
                                          TimeTicksToIntMs(clock->NowTicks())));
 
-  idle_task_runner->PostIdleTask(FROM_HERE,
-                                 base::Bind(&TimelineIdleTestTask, timeline));
+  idle_task_runner->PostIdleTask(
+      FROM_HERE, base::BindOnce(&TimelineIdleTestTask, timeline));
 }
 
 TEST_F(WorkerSchedulerImplTest, TestLongIdlePeriodTimeline) {
@@ -358,22 +361,23 @@
   // the idle task run.
   default_task_runner_->PostDelayedTask(
       FROM_HERE,
-      base::Bind(&PostIdleTask, base::Unretained(&timeline),
-                 base::Unretained(&clock_),
-                 base::Unretained(idle_task_runner_.get())),
+      base::BindOnce(&PostIdleTask, base::Unretained(&timeline),
+                     base::Unretained(&clock_),
+                     base::Unretained(idle_task_runner_.get())),
       base::TimeDelta::FromMilliseconds(30));
 
   timeline.push_back("PostFirstIdleTask");
-  idle_task_runner_->PostIdleTask(FROM_HERE,
-                                  base::Bind(&TimelineIdleTestTask, &timeline));
+  idle_task_runner_->PostIdleTask(
+      FROM_HERE, base::BindOnce(&TimelineIdleTestTask, &timeline));
   RunUntilIdle();
   new_idle_period_deadline = scheduler_->CurrentIdleTaskDeadlineForTesting();
 
   // Running a normal task will mark the system as non-quiescent.
   timeline.push_back("Post RecordTimelineTask");
   default_task_runner_->PostTask(
-      FROM_HERE, base::Bind(&RecordTimelineTask, base::Unretained(&timeline),
-                            base::Unretained(&clock_)));
+      FROM_HERE,
+      base::BindOnce(&RecordTimelineTask, base::Unretained(&timeline),
+                     base::Unretained(&clock_)));
   RunUntilIdle();
 
   std::string expected_timeline[] = {"RunUntilIdle begin @ 55",
diff --git a/third_party/WebKit/Source/platform/scheduler/child/worker_task_queue.cc b/third_party/WebKit/Source/platform/scheduler/child/worker_task_queue.cc
index 2bed41e..020003dc 100644
--- a/third_party/WebKit/Source/platform/scheduler/child/worker_task_queue.cc
+++ b/third_party/WebKit/Source/platform/scheduler/child/worker_task_queue.cc
@@ -16,8 +16,8 @@
     : TaskQueue(std::move(impl), spec), worker_scheduler_(worker_scheduler) {
   if (GetTaskQueueImpl()) {
     // TaskQueueImpl may be null for tests.
-    GetTaskQueueImpl()->SetOnTaskCompletedHandler(
-        base::Bind(&WorkerTaskQueue::OnTaskCompleted, base::Unretained(this)));
+    GetTaskQueueImpl()->SetOnTaskCompletedHandler(base::BindRepeating(
+        &WorkerTaskQueue::OnTaskCompleted, base::Unretained(this)));
   }
 }
 
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/auto_advancing_virtual_time_domain_unittest.cc b/third_party/WebKit/Source/platform/scheduler/renderer/auto_advancing_virtual_time_domain_unittest.cc
index 38b5379..7f0f1f4d 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/auto_advancing_virtual_time_domain_unittest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/auto_advancing_virtual_time_domain_unittest.cc
@@ -79,7 +79,7 @@
 
   base::TimeDelta delay = base::TimeDelta::FromMilliseconds(10);
   bool task_run = false;
-  task_queue_->PostDelayedTask(FROM_HERE, base::Bind(NopTask, &task_run),
+  task_queue_->PostDelayedTask(FROM_HERE, base::BindOnce(NopTask, &task_run),
                                delay);
 
   EXPECT_CALL(mock_observer, OnVirtualTimeAdvanced());
@@ -99,7 +99,7 @@
 
   base::TimeDelta delay = base::TimeDelta::FromMilliseconds(10);
   bool task_run = false;
-  task_queue_->PostDelayedTask(FROM_HERE, base::Bind(NopTask, &task_run),
+  task_queue_->PostDelayedTask(FROM_HERE, base::BindOnce(NopTask, &task_run),
                                delay);
 
   auto_advancing_time_domain_->SetCanAdvanceVirtualTime(false);
@@ -123,7 +123,7 @@
     return;
 
   task_queue->PostTask(
-      FROM_HERE, base::Bind(&RepostingTask, task_queue, max_count, count));
+      FROM_HERE, base::BindOnce(&RepostingTask, task_queue, max_count, count));
 }
 
 void DelayedTask(int* count_in, int* count_out) {
@@ -141,7 +141,8 @@
   int delayed_task_run_at_count = 0;
   RepostingTask(task_queue_, 1000, &count);
   task_queue_->PostDelayedTask(
-      FROM_HERE, base::Bind(DelayedTask, &count, &delayed_task_run_at_count),
+      FROM_HERE,
+      base::BindOnce(DelayedTask, &count, &delayed_task_run_at_count),
       base::TimeDelta::FromMilliseconds(10));
 
   mock_task_runner_->RunUntilIdle();
@@ -159,7 +160,8 @@
   int delayed_task_run_at_count = 0;
   RepostingTask(task_queue_, 1000, &count);
   task_queue_->PostDelayedTask(
-      FROM_HERE, base::Bind(DelayedTask, &count, &delayed_task_run_at_count),
+      FROM_HERE,
+      base::BindOnce(DelayedTask, &count, &delayed_task_run_at_count),
       base::TimeDelta::FromMilliseconds(10));
 
   mock_task_runner_->RunUntilIdle();
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/cpu_time_budget_pool.cc b/third_party/WebKit/Source/platform/scheduler/renderer/cpu_time_budget_pool.cc
index a6b9af1..b607860 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/cpu_time_budget_pool.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/cpu_time_budget_pool.cc
@@ -72,7 +72,7 @@
 }
 
 void CPUTimeBudgetPool::SetReportingCallback(
-    base::Callback<void(base::TimeDelta)> reporting_callback) {
+    base::RepeatingCallback<void(base::TimeDelta)> reporting_callback) {
   reporting_callback_ = reporting_callback;
 }
 
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/cpu_time_budget_pool.h b/third_party/WebKit/Source/platform/scheduler/renderer/cpu_time_budget_pool.h
index b5126c59..0b6c89e 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/cpu_time_budget_pool.h
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/cpu_time_budget_pool.h
@@ -69,7 +69,7 @@
   // is throttled. Throttling duration (time until the queue is allowed
   // to run again) is passed as a parameter to callback.
   void SetReportingCallback(
-      base::Callback<void(base::TimeDelta)> reporting_callback);
+      base::RepeatingCallback<void(base::TimeDelta)> reporting_callback);
 
   // BudgetPool implementation:
   void RecordTaskRunTime(TaskQueue* queue,
@@ -122,7 +122,7 @@
   base::TimeTicks last_checkpoint_;
   double cpu_percentage_;
 
-  base::Callback<void(base::TimeDelta)> reporting_callback_;
+  base::RepeatingCallback<void(base::TimeDelta)> reporting_callback_;
 
   DISALLOW_COPY_AND_ASSIGN(CPUTimeBudgetPool);
 };
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/deadline_task_runner.cc b/third_party/WebKit/Source/platform/scheduler/renderer/deadline_task_runner.cc
index c1f8443..610d083 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/deadline_task_runner.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/deadline_task_runner.cc
@@ -10,11 +10,11 @@
 namespace scheduler {
 
 DeadlineTaskRunner::DeadlineTaskRunner(
-    const base::Closure& callback,
+    const base::RepeatingClosure& callback,
     scoped_refptr<base::SingleThreadTaskRunner> task_runner)
     : callback_(callback), task_runner_(task_runner) {
-  cancelable_run_internal_.Reset(
-      base::Bind(&DeadlineTaskRunner::RunInternal, base::Unretained(this)));
+  cancelable_run_internal_.Reset(base::BindRepeating(
+      &DeadlineTaskRunner::RunInternal, base::Unretained(this)));
 }
 
 DeadlineTaskRunner::~DeadlineTaskRunner() = default;
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/deadline_task_runner.h b/third_party/WebKit/Source/platform/scheduler/renderer/deadline_task_runner.h
index 9041e00..1c74fa09 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/deadline_task_runner.h
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/deadline_task_runner.h
@@ -18,7 +18,7 @@
 // Runs a posted task at latest by a given deadline, but possibly sooner.
 class PLATFORM_EXPORT DeadlineTaskRunner {
  public:
-  DeadlineTaskRunner(const base::Closure& callback,
+  DeadlineTaskRunner(const base::RepeatingClosure& callback,
                      scoped_refptr<base::SingleThreadTaskRunner> task_runner);
 
   ~DeadlineTaskRunner();
@@ -38,7 +38,7 @@
   void RunInternal();
 
   CancelableClosureHolder cancelable_run_internal_;
-  base::Closure callback_;
+  base::RepeatingClosure callback_;
   base::TimeTicks deadline_;
   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
 
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/deadline_task_runner_unittest.cc b/third_party/WebKit/Source/platform/scheduler/renderer/deadline_task_runner_unittest.cc
index 1b9f6bd..0fcaa7a 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/deadline_task_runner_unittest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/deadline_task_runner_unittest.cc
@@ -24,7 +24,8 @@
     clock_->Advance(base::TimeDelta::FromMicroseconds(5000));
     mock_task_runner_ = new cc::OrderedSimpleTaskRunner(clock_.get(), true);
     deadline_task_runner_.reset(new DeadlineTaskRunner(
-        base::Bind(&DeadlineTaskRunnerTest::TestTask, base::Unretained(this)),
+        base::BindRepeating(&DeadlineTaskRunnerTest::TestTask,
+                            base::Unretained(this)),
         mock_task_runner_));
     run_times_.clear();
   }
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/main_thread_task_queue.cc b/third_party/WebKit/Source/platform/scheduler/renderer/main_thread_task_queue.cc
index 40f2b57..5cd6ec7ce 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/main_thread_task_queue.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/main_thread_task_queue.cc
@@ -102,9 +102,9 @@
       web_frame_scheduler_(nullptr) {
   if (GetTaskQueueImpl()) {
     // TaskQueueImpl may be null for tests.
-    GetTaskQueueImpl()->SetOnTaskStartedHandler(base::Bind(
+    GetTaskQueueImpl()->SetOnTaskStartedHandler(base::BindRepeating(
         &MainThreadTaskQueue::OnTaskStarted, base::Unretained(this)));
-    GetTaskQueueImpl()->SetOnTaskCompletedHandler(base::Bind(
+    GetTaskQueueImpl()->SetOnTaskCompletedHandler(base::BindRepeating(
         &MainThreadTaskQueue::OnTaskCompleted, base::Unretained(this)));
   }
 }
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_metrics_helper.cc b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_metrics_helper.cc
index 31c03bc..d09df5d 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_metrics_helper.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_metrics_helper.cc
@@ -47,18 +47,20 @@
       renderer_scheduler_(renderer_scheduler),
       main_thread_load_tracker(
           now,
-          base::Bind(&RendererMetricsHelper::RecordMainThreadTaskLoad,
-                     base::Unretained(this)),
+          base::BindRepeating(&RendererMetricsHelper::RecordMainThreadTaskLoad,
+                              base::Unretained(this)),
           kThreadLoadTrackerReportingInterval),
       background_main_thread_load_tracker(
           now,
-          base::Bind(&RendererMetricsHelper::RecordBackgroundMainThreadTaskLoad,
-                     base::Unretained(this)),
+          base::BindRepeating(
+              &RendererMetricsHelper::RecordBackgroundMainThreadTaskLoad,
+              base::Unretained(this)),
           kThreadLoadTrackerReportingInterval),
       foreground_main_thread_load_tracker(
           now,
-          base::Bind(&RendererMetricsHelper::RecordForegroundMainThreadTaskLoad,
-                     base::Unretained(this)),
+          base::BindRepeating(
+              &RendererMetricsHelper::RecordForegroundMainThreadTaskLoad,
+              base::Unretained(this)),
           kThreadLoadTrackerReportingInterval),
       per_queue_type_task_duration_reporter(
           DURATION_PER_QUEUE_TYPE_METRIC_NAME),
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc
index 91e7efa..297b32a6 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl.cc
@@ -236,8 +236,8 @@
       input_task_queue_enabled_voter_(
           input_task_queue_->CreateQueueEnabledVoter()),
       delayed_update_policy_runner_(
-          base::Bind(&RendererSchedulerImpl::UpdatePolicy,
-                     base::Unretained(this)),
+          base::BindRepeating(&RendererSchedulerImpl::UpdatePolicy,
+                              base::Unretained(this)),
           helper_.ControlMainThreadTaskQueue()),
       seqlock_queueing_time_estimator_(
           QueueingTimeEstimator(this, kQueueingTimeWindowDuration, 20)),
@@ -250,9 +250,9 @@
       weak_factory_(this) {
   task_queue_throttler_.reset(
       new TaskQueueThrottler(this, &tracing_controller_));
-  update_policy_closure_ = base::Bind(&RendererSchedulerImpl::UpdatePolicy,
-                                      weak_factory_.GetWeakPtr());
-  end_renderer_hidden_idle_period_closure_.Reset(base::Bind(
+  update_policy_closure_ = base::BindRepeating(
+      &RendererSchedulerImpl::UpdatePolicy, weak_factory_.GetWeakPtr());
+  end_renderer_hidden_idle_period_closure_.Reset(base::BindRepeating(
       &RendererSchedulerImpl::EndIdlePeriod, weak_factory_.GetWeakPtr()));
 
   // Compositor task queue and default task queue should be managed by
@@ -1267,8 +1267,8 @@
     const base::Closure& callback) {
   main_thread_only().in_idle_period_for_testing = true;
   IdleTaskRunner()->PostIdleTask(
-      FROM_HERE, base::Bind(&RendererSchedulerImpl::EndIdlePeriodForTesting,
-                            weak_factory_.GetWeakPtr(), callback));
+      FROM_HERE, base::BindOnce(&RendererSchedulerImpl::EndIdlePeriodForTesting,
+                                weak_factory_.GetWeakPtr(), callback));
   idle_helper_.EnableLongIdlePeriod();
 }
 
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl_unittest.cc b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl_unittest.cc
index d666bde5..604f7dce 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl_unittest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/renderer_scheduler_impl_unittest.cc
@@ -63,10 +63,10 @@
                                  int max_reentrant_count) {
   vector->push_back((*reentrant_count)++);
   if (*reentrant_count < max_reentrant_count) {
-    task_runner->PostTask(
-        FROM_HERE,
-        base::Bind(AppendToVectorReentrantTask, base::Unretained(task_runner),
-                   vector, reentrant_count, max_reentrant_count));
+    task_runner->PostTask(FROM_HERE,
+                          base::BindOnce(AppendToVectorReentrantTask,
+                                         base::Unretained(task_runner), vector,
+                                         reentrant_count, max_reentrant_count));
   }
 }
 
@@ -84,8 +84,9 @@
                            base::TimeTicks deadline) {
   if ((*run_count + 1) < g_max_idle_task_reposts) {
     idle_task_runner->PostIdleTask(
-        FROM_HERE, base::Bind(&RepostingIdleTestTask,
-                              base::Unretained(idle_task_runner), run_count));
+        FROM_HERE,
+        base::BindOnce(&RepostingIdleTestTask,
+                       base::Unretained(idle_task_runner), run_count));
   }
   (*run_count)++;
 }
@@ -99,9 +100,9 @@
     base::TimeTicks deadline) {
   if ((*run_count + 1) < g_max_idle_task_reposts) {
     idle_task_runner->PostIdleTask(
-        FROM_HERE, base::Bind(&RepostingUpdateClockIdleTestTask,
-                              base::Unretained(idle_task_runner), run_count,
-                              clock, advance_time, deadlines));
+        FROM_HERE, base::BindOnce(&RepostingUpdateClockIdleTestTask,
+                                  base::Unretained(idle_task_runner), run_count,
+                                  clock, advance_time, deadlines));
   }
   deadlines->push_back(deadline);
   (*run_count)++;
@@ -131,7 +132,7 @@
                              bool* should_yield_before,
                              bool* should_yield_after) {
   *should_yield_before = scheduler->ShouldYieldForHighPriorityWork();
-  task_runner->PostTask(FROM_HERE, base::Bind(NullTask));
+  task_runner->PostTask(FROM_HERE, base::BindOnce(NullTask));
   if (simulate_input) {
     scheduler->DidHandleInputEventOnCompositorThread(
         FakeInputEvent(blink::WebInputEvent::kTouchMove),
@@ -267,14 +268,14 @@
   using UseCase = RendererSchedulerImpl::UseCase;
 
   RendererSchedulerImplTest()
-      : fake_task_(TaskQueue::PostedTask(base::Bind([] {}), FROM_HERE),
+      : fake_task_(TaskQueue::PostedTask(base::BindOnce([] {}), FROM_HERE),
                    base::TimeTicks()) {
     feature_list_.InitAndEnableFeature(kHighPriorityInput);
     clock_.Advance(base::TimeDelta::FromMicroseconds(5000));
   }
 
   RendererSchedulerImplTest(base::MessageLoop* message_loop)
-      : fake_task_(TaskQueue::PostedTask(base::Bind([] {}), FROM_HERE),
+      : fake_task_(TaskQueue::PostedTask(base::BindOnce([] {}), FROM_HERE),
                    base::TimeTicks()),
         message_loop_(message_loop) {
     clock_.Advance(base::TimeDelta::FromMicroseconds(5000));
@@ -380,10 +381,10 @@
 
     // Simulate a bunch of expensive tasks
     for (int i = 0; i < 10; i++) {
-      task_runner->PostTask(FROM_HERE,
-                            base::Bind(&base::SimpleTestTickClock::Advance,
-                                       base::Unretained(&clock_),
-                                       base::TimeDelta::FromMilliseconds(500)));
+      task_runner->PostTask(
+          FROM_HERE, base::BindOnce(&base::SimpleTestTickClock::Advance,
+                                    base::Unretained(&clock_),
+                                    base::TimeDelta::FromMilliseconds(500)));
     }
 
     RunUntilIdle();
@@ -606,9 +607,9 @@
     // slow and thus compositor tasks will not be prioritized.
     compositor_task_runner_->PostTask(
         FROM_HERE,
-        base::Bind(&RendererSchedulerImplTest::SimulateMainThreadCompositorTask,
-                   base::Unretained(this),
-                   base::TimeDelta::FromMilliseconds(1000)));
+        base::BindOnce(
+            &RendererSchedulerImplTest::SimulateMainThreadCompositorTask,
+            base::Unretained(this), base::TimeDelta::FromMilliseconds(1000)));
     RunUntilIdle();
   }
 
@@ -632,36 +633,43 @@
       switch (task[0]) {
         case 'D':
           default_task_runner_->PostTask(
-              FROM_HERE, base::Bind(&AppendToVectorTestTask, run_order, task));
+              FROM_HERE,
+              base::BindOnce(&AppendToVectorTestTask, run_order, task));
           break;
         case 'C':
           compositor_task_runner_->PostTask(
-              FROM_HERE, base::Bind(&AppendToVectorTestTask, run_order, task));
+              FROM_HERE,
+              base::BindOnce(&AppendToVectorTestTask, run_order, task));
           break;
         case 'P':
           input_task_runner_->PostTask(
-              FROM_HERE, base::Bind(&AppendToVectorTestTask, run_order, task));
+              FROM_HERE,
+              base::BindOnce(&AppendToVectorTestTask, run_order, task));
           break;
         case 'L':
           loading_task_runner_->PostTask(
-              FROM_HERE, base::Bind(&AppendToVectorTestTask, run_order, task));
+              FROM_HERE,
+              base::BindOnce(&AppendToVectorTestTask, run_order, task));
           break;
         case 'M':
           loading_control_task_runner_->PostTask(
-              FROM_HERE, base::Bind(&AppendToVectorTestTask, run_order, task));
+              FROM_HERE,
+              base::BindOnce(&AppendToVectorTestTask, run_order, task));
           break;
         case 'I':
           idle_task_runner_->PostIdleTask(
               FROM_HERE,
-              base::Bind(&AppendToVectorIdleTestTask, run_order, task));
+              base::BindOnce(&AppendToVectorIdleTestTask, run_order, task));
           break;
         case 'T':
           timer_task_runner_->PostTask(
-              FROM_HERE, base::Bind(&AppendToVectorTestTask, run_order, task));
+              FROM_HERE,
+              base::BindOnce(&AppendToVectorTestTask, run_order, task));
           break;
         case 'V':
           v8_task_runner_->PostTask(
-              FROM_HERE, base::Bind(&AppendToVectorTestTask, run_order, task));
+              FROM_HERE,
+              base::BindOnce(&AppendToVectorTestTask, run_order, task));
           break;
         default:
           NOTREACHED();
@@ -773,9 +781,9 @@
   int count = 0;
   std::vector<int> run_order;
   default_task_runner_->PostTask(
-      FROM_HERE, base::Bind(AppendToVectorReentrantTask,
-                            base::RetainedRef(default_task_runner_), &run_order,
-                            &count, 5));
+      FROM_HERE, base::BindOnce(AppendToVectorReentrantTask,
+                                base::RetainedRef(default_task_runner_),
+                                &run_order, &count, 5));
   RunUntilIdle();
 
   EXPECT_THAT(run_order, ::testing::ElementsAre(0, 1, 2, 3, 4));
@@ -789,7 +797,7 @@
 
   clock_.Advance(base::TimeDelta::FromMilliseconds(100));
   idle_task_runner_->PostIdleTask(
-      FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task));
+      FROM_HERE, base::BindOnce(&IdleTestTask, &run_count, &deadline_in_task));
 
   RunUntilIdle();
   EXPECT_EQ(0, run_count);  // Shouldn't run yet as no WillBeginFrame.
@@ -822,8 +830,9 @@
 
   g_max_idle_task_reposts = 2;
   idle_task_runner_->PostIdleTask(
-      FROM_HERE, base::Bind(&RepostingIdleTestTask,
-                            base::RetainedRef(idle_task_runner_), &run_count));
+      FROM_HERE,
+      base::BindOnce(&RepostingIdleTestTask,
+                     base::RetainedRef(idle_task_runner_), &run_count));
   EnableIdleTasks();
   RunUntilIdle();
   EXPECT_EQ(1, run_count);
@@ -844,10 +853,10 @@
   // Post two UpdateClockToDeadlineIdleTestTask tasks.
   idle_task_runner_->PostIdleTask(
       FROM_HERE,
-      base::Bind(&UpdateClockToDeadlineIdleTestTask, &clock_, &run_count));
+      base::BindOnce(&UpdateClockToDeadlineIdleTestTask, &clock_, &run_count));
   idle_task_runner_->PostIdleTask(
       FROM_HERE,
-      base::Bind(&UpdateClockToDeadlineIdleTestTask, &clock_, &run_count));
+      base::BindOnce(&UpdateClockToDeadlineIdleTestTask, &clock_, &run_count));
 
   EnableIdleTasks();
   RunUntilIdle();
@@ -865,7 +874,7 @@
 
   base::TimeTicks deadline_in_task;
   idle_task_runner_->PostIdleTask(
-      FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task));
+      FROM_HERE, base::BindOnce(&IdleTestTask, &run_count, &deadline_in_task));
 
   // Trigger the beginning of an idle period for 1000ms.
   scheduler_->WillBeginFrame(viz::BeginFrameArgs::Create(
@@ -892,7 +901,7 @@
 
   // Post a task which simulates running until after the previous end idle
   // period delayed task was scheduled for
-  scheduler_->DefaultTaskQueue()->PostTask(FROM_HERE, base::Bind(NullTask));
+  scheduler_->DefaultTaskQueue()->PostTask(FROM_HERE, base::BindOnce(NullTask));
   clock_.Advance(base::TimeDelta::FromMilliseconds(300));
 
   RunUntilIdle();
@@ -1644,7 +1653,7 @@
   PostTestTasks(&run_order, "D1 C1");
 
   for (int i = 0; i < 20; i++) {
-    compositor_task_runner_->PostTask(FROM_HERE, base::Bind(&NullTask));
+    compositor_task_runner_->PostTask(FROM_HERE, base::BindOnce(&NullTask));
   }
   PostTestTasks(&run_order, "C2");
 
@@ -1743,9 +1752,9 @@
 
   scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true);
   default_task_runner_->PostTask(
-      FROM_HERE, base::Bind(&AnticipationTestTask, scheduler_.get(),
-                            SimulateInputType::kNone, &is_anticipated_before,
-                            &is_anticipated_after));
+      FROM_HERE, base::BindOnce(&AnticipationTestTask, scheduler_.get(),
+                                SimulateInputType::kNone,
+                                &is_anticipated_before, &is_anticipated_after));
   RunUntilIdle();
   // In its default state, without input receipt, the scheduler should indicate
   // that no high-priority is anticipated.
@@ -1753,21 +1762,21 @@
   EXPECT_FALSE(is_anticipated_after);
 
   default_task_runner_->PostTask(
-      FROM_HERE, base::Bind(&AnticipationTestTask, scheduler_.get(),
-                            SimulateInputType::kTouchStart,
-                            &is_anticipated_before, &is_anticipated_after));
+      FROM_HERE, base::BindOnce(&AnticipationTestTask, scheduler_.get(),
+                                SimulateInputType::kTouchStart,
+                                &is_anticipated_before, &is_anticipated_after));
   bool dummy;
   default_task_runner_->PostTask(
-      FROM_HERE, base::Bind(&AnticipationTestTask, scheduler_.get(),
-                            SimulateInputType::kTouchEnd, &dummy, &dummy));
+      FROM_HERE, base::BindOnce(&AnticipationTestTask, scheduler_.get(),
+                                SimulateInputType::kTouchEnd, &dummy, &dummy));
   default_task_runner_->PostTask(
       FROM_HERE,
-      base::Bind(&AnticipationTestTask, scheduler_.get(),
-                 SimulateInputType::kGestureScrollBegin, &dummy, &dummy));
+      base::BindOnce(&AnticipationTestTask, scheduler_.get(),
+                     SimulateInputType::kGestureScrollBegin, &dummy, &dummy));
   default_task_runner_->PostTask(
       FROM_HERE,
-      base::Bind(&AnticipationTestTask, scheduler_.get(),
-                 SimulateInputType::kGestureScrollEnd, &dummy, &dummy));
+      base::BindOnce(&AnticipationTestTask, scheduler_.get(),
+                     SimulateInputType::kGestureScrollEnd, &dummy, &dummy));
 
   RunUntilIdle();
   // When input is received, the scheduler should indicate that high-priority
@@ -1777,9 +1786,9 @@
 
   clock_.Advance(priority_escalation_after_input_duration() * 2);
   default_task_runner_->PostTask(
-      FROM_HERE, base::Bind(&AnticipationTestTask, scheduler_.get(),
-                            SimulateInputType::kNone, &is_anticipated_before,
-                            &is_anticipated_after));
+      FROM_HERE, base::BindOnce(&AnticipationTestTask, scheduler_.get(),
+                                SimulateInputType::kNone,
+                                &is_anticipated_before, &is_anticipated_after));
   RunUntilIdle();
   // Without additional input, the scheduler should go into NONE
   // use case but with scrolling expected where high-priority work is still
@@ -1791,9 +1800,9 @@
 
   clock_.Advance(subsequent_input_expected_after_input_duration() * 2);
   default_task_runner_->PostTask(
-      FROM_HERE, base::Bind(&AnticipationTestTask, scheduler_.get(),
-                            SimulateInputType::kNone, &is_anticipated_before,
-                            &is_anticipated_after));
+      FROM_HERE, base::BindOnce(&AnticipationTestTask, scheduler_.get(),
+                                SimulateInputType::kNone,
+                                &is_anticipated_before, &is_anticipated_after));
   RunUntilIdle();
   // Eventually the scheduler should go into the default use case where
   // high-priority work is no longer anticipated.
@@ -1808,27 +1817,29 @@
   bool should_yield_after = false;
 
   default_task_runner_->PostTask(
-      FROM_HERE, base::Bind(&PostingYieldingTestTask, scheduler_.get(),
-                            base::RetainedRef(default_task_runner_), false,
-                            &should_yield_before, &should_yield_after));
+      FROM_HERE, base::BindOnce(&PostingYieldingTestTask, scheduler_.get(),
+                                base::RetainedRef(default_task_runner_), false,
+                                &should_yield_before, &should_yield_after));
   RunUntilIdle();
   // Posting to default runner shouldn't cause yielding.
   EXPECT_FALSE(should_yield_before);
   EXPECT_FALSE(should_yield_after);
 
   default_task_runner_->PostTask(
-      FROM_HERE, base::Bind(&PostingYieldingTestTask, scheduler_.get(),
-                            base::RetainedRef(compositor_task_runner_), false,
-                            &should_yield_before, &should_yield_after));
+      FROM_HERE,
+      base::BindOnce(&PostingYieldingTestTask, scheduler_.get(),
+                     base::RetainedRef(compositor_task_runner_), false,
+                     &should_yield_before, &should_yield_after));
   RunUntilIdle();
   // Posting while not mainthread scrolling shouldn't cause yielding.
   EXPECT_FALSE(should_yield_before);
   EXPECT_FALSE(should_yield_after);
 
   default_task_runner_->PostTask(
-      FROM_HERE, base::Bind(&PostingYieldingTestTask, scheduler_.get(),
-                            base::RetainedRef(compositor_task_runner_), true,
-                            &should_yield_before, &should_yield_after));
+      FROM_HERE,
+      base::BindOnce(&PostingYieldingTestTask, scheduler_.get(),
+                     base::RetainedRef(compositor_task_runner_), true,
+                     &should_yield_before, &should_yield_after));
   RunUntilIdle();
   // We should be able to switch to compositor priority mid-task.
   EXPECT_FALSE(should_yield_before);
@@ -2138,24 +2149,26 @@
   std::vector<std::string> order;
   idle_task_runner_->PostIdleTask(
       FROM_HERE,
-      base::Bind(&AppendToVectorIdleTestTask, &order, std::string("1")));
+      base::BindOnce(&AppendToVectorIdleTestTask, &order, std::string("1")));
   idle_task_runner_->PostIdleTask(
       FROM_HERE,
-      base::Bind(&AppendToVectorIdleTestTask, &order, std::string("2")));
+      base::BindOnce(&AppendToVectorIdleTestTask, &order, std::string("2")));
 
   std::vector<std::pair<SingleThreadIdleTaskRunner::IdleTask, bool>>
       tasks_to_post_from_nested_loop;
   tasks_to_post_from_nested_loop.push_back(std::make_pair(
-      base::Bind(&AppendToVectorIdleTestTask, &order, std::string("3")),
+      base::BindOnce(&AppendToVectorIdleTestTask, &order, std::string("3")),
       false));
   tasks_to_post_from_nested_loop.push_back(std::make_pair(
-      base::Bind(&AppendToVectorIdleTestTask, &order, std::string("4")), true));
+      base::BindOnce(&AppendToVectorIdleTestTask, &order, std::string("4")),
+      true));
   tasks_to_post_from_nested_loop.push_back(std::make_pair(
-      base::Bind(&AppendToVectorIdleTestTask, &order, std::string("5")), true));
+      base::BindOnce(&AppendToVectorIdleTestTask, &order, std::string("5")),
+      true));
 
   default_task_runner_->PostTask(
       FROM_HERE,
-      base::Bind(
+      base::BindOnce(
           &RendererSchedulerImplWithMessageLoopTest::PostFromNestedRunloop,
           base::Unretained(this),
           base::Unretained(&tasks_to_post_from_nested_loop)));
@@ -2175,7 +2188,7 @@
   int run_count = 0;
 
   idle_task_runner_->PostIdleTask(
-      FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task));
+      FROM_HERE, base::BindOnce(&IdleTestTask, &run_count, &deadline_in_task));
 
   RunUntilIdle();
   EXPECT_EQ(0, run_count);  // Shouldn't run yet as no idle period.
@@ -2197,7 +2210,7 @@
   int run_count = 0;
 
   idle_task_runner_->PostIdleTask(
-      FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task));
+      FROM_HERE, base::BindOnce(&IdleTestTask, &run_count, &deadline_in_task));
 
   RunUntilIdle();
   EXPECT_EQ(0, run_count);  // Shouldn't run yet as no idle period.
@@ -2215,8 +2228,8 @@
   int run_count = 0;
 
   idle_task_runner_->PostIdleTask(
-      FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task));
-  default_task_runner_->PostDelayedTask(FROM_HERE, base::Bind(&NullTask),
+      FROM_HERE, base::BindOnce(&IdleTestTask, &run_count, &deadline_in_task));
+  default_task_runner_->PostDelayedTask(FROM_HERE, base::BindOnce(&NullTask),
                                         pending_task_delay);
 
   scheduler_->BeginFrameNotExpectedSoon();
@@ -2231,7 +2244,7 @@
   base::TimeTicks deadline_in_task;
   int run_count = 0;
 
-  default_task_runner_->PostDelayedTask(FROM_HERE, base::Bind(&NullTask),
+  default_task_runner_->PostDelayedTask(FROM_HERE, base::BindOnce(&NullTask),
                                         pending_task_delay);
 
   // Advance clock until after delayed task was meant to be run.
@@ -2241,7 +2254,7 @@
   // period. Since there is a late pending delayed task this shouldn't actually
   // start an idle period.
   idle_task_runner_->PostIdleTask(
-      FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task));
+      FROM_HERE, base::BindOnce(&IdleTestTask, &run_count, &deadline_in_task));
   scheduler_->BeginFrameNotExpectedSoon();
   RunUntilIdle();
   EXPECT_EQ(0, run_count);
@@ -2261,9 +2274,10 @@
   base::TimeTicks clock_before(clock_.NowTicks());
   base::TimeDelta idle_task_runtime(base::TimeDelta::FromMilliseconds(10));
   idle_task_runner_->PostIdleTask(
-      FROM_HERE, base::Bind(&RepostingUpdateClockIdleTestTask,
-                            base::RetainedRef(idle_task_runner_), &run_count,
-                            &clock_, idle_task_runtime, &actual_deadlines));
+      FROM_HERE,
+      base::BindOnce(&RepostingUpdateClockIdleTestTask,
+                     base::RetainedRef(idle_task_runner_), &run_count, &clock_,
+                     idle_task_runtime, &actual_deadlines));
   scheduler_->BeginFrameNotExpectedSoon();
   RunUntilIdle();
   EXPECT_EQ(3, run_count);
@@ -2277,13 +2291,14 @@
   // new BeginMainFrame.
   g_max_idle_task_reposts = 5;
   idle_task_runner_->PostIdleTask(
-      FROM_HERE, base::Bind(&RepostingUpdateClockIdleTestTask,
-                            base::RetainedRef(idle_task_runner_), &run_count,
-                            &clock_, idle_task_runtime, &actual_deadlines));
-  idle_task_runner_->PostIdleTask(
       FROM_HERE,
-      base::Bind(&WillBeginFrameIdleTask, base::Unretained(scheduler_.get()),
-                 next_begin_frame_number_++, &clock_));
+      base::BindOnce(&RepostingUpdateClockIdleTestTask,
+                     base::RetainedRef(idle_task_runner_), &run_count, &clock_,
+                     idle_task_runtime, &actual_deadlines));
+  idle_task_runner_->PostIdleTask(
+      FROM_HERE, base::BindOnce(&WillBeginFrameIdleTask,
+                                base::Unretained(scheduler_.get()),
+                                next_begin_frame_number_++, &clock_));
   RunUntilIdle();
   EXPECT_EQ(4, run_count);
 }
@@ -2294,7 +2309,7 @@
   int run_count = 0;
 
   idle_task_runner_->PostIdleTask(
-      FROM_HERE, base::Bind(&IdleTestTask, &run_count, &deadline_in_task));
+      FROM_HERE, base::BindOnce(&IdleTestTask, &run_count, &deadline_in_task));
 
   // Observation of touchstart should defer the start of the long idle period.
   scheduler_->DidHandleInputEventOnCompositorThread(
@@ -2328,8 +2343,8 @@
   // Should return false for short idle periods.
   idle_task_runner_->PostIdleTask(
       FROM_HERE,
-      base::Bind(&TestCanExceedIdleDeadlineIfRequiredTask, scheduler_.get(),
-                 &can_exceed_idle_deadline, &run_count));
+      base::BindOnce(&TestCanExceedIdleDeadlineIfRequiredTask, scheduler_.get(),
+                     &can_exceed_idle_deadline, &run_count));
   EnableIdleTasks();
   RunUntilIdle();
   EXPECT_EQ(1, run_count);
@@ -2337,12 +2352,12 @@
 
   // Should return false for a long idle period which is shortened due to a
   // pending delayed task.
-  default_task_runner_->PostDelayedTask(FROM_HERE, base::Bind(&NullTask),
+  default_task_runner_->PostDelayedTask(FROM_HERE, base::BindOnce(&NullTask),
                                         base::TimeDelta::FromMilliseconds(10));
   idle_task_runner_->PostIdleTask(
       FROM_HERE,
-      base::Bind(&TestCanExceedIdleDeadlineIfRequiredTask, scheduler_.get(),
-                 &can_exceed_idle_deadline, &run_count));
+      base::BindOnce(&TestCanExceedIdleDeadlineIfRequiredTask, scheduler_.get(),
+                     &can_exceed_idle_deadline, &run_count));
   scheduler_->BeginFrameNotExpectedSoon();
   RunUntilIdle();
   EXPECT_EQ(2, run_count);
@@ -2353,8 +2368,8 @@
   clock_.Advance(maximum_idle_period_duration());
   idle_task_runner_->PostIdleTask(
       FROM_HERE,
-      base::Bind(&TestCanExceedIdleDeadlineIfRequiredTask, scheduler_.get(),
-                 &can_exceed_idle_deadline, &run_count));
+      base::BindOnce(&TestCanExceedIdleDeadlineIfRequiredTask, scheduler_.get(),
+                     &can_exceed_idle_deadline, &run_count));
   RunUntilIdle();
   EXPECT_EQ(3, run_count);
   EXPECT_TRUE(can_exceed_idle_deadline);
@@ -2375,8 +2390,9 @@
 
   g_max_idle_task_reposts = 2;
   idle_task_runner_->PostIdleTask(
-      FROM_HERE, base::Bind(&RepostingIdleTestTask,
-                            base::RetainedRef(idle_task_runner_), &run_count));
+      FROM_HERE,
+      base::BindOnce(&RepostingIdleTestTask,
+                     base::RetainedRef(idle_task_runner_), &run_count));
 
   // Renderer should start in visible state.
   RunUntilIdle();
@@ -2393,8 +2409,9 @@
   // idle tasks when hidden (plus some slack) - idle period should have ended.
   g_max_idle_task_reposts = 3;
   idle_task_runner_->PostIdleTask(
-      FROM_HERE, base::Bind(&RepostingIdleTestTask,
-                            base::RetainedRef(idle_task_runner_), &run_count));
+      FROM_HERE,
+      base::BindOnce(&RepostingIdleTestTask,
+                     base::RetainedRef(idle_task_runner_), &run_count));
   clock_.Advance(end_idle_when_hidden_delay() +
                  base::TimeDelta::FromMilliseconds(10));
   RunUntilIdle();
@@ -3015,14 +3032,15 @@
     scheduler_->WillBeginFrame(begin_frame_args);
 
     compositor_task_runner_->PostTask(
-        FROM_HERE, base::Bind(&RendererSchedulerImplTest::
-                                  SimulateMainThreadInputHandlingCompositorTask,
-                              base::Unretained(this),
-                              base::TimeDelta::FromMilliseconds(8)));
+        FROM_HERE,
+        base::BindOnce(&RendererSchedulerImplTest::
+                           SimulateMainThreadInputHandlingCompositorTask,
+                       base::Unretained(this),
+                       base::TimeDelta::FromMilliseconds(8)));
     timer_task_runner_->PostTask(
-        FROM_HERE, base::Bind(&RendererSchedulerImplTest::SimulateTimerTask,
-                              base::Unretained(this),
-                              base::TimeDelta::FromMilliseconds(4)));
+        FROM_HERE, base::BindOnce(&RendererSchedulerImplTest::SimulateTimerTask,
+                                  base::Unretained(this),
+                                  base::TimeDelta::FromMilliseconds(4)));
 
     RunUntilIdle();
     EXPECT_TRUE(simulate_timer_task_ran_) << " i = " << i;
@@ -3056,13 +3074,13 @@
 
     compositor_task_runner_->PostTask(
         FROM_HERE,
-        base::Bind(&RendererSchedulerImplTest::SimulateMainThreadCompositorTask,
-                   base::Unretained(this),
-                   base::TimeDelta::FromMilliseconds(8)));
+        base::BindOnce(
+            &RendererSchedulerImplTest::SimulateMainThreadCompositorTask,
+            base::Unretained(this), base::TimeDelta::FromMilliseconds(8)));
     timer_task_runner_->PostTask(
-        FROM_HERE, base::Bind(&RendererSchedulerImplTest::SimulateTimerTask,
-                              base::Unretained(this),
-                              base::TimeDelta::FromMilliseconds(40)));
+        FROM_HERE, base::BindOnce(&RendererSchedulerImplTest::SimulateTimerTask,
+                                  base::Unretained(this),
+                                  base::TimeDelta::FromMilliseconds(40)));
 
     RunUntilIdle();
     EXPECT_TRUE(simulate_timer_task_ran_) << " i = " << i;
@@ -3096,14 +3114,15 @@
     scheduler_->WillBeginFrame(begin_frame_args);
 
     compositor_task_runner_->PostTask(
-        FROM_HERE, base::Bind(&RendererSchedulerImplTest::
-                                  SimulateMainThreadInputHandlingCompositorTask,
-                              base::Unretained(this),
-                              base::TimeDelta::FromMilliseconds(8)));
+        FROM_HERE,
+        base::BindOnce(&RendererSchedulerImplTest::
+                           SimulateMainThreadInputHandlingCompositorTask,
+                       base::Unretained(this),
+                       base::TimeDelta::FromMilliseconds(8)));
     timer_task_runner_->PostTask(
-        FROM_HERE, base::Bind(&RendererSchedulerImplTest::SimulateTimerTask,
-                              base::Unretained(this),
-                              base::TimeDelta::FromMilliseconds(10)));
+        FROM_HERE, base::BindOnce(&RendererSchedulerImplTest::SimulateTimerTask,
+                                  base::Unretained(this),
+                                  base::TimeDelta::FromMilliseconds(10)));
 
     RunUntilIdle();
     EXPECT_EQ(RendererSchedulerImpl::UseCase::kMainThreadCustomInputHandling,
@@ -3162,9 +3181,10 @@
 
   compositor_task_runner_->PostTask(
       FROM_HERE,
-      base::Bind(&RendererSchedulerImplTest::
-                     SimulateMainThreadInputHandlingCompositorTask,
-                 base::Unretained(this), base::TimeDelta::FromMilliseconds(5)));
+      base::BindOnce(&RendererSchedulerImplTest::
+                         SimulateMainThreadInputHandlingCompositorTask,
+                     base::Unretained(this),
+                     base::TimeDelta::FromMilliseconds(5)));
 
   RunUntilIdle();
   EXPECT_EQ(UseCase::kMainThreadGesture, CurrentUseCase());
@@ -3186,9 +3206,10 @@
 
   compositor_task_runner_->PostTask(
       FROM_HERE,
-      base::Bind(&RendererSchedulerImplTest::
-                     SimulateMainThreadInputHandlingCompositorTask,
-                 base::Unretained(this), base::TimeDelta::FromMilliseconds(5)));
+      base::BindOnce(&RendererSchedulerImplTest::
+                         SimulateMainThreadInputHandlingCompositorTask,
+                     base::Unretained(this),
+                     base::TimeDelta::FromMilliseconds(5)));
 
   RunUntilIdle();
   EXPECT_EQ(UseCase::kMainThreadCustomInputHandling, CurrentUseCase());
@@ -3211,8 +3232,9 @@
 
   compositor_task_runner_->PostTask(
       FROM_HERE,
-      base::Bind(&RendererSchedulerImplTest::SimulateMainThreadCompositorTask,
-                 base::Unretained(this), base::TimeDelta::FromMilliseconds(5)));
+      base::BindOnce(
+          &RendererSchedulerImplTest::SimulateMainThreadCompositorTask,
+          base::Unretained(this), base::TimeDelta::FromMilliseconds(5)));
 
   RunUntilIdle();
   EXPECT_EQ(UseCase::kSynchronizedGesture, CurrentUseCase());
@@ -3249,8 +3271,9 @@
                       scoped_refptr<base::SingleThreadTaskRunner> timer_queue) {
   clock->Advance(base::TimeDelta::FromMilliseconds(task_duration));
   if (++(*count) < 500) {
-    timer_queue->PostTask(FROM_HERE, base::Bind(SlowCountingTask, count, clock,
-                                                task_duration, timer_queue));
+    timer_queue->PostTask(
+        FROM_HERE, base::BindOnce(SlowCountingTask, count, clock, task_duration,
+                                  timer_queue));
   }
 }
 }
@@ -3283,13 +3306,13 @@
     simulate_compositor_task_ran_ = false;
     compositor_task_runner_->PostTask(
         FROM_HERE,
-        base::Bind(&RendererSchedulerImplTest::SimulateMainThreadCompositorTask,
-                   base::Unretained(this),
-                   base::TimeDelta::FromMilliseconds(10)));
+        base::BindOnce(
+            &RendererSchedulerImplTest::SimulateMainThreadCompositorTask,
+            base::Unretained(this), base::TimeDelta::FromMilliseconds(10)));
 
-    mock_task_runner_->RunTasksWhile(
-        base::Bind(&RendererSchedulerImplTest::SimulatedCompositorTaskPending,
-                   base::Unretained(this)));
+    mock_task_runner_->RunTasksWhile(base::BindRepeating(
+        &RendererSchedulerImplTest::SimulatedCompositorTaskPending,
+        base::Unretained(this)));
     EXPECT_EQ(UseCase::kSynchronizedGesture, CurrentUseCase()) << "i = " << i;
 
     // We expect the queue to get throttled on the second iteration which is
@@ -3347,13 +3370,13 @@
     simulate_compositor_task_ran_ = false;
     compositor_task_runner_->PostTask(
         FROM_HERE,
-        base::Bind(&RendererSchedulerImplTest::SimulateMainThreadCompositorTask,
-                   base::Unretained(this),
-                   base::TimeDelta::FromMilliseconds(10)));
+        base::BindOnce(
+            &RendererSchedulerImplTest::SimulateMainThreadCompositorTask,
+            base::Unretained(this), base::TimeDelta::FromMilliseconds(10)));
 
-    mock_task_runner_->RunTasksWhile(
-        base::Bind(&RendererSchedulerImplTest::SimulatedCompositorTaskPending,
-                   base::Unretained(this)));
+    mock_task_runner_->RunTasksWhile(base::BindRepeating(
+        &RendererSchedulerImplTest::SimulatedCompositorTaskPending,
+        base::Unretained(this)));
     EXPECT_EQ(UseCase::kSynchronizedGesture, CurrentUseCase()) << "i = " << i;
 
     // Before the policy is updated the queue will be enabled. Subsequently it
@@ -3403,13 +3426,13 @@
     simulate_compositor_task_ran_ = false;
     compositor_task_runner_->PostTask(
         FROM_HERE,
-        base::Bind(&RendererSchedulerImplTest::SimulateMainThreadCompositorTask,
-                   base::Unretained(this),
-                   base::TimeDelta::FromMilliseconds(10)));
+        base::BindOnce(
+            &RendererSchedulerImplTest::SimulateMainThreadCompositorTask,
+            base::Unretained(this), base::TimeDelta::FromMilliseconds(10)));
 
-    mock_task_runner_->RunTasksWhile(
-        base::Bind(&RendererSchedulerImplTest::SimulatedCompositorTaskPending,
-                   base::Unretained(this)));
+    mock_task_runner_->RunTasksWhile(base::BindRepeating(
+        &RendererSchedulerImplTest::SimulatedCompositorTaskPending,
+        base::Unretained(this)));
     EXPECT_EQ(UseCase::kSynchronizedGesture, CurrentUseCase()) << "i = " << i;
     EXPECT_TRUE(timer_task_runner_->IsQueueEnabled()) << "i = " << i;
   }
@@ -3505,13 +3528,13 @@
     simulate_compositor_task_ran_ = false;
     compositor_task_runner_->PostTask(
         FROM_HERE,
-        base::Bind(&RendererSchedulerImplTest::SimulateMainThreadCompositorTask,
-                   base::Unretained(this),
-                   base::TimeDelta::FromMilliseconds(20)));
+        base::BindOnce(
+            &RendererSchedulerImplTest::SimulateMainThreadCompositorTask,
+            base::Unretained(this), base::TimeDelta::FromMilliseconds(20)));
 
-    mock_task_runner_->RunTasksWhile(
-        base::Bind(&RendererSchedulerImplTest::SimulatedCompositorTaskPending,
-                   base::Unretained(this)));
+    mock_task_runner_->RunTasksWhile(base::BindRepeating(
+        &RendererSchedulerImplTest::SimulatedCompositorTaskPending,
+        base::Unretained(this)));
     EXPECT_EQ(UseCase::kSynchronizedGesture, CurrentUseCase()) << "i = " << i;
   }
 
@@ -3547,13 +3570,13 @@
     simulate_compositor_task_ran_ = false;
     compositor_task_runner_->PostTask(
         FROM_HERE,
-        base::Bind(&RendererSchedulerImplTest::SimulateMainThreadCompositorTask,
-                   base::Unretained(this),
-                   base::TimeDelta::FromMilliseconds(20)));
+        base::BindOnce(
+            &RendererSchedulerImplTest::SimulateMainThreadCompositorTask,
+            base::Unretained(this), base::TimeDelta::FromMilliseconds(20)));
 
-    mock_task_runner_->RunTasksWhile(
-        base::Bind(&RendererSchedulerImplTest::SimulatedCompositorTaskPending,
-                   base::Unretained(this)));
+    mock_task_runner_->RunTasksWhile(base::BindRepeating(
+        &RendererSchedulerImplTest::SimulatedCompositorTaskPending,
+        base::Unretained(this)));
     EXPECT_EQ(UseCase::kMainThreadCustomInputHandling, CurrentUseCase())
         << "i = " << i;
   }
@@ -3591,13 +3614,13 @@
     simulate_compositor_task_ran_ = false;
     compositor_task_runner_->PostTask(
         FROM_HERE,
-        base::Bind(&RendererSchedulerImplTest::SimulateMainThreadCompositorTask,
-                   base::Unretained(this),
-                   base::TimeDelta::FromMilliseconds(20)));
+        base::BindOnce(
+            &RendererSchedulerImplTest::SimulateMainThreadCompositorTask,
+            base::Unretained(this), base::TimeDelta::FromMilliseconds(20)));
 
-    mock_task_runner_->RunTasksWhile(
-        base::Bind(&RendererSchedulerImplTest::SimulatedCompositorTaskPending,
-                   base::Unretained(this)));
+    mock_task_runner_->RunTasksWhile(base::BindRepeating(
+        &RendererSchedulerImplTest::SimulatedCompositorTaskPending,
+        base::Unretained(this)));
     EXPECT_EQ(UseCase::kMainThreadGesture, CurrentUseCase()) << "i = " << i;
   }
 
@@ -3696,11 +3719,11 @@
   size_t timer_count = 0;
   size_t unthrottled_count = 0;
   timer_task_runner_->PostTask(
-      FROM_HERE, base::Bind(SlowCountingTask, &timer_count, &clock_, 7,
-                            timer_task_runner_));
+      FROM_HERE, base::BindOnce(SlowCountingTask, &timer_count, &clock_, 7,
+                                timer_task_runner_));
   unthrottled_task_runner->PostTask(
-      FROM_HERE, base::Bind(SlowCountingTask, &unthrottled_count, &clock_, 7,
-                            unthrottled_task_runner));
+      FROM_HERE, base::BindOnce(SlowCountingTask, &unthrottled_count, &clock_,
+                                7, unthrottled_task_runner));
   auto handle = scheduler_->PauseRenderer();
 
   for (int i = 0; i < 1000; i++) {
@@ -3717,13 +3740,13 @@
     simulate_compositor_task_ran_ = false;
     compositor_task_runner_->PostTask(
         FROM_HERE,
-        base::Bind(&RendererSchedulerImplTest::SimulateMainThreadCompositorTask,
-                   base::Unretained(this),
-                   base::TimeDelta::FromMilliseconds(10)));
+        base::BindOnce(
+            &RendererSchedulerImplTest::SimulateMainThreadCompositorTask,
+            base::Unretained(this), base::TimeDelta::FromMilliseconds(10)));
 
-    mock_task_runner_->RunTasksWhile(
-        base::Bind(&RendererSchedulerImplTest::SimulatedCompositorTaskPending,
-                   base::Unretained(this)));
+    mock_task_runner_->RunTasksWhile(base::BindRepeating(
+        &RendererSchedulerImplTest::SimulatedCompositorTaskPending,
+        base::Unretained(this)));
     EXPECT_EQ(UseCase::kSynchronizedGesture, CurrentUseCase()) << "i = " << i;
   }
 
@@ -3928,7 +3951,7 @@
   std::vector<base::TimeTicks> run_times;
 
   timer_task_runner_->PostTask(
-      FROM_HERE, base::Bind(&RecordingTimeTestTask, &run_times, &clock_));
+      FROM_HERE, base::BindOnce(&RecordingTimeTestTask, &run_times, &clock_));
 
   mock_task_runner_->RunUntilTime(base::TimeTicks() +
                                   base::TimeDelta::FromMilliseconds(1100));
@@ -3939,7 +3962,7 @@
   run_times.clear();
 
   timer_task_runner_->PostDelayedTask(
-      FROM_HERE, base::Bind(&RecordingTimeTestTask, &run_times, &clock_),
+      FROM_HERE, base::BindOnce(&RecordingTimeTestTask, &run_times, &clock_),
       base::TimeDelta::FromMilliseconds(200));
 
   scheduler_->SetRendererBackgrounded(false);
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/task_queue_throttler.cc b/third_party/WebKit/Source/platform/scheduler/renderer/task_queue_throttler.cc
index cc562ee9..362b8ca2 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/task_queue_throttler.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/task_queue_throttler.cc
@@ -73,11 +73,11 @@
       time_domain_(new ThrottledTimeDomain()),
       allow_throttling_(true),
       weak_factory_(this) {
-  pump_throttled_tasks_closure_.Reset(base::Bind(
+  pump_throttled_tasks_closure_.Reset(base::BindRepeating(
       &TaskQueueThrottler::PumpThrottledTasks, weak_factory_.GetWeakPtr()));
   forward_immediate_work_callback_ =
-      base::Bind(&TaskQueueThrottler::OnQueueNextWakeUpChanged,
-                 weak_factory_.GetWeakPtr());
+      base::BindRepeating(&TaskQueueThrottler::OnQueueNextWakeUpChanged,
+                          weak_factory_.GetWeakPtr());
 
   renderer_scheduler_->RegisterTimeDomain(time_domain_.get());
 }
@@ -193,8 +193,8 @@
     base::TimeTicks next_wake_up) {
   if (!control_task_queue_->RunsTasksInCurrentSequence()) {
     control_task_queue_->PostTask(
-        FROM_HERE, base::Bind(forward_immediate_work_callback_,
-                              base::RetainedRef(queue), next_wake_up));
+        FROM_HERE, base::BindOnce(forward_immediate_work_callback_,
+                                  base::RetainedRef(queue), next_wake_up));
     return;
   }
 
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/task_queue_throttler.h b/third_party/WebKit/Source/platform/scheduler/renderer/task_queue_throttler.h
index ed152ba..9fc34d5 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/task_queue_throttler.h
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/task_queue_throttler.h
@@ -198,7 +198,7 @@
                                                    TaskQueue* queue);
 
   TaskQueueMap queue_details_;
-  base::Callback<void(TaskQueue*, base::TimeTicks)>
+  base::RepeatingCallback<void(TaskQueue*, base::TimeTicks)>
       forward_immediate_work_callback_;
   scoped_refptr<TaskQueue> control_task_queue_;
   RendererSchedulerImpl* renderer_scheduler_;  // NOT OWNED
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/web_frame_scheduler_impl.cc b/third_party/WebKit/Source/platform/scheduler/renderer/web_frame_scheduler_impl.cc
index d36288b..e22e088 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/web_frame_scheduler_impl.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/web_frame_scheduler_impl.cc
@@ -122,6 +122,7 @@
                     this,
                     &tracing_controller_,
                     CrossOriginStateToString),
+      url_tracer_("WebFrameScheduler.URL", this),
       frame_type_(frame_type),
       active_connection_count_(0),
       weak_factory_(this) {
@@ -228,6 +229,10 @@
   return cross_origin_;
 }
 
+void WebFrameSchedulerImpl::TraceUrlChange(const String& url) {
+  url_tracer_.TraceString(url);
+}
+
 WebFrameScheduler::FrameType WebFrameSchedulerImpl::GetFrameType() const {
   return frame_type_;
 }
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/web_frame_scheduler_impl.h b/third_party/WebKit/Source/platform/scheduler/renderer/web_frame_scheduler_impl.h
index 742a584..5b29344 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/web_frame_scheduler_impl.h
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/web_frame_scheduler_impl.h
@@ -17,7 +17,6 @@
 #include "platform/scheduler/child/page_visibility_state.h"
 #include "platform/scheduler/child/worker_scheduler_proxy.h"
 #include "platform/scheduler/util/tracing_helper.h"
-#include "platform/wtf/HashSet.h"
 
 namespace base {
 namespace trace_event {
@@ -67,6 +66,7 @@
 
   void SetCrossOrigin(bool cross_origin) override;
   bool IsCrossOrigin() const override;
+  void TraceUrlChange(const String& url) override;
   WebFrameScheduler::FrameType GetFrameType() const override;
   scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner(TaskType) override;
   WebViewScheduler* GetWebViewScheduler() const override;
@@ -166,6 +166,7 @@
   TraceableState<bool, kTracingCategoryNameInfo> page_frozen_;
   TraceableState<bool, kTracingCategoryNameInfo> frame_paused_;
   TraceableState<bool, kTracingCategoryNameInfo> cross_origin_;
+  StateTracer<kTracingCategoryNameInfo> url_tracer_;
   WebFrameScheduler::FrameType frame_type_;
   int active_connection_count_;
 
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/web_frame_scheduler_impl_unittest.cc b/third_party/WebKit/Source/platform/scheduler/renderer/web_frame_scheduler_impl_unittest.cc
index cd5252e..cd8018e01 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/web_frame_scheduler_impl_unittest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/web_frame_scheduler_impl_unittest.cc
@@ -115,10 +115,10 @@
 
 void RunRepeatingTask(scoped_refptr<TaskQueue> task_queue, int* run_count);
 
-base::Closure MakeRepeatingTask(scoped_refptr<TaskQueue> task_queue,
-                                int* run_count) {
-  return base::Bind(&RunRepeatingTask, base::Passed(std::move(task_queue)),
-                    base::Unretained(run_count));
+base::OnceClosure MakeRepeatingTask(scoped_refptr<TaskQueue> task_queue,
+                                    int* run_count) {
+  return base::BindOnce(&RunRepeatingTask, std::move(task_queue),
+                        base::Unretained(run_count));
 }
 
 void RunRepeatingTask(scoped_refptr<TaskQueue> task_queue, int* run_count) {
@@ -240,15 +240,15 @@
 TEST_F(WebFrameSchedulerImplTest, PauseAndResume) {
   int counter = 0;
   LoadingTaskQueue()->PostTask(
-      FROM_HERE, base::Bind(&IncrementCounter, base::Unretained(&counter)));
+      FROM_HERE, base::BindOnce(&IncrementCounter, base::Unretained(&counter)));
   ThrottleableTaskQueue()->PostTask(
-      FROM_HERE, base::Bind(&IncrementCounter, base::Unretained(&counter)));
+      FROM_HERE, base::BindOnce(&IncrementCounter, base::Unretained(&counter)));
   DeferrableTaskQueue()->PostTask(
-      FROM_HERE, base::Bind(&IncrementCounter, base::Unretained(&counter)));
+      FROM_HERE, base::BindOnce(&IncrementCounter, base::Unretained(&counter)));
   PausableTaskQueue()->PostTask(
-      FROM_HERE, base::Bind(&IncrementCounter, base::Unretained(&counter)));
+      FROM_HERE, base::BindOnce(&IncrementCounter, base::Unretained(&counter)));
   UnpausableTaskQueue()->PostTask(
-      FROM_HERE, base::Bind(&IncrementCounter, base::Unretained(&counter)));
+      FROM_HERE, base::BindOnce(&IncrementCounter, base::Unretained(&counter)));
 
   web_frame_scheduler_->SetPaused(true);
 
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler_impl_unittest.cc b/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler_impl_unittest.cc
index bfac5416..326ae82 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler_impl_unittest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/web_view_scheduler_impl_unittest.cc
@@ -111,10 +111,10 @@
 
 void RunRepeatingTask(scoped_refptr<TaskQueue> task_queue, int* run_count);
 
-base::Closure MakeRepeatingTask(scoped_refptr<TaskQueue> task_queue,
-                                int* run_count) {
-  return base::Bind(&RunRepeatingTask, base::Passed(std::move(task_queue)),
-                    base::Unretained(run_count));
+base::OnceClosure MakeRepeatingTask(scoped_refptr<TaskQueue> task_queue,
+                                    int* run_count) {
+  return base::BindOnce(&RunRepeatingTask, std::move(task_queue),
+                        base::Unretained(run_count));
 }
 
 void RunRepeatingTask(scoped_refptr<TaskQueue> task_queue, int* run_count) {
@@ -334,8 +334,9 @@
                          scoped_refptr<TaskQueue> task_queue,
                          std::vector<int>* out_run_order) {
   out_run_order->push_back(index);
-  task_queue->PostTask(FROM_HERE, base::Bind(&RunOrderTask, index + 1,
-                                             base::Unretained(out_run_order)));
+  task_queue->PostTask(FROM_HERE,
+                       base::BindOnce(&RunOrderTask, index + 1,
+                                      base::Unretained(out_run_order)));
 }
 }
 
@@ -346,18 +347,19 @@
   web_view_scheduler_->EnableVirtualTime();
 
   ThrottleableTaskQueue()->PostTask(
-      FROM_HERE, base::Bind(&RunOrderTask, 0, base::Unretained(&run_order)));
+      FROM_HERE,
+      base::BindOnce(&RunOrderTask, 0, base::Unretained(&run_order)));
 
   ThrottleableTaskQueue()->PostDelayedTask(
       FROM_HERE,
-      base::Bind(&DelayedRunOrderTask, 1, base::Passed(ThrottleableTaskQueue()),
-                 base::Unretained(&run_order)),
+      base::BindOnce(&DelayedRunOrderTask, 1, ThrottleableTaskQueue(),
+                     base::Unretained(&run_order)),
       base::TimeDelta::FromMilliseconds(2));
 
   ThrottleableTaskQueue()->PostDelayedTask(
       FROM_HERE,
-      base::Bind(&DelayedRunOrderTask, 3, base::Passed(ThrottleableTaskQueue()),
-                 base::Unretained(&run_order)),
+      base::BindOnce(&DelayedRunOrderTask, 3, ThrottleableTaskQueue(),
+                     base::Unretained(&run_order)),
       base::TimeDelta::FromMilliseconds(4));
 
   mock_task_runner_->RunUntilIdle();
@@ -373,18 +375,19 @@
   web_view_scheduler_->EnableVirtualTime();
 
   ThrottleableTaskQueue()->PostTask(
-      FROM_HERE, base::Bind(&RunOrderTask, 0, base::Unretained(&run_order)));
+      FROM_HERE,
+      base::BindOnce(&RunOrderTask, 0, base::Unretained(&run_order)));
 
   ThrottleableTaskQueue()->PostDelayedTask(
       FROM_HERE,
-      base::Bind(&DelayedRunOrderTask, 1, base::Passed(ThrottleableTaskQueue()),
-                 base::Unretained(&run_order)),
+      base::BindOnce(&DelayedRunOrderTask, 1, ThrottleableTaskQueue(),
+                     base::Unretained(&run_order)),
       base::TimeDelta::FromMilliseconds(2));
 
   ThrottleableTaskQueue()->PostDelayedTask(
       FROM_HERE,
-      base::Bind(&DelayedRunOrderTask, 3, base::Passed(ThrottleableTaskQueue()),
-                 base::Unretained(&run_order)),
+      base::BindOnce(&DelayedRunOrderTask, 3, ThrottleableTaskQueue(),
+                     base::Unretained(&run_order)),
       base::TimeDelta::FromMilliseconds(4));
 
   mock_task_runner_->RunUntilIdle();
@@ -427,7 +430,8 @@
 
   ThrottleableTaskQueueForScheduler(web_frame_scheduler.get())
       ->PostDelayedTask(
-          FROM_HERE, base::Bind(&RunOrderTask, 1, base::Unretained(&run_order)),
+          FROM_HERE,
+          base::BindOnce(&RunOrderTask, 1, base::Unretained(&run_order)),
           base::TimeDelta::FromMilliseconds(1));
 
   mock_task_runner_->RunUntilIdle();
@@ -442,8 +446,8 @@
 namespace {
 
 template <typename T>
-base::Closure MakeDeletionTask(T* obj) {
-  return base::Bind([](T* obj) { delete obj; }, base::Unretained(obj));
+base::OnceClosure MakeDeletionTask(T* obj) {
+  return base::BindOnce([](T* obj) { delete obj; }, base::Unretained(obj));
 }
 
 }  // namespace
@@ -597,8 +601,8 @@
   web_view_scheduler_->EnableVirtualTime();
 
   ThrottleableTaskQueueForScheduler(web_frame_scheduler.get())
-      ->PostTask(FROM_HERE,
-                 base::Bind(&RunOrderTask, 1, base::Unretained(&run_order)));
+      ->PostTask(FROM_HERE, base::BindOnce(&RunOrderTask, 1,
+                                           base::Unretained(&run_order)));
 
   mock_task_runner_->RunUntilIdle();
   EXPECT_TRUE(run_order.empty());
@@ -698,13 +702,16 @@
   web_view_scheduler_->EnableVirtualTime();
 
   ThrottleableTaskQueue()->PostDelayedTask(
-      FROM_HERE, base::Bind(&NopTask), base::TimeDelta::FromMilliseconds(200));
+      FROM_HERE, base::BindOnce(&NopTask),
+      base::TimeDelta::FromMilliseconds(200));
 
   ThrottleableTaskQueue()->PostDelayedTask(
-      FROM_HERE, base::Bind(&NopTask), base::TimeDelta::FromMilliseconds(20));
+      FROM_HERE, base::BindOnce(&NopTask),
+      base::TimeDelta::FromMilliseconds(20));
 
   ThrottleableTaskQueue()->PostDelayedTask(
-      FROM_HERE, base::Bind(&NopTask), base::TimeDelta::FromMilliseconds(2));
+      FROM_HERE, base::BindOnce(&NopTask),
+      base::TimeDelta::FromMilliseconds(2));
 
   web_view_scheduler_->GrantVirtualTimeBudget(
       base::TimeDelta::FromMilliseconds(1000),
@@ -731,8 +738,8 @@
     return;
 
   task_queue->PostTask(FROM_HERE,
-                       base::Bind(&RepostingTask, task_queue, max_count,
-                                  base::Unretained(count)));
+                       base::BindOnce(&RepostingTask, task_queue, max_count,
+                                      base::Unretained(count)));
 }
 
 void DelayedTask(int* count_in, int* count_out) {
@@ -751,8 +758,8 @@
   RepostingTask(ThrottleableTaskQueue(), 1000, &count);
   ThrottleableTaskQueue()->PostDelayedTask(
       FROM_HERE,
-      base::Bind(DelayedTask, base::Unretained(&count),
-                 base::Unretained(&delayed_task_run_at_count)),
+      base::BindOnce(DelayedTask, base::Unretained(&count),
+                     base::Unretained(&delayed_task_run_at_count)),
       base::TimeDelta::FromMilliseconds(10));
 
   web_view_scheduler_->GrantVirtualTimeBudget(
@@ -782,8 +789,8 @@
   RepostingTask(ThrottleableTaskQueue(), 1000, &count);
   ThrottleableTaskQueue()->PostDelayedTask(
       FROM_HERE,
-      base::Bind(DelayedTask, WTF::Unretained(&count),
-                 WTF::Unretained(&delayed_task_run_at_count)),
+      base::BindOnce(DelayedTask, WTF::Unretained(&count),
+                     WTF::Unretained(&delayed_task_run_at_count)),
       base::TimeDelta::FromMilliseconds(10));
 
   web_view_scheduler_->GrantVirtualTimeBudget(
@@ -810,8 +817,8 @@
   RepostingTask(ThrottleableTaskQueue(), 1000, &count);
   ThrottleableTaskQueue()->PostDelayedTask(
       FROM_HERE,
-      base::Bind(DelayedTask, WTF::Unretained(&count),
-                 WTF::Unretained(&delayed_task_run_at_count)),
+      base::BindOnce(DelayedTask, WTF::Unretained(&count),
+                     WTF::Unretained(&delayed_task_run_at_count)),
       base::TimeDelta::FromMilliseconds(10));
 
   web_view_scheduler_->GrantVirtualTimeBudget(
@@ -874,10 +881,10 @@
                                   base::TimeDelta::FromMilliseconds(2500));
 
   ThrottleableTaskQueue()->PostDelayedTask(
-      FROM_HERE, base::Bind(&ExpensiveTestTask, &clock_, &run_times),
+      FROM_HERE, base::BindOnce(&ExpensiveTestTask, &clock_, &run_times),
       base::TimeDelta::FromMilliseconds(1));
   ThrottleableTaskQueue()->PostDelayedTask(
-      FROM_HERE, base::Bind(&ExpensiveTestTask, &clock_, &run_times),
+      FROM_HERE, base::BindOnce(&ExpensiveTestTask, &clock_, &run_times),
       base::TimeDelta::FromMilliseconds(1));
 
   mock_task_runner_->RunUntilTime(base::TimeTicks() +
@@ -894,10 +901,10 @@
   web_view_scheduler_->SetPageVisible(false);
 
   ThrottleableTaskQueue()->PostDelayedTask(
-      FROM_HERE, base::Bind(&ExpensiveTestTask, &clock_, &run_times),
+      FROM_HERE, base::BindOnce(&ExpensiveTestTask, &clock_, &run_times),
       base::TimeDelta::FromMicroseconds(1));
   ThrottleableTaskQueue()->PostDelayedTask(
-      FROM_HERE, base::Bind(&ExpensiveTestTask, &clock_, &run_times),
+      FROM_HERE, base::BindOnce(&ExpensiveTestTask, &clock_, &run_times),
       base::TimeDelta::FromMicroseconds(1));
 
   mock_task_runner_->RunUntilIdle();
@@ -938,9 +945,9 @@
 
   for (size_t i = 0; i < 3; ++i) {
     ThrottleableTaskQueueForScheduler(web_frame_scheduler1.get())
-        ->PostDelayedTask(FROM_HERE,
-                          base::Bind(&ExpensiveTestTask, &clock_, &run_times),
-                          base::TimeDelta::FromMilliseconds(1));
+        ->PostDelayedTask(
+            FROM_HERE, base::BindOnce(&ExpensiveTestTask, &clock_, &run_times),
+            base::TimeDelta::FromMilliseconds(1));
   }
 
   mock_task_runner_->RunUntilTime(base::TimeTicks() +
@@ -959,9 +966,9 @@
 
   for (size_t i = 0; i < 3; ++i) {
     ThrottleableTaskQueueForScheduler(web_frame_scheduler1.get())
-        ->PostDelayedTask(FROM_HERE,
-                          base::Bind(&ExpensiveTestTask, &clock_, &run_times),
-                          base::TimeDelta::FromMilliseconds(1));
+        ->PostDelayedTask(
+            FROM_HERE, base::BindOnce(&ExpensiveTestTask, &clock_, &run_times),
+            base::TimeDelta::FromMilliseconds(1));
   }
 
   mock_task_runner_->RunUntilTime(base::TimeTicks() +
@@ -979,9 +986,9 @@
 
   for (size_t i = 0; i < 3; ++i) {
     ThrottleableTaskQueueForScheduler(web_frame_scheduler2.get())
-        ->PostDelayedTask(FROM_HERE,
-                          base::Bind(&ExpensiveTestTask, &clock_, &run_times),
-                          base::TimeDelta::FromMilliseconds(1));
+        ->PostDelayedTask(
+            FROM_HERE, base::BindOnce(&ExpensiveTestTask, &clock_, &run_times),
+            base::TimeDelta::FromMilliseconds(1));
   }
 
   mock_task_runner_->RunUntilTime(base::TimeTicks() +
@@ -1004,9 +1011,9 @@
 
   for (size_t i = 0; i < 3; ++i) {
     ThrottleableTaskQueueForScheduler(web_frame_scheduler1.get())
-        ->PostDelayedTask(FROM_HERE,
-                          base::Bind(&ExpensiveTestTask, &clock_, &run_times),
-                          base::TimeDelta::FromMilliseconds(1));
+        ->PostDelayedTask(
+            FROM_HERE, base::BindOnce(&ExpensiveTestTask, &clock_, &run_times),
+            base::TimeDelta::FromMilliseconds(1));
   }
 
   mock_task_runner_->RunUntilIdle();
diff --git a/third_party/WebKit/Source/platform/scheduler/renderer/webthread_impl_for_renderer_scheduler_unittest.cc b/third_party/WebKit/Source/platform/scheduler/renderer/webthread_impl_for_renderer_scheduler_unittest.cc
index 6e04533..a5f80a61 100644
--- a/third_party/WebKit/Source/platform/scheduler/renderer/webthread_impl_for_renderer_scheduler_unittest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/renderer/webthread_impl_for_renderer_scheduler_unittest.cc
@@ -194,8 +194,8 @@
   }
 
   message_loop_.task_runner()->PostTask(
-      FROM_HERE, base::Bind(&EnterRunLoop, base::Unretained(&message_loop_),
-                            base::Unretained(thread_.get())));
+      FROM_HERE, base::BindOnce(&EnterRunLoop, base::Unretained(&message_loop_),
+                                base::Unretained(thread_.get())));
   base::RunLoop().RunUntilIdle();
   thread_->RemoveTaskObserver(&observer);
 }
diff --git a/third_party/WebKit/Source/platform/scheduler/test/fake_web_frame_scheduler.h b/third_party/WebKit/Source/platform/scheduler/test/fake_web_frame_scheduler.h
index fb35c7de..ef77709 100644
--- a/third_party/WebKit/Source/platform/scheduler/test/fake_web_frame_scheduler.h
+++ b/third_party/WebKit/Source/platform/scheduler/test/fake_web_frame_scheduler.h
@@ -113,6 +113,7 @@
   void SetPaused(bool) override {}
   void SetCrossOrigin(bool) override {}
   bool IsCrossOrigin() const override { return is_cross_origin_; }
+  void TraceUrlChange(const String&) override {}
   WebFrameScheduler::FrameType GetFrameType() const override {
     return frame_type_;
   }
diff --git a/third_party/WebKit/Source/platform/scheduler/util/thread_load_tracker.h b/third_party/WebKit/Source/platform/scheduler/util/thread_load_tracker.h
index 6a9b31d..23f0d76 100644
--- a/third_party/WebKit/Source/platform/scheduler/util/thread_load_tracker.h
+++ b/third_party/WebKit/Source/platform/scheduler/util/thread_load_tracker.h
@@ -21,7 +21,7 @@
 class PLATFORM_EXPORT ThreadLoadTracker {
  public:
   // Callback is called with (current_time, load_level) parameters.
-  using Callback = base::Callback<void(base::TimeTicks, double)>;
+  using Callback = base::RepeatingCallback<void(base::TimeTicks, double)>;
 
   ThreadLoadTracker(base::TimeTicks now,
                     const Callback& callback,
diff --git a/third_party/WebKit/Source/platform/scheduler/util/thread_load_tracker_unittest.cc b/third_party/WebKit/Source/platform/scheduler/util/thread_load_tracker_unittest.cc
index 83e925cb..5e8a259 100644
--- a/third_party/WebKit/Source/platform/scheduler/util/thread_load_tracker_unittest.cc
+++ b/third_party/WebKit/Source/platform/scheduler/util/thread_load_tracker_unittest.cc
@@ -31,7 +31,8 @@
   std::vector<std::pair<base::TimeTicks, double>> result;
 
   ThreadLoadTracker thread_load_tracker(
-      SecondsToTime(1), base::Bind(&AddToVector, base::Unretained(&result)),
+      SecondsToTime(1),
+      base::BindRepeating(&AddToVector, base::Unretained(&result)),
       base::TimeDelta::FromSeconds(1));
   thread_load_tracker.Resume(SecondsToTime(1));
 
@@ -66,7 +67,8 @@
   std::vector<std::pair<base::TimeTicks, double>> result;
 
   ThreadLoadTracker thread_load_tracker(
-      SecondsToTime(1), base::Bind(&AddToVector, base::Unretained(&result)),
+      SecondsToTime(1),
+      base::BindRepeating(&AddToVector, base::Unretained(&result)),
       base::TimeDelta::FromSeconds(1));
   thread_load_tracker.Resume(SecondsToTime(1));
 
@@ -102,7 +104,8 @@
 TEST(ThreadLoadTrackerTest, DisabledByDefault) {
   std::vector<std::pair<base::TimeTicks, double>> result;
   ThreadLoadTracker thread_load_tracker(
-      SecondsToTime(1), base::Bind(&AddToVector, base::Unretained(&result)),
+      SecondsToTime(1),
+      base::BindRepeating(&AddToVector, base::Unretained(&result)),
       base::TimeDelta::FromSeconds(1));
 
   // ThreadLoadTracker should be disabled and these tasks should be
@@ -121,7 +124,8 @@
 TEST(ThreadLoadTrackerTest, Reset) {
   std::vector<std::pair<base::TimeTicks, double>> result;
   ThreadLoadTracker thread_load_tracker(
-      SecondsToTime(1), base::Bind(&AddToVector, base::Unretained(&result)),
+      SecondsToTime(1),
+      base::BindRepeating(&AddToVector, base::Unretained(&result)),
       base::TimeDelta::FromSeconds(1));
 
   thread_load_tracker.Resume(SecondsToTime(1));
diff --git a/third_party/WebKit/Source/platform/scheduler/util/tracing_helper.h b/third_party/WebKit/Source/platform/scheduler/util/tracing_helper.h
index 743a037..728f7d1 100644
--- a/third_party/WebKit/Source/platform/scheduler/util/tracing_helper.h
+++ b/third_party/WebKit/Source/platform/scheduler/util/tracing_helper.h
@@ -13,6 +13,7 @@
 #include "base/time/time.h"
 #include "base/trace_event/trace_event.h"
 #include "platform/PlatformExport.h"
+#include "platform/wtf/text/WTFString.h"
 
 namespace blink {
 namespace scheduler {
@@ -80,9 +81,77 @@
 // of category. Hence, we need distinct version for each category in order to
 // prevent unintended leak of state.
 
-template <typename T, const char* category>
-class TraceableState : public TraceableVariable {
+template <const char* category>
+class StateTracer {
  public:
+  StateTracer(const char* name, const void* object)
+      : name_(name), object_(object), slice_is_open_(false) {
+    internal::ValidateTracingCategory(category);
+  }
+
+  ~StateTracer() {
+    if (slice_is_open_)
+      TRACE_EVENT_ASYNC_END0(category, name_, object_);
+  }
+
+  // String will be copied before leaving this function.
+  void TraceString(const String& state) {
+    TraceImpl(state.Utf8().data(), true);
+  }
+
+  // Trace compile-time defined const string, so no copy needed.
+  // Null may be passed to indicate the absence of state.
+  void TraceCompileTimeString(const char* state) {
+    TraceImpl(state, false);
+  }
+
+ protected:
+  bool is_enabled() const {
+    bool result = false;
+    TRACE_EVENT_CATEGORY_GROUP_ENABLED(category, &result);  // Cached.
+    return result;
+  }
+
+ private:
+  void TraceImpl(const char* state, bool need_copy) {
+    if (slice_is_open_) {
+      TRACE_EVENT_ASYNC_END0(category, name_, object_);
+      slice_is_open_ = false;
+    }
+    if (!state || !is_enabled())
+      return;
+
+    // Trace viewer logic relies on subslice starting at the exact same time
+    // as the async event.
+    base::TimeTicks now = TRACE_TIME_TICKS_NOW();
+    TRACE_EVENT_ASYNC_BEGIN_WITH_TIMESTAMP0(category, name_, object_, now);
+    if (need_copy) {
+      TRACE_EVENT_ASYNC_STEP_INTO_WITH_TIMESTAMP0(category, name_, object_,
+                                                  TRACE_STR_COPY(state), now);
+    } else {
+      TRACE_EVENT_ASYNC_STEP_INTO_WITH_TIMESTAMP0(category, name_, object_,
+                                                  state, now);
+    }
+    slice_is_open_ = true;
+  }
+
+  const char* const name_;    // Not owned.
+  const void* const object_;  // Not owned.
+
+  // We have to track whether slice is open to avoid confusion since assignment,
+  // "absent" state and OnTraceLogEnabled can happen anytime.
+  bool slice_is_open_;
+
+  DISALLOW_COPY_AND_ASSIGN(StateTracer);
+};
+
+// TODO(kraynov): Rename to something less generic and reflecting
+// the enum nature of such variables.
+template <typename T, const char* category>
+class TraceableState : public TraceableVariable, private StateTracer<category> {
+ public:
+  // Converter must return compile-time defined const strings because tracing
+  // will not make a copy of them.
   using ConverterFuncPtr = const char* (*)(T);
 
   TraceableState(T initial_state,
@@ -91,19 +160,13 @@
                  TraceableVariableController* controller,
                  ConverterFuncPtr converter)
       : TraceableVariable(controller),
-        name_(name),
-        object_(object),
+        StateTracer<category>(name, object),
         converter_(converter),
-        state_(initial_state),
-        slice_is_open_(false) {
-    internal::ValidateTracingCategory(category);
+        state_(initial_state) {
     Trace();
   }
 
-  ~TraceableState() override {
-    if (slice_is_open_)
-      TRACE_EVENT_ASYNC_END0(category, name_, object_);
-  }
+  ~TraceableState() override = default;
 
   TraceableState& operator =(const T& value) {
     Assign(value);
@@ -142,40 +205,19 @@
       return;
     }
 
-    if (slice_is_open_) {
-      TRACE_EVENT_ASYNC_END0(category, name_, object_);
-      slice_is_open_ = false;
+    // Null state string means the absence of state.
+    const char* state_str = nullptr;
+    if (StateTracer<category>::is_enabled()) {
+      state_str = converter_(state_);
     }
-    if (!is_enabled())
-      return;
-    // Converter returns nullptr to indicate the absence of state.
-    const char* state_str = converter_(state_);
-    if (!state_str)
-      return;
 
-    // Trace viewer logic relies on subslice starting at the exact same time
-    // as the async event.
-    base::TimeTicks now = base::TimeTicks::Now();
-    TRACE_EVENT_ASYNC_BEGIN_WITH_TIMESTAMP0(category, name_, object_, now);
-    TRACE_EVENT_ASYNC_STEP_INTO_WITH_TIMESTAMP0(category, name_, object_,
-                                                state_str, now);
-    slice_is_open_ = true;
+    // We have to be explicit to deal with two-phase name lookup in templates:
+    // http://blog.llvm.org/2009/12/dreaded-two-phase-name-lookup.html
+    StateTracer<category>::TraceCompileTimeString(state_str);
   }
 
-  bool is_enabled() const {
-    bool result = false;
-    TRACE_EVENT_CATEGORY_GROUP_ENABLED(category, &result);  // Cached.
-    return result;
-  }
-
-  const char* const name_;  // Not owned.
-  const void* const object_;  // Not owned.
   const ConverterFuncPtr converter_;
-
   T state_;
-  // We have to track whether slice is open to avoid confusion since assignment,
-  // "absent" state and OnTraceLogEnabled can happen anytime.
-  bool slice_is_open_;
 
   DISALLOW_COPY(TraceableState);
 };
diff --git a/third_party/WebKit/Source/platform/wtf/HashTable.h b/third_party/WebKit/Source/platform/wtf/HashTable.h
index 6fb75807..9dde70b 100644
--- a/third_party/WebKit/Source/platform/wtf/HashTable.h
+++ b/third_party/WebKit/Source/platform/wtf/HashTable.h
@@ -2102,14 +2102,11 @@
   if (!table_)
     return;
 
-  // Backing store can be moved during compaction.
-  Allocator::RegisterBackingStoreReference(visitor, &table_);
-
   if (Traits::kWeakHandlingFlag == kNoWeakHandling) {
     // Strong HashTable.
     DCHECK(IsTraceableInCollectionTrait<Traits>::value);
-    Allocator::template TraceHashTableBacking<ValueType, HashTable>(visitor,
-                                                                    table_);
+    Allocator::template TraceHashTableBackingStrongly<ValueType, HashTable>(
+        visitor, table_, &table_);
   } else {
     // Weak HashTable. The HashTable may be held alive strongly from somewhere
     // else, e.g., an iterator.
@@ -2117,7 +2114,9 @@
     // Marking of the table is delayed because the backing store is potentially
     // held alive strongly by other objects. Delayed marking happens after
     // regular marking.
-    Allocator::RegisterDelayedMarkNoTracing(visitor, table_);
+    Allocator::template TraceHashTableBackingWeakly<ValueType, HashTable>(
+        visitor, table_, &table_);
+
     // It is safe to register the table multiple times.
     Allocator::RegisterWeakMembers(
         visitor, this,
diff --git a/third_party/WebKit/public/platform/InterfaceRegistry.h b/third_party/WebKit/public/platform/InterfaceRegistry.h
index bbed26f3..0cc0770 100644
--- a/third_party/WebKit/public/platform/InterfaceRegistry.h
+++ b/third_party/WebKit/public/platform/InterfaceRegistry.h
@@ -24,9 +24,10 @@
 
 namespace blink {
 
-using InterfaceFactory = base::Callback<void(mojo::ScopedMessagePipeHandle)>;
+using InterfaceFactory =
+    base::RepeatingCallback<void(mojo::ScopedMessagePipeHandle)>;
 using AssociatedInterfaceFactory =
-    base::Callback<void(mojo::ScopedInterfaceEndpointHandle)>;
+    base::RepeatingCallback<void(mojo::ScopedInterfaceEndpointHandle)>;
 
 class BLINK_PLATFORM_EXPORT InterfaceRegistry {
  public:
diff --git a/third_party/gvr-android-sdk/display_synchronizer_jni.h b/third_party/gvr-android-sdk/display_synchronizer_jni.h
index 4e677cd2..98bfee9 100644
--- a/third_party/gvr-android-sdk/display_synchronizer_jni.h
+++ b/third_party/gvr-android-sdk/display_synchronizer_jni.h
@@ -72,6 +72,12 @@
     jlong syncTime,
     jint currentRotation);
 
+extern "C" __attribute__((visibility("default"))) void
+Java_com_google_vr_cardboard_DisplaySynchronizer_nativeOnMetricsChanged(
+    JNIEnv* env,
+    jobject obj,
+    jlong native_object);
+
 // Step 3: RegisterNatives.
 
 static const JNINativeMethod kMethodsDisplaySynchronizer[] = {
@@ -108,6 +114,13 @@
      "V",
      reinterpret_cast<void*>(
          Java_com_google_vr_cardboard_DisplaySynchronizer_nativeUpdate)},
+    {"nativeOnMetricsChanged",
+     "("
+     "J"
+     ")"
+     "V",
+     reinterpret_cast<void*>(
+         Java_com_google_vr_cardboard_DisplaySynchronizer_nativeOnMetricsChanged)},
 };
 
 static bool RegisterNativesImpl(JNIEnv* env) {
diff --git a/third_party/libprotobuf-mutator/BUILD.gn b/third_party/libprotobuf-mutator/BUILD.gn
index 3ee754e..cea5363 100644
--- a/third_party/libprotobuf-mutator/BUILD.gn
+++ b/third_party/libprotobuf-mutator/BUILD.gn
@@ -73,7 +73,7 @@
   #   generator_plugin_suffix = ".pb"
   #   # The plugin will generate cc, so don't ask for it to be done by protoc.
   #   generate_cc = false
-  #   deps = ["//third_party/libprotobuf-mutator:protoc_plugin"]
+  #   deps = ["//third_party/libprotobuf-mutator:override_lite_runtime_plugin"]
   # }
 }
 
diff --git a/tools/android/native_lib_memory/extract_symbols.py b/tools/android/native_lib_memory/extract_symbols.py
index fa992719..da1b383f 100755
--- a/tools/android/native_lib_memory/extract_symbols.py
+++ b/tools/android/native_lib_memory/extract_symbols.py
@@ -44,7 +44,7 @@
     of the output_directory part.
   """
   path = os.path.join(build_directory, 'obj')
-  object_filenames = cyglog_to_orderfile.GetObjectFileNames(path)
+  object_filenames = cyglog_to_orderfile.GetObjectFilenames(path)
   pool = multiprocessing.Pool()
   symbol_infos_filename = zip(
       pool.map(symbol_extractor.SymbolInfosFromBinary, object_filenames),
diff --git a/tools/battor_agent/battor_agent.cc b/tools/battor_agent/battor_agent.cc
index 7c260dc..cce7dae 100644
--- a/tools/battor_agent/battor_agent.cc
+++ b/tools/battor_agent/battor_agent.cc
@@ -93,7 +93,7 @@
     Listener* listener,
     scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner)
     : connection_(new BattOrConnectionImpl(path, this, ui_thread_task_runner)),
-      tick_clock_(std::make_unique<base::DefaultTickClock>()),
+      tick_clock_(base::DefaultTickClock::GetInstance()),
       listener_(listener),
       last_action_(Action::INVALID),
       command_(Command::INVALID),
diff --git a/tools/battor_agent/battor_agent.h b/tools/battor_agent/battor_agent.h
index 1dc34c86..eb3e2ca 100644
--- a/tools/battor_agent/battor_agent.h
+++ b/tools/battor_agent/battor_agent.h
@@ -103,7 +103,7 @@
   std::unique_ptr<BattOrConnection> connection_;
 
   // A source of TimeTicks. Protected so that it can be faked in testing.
-  std::unique_ptr<base::TickClock> tick_clock_;
+  base::TickClock* tick_clock_;
 
   // Timeout for when an action isn't completed within the allotted time. This
   // is virtual and protected so that timeouts can be disabled in testing. The
diff --git a/tools/battor_agent/battor_agent_unittest.cc b/tools/battor_agent/battor_agent_unittest.cc
index 23e1d1b5..a1f48cb 100644
--- a/tools/battor_agent/battor_agent_unittest.cc
+++ b/tools/battor_agent/battor_agent_unittest.cc
@@ -84,11 +84,11 @@
 class TestableBattOrAgent : public BattOrAgent {
  public:
   TestableBattOrAgent(BattOrAgent::Listener* listener,
-                      std::unique_ptr<base::TickClock> tick_clock)
+                      base::TickClock* tick_clock)
       : BattOrAgent("/dev/test", listener, nullptr) {
     connection_ =
         std::unique_ptr<BattOrConnection>(new MockBattOrConnection(this));
-    tick_clock_ = std::move(tick_clock);
+    tick_clock_ = tick_clock;
   }
 
   MockBattOrConnection* GetConnection() {
@@ -149,8 +149,8 @@
 
  protected:
   void SetUp() override {
-    agent_.reset(
-        new TestableBattOrAgent(this, task_runner_->GetMockTickClock()));
+    tick_clock_ = task_runner_->GetMockTickClock();
+    agent_.reset(new TestableBattOrAgent(this, tick_clock_.get()));
     task_runner_->ClearPendingTasks();
     is_command_complete_ = false;
     command_error_ = BATTOR_ERROR_NONE;
@@ -346,6 +346,11 @@
 
  private:
   scoped_refptr<base::TestMockTimeTaskRunner> task_runner_;
+
+  // TODO(tzik): Remove |tick_clock_| after updating GetMockTickClock to own the
+  // instance.
+  std::unique_ptr<base::TickClock> tick_clock_;
+
   // Needed to support ThreadTaskRunnerHandle::Get() in code under test.
   base::ThreadTaskRunnerHandle thread_task_runner_handle_;
 
diff --git a/tools/battor_agent/battor_connection_impl.cc b/tools/battor_agent/battor_connection_impl.cc
index c7d9898..91b9fb8 100644
--- a/tools/battor_agent/battor_connection_impl.cc
+++ b/tools/battor_agent/battor_connection_impl.cc
@@ -83,7 +83,7 @@
     serial_log_.open(serial_log_path.c_str(),
                      std::fstream::out | std::fstream::trunc);
   }
-  tick_clock_ = std::make_unique<base::DefaultTickClock>();
+  tick_clock_ = base::DefaultTickClock::GetInstance();
 }
 
 BattOrConnectionImpl::~BattOrConnectionImpl() = default;
diff --git a/tools/battor_agent/battor_connection_impl.h b/tools/battor_agent/battor_connection_impl.h
index 8cb142b..a2db3b0 100644
--- a/tools/battor_agent/battor_connection_impl.h
+++ b/tools/battor_agent/battor_connection_impl.h
@@ -64,7 +64,7 @@
   // IO handler capable of reading and writing from the serial connection.
   scoped_refptr<device::SerialIoHandler> io_handler_;
 
-  std::unique_ptr<base::TickClock> tick_clock_;
+  base::TickClock* tick_clock_;
 
  private:
   void OnOpened(bool success);
diff --git a/tools/battor_agent/battor_connection_impl_unittest.cc b/tools/battor_agent/battor_connection_impl_unittest.cc
index 34a87f0a..15268c4 100644
--- a/tools/battor_agent/battor_connection_impl_unittest.cc
+++ b/tools/battor_agent/battor_connection_impl_unittest.cc
@@ -31,9 +31,9 @@
 class TestableBattOrConnection : public BattOrConnectionImpl {
  public:
   TestableBattOrConnection(BattOrConnection::Listener* listener,
-                           std::unique_ptr<base::TickClock> tick_clock)
+                           base::TickClock* tick_clock)
       : BattOrConnectionImpl("/dev/test", listener, nullptr) {
-    tick_clock_ = std::move(tick_clock);
+    tick_clock_ = tick_clock;
   }
   scoped_refptr<device::SerialIoHandler> CreateIoHandler() override {
     return device::TestSerialIoHandler::Create();
@@ -73,8 +73,8 @@
 
  protected:
   void SetUp() override {
-    connection_.reset(
-        new TestableBattOrConnection(this, task_runner_->GetMockTickClock()));
+    tick_clock_ = task_runner_->GetMockTickClock();
+    connection_.reset(new TestableBattOrConnection(this, tick_clock_.get()));
     task_runner_->ClearPendingTasks();
   }
 
@@ -149,11 +149,15 @@
   std::vector<char>* GetReadMessage() { return read_bytes_.get(); }
 
  private:
-  std::unique_ptr<TestableBattOrConnection> connection_;
+  // TODO(tzik): Remove |tick_clock_| after updating GetMockTickClock to own the
+  // instance.
+  std::unique_ptr<base::TickClock> tick_clock_;
 
   scoped_refptr<base::TestMockTimeTaskRunner> task_runner_;
   base::ThreadTaskRunnerHandle thread_task_runner_handle_;
 
+  std::unique_ptr<TestableBattOrConnection> connection_;
+
   // Result from the last connect command.
   bool open_success_;
   // Results from the last flush command.
diff --git a/tools/binary_size/libsupersize/archive.py b/tools/binary_size/libsupersize/archive.py
index f3aa2df..45fba505 100644
--- a/tools/binary_size/libsupersize/archive.py
+++ b/tools/binary_size/libsupersize/archive.py
@@ -34,20 +34,27 @@
 from grit.format import data_pack
 
 
-# Effect of _MAX_SAME_NAME_ALIAS_COUNT (as of Oct 2017, with min_pss = max):
-# 1: shared .text symbols = 1772874 bytes, file size = 9.43MiB (645476 symbols).
-# 2: shared .text symbols = 1065654 bytes, file size = 9.58MiB (669952 symbols).
-# 6: shared .text symbols = 464058 bytes, file size = 10.11MiB (782693 symbols).
-# 10: shared .text symbols = 365648 bytes, file size =10.24MiB (813758 symbols).
-# 20: shared .text symbols = 86202 bytes, file size = 10.38MiB (854548 symbols).
-# 40: shared .text symbols = 48424 bytes, file size = 10.50MiB (890396 symbols).
-# 50: shared .text symbols = 41860 bytes, file size = 10.54MiB (902304 symbols).
-# max: shared .text symbols = 0 bytes, file size = 11.10MiB (1235449 symbols).
-_MAX_SAME_NAME_ALIAS_COUNT = 40  # 50kb is basically negligable.
+# Tunable "knobs" for CreateSectionSizesAndSymbols().
+class SectionSizeKnobs(object):
+  def __init__(self):
+    # A limit on the number of symbols an address can have, before these symbols
+    # are compacted into shared symbols. Increasing this value causes more data
+    # to be stored .size files, but is also more expensive.
+    # Effect of max_same_name_alias_count (as of Oct 2017, with min_pss = max):
+    # 1: shared .text syms = 1772874 bytes, file size = 9.43MiB (645476 syms).
+    # 2: shared .text syms = 1065654 bytes, file size = 9.58MiB (669952 syms).
+    # 6: shared .text syms = 464058 bytes, file size = 10.11MiB (782693 syms).
+    # 10: shared .text syms = 365648 bytes, file size = 10.24MiB (813758 syms).
+    # 20: shared .text syms = 86202 bytes, file size = 10.38MiB (854548 syms).
+    # 40: shared .text syms = 48424 bytes, file size = 10.50MiB (890396 syms).
+    # 50: shared .text syms = 41860 bytes, file size = 10.54MiB (902304 syms).
+    # max: shared .text syms = 0 bytes, file size = 11.10MiB (1235449 syms).
+    self.max_same_name_alias_count = 40  # 50kb is basically negligable.
 
-# This is an estimate of pak translation compression ratio to make comparisons
-# between .size files reasonable. Otherwise this can differ every pak change.
-_PAK_COMPRESSION_RATIO = 0.33
+    # An estimate of pak translation compression ratio to make comparisons
+    # between .size files reasonable. Otherwise this can differ every pak
+    # change.
+    self.pak_compression_ratio = 0.33
 
 
 def _OpenMaybeGz(path):
@@ -239,7 +246,7 @@
   return os.path.join(os.path.dirname(prefix), '{shared}', symbol_count_str)
 
 
-def _CompactLargeAliasesIntoSharedSymbols(raw_symbols):
+def _CompactLargeAliasesIntoSharedSymbols(raw_symbols, knobs):
   """Converts symbols with large number of aliases into single symbols.
 
   The merged symbol's path fields are changed to common-ancestor paths in
@@ -256,7 +263,7 @@
     raw_symbols[dst_cursor] = symbol
     dst_cursor += 1
     aliases = symbol.aliases
-    if aliases and len(aliases) > _MAX_SAME_NAME_ALIAS_COUNT:
+    if aliases and len(aliases) > knobs.max_same_name_alias_count:
       symbol.source_path = _ComputeAncestorPath(
           [s.source_path for s in aliases if s.source_path], len(aliases))
       symbol.object_path = _ComputeAncestorPath(
@@ -678,8 +685,6 @@
             # is fast enough since len(merge_string_syms) < 10.
             raw_symbols[idx:idx + 1] = literal_syms
 
-  logging.debug('Connecting nm aliases')
-  _ConnectNmAliases(raw_symbols)
   return section_sizes, raw_symbols
 
 
@@ -810,7 +815,7 @@
   return apk_symbols
 
 
-def _FindPakSymbolsFromApk(apk_path, output_directory):
+def _FindPakSymbolsFromApk(apk_path, output_directory, knobs):
   with zipfile.ZipFile(apk_path) as z:
     pak_zip_infos = (f for f in z.infolist() if f.filename.endswith('.pak'))
     apk_info_name = os.path.basename(apk_path) + '.pak.info'
@@ -825,7 +830,7 @@
       if zip_info.compress_size < zip_info.file_size:
         total_compressed_size += zip_info.compress_size
         total_uncompressed_size += zip_info.file_size
-        compression_ratio = _PAK_COMPRESSION_RATIO
+        compression_ratio = knobs.pak_compression_ratio
       _ComputePakFileSymbols(
           os.path.relpath(zip_info.filename, output_directory), contents,
           res_info, symbols_by_id, compression_ratio=compression_ratio)
@@ -833,8 +838,9 @@
       actual_ratio = (
           float(total_compressed_size) / total_uncompressed_size)
       logging.info('Pak Compression Ratio: %f Actual: %f Diff: %.0f',
-          _PAK_COMPRESSION_RATIO, actual_ratio,
-          (_PAK_COMPRESSION_RATIO - actual_ratio) * total_uncompressed_size)
+          knobs.pak_compression_ratio, actual_ratio,
+          (knobs.pak_compression_ratio - actual_ratio) *
+              total_uncompressed_size)
   return symbols_by_id
 
 
@@ -866,7 +872,8 @@
 def CreateSectionSizesAndSymbols(
       map_path=None, tool_prefix=None, output_directory=None, elf_path=None,
       apk_path=None, track_string_literals=True, metadata=None,
-      apk_elf_result=None, pak_files=None, pak_info_file=None):
+      apk_elf_result=None, pak_files=None, pak_info_file=None,
+      knobs=SectionSizeKnobs()):
   """Creates sections sizes and symbols for a SizeInfo.
 
   Args:
@@ -899,7 +906,8 @@
 
   pak_symbols_by_id = None
   if apk_path:
-    pak_symbols_by_id = _FindPakSymbolsFromApk(apk_path, output_directory)
+    pak_symbols_by_id = _FindPakSymbolsFromApk(apk_path, output_directory,
+                                               knobs)
     section_sizes, elf_overhead_size = _ParseApkElfSectionSize(
         section_sizes, metadata, apk_elf_result)
     raw_symbols.extend(_ParseApkOtherSymbols(section_sizes, apk_path))
@@ -922,7 +930,9 @@
 
   _ExtractSourcePathsAndNormalizeObjectPaths(raw_symbols, source_mapper)
   logging.info('Converting excessive aliases into shared-path symbols')
-  _CompactLargeAliasesIntoSharedSymbols(raw_symbols)
+  _CompactLargeAliasesIntoSharedSymbols(raw_symbols, knobs)
+  logging.debug('Connecting nm aliases')
+  _ConnectNmAliases(raw_symbols)
   return section_sizes, raw_symbols
 
 
diff --git a/tools/binary_size/libsupersize/integration_test.py b/tools/binary_size/libsupersize/integration_test.py
index 1737e851..e1b9294 100755
--- a/tools/binary_size/libsupersize/integration_test.py
+++ b/tools/binary_size/libsupersize/integration_test.py
@@ -123,15 +123,20 @@
     if cache_key not in IntegrationTest.cached_size_info:
       elf_path = _TEST_ELF_PATH if use_elf else None
       output_directory = _TEST_OUTPUT_DIR if use_output_directory else None
+      knobs = archive.SectionSizeKnobs()
+      # Override for testing. Lower the bar for compacting symbols, to allow
+      # smaller test cases to be created.
+      knobs.max_same_name_alias_count = 3
       if use_pak:
         section_sizes, raw_symbols = archive.CreateSectionSizesAndSymbols(
             map_path=_TEST_MAP_PATH, tool_prefix=_TEST_TOOL_PREFIX,
             elf_path=elf_path, output_directory=output_directory,
-            pak_files=[_TEST_PAK_PATH], pak_info_file=_TEST_PAK_INFO_PATH)
+            pak_files=[_TEST_PAK_PATH], pak_info_file=_TEST_PAK_INFO_PATH,
+            knobs=knobs)
       else:
         section_sizes, raw_symbols = archive.CreateSectionSizesAndSymbols(
             map_path=_TEST_MAP_PATH, tool_prefix=_TEST_TOOL_PREFIX,
-            elf_path=elf_path, output_directory=output_directory)
+            elf_path=elf_path, output_directory=output_directory, knobs=knobs)
       metadata = None
       if use_elf:
         with _AddMocksToPath():
diff --git a/tools/clang/base_bind_rewriters/BaseBindRewriters.cpp b/tools/clang/base_bind_rewriters/BaseBindRewriters.cpp
index a588740..0c89dbf 100644
--- a/tools/clang/base_bind_rewriters/BaseBindRewriters.cpp
+++ b/tools/clang/base_bind_rewriters/BaseBindRewriters.cpp
@@ -197,7 +197,7 @@
         llvm::make_unique<PassedToMoveRewriter>(&replacements);
     match_finder.addMatcher(passed_to_move->GetMatcher(), passed_to_move.get());
     rewriter = std::move(passed_to_move);
-  } else if (rewriter_option == "bind_toBind_once") {
+  } else if (rewriter_option == "bind_to_bind_once") {
     auto bind_once = llvm::make_unique<BindOnceRewriter>(&replacements);
     match_finder.addMatcher(bind_once->GetMatcher(), bind_once.get());
     rewriter = std::move(bind_once);
diff --git a/tools/cygprofile/BUILD.gn b/tools/cygprofile/BUILD.gn
index f5f9016..0ba8b6a 100644
--- a/tools/cygprofile/BUILD.gn
+++ b/tools/cygprofile/BUILD.gn
@@ -5,8 +5,9 @@
 import("//build/config/android/config.gni")
 
 if (target_cpu == "arm") {
-  static_library("lightweight_cygprofile") {
+  static_library("cygprofile") {
     sources = [
+      "delayed_dumper.cc",
       "lightweight_cygprofile.cc",
       "lightweight_cygprofile.h",
     ]
@@ -17,71 +18,8 @@
     configs -= [ "//build/config/android:default_cygprofile_instrumentation" ]
     configs += [ "//build/config/android:no_cygprofile_instrumentation" ]
   }
-}
 
-static_library("cygprofile") {
-  deps = [
-    # This adds uninstrumented symbols to the static library from base.
-    # These symbols are likely *not* to be used because there are many other
-    # duplicates in other objects/libraries.
-    "//base",
-  ]
-
-  if (use_lightweight_order_profiling) {
-    assert(use_order_profiling)
-    assert(target_cpu == "arm")
-    sources = [
-      "delayed_dumper.cc",
-    ]
-    deps += [ ":lightweight_cygprofile" ]
-  } else {
-    sources = [
-      "cygprofile.cc",
-      "cygprofile.h",
-    ]
-  }
-
-  configs -= [ "//build/config/android:default_cygprofile_instrumentation" ]
-  configs += [ "//build/config/android:no_cygprofile_instrumentation" ]
-}
-
-executable("cygprofile_unittests") {
-  testonly = true
-
-  sources = [
-    "cygprofile_unittest.cc",
-  ]
-
-  configs -= [ "//build/config/android:default_cygprofile_instrumentation" ]
-  configs += [ "//build/config/android:no_cygprofile_instrumentation" ]
-
-  deps = [
-    ":cygprofile",
-    "//base",
-    "//testing/gtest",
-  ]
-}
-
-executable("cygprofile_perftests") {
-  testonly = true
-
-  sources = [
-    "cygprofile_perftest.cc",
-  ]
-
-  configs -= [ "//build/config/android:default_cygprofile_instrumentation" ]
-  configs += [ "//build/config/android:no_cygprofile_instrumentation" ]
-
-  deps = [
-    ":cygprofile",
-    "//base",
-    "//testing/gtest",
-    "//testing/perf",
-  ]
-}
-
-if (target_cpu == "arm") {
-  executable("lightweight_cygprofile_perftests") {
+  executable("cygprofile_perftests") {
     testonly = true
 
     sources = [
@@ -92,7 +30,7 @@
     configs += [ "//build/config/android:no_cygprofile_instrumentation" ]
 
     deps = [
-      ":lightweight_cygprofile",
+      ":cygprofile",
       "//base",
       "//testing/gtest",
       "//testing/perf",
diff --git a/tools/cygprofile/cyglog_to_orderfile.py b/tools/cygprofile/cyglog_to_orderfile.py
index 0fb2e90..cf9afbb 100755
--- a/tools/cygprofile/cyglog_to_orderfile.py
+++ b/tools/cygprofile/cyglog_to_orderfile.py
@@ -13,7 +13,6 @@
 import multiprocessing
 import os
 import re
-import string
 import sys
 import tempfile
 
@@ -32,6 +31,17 @@
     return repr(self.value)
 
 
+def GetObjectFilenames(obj_dir):
+  """Returns all a list of .o files in a given directory tree."""
+  obj_files = []
+  # Scan _obj_dir recursively for .o files.
+  for (dirpath, _, filenames) in os.walk(obj_dir):
+    for file_name in filenames:
+      if file_name.endswith('.o'):
+        obj_files.append(os.path.join(dirpath, file_name))
+  return obj_files
+
+
 class ObjectFileProcessor(object):
   """Processes symbols found in the object file tree.
 
@@ -108,13 +118,7 @@
             symbol_extractor.DemangleSymbol(symbol2))
 
   def _GetAllSymbolInfos(self):
-    obj_files = []
-    # Scan _obj_dir recursively for .o files.
-    for (dirpath, _, filenames) in os.walk(self._obj_dir):
-      for file_name in filenames:
-        if file_name.endswith('.o'):
-          obj_files.append(os.path.join(dirpath, file_name))
-
+    obj_files = GetObjectFilenames(self._obj_dir)
     pool = multiprocessing.Pool()
     # Hopefully the object files are in the page cache at this point as
     # typically the library has just been built before the object files are
@@ -123,6 +127,7 @@
     symbol_infos_nested = pool.map(
         symbol_extractor.SymbolInfosFromBinary, obj_files)
     pool.close()
+    pool.join()
     result = []
     for symbol_infos in symbol_infos_nested:
       result += symbol_infos
@@ -201,47 +206,6 @@
       raise _SymbolNotFoundException(offset)
 
 
-def _ParseLogLines(log_file_lines):
-  """Parses a merged cyglog produced by mergetraces.py.
-
-  Args:
-    log_file_lines: array of lines in log file produced by profiled run
-
-    Below is an example of a small log file:
-    5086e000-52e92000 r-xp 00000000 b3:02 51276      libchromeview.so
-    secs       usecs      pid:threadid    func
-    START
-    1314897086 795828     3587:1074648168 0x509e105c
-    1314897086 795874     3587:1074648168 0x509e0eb4
-    1314897086 796326     3587:1074648168 0x509e0e3c
-    1314897086 796552     3587:1074648168 0x509e07bc
-    END
-
-  Returns:
-    An ordered list of callee offsets.
-  """
-  call_lines = []
-  vm_start = 0
-  line = log_file_lines[0]
-  assert 'r-xp' in line
-  end_index = line.find('-')
-  vm_start = int(line[:end_index], 16)
-  for line in log_file_lines[3:]:
-    fields = line.split()
-    if len(fields) == 4:
-      call_lines.append(fields)
-    else:
-      assert fields[0] == 'END'
-  # Convert strings to int in fields.
-  call_info = []
-  for call_line in call_lines:
-    addr = int(call_line[3], 16)
-    if vm_start < addr:
-      addr -= vm_start
-      call_info.append(addr)
-  return call_info
-
-
 def _WarnAboutDuplicates(offsets):
   """Warns about duplicate offsets.
 
@@ -275,9 +239,7 @@
   parser.add_argument('--target-arch', required=False,
                       choices=['arm', 'arm64', 'x86', 'x86_64', 'x64', 'mips'],
                       help='The target architecture for libchrome.so')
-  parser.add_argument('--merged-cyglog', type=str, required=False,
-                      help='Path to the merged cyglog')
-  parser.add_argument('--reached-offsets', type=str, required=False,
+  parser.add_argument('--reached-offsets', type=str, required=True,
                       help='Path to the reached offsets')
   parser.add_argument('--native-library', type=str, required=True,
                       help='Path to the unstripped instrumented library')
@@ -290,20 +252,13 @@
   parser = _CreateArgumentParser()
   args = parser.parse_args()
 
-  assert bool(args.merged_cyglog) ^ bool(args.reached_offsets)
-
   if not args.target_arch:
     args.arch = cygprofile_utils.DetectArchitecture()
   symbol_extractor.SetArchitecture(args.target_arch)
 
   obj_dir = cygprofile_utils.GetObjDir(args.native_library)
 
-  offsets = []
-  if args.merged_cyglog:
-    log_file_lines = map(string.rstrip, open(args.merged_cyglog).readlines())
-    offsets = _ParseLogLines(log_file_lines)
-  else:
-    offsets = _ReadReachedOffsets(args.reached_offsets)
+  offsets = _ReadReachedOffsets(args.reached_offsets)
   assert offsets
   _WarnAboutDuplicates(offsets)
 
diff --git a/tools/cygprofile/cyglog_to_orderfile_unittest.py b/tools/cygprofile/cyglog_to_orderfile_unittest.py
index 37722570..2aae4d4 100755
--- a/tools/cygprofile/cyglog_to_orderfile_unittest.py
+++ b/tools/cygprofile/cyglog_to_orderfile_unittest.py
@@ -76,17 +76,6 @@
     if failure_items:
       raise self.failureException('\n'.join(failure_items))
 
-  def testParseLogLines(self):
-    lines = """5086e000-52e92000 r-xp 00000000 b3:02 51276      libchromeview.so
-secs       usecs      pid:threadid    func
-START
-1314897086 795828     3587:1074648168 0x509e105c
-1314897086 795874     3587:1074648168 0x509e0eb4
-END""".split('\n')
-    offsets = cyglog_to_orderfile._ParseLogLines(lines)
-    self.assertListEqual(
-        offsets, [0x509e105c - 0x5086e000, 0x509e0eb4 - 0x5086e000])
-
   def testWarnAboutDuplicates(self):
     offsets = [0x1, 0x2, 0x3]
     self.assertTrue(cyglog_to_orderfile._WarnAboutDuplicates(offsets))
diff --git a/tools/cygprofile/cygprofile.cc b/tools/cygprofile/cygprofile.cc
deleted file mode 100644
index 7c04fed..0000000
--- a/tools/cygprofile/cygprofile.cc
+++ /dev/null
@@ -1,400 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "tools/cygprofile/cygprofile.h"
-
-#include <fcntl.h>
-#include <pthread.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <sys/stat.h>
-#include <sys/syscall.h>
-#include <sys/time.h>
-#include <sys/types.h>
-
-#include <cstdio>
-#include <fstream>
-#include <string>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/containers/hash_tables.h"
-#include "base/files/scoped_file.h"
-#include "base/lazy_instance.h"
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "base/stl_util.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_piece.h"
-#include "base/strings/stringprintf.h"
-#include "base/synchronization/lock.h"
-
-namespace cygprofile {
-namespace {
-
-// Allow 8 MBytes of data for each thread log.
-const size_t kMaxBufferSize = 8 * 1024 * 1024 / sizeof(LogEntry);
-
-// Have the background internal thread do its flush every 15 sec.
-const int kFlushThreadIdleTimeSec = 15;
-
-const char kLogFileNamePrefix[] = "/data/local/tmp/chrome/cyglog/";
-
-// "cyglog.PID.LWP.PPID"
-const char kLogFilenameFormat[] = "%scyglog.%d.%d-%d";
-
-// Magic value of above to prevent instrumentation. Used when ThreadLog is being
-// constructed (to prevent reentering by malloc, for example) and by the flush
-// log thread (to prevent it from being logged0.
-ThreadLog* const kMagicBeingConstructed = reinterpret_cast<ThreadLog*>(1);
-
-// Per-thread pointer to the current log object.
-pthread_key_t g_tls_slot;
-
-// Used to initialize the tls slot, once per the entire process.
-pthread_once_t g_tls_slot_initializer_once = PTHREAD_ONCE_INIT;
-
-// This variable is to prevent re-entrancy in the __cyg_profile_func_enter()
-// while the TLS slot itself is being initialized. Volatile here is required
-// to avoid compiler optimizations as this need to be read in a re-entrant way.
-// This variable is written by one thread only, which is the first thread that
-// happens to run the TLSSlotInitializer(). In practice this will happen very
-// early in the startup process, as soon as the first instrumented function is
-// called.
-volatile bool g_tls_slot_being_initialized = false;
-
-// Initializes the global TLS slot. This is invoked only once per process.
-static void TLSSlotInitializer()
-{
-    g_tls_slot_being_initialized = true;
-    PCHECK(0 == pthread_key_create(&g_tls_slot, NULL));
-    g_tls_slot_being_initialized = false;
-}
-
-// Returns light-weight process ID. On Linux, this is a system-wide unique
-// thread id.
-pid_t GetTID() {
-  return syscall(__NR_gettid);
-}
-
-timespec GetCurrentTime() {
-  timespec timestamp;
-  clock_gettime(CLOCK_MONOTONIC, &timestamp);
-  return timestamp;
-}
-
-// Sleeps for |sec| seconds.
-void SleepSec(int sec) {
-  for (int secs_to_sleep = sec; secs_to_sleep != 0;)
-    secs_to_sleep = sleep(secs_to_sleep);
-}
-
-// Exposes the string header that will appear at the top of every trace file.
-// This string contains memory mapping information for the mapped
-// library/executable which is used offline during symbolization. Note that
-// this class is meant to be instantiated once per process and lazily (during
-// the first flush).
-struct ImmutableFileHeaderLine {
-  ImmutableFileHeaderLine() : value(MakeFileHeaderLine()) {}
-
-  const std::string value;
-
- private:
-  // Returns whether the integer representation of the hexadecimal address
-  // stored in |line| at position |start_offset| was successfully stored in
-  // |result|.
-  static bool ParseAddress(const std::string& line,
-                           size_t start_offset,
-                           size_t length,
-                           uint64_t* result) {
-    if (start_offset >= line.length())
-      return false;
-
-    uint64_t address;
-    const bool ret = HexStringToUInt64(
-        base::StringPiece(line.c_str() + start_offset, length), &address);
-    if (!ret)
-      return false;
-
-    *result = address;
-    return true;
-  }
-
-  // Parses /proc/self/maps and returns a two line string such as:
-  // 758c6000-79f4b000 r-xp 00000000 b3:17 309475 libchrome.2009.0.so
-  // secs    usecs   pid:threadid    func
-  static std::string MakeFileHeaderLine() {
-    std::ifstream mapsfile("/proc/self/maps");
-    CHECK(mapsfile.good());
-    std::string result;
-
-    for (std::string line; std::getline(mapsfile, line); ) {
-      if (line.find("r-xp") == std::string::npos)
-        continue;
-
-      const size_t address_length = line.find('-');
-      uint64_t start_address = 0;
-      CHECK(ParseAddress(line, 0, address_length, &start_address));
-
-      uint64_t end_address = 0;
-      CHECK(ParseAddress(line, address_length + 1, address_length,
-                         &end_address));
-
-      const uintptr_t current_func_addr = reinterpret_cast<uintptr_t>(
-          &MakeFileHeaderLine);
-      if (current_func_addr >= start_address &&
-          current_func_addr < end_address) {
-        result.swap(line);
-        break;
-      }
-    }
-    CHECK(!result.empty());
-    result.append("\nsecs\tusecs\tpid:threadid\tfunc\n");
-    return result;
-  }
-};
-
-base::LazyInstance<ThreadLogsManager>::Leaky g_logs_manager =
-    LAZY_INSTANCE_INITIALIZER;
-
-base::LazyInstance<ImmutableFileHeaderLine>::Leaky g_file_header_line =
-    LAZY_INSTANCE_INITIALIZER;
-
-}  // namespace
-
-// Custom thread implementation that joins on destruction. Note that
-// base::Thread has non-trivial dependencies on e.g. AtExitManager which makes
-// it hard to use it early.
-class Thread {
- public:
-  Thread(const base::Closure& thread_callback)
-      : thread_callback_(thread_callback) {
-    PCHECK(0 == pthread_create(&handle_, NULL, &Thread::EntryPoint, this));
-  }
-
-  ~Thread() {
-    PCHECK(0 == pthread_join(handle_, NULL));
-  }
-
- private:
-  static void* EntryPoint(void* data) {
-    // Disable logging on this thread. Although this routine is not instrumented
-    // (cygprofile.gyp provides that), the called routines are and thus will
-    // call instrumentation.
-    pthread_once(&g_tls_slot_initializer_once, TLSSlotInitializer);
-    ThreadLog* thread_log = reinterpret_cast<ThreadLog*>(
-        pthread_getspecific(g_tls_slot));
-    CHECK(thread_log == NULL);  // Must be 0 as this is a new thread.
-    PCHECK(0 == pthread_setspecific(g_tls_slot, kMagicBeingConstructed));
-
-    Thread* const instance = reinterpret_cast<Thread*>(data);
-    instance->thread_callback_.Run();
-    return NULL;
-  }
-
-  const base::Closure thread_callback_;
-  pthread_t handle_;
-
-  DISALLOW_COPY_AND_ASSIGN(Thread);
-};
-
-// Single log entry recorded for each function call.
-LogEntry::LogEntry(const void* address, pid_t pid, pid_t tid)
-    : time(GetCurrentTime()), pid(pid), tid(tid), address(address) {}
-
-ThreadLog::ThreadLog()
-    : pid_(getpid()),
-      tid_(GetTID()),
-      in_use_(false),
-      flush_callback_(
-          base::Bind(&ThreadLog::FlushInternal, base::Unretained(this))) {}
-
-ThreadLog::ThreadLog(const FlushCallback& flush_callback)
-    : pid_(getpid()),
-      tid_(GetTID()),
-      in_use_(false),
-      flush_callback_(flush_callback) {}
-
-ThreadLog::~ThreadLog() {
-  PCHECK(0 == pthread_setspecific(g_tls_slot, NULL));
-}
-
-void ThreadLog::AddEntry(void* address) {
-  if (in_use_)
-    return;
-  in_use_ = true;
-
-  DCHECK_EQ(tid_, GetTID());
-  bool did_insert = called_functions_.insert(address).second;
-
-  if (did_insert) {
-    base::AutoLock auto_lock(lock_);
-    entries_.emplace_back(address, pid_, tid_);
-    // Crash in a quickly understandable way instead of crashing (or maybe not
-    // though) due to OOM.
-    CHECK_LE(entries_.size(), kMaxBufferSize);
-  }
-
-  in_use_ = false;
-}
-
-void ThreadLog::TakeEntries(std::vector<LogEntry>* destination) {
-  base::AutoLock auto_lock(lock_);
-  destination->swap(entries_);
-  base::STLClearObject(&entries_);
-}
-
-void ThreadLog::Flush(std::vector<LogEntry>* entries) const {
-  flush_callback_.Run(entries);
-}
-
-void ThreadLog::FlushInternal(std::vector<LogEntry>* entries) const {
-  const std::string log_filename(
-      base::StringPrintf(
-          kLogFilenameFormat, kLogFileNamePrefix, getpid(), tid_, getppid()));
-  const base::ScopedFILE file(fopen(log_filename.c_str(), "a"));
-  CHECK(file.get());
-
-  const long offset = ftell(file.get());
-  if (offset == 0)
-    fprintf(file.get(), "%s", g_file_header_line.Get().value.c_str());
-
-  for (std::vector<LogEntry>::const_iterator it = entries->begin();
-       it != entries->end(); ++it) {
-    fprintf(file.get(), "%ld %ld\t%d:%d\t%p\n", it->time.tv_sec,
-            it->time.tv_nsec / 1000, it->pid, it->tid, it->address);
-  }
-
-  base::STLClearObject(entries);
-}
-
-ThreadLogsManager::ThreadLogsManager()
-    : wait_callback_(base::Bind(&SleepSec, kFlushThreadIdleTimeSec)) {
-}
-
-ThreadLogsManager::ThreadLogsManager(const base::Closure& wait_callback,
-                                     const base::Closure& notify_callback)
-
-    : wait_callback_(wait_callback),
-      notify_callback_(notify_callback) {
-}
-
-ThreadLogsManager::~ThreadLogsManager() {
-  // Note that the internal thread does some work until it sees |flush_thread_|
-  // = NULL.
-  std::unique_ptr<Thread> flush_thread;
-  {
-    base::AutoLock auto_lock(lock_);
-    flush_thread_.swap(flush_thread);
-  }
-  flush_thread.reset();  // Joins the flush thread.
-}
-
-void ThreadLogsManager::AddLog(std::unique_ptr<ThreadLog> new_log) {
-  base::AutoLock auto_lock(lock_);
-
-  if (logs_.empty())
-    StartInternalFlushThread_Locked();
-
-  logs_.push_back(std::move(new_log));
-}
-
-void ThreadLogsManager::StartInternalFlushThread_Locked() {
-  lock_.AssertAcquired();
-  CHECK(!flush_thread_);
-  // Note that the |flush_thread_| joins at destruction which guarantees that it
-  // will never outlive |this|, i.e. it's safe not to use ref-counting.
-  flush_thread_.reset(
-      new Thread(base::Bind(&ThreadLogsManager::FlushAllLogsOnFlushThread,
-                            base::Unretained(this))));
-}
-
-// Type used below for flushing.
-struct LogData {
-  LogData(ThreadLog* thread_log) : thread_log(thread_log) {}
-
-  ThreadLog* const thread_log;
-  std::vector<LogEntry> entries;
-};
-
-void ThreadLogsManager::FlushAllLogsOnFlushThread() {
-  while (true) {
-    {
-      base::AutoLock auto_lock(lock_);
-      // The |flush_thread_| field is reset during destruction.
-      if (!flush_thread_)
-        return;
-    }
-    // Sleep for a few secs and then flush all thread's buffers. There is a
-    // danger that, when quitting Chrome, this thread may see unallocated data
-    // and segfault. We do not care because we need logs when Chrome is working.
-    wait_callback_.Run();
-
-    // Copy the ThreadLog pointers to avoid acquiring both the logs manager's
-    // lock and the one for individual thread logs.
-    std::vector<ThreadLog*> thread_logs_copy;
-    {
-      base::AutoLock auto_lock(lock_);
-      for (const auto& log : logs_)
-        thread_logs_copy.push_back(log.get());
-    }
-
-    // Move the logs' data before flushing them so that the mutexes are not
-    // acquired for too long.
-    std::vector<LogData> logs;
-    for (std::vector<ThreadLog*>::const_iterator it =
-             thread_logs_copy.begin();
-         it != thread_logs_copy.end(); ++it) {
-      ThreadLog* const thread_log = *it;
-      LogData log_data(thread_log);
-      logs.push_back(log_data);
-      thread_log->TakeEntries(&logs.back().entries);
-    }
-
-    for (std::vector<LogData>::iterator it = logs.begin();
-         it != logs.end(); ++it) {
-      if (!it->entries.empty())
-        it->thread_log->Flush(&it->entries);
-    }
-
-    if (!notify_callback_.is_null())
-      notify_callback_.Run();
-  }
-}
-
-extern "C" {
-
-// The GCC compiler callbacks, called on every function invocation providing
-// addresses of caller and callee codes.
-void __cyg_profile_func_enter(void* this_fn, void* call_site)
-    __attribute__((no_instrument_function));
-void __cyg_profile_func_exit(void* this_fn, void* call_site)
-    __attribute__((no_instrument_function));
-
-void __cyg_profile_func_enter(void* this_fn, void* callee_unused) {
-  // Avoid re-entrancy while initializing the TLS slot (once per process).
-  if (g_tls_slot_being_initialized)
-    return;
-
-  pthread_once(&g_tls_slot_initializer_once, TLSSlotInitializer);
-  ThreadLog* thread_log = reinterpret_cast<ThreadLog*>(
-      pthread_getspecific(g_tls_slot));
-
-  if (thread_log == NULL) {
-    PCHECK(0 == pthread_setspecific(g_tls_slot, kMagicBeingConstructed));
-    thread_log = new ThreadLog();
-    CHECK(thread_log);
-    g_logs_manager.Pointer()->AddLog(base::WrapUnique(thread_log));
-    PCHECK(0 == pthread_setspecific(g_tls_slot, thread_log));
-  }
-
-  if (thread_log != kMagicBeingConstructed)
-    thread_log->AddEntry(this_fn);
-}
-
-void __cyg_profile_func_exit(void* this_fn, void* call_site) {}
-
-}  // extern "C"
-}  // namespace cygprofile
diff --git a/tools/cygprofile/cygprofile.h b/tools/cygprofile/cygprofile.h
deleted file mode 100644
index 97684e78..0000000
--- a/tools/cygprofile/cygprofile.h
+++ /dev/null
@@ -1,169 +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.
-//
-// Tool to log the execution of the process (Chrome). Writes logs containing
-// time and address of the callback being called for the first time.
-//
-// For performance reasons logs are buffered. Every thread has its own buffer
-// and log file so the contention between threads is minimal. As a side-effect,
-// functions called might be mentioned in many thread logs.
-//
-// A special thread is created in the process to periodically flush logs for all
-// threads in case the thread had stopped before flushing its logs.
-//
-// Also note that the instrumentation code is self-activated. It begins to
-// record the log data when it is called first, including the run-time startup.
-// Have it in mind when modifying it, in particular do not use global objects
-// with constructors as they are called during startup (too late for us).
-
-#ifndef TOOLS_CYGPROFILE_CYGPROFILE_H_
-#define TOOLS_CYGPROFILE_CYGPROFILE_H_
-
-#include <sys/time.h>
-#include <sys/types.h>
-
-#include <memory>
-#include <vector>
-
-#include "base/callback.h"
-#include "base/containers/hash_tables.h"
-#include "base/macros.h"
-#include "base/synchronization/lock.h"
-#include "build/build_config.h"
-
-#if !defined(OS_ANDROID)
-// This is only supported on Android thanks to the fact that on Android
-// processes (other than the system's zygote) don't fork.
-//
-// To make cygprofile truly work (i.e. without any deadlock) on Chrome
-// platforms that use fork(), cygprofile.cc should be written in a way that
-// guarantees that:
-// - No lock is acquired by a foreign thread during fork(). In particular this
-// means that cygprofile.cc should not perform any heap allocation (since heap
-// allocators, including TCMalloc generally use locks).
-// - Only cygprofile.cc uses pthread_atfork() in the whole process. Unlike POSIX
-// signals, pthread_atfork() doesn't provide a way to install multiple handlers.
-// Calling pthread_atfork() in cygprofile.cc would override any handler that
-// could have been installed previously.
-//
-// Chrome happens to violate the first requirement at least once by having its
-// process launcher thread fork. However the child process in that case, when
-// it's not instrumented with cygprofile, directly calls exec(). This is safe
-// since the child process doesn't try to release a lock acquired by another
-// thread in the parent process which would lead to a deadlock. This problem was
-// actually observed by trying to port the current version of cygprofile.cc to
-// Linux.
-#error This is only supported on Android.
-#endif
-
-// The following is only exposed for testing.
-namespace cygprofile {
-
-class Thread;
-
-// Single log entry recorded for each function call.
-struct LogEntry {
-  LogEntry(const void* address, pid_t pid, pid_t tid);
-
-  const timespec time;
-  const pid_t pid;
-  const pid_t tid;
-  const void* const address;
-};
-
-// Per-thread function calls log.
-class ThreadLog {
- public:
-  // Callback invoked for flushing that can be provided for testing.
-  typedef base::Callback<void (std::vector<LogEntry>*)> FlushCallback;
-
-  ThreadLog();
-
-  // Used for testing.
-  ThreadLog(const FlushCallback& flush_callback);
-
-  ~ThreadLog();
-
-  // Must only be called from the thread this ThreadLog instance is watching.
-  void AddEntry(void* address);
-
-  // Can be called from any thread.
-  void TakeEntries(std::vector<LogEntry>* output);
-
-  // Flushes the provided vector of entries to a file and clears it. Note that
-  // this can be called from any thread.
-  void Flush(std::vector<LogEntry>* entries) const;
-
- private:
-  // Default implementation (that can be overridden for testing) of the method
-  // above.
-  void FlushInternal(std::vector<LogEntry>* entries) const;
-
-  // Process ID, as returned by getpid().
-  const pid_t pid_;
-
-  // Thread identifier as Linux kernel shows it.  LWP (light-weight process) is
-  // a unique ID of the thread in the system, unlike pthread_self() which is the
-  // same for fork()-ed threads.
-  const pid_t tid_;
-
-  // Current thread is inside the instrumentation routine.
-  bool in_use_;
-
-  // Callback used to flush entries.
-  const FlushCallback flush_callback_;
-
-  // Keeps track of all functions that have been logged on this thread so we do
-  // not record duplicates.
-  base::hash_set<void*> called_functions_;
-
-  // A lock that guards |entries_| usage between per-thread instrumentation
-  // routine and timer flush callback. So the contention could happen only
-  // during the flush, every 15 secs.
-  base::Lock lock_;
-
-  std::vector<LogEntry> entries_;
-
-  DISALLOW_COPY_AND_ASSIGN(ThreadLog);
-};
-
-// Manages a list of per-thread logs.
-class ThreadLogsManager {
- public:
-  ThreadLogsManager();
-
-  // Used for testing. The provided callbacks are used for testing to
-  // synchronize the internal thread with the unit test running on the main
-  // thread.
-  ThreadLogsManager(const base::Closure& wait_callback,
-                    const base::Closure& notify_callback);
-
-  ~ThreadLogsManager();
-
-  // Can be called from any thread.
-  void AddLog(std::unique_ptr<ThreadLog> new_log);
-
- private:
-  void StartInternalFlushThread_Locked();
-
-  // Flush thread's entry point.
-  void FlushAllLogsOnFlushThread();
-
-  // Used to make the internal thread sleep before each flush iteration.
-  const base::Closure wait_callback_;
-  // Used to trigger a notification when a flush happened on the internal
-  // thread.
-  const base::Closure notify_callback_;
-
-  // Protects the state below.
-  base::Lock lock_;
-  std::unique_ptr<Thread> flush_thread_;
-  std::vector<std::unique_ptr<ThreadLog>> logs_;
-
-  DISALLOW_COPY_AND_ASSIGN(ThreadLogsManager);
-};
-
-}  // namespace cygprofile
-
-#endif  // TOOLS_CYGPROFILE_CYGPROFILE_H_
diff --git a/tools/cygprofile/cygprofile_perftest.cc b/tools/cygprofile/cygprofile_perftest.cc
deleted file mode 100644
index ae8fe3e7..0000000
--- a/tools/cygprofile/cygprofile_perftest.cc
+++ /dev/null
@@ -1,67 +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 "tools/cygprofile/cygprofile.h"
-
-#include <cstdint>
-#include <vector>
-
-#include "base/strings/stringprintf.h"
-#include "base/time/time.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/perf/perf_test.h"
-
-namespace cygprofile {
-
-namespace {
-
-void AddEntryCost(int iterations, int addresses_count) {
-  // This is intentionally leaky. ThreadLog() destructor would call abort(),
-  // limiting us to a single test. Leaking ThreadLog is fine as long as we clean
-  // up the entries.
-  auto* thread_log = new ThreadLog();
-
-  auto tick = base::TimeTicks::Now();
-  for (int i = 0; i < iterations; i++) {
-    for (int address = 0; address < addresses_count; address++) {
-      thread_log->AddEntry(reinterpret_cast<void*>(address));
-    }
-  }
-  auto tock = base::TimeTicks::Now();
-  double nanos = static_cast<double>((tock - tick).InNanoseconds());
-  auto ns_per_call =
-      nanos / (iterations * static_cast<double>(addresses_count));
-  auto modifier = base::StringPrintf("_%d_%d", iterations, addresses_count);
-  perf_test::PrintResult("AddEntryCostPerCall", modifier, "", ns_per_call, "ns",
-                         true);
-
-  // Entries cleanup, see comment at the beginning of the function.
-  std::vector<LogEntry> entries;
-  thread_log->TakeEntries(&entries);
-}
-}  // namespace
-
-TEST(CygprofilePerfTest, CreateEntries_10_10000) {
-  AddEntryCost(10, 10000);
-}
-
-TEST(CygprofilePerfTest, CreateEntries_100_10000) {
-  AddEntryCost(100, 10000);
-}
-
-TEST(CygprofilePerfTest, CreateEntries_10_100000) {
-  AddEntryCost(10, 100000);
-}
-
-TEST(CygprofilePerfTest, CreateEntries_100_1000000) {
-  AddEntryCost(100, 100000);
-}
-
-}  // namespace cygprofile
-
-// Custom runner implementation since base's one requires JNI on Android.
-int main(int argc, char** argv) {
-  testing::InitGoogleTest(&argc, argv);
-  return RUN_ALL_TESTS();
-}
diff --git a/tools/cygprofile/cygprofile_unittest.cc b/tools/cygprofile/cygprofile_unittest.cc
deleted file mode 100644
index 5be4804..0000000
--- a/tools/cygprofile/cygprofile_unittest.cc
+++ /dev/null
@@ -1,106 +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 "tools/cygprofile/cygprofile.h"
-
-#include <stdint.h>
-#include <sys/time.h>
-#include <utility>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/callback.h"
-#include "base/logging.h"
-#include "base/synchronization/waitable_event.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace cygprofile {
-namespace {
-
-void FlushEntries(std::vector<LogEntry>* destination,
-                  std::vector<LogEntry>* entries) {
-  CHECK_EQ(0U, destination->size());
-  // Move the provided |entries| vector to the provided |destination| so that
-  // the unit test that triggered the flush can check it.
-  destination->swap(*entries);
-}
-
-// Flush callback that should not be invoked.
-void CheckFlushDoesNotHappen(std::vector<LogEntry>* entries) {
-  NOTREACHED();
-}
-
-uint64_t GetUsecSecTimeFromTimeSpec(struct timespec timespec) {
-  return timespec.tv_sec * 1000 * 1000 + timespec.tv_nsec / 1000;
-}
-
-TEST(CygprofileTest, ThreadLogBasic) {
-  ThreadLog thread_log(base::Bind(&CheckFlushDoesNotHappen));
-
-  thread_log.AddEntry(reinterpret_cast<void*>(0x2));
-  thread_log.AddEntry(reinterpret_cast<void*>(0x1));
-
-  std::vector<LogEntry> entries;
-  thread_log.TakeEntries(&entries);
-
-  ASSERT_EQ(2U, entries.size());
-  // The entries should appear in their insertion order.
-  const LogEntry& first_entry = entries[0];
-  ASSERT_EQ(reinterpret_cast<uintptr_t>(first_entry.address), 2U);
-  ASSERT_EQ(getpid(), first_entry.pid);
-  ASSERT_LT(0, first_entry.tid);
-
-  const LogEntry& second_entry = entries[1];
-  ASSERT_EQ(1U, reinterpret_cast<uintptr_t>(second_entry.address));
-  ASSERT_EQ(first_entry.pid, second_entry.pid);
-  ASSERT_EQ(first_entry.tid, second_entry.tid);
-
-  ASSERT_GE(GetUsecSecTimeFromTimeSpec(second_entry.time),
-            GetUsecSecTimeFromTimeSpec(first_entry.time));
-}
-
-TEST(CygprofileTest, ManagerBasic) {
-  base::WaitableEvent wait_event(
-      base::WaitableEvent::ResetPolicy::MANUAL,
-      base::WaitableEvent::InitialState::NOT_SIGNALED);
-  base::WaitableEvent notify_event(
-      base::WaitableEvent::ResetPolicy::MANUAL,
-      base::WaitableEvent::InitialState::NOT_SIGNALED);
-
-  ThreadLogsManager manager(
-      base::Bind(&base::WaitableEvent::Wait, base::Unretained(&wait_event)),
-      base::Bind(&base::WaitableEvent::Signal,
-                 base::Unretained(&notify_event)));
-
-  std::vector<LogEntry> entries;
-  std::unique_ptr<ThreadLog> thread_log(
-      new ThreadLog(base::Bind(&FlushEntries, base::Unretained(&entries))));
-
-  thread_log->AddEntry(reinterpret_cast<void*>(0x2));
-  thread_log->AddEntry(reinterpret_cast<void*>(0x3));
-
-  // This should make the manager spawn its internal flush thread which will
-  // wait for a notification before it starts doing some work.
-  manager.AddLog(std::move(thread_log));
-
-  EXPECT_EQ(0U, entries.size());
-  // This will wake up the internal thread.
-  wait_event.Signal();
-  // Now it's our turn to wait until it performed the flush.
-  notify_event.Wait();
-
-  // The flush should have moved the data to the local vector of entries.
-  EXPECT_EQ(2U, entries.size());
-  ASSERT_EQ(2U, reinterpret_cast<uintptr_t>(entries[0].address));
-  ASSERT_EQ(3U, reinterpret_cast<uintptr_t>(entries[1].address));
-}
-
-}  // namespace
-}  // namespace cygprofile
-
-// Custom runner implementation since base's one requires JNI on Android.
-int main(int argc, char** argv) {
-  testing::InitGoogleTest(&argc, argv);
-  return RUN_ALL_TESTS();
-}
diff --git a/tools/cygprofile/mergetraces.py b/tools/cygprofile/mergetraces.py
deleted file mode 100755
index 2ac8393..0000000
--- a/tools/cygprofile/mergetraces.py
+++ /dev/null
@@ -1,254 +0,0 @@
-#!/usr/bin/python
-# Copyright 2013 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# Use: ../mergetraces.py `ls cyglog.* -Sr` > merged_cyglog
-
-""""Merge multiple logs files from different processes into a single log.
-
-Given two log files of execution traces, merge the traces into a single trace.
-Merging will use timestamps (i.e. the first two columns of logged calls) to
-create a single log that is an ordered trace of calls by both processes.
-"""
-
-import optparse
-import string
-import sys
-
-
-def ParseLogLines(lines):
-  """Parse log file lines.
-
-  Args:
-    lines: lines from log file produced by profiled run
-
-    Below is an example of a small log file:
-    5086e000-52e92000 r-xp 00000000 b3:02 51276      libchromeview.so
-    secs       usecs      pid:threadid    func
-    START
-    1314897086 795828     3587:1074648168 0x509e105c
-    1314897086 795874     3587:1074648168 0x509e0eb4
-    1314897086 796326     3587:1074648168 0x509e0e3c
-    1314897086 796552     3587:1074648168 0x509e07bc
-    END
-
-  Returns:
-    tuple conisiting of 1) an ordered list of the logged calls, as an array of
-    fields, 2) the virtual start address of the library, used to compute the
-    offset of the symbol in the library and 3) the virtual end address
-  """
-  call_lines = []
-  vm_start = 0
-  vm_end = 0
-  dash_index = lines[0].find ('-')
-  space_index = lines[0].find (' ')
-  vm_start = int (lines[0][:dash_index], 16)
-  vm_end = int (lines[0][dash_index+1:space_index], 16)
-  for line in lines[2:]:
-    line = line.strip()
-    fields = line.split()
-    call_lines.append (fields)
-
-  return (call_lines, vm_start, vm_end)
-
-
-def HasDuplicates(calls):
-  """Makes sure that calls are only logged once.
-
-  Args:
-    calls: list of calls logged
-
-  Returns:
-    boolean indicating if calls has duplicate calls
-  """
-  seen = set([])
-  for call in calls:
-    if call[3] in seen:
-      return True
-    seen.add(call[3])
-  return False
-
-def CheckTimestamps(calls):
-  """Prints warning to stderr if the call timestamps are not in order.
-
-  Args:
-    calls: list of calls logged
-  """
-  index = 0
-  last_timestamp_secs = -1
-  last_timestamp_us = -1
-  while (index < len (calls)):
-    timestamp_secs = int (calls[index][0])
-    timestamp_us = int (calls[index][1])
-    timestamp = (timestamp_secs * 1000000) + timestamp_us
-    last_timestamp = (last_timestamp_secs * 1000000) + last_timestamp_us
-    if (timestamp < last_timestamp):
-      raise Exception("last_timestamp: " + str(last_timestamp_secs)
-                       + " " + str(last_timestamp_us) + " timestamp: "
-                       + str(timestamp_secs) + " " + str(timestamp_us) + "\n")
-    last_timestamp_secs = timestamp_secs
-    last_timestamp_us = timestamp_us
-    index = index + 1
-
-
-def Convert(call_lines, start_address, end_address):
-  """Converts the call addresses to static offsets and removes invalid calls.
-
-  Removes profiled calls not in shared library using start and end virtual
-  addresses, converts strings to integer values, coverts virtual addresses to
-  address in shared library.
-
-  Returns:
-     list of calls as tuples (sec, usec, pid:tid, callee)
-  """
-  converted_calls = []
-  call_addresses = set()
-  for fields in call_lines:
-    secs = int (fields[0])
-    usecs = int (fields[1])
-    callee = int (fields[3], 16)
-    # Eliminate repetitions of the same function.
-    if callee in call_addresses:
-      continue
-    # Eliminate small addresses. It should be safe to do so because these point
-    # before the .text section (it is in .plt or earlier).
-    # TODO(pasko): understand why __cyg_profile_func_enter may output a small
-    # offset sometimes.
-    if callee < start_address + 4096:
-      sys.stderr.write('WARNING: ignoring small address: %s' %
-          hex(callee - start_address))
-      call_addresses.add(callee)
-      continue
-    if start_address <= callee < end_address:
-      converted_calls.append((secs, usecs, fields[2], (callee - start_address)))
-      call_addresses.add(callee)
-  return converted_calls
-
-
-def Timestamp(trace_entry):
-  return int (trace_entry[0]) * 1000000 + int(trace_entry[1])
-
-
-def AddTrace (tracemap, trace):
-  """Adds a trace to the tracemap.
-
-  Adds entries in the trace to the tracemap. All new calls will be added to
-  the tracemap. If the calls already exist in the tracemap then they will be
-  replaced if they happened sooner in the new trace.
-
-  Args:
-    tracemap: the tracemap
-    trace: the trace
-
-  """
-  for trace_entry in trace:
-    call = trace_entry[3]
-    if (not call in tracemap) or (
-        Timestamp(tracemap[call]) > Timestamp(trace_entry)):
-      tracemap[call] = trace_entry
-
-
-def GroupByProcessAndThreadId(input_trace):
-  """Returns an array of traces grouped by pid and tid.
-
-  This is used to make the order of functions not depend on thread scheduling
-  which can be greatly impacted when profiling is done with cygprofile. As a
-  result each thread has its own contiguous segment of code (ordered by
-  timestamp) and processes also have their code isolated (i.e. not interleaved).
-  """
-  def MakeTimestamp(sec, usec):
-    return sec * 1000000 + usec
-
-  def PidAndTidFromString(pid_and_tid):
-    strings = pid_and_tid.split(':')
-    return (int(strings[0]), int(strings[1]))
-
-  tid_to_pid_map = {}
-  pid_first_seen = {}
-  tid_first_seen = {}
-
-  for (sec, usec, pid_and_tid, _) in input_trace:
-    (pid, tid) = PidAndTidFromString(pid_and_tid)
-
-    # Make sure that thread IDs are unique since this is a property we rely on.
-    if tid_to_pid_map.setdefault(tid, pid) != pid:
-      raise Exception(
-          'Seen PIDs %d and %d for TID=%d. Thread-IDs must be unique' % (
-              tid_to_pid_map[tid], pid, tid))
-
-    if not pid in pid_first_seen:
-      pid_first_seen[pid] = MakeTimestamp(sec, usec)
-    if not tid in tid_first_seen:
-      tid_first_seen[tid] = MakeTimestamp(sec, usec)
-
-  def CompareEvents(event1, event2):
-    (sec1, usec1, pid_and_tid, _) = event1
-    (pid1, tid1) = PidAndTidFromString(pid_and_tid)
-    (sec2, usec2, pid_and_tid, _) = event2
-    (pid2, tid2) = PidAndTidFromString(pid_and_tid)
-
-    pid_cmp = cmp(pid_first_seen[pid1], pid_first_seen[pid2])
-    if pid_cmp != 0:
-      return pid_cmp
-    tid_cmp = cmp(tid_first_seen[tid1], tid_first_seen[tid2])
-    if tid_cmp != 0:
-      return tid_cmp
-    return cmp(MakeTimestamp(sec1, usec1), MakeTimestamp(sec2, usec2))
-
-  return sorted(input_trace, cmp=CompareEvents)
-
-
-def Main():
-  """Merge two traces for code in specified library and write to stdout.
-
-  Merges the two traces and coverts the virtual addresses to the offsets in the
-  library.  First line of merged trace has dummy virtual address of 0-ffffffff
-  so that symbolizing the addresses uses the addresses in the log, since the
-  addresses have already been converted to static offsets.
-  """
-  parser = optparse.OptionParser('usage: %prog trace1 ... traceN')
-  (_, args) = parser.parse_args()
-  if len(args) <= 1:
-    parser.error('expected at least the following args: trace1 trace2')
-
-  step = 0
-
-  # Maps function addresses to their corresponding trace entry.
-  tracemap = dict()
-
-  for trace_file in args:
-    step += 1
-    sys.stderr.write("    " + str(step) + "/" + str(len(args)) +
-                     ": " + trace_file + ":\n")
-
-    trace_lines = map(string.rstrip, open(trace_file).readlines())
-    (trace_calls, trace_start, trace_end) = ParseLogLines(trace_lines)
-    CheckTimestamps(trace_calls)
-    sys.stderr.write("Len: " + str(len(trace_calls)) +
-                     ". Start: " + hex(trace_start) +
-                     ", end: " + hex(trace_end) + '\n')
-
-    trace_calls = Convert(trace_calls, trace_start, trace_end)
-    sys.stderr.write("Converted len: " + str(len(trace_calls)) + "\n")
-
-    AddTrace(tracemap, trace_calls)
-    sys.stderr.write("Merged len: " + str(len(tracemap)) + "\n")
-
-  # Extract the resulting trace from the tracemap
-  merged_trace = []
-  for call in tracemap:
-    merged_trace.append(tracemap[call])
-  merged_trace.sort(key=Timestamp)
-
-  grouped_trace = GroupByProcessAndThreadId(merged_trace)
-
-  print "0-ffffffff r-xp 00000000 xx:00 00000 ./"
-  print "secs\tusecs\tpid:threadid\tfunc"
-  for call in grouped_trace:
-    print (str(call[0]) + "\t" + str(call[1]) + "\t" + call[2] + "\t" +
-           hex(call[3]))
-
-
-if __name__ == '__main__':
-  Main()
diff --git a/tools/cygprofile/mergetraces_unittest.py b/tools/cygprofile/mergetraces_unittest.py
deleted file mode 100644
index de88137..0000000
--- a/tools/cygprofile/mergetraces_unittest.py
+++ /dev/null
@@ -1,51 +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.
-
-import unittest
-
-import mergetraces
-
-class GroupByProcessAndThreadIdTestBasic(unittest.TestCase):
-  def runTest(self):
-    # (sec, usec, 'pid:tid', function address).
-    input_trace = [
-        (100, 10, '2000:2001', 0x5),
-        (100, 11, '2000:2001', 0x3),
-        (100, 13, '2000:1999', 0x8),
-        (100, 14, '2000:2000', 0x7),
-        (120, 13, '2001:2003', 0x9),
-        (150, 12, '2001:2004', 0x6),
-        (180, 11, '2000:2000', 0x1),
-    ]
-
-    # Functions should be grouped by thread-id and PIDs should not be
-    # interleaved.
-    expected_trace = [
-        (100, 10, '2000:2001', 0x5),
-        (100, 11, '2000:2001', 0x3),
-        (100, 13, '2000:1999', 0x8),
-        (100, 14, '2000:2000', 0x7),
-        (180, 11, '2000:2000', 0x1),
-        (120, 13, '2001:2003', 0x9),
-        (150, 12, '2001:2004', 0x6),
-    ]
-
-    grouped_trace = mergetraces.GroupByProcessAndThreadId(input_trace)
-
-    self.assertEqual(grouped_trace, expected_trace)
-
-class GroupByProcessAndThreadIdFailsWithNonUniqueTIDs(unittest.TestCase):
-  def runTest(self):
-    # (sec, usec, 'pid:tid', function address).
-    input_trace = [
-        (100, 10, '1999:2001', 0x5),
-        (100, 10, '1988:2001', 0x5),
-    ]
-
-    try:
-      mergetraces.GroupByProcessAndThreadId(input_trace)
-    except Exception:
-      return
-
-    self.fail('Multiple processes should not have a same thread-ID.')
diff --git a/tools/cygprofile/orderfile_generator_backend.py b/tools/cygprofile/orderfile_generator_backend.py
index 147a067..96348a5 100755
--- a/tools/cygprofile/orderfile_generator_backend.py
+++ b/tools/cygprofile/orderfile_generator_backend.py
@@ -250,7 +250,7 @@
   """Handles compilation of clank."""
 
   def __init__(self, out_dir, step_recorder, arch, jobs, max_load, use_goma,
-               goma_dir, lightweight_instrumentation):
+               goma_dir):
     self._out_dir = out_dir
     self._step_recorder = step_recorder
     self._arch = arch
@@ -258,7 +258,6 @@
     self._max_load = max_load
     self._use_goma = use_goma
     self._goma_dir = goma_dir
-    self._lightweight_instrumentation = lightweight_instrumentation
     lib_chrome_so_dir = 'lib.unstripped'
     self.lib_chrome_so = os.path.join(
         self._out_dir, 'Release', lib_chrome_so_dir, 'libchrome.so')
@@ -288,8 +287,6 @@
         'use_goma=' + str(self._use_goma).lower(),
         'use_order_profiling=' + str(instrumented).lower(),
     ]
-    if instrumented and self._lightweight_instrumentation:
-      args.append('use_lightweight_order_profiling=true')
     if self._goma_dir:
       args += ['goma_dir="%s"' % self._goma_dir]
 
@@ -420,8 +417,6 @@
   generates an updated orderfile.
   """
   _CLANK_REPO = os.path.join(constants.DIR_SOURCE_ROOT, 'clank')
-  _MERGE_TRACES_SCRIPT = os.path.join(
-      constants.DIR_SOURCE_ROOT, 'tools', 'cygprofile', 'mergetraces.py')
   _CYGLOG_TO_ORDERFILE_SCRIPT = os.path.join(
       constants.DIR_SOURCE_ROOT, 'tools', 'cygprofile',
       'cyglog_to_orderfile.py')
@@ -460,18 +455,12 @@
     if options.profile:
       output_directory = os.path.join(self._instrumented_out_dir, 'Release')
       host_cyglog_dir = os.path.join(output_directory, 'cyglog_data')
-      # Only override the defaults when using lightweight instrumentation,
-      # as the regular profiling code is likely too slow for these.
       urls = [profile_android_startup.AndroidProfileTool.TEST_URL]
       use_wpr = True
       simulate_user = False
-      if options.simulate_user and not options.lightweight_instrumentation:
-        logging.error(
-            '--simulate-user required --lightweight-instrumentation, ignoring.')
-      if options.lightweight_instrumentation:
-        urls = options.urls
-        use_wpr = not options.no_wpr
-        simulate_user = options.simulate_user
+      urls = options.urls
+      use_wpr = not options.no_wpr
+      simulate_user = options.simulate_user
       self._profiler = profile_android_startup.AndroidProfileTool(
           output_directory, host_cyglog_dir, use_wpr, urls, simulate_user)
 
@@ -486,27 +475,6 @@
     assert os.path.isdir(constants.DIR_SOURCE_ROOT), 'No src directory found'
     symbol_extractor.SetArchitecture(options.arch)
 
-  def _RunCygprofileUnitTests(self):
-    """Builds, deploys and runs cygprofile_unittests."""
-    # There an no unittests (yet) for the lightweight instrumentation.
-    # TODO(lizeb): Fix this.
-    if self._options.lightweight_instrumentation:
-      return
-    tools_compiler = ClankCompiler(
-        os.path.dirname(constants.GetOutDirectory()),
-        self._step_recorder, self._options.arch, self._options.jobs,
-        self._options.max_load, self._options.use_goma, self._options.goma_dir,
-        self._options.lightweight_instrumentation)
-    tools_compiler.Build(instrumented=False, target='android_tools')
-    self._compiler.Build(instrumented=True, target='cygprofile_unittests')
-
-    self._step_recorder.BeginStep('Deploy and run cygprofile_unittests')
-    exit_code = self._profiler.RunCygprofileTests()
-
-    if exit_code != 0:
-      self._step_recorder.FailStep(
-          'cygprofile_unittests exited with non-0 status: %d' % exit_code)
-
   @staticmethod
   def _RemoveBlanks(src_file, dest_file):
     """A utility to remove blank lines from a file.
@@ -537,20 +505,14 @@
           self._compiler.chrome_apk,
           constants.PACKAGE_INFO['chrome'])
       self._step_recorder.BeginStep('Process cyglog')
-      if self._options.lightweight_instrumentation:
-        assert os.path.exists(self._compiler.lib_chrome_so)
-        offsets = process_profiles.GetReachedOffsetsFromDumpFiles(
-            files, self._compiler.lib_chrome_so)
-        if not offsets:
-          raise Exception('No profiler offsets found in {}'.format(
-                          '\n'.join(files)))
-        with open(self._MERGED_CYGLOG_FILENAME, 'w') as f:
-          f.write('\n'.join(map(str, offsets)))
-      else:
-        with open(self._MERGED_CYGLOG_FILENAME, 'w') as merged_cyglog:
-          self._step_recorder.RunCommand([self._MERGE_TRACES_SCRIPT] + files,
-                                         constants.DIR_SOURCE_ROOT,
-                                         stdout=merged_cyglog)
+      assert os.path.exists(self._compiler.lib_chrome_so)
+      offsets = process_profiles.GetReachedOffsetsFromDumpFiles(
+          files, self._compiler.lib_chrome_so)
+      if not offsets:
+        raise Exception('No profiler offsets found in {}'.format(
+            '\n'.join(files)))
+      with open(self._MERGED_CYGLOG_FILENAME, 'w') as f:
+        f.write('\n'.join(map(str, offsets)))
     except Exception:
       for f in files:
         self._SaveForDebugging(f)
@@ -564,10 +526,7 @@
           '--target-arch=' + self._options.arch,
           '--native-library=' + self._compiler.lib_chrome_so,
           '--output=' + self._GetUnpatchedOrderfileFilename()]
-      if self._options.lightweight_instrumentation:
-        command_args.append('--reached-offsets=' + self._MERGED_CYGLOG_FILENAME)
-      else:
-        command_args.append('--merged-cyglog=' + self._MERGED_CYGLOG_FILENAME)
+      command_args.append('--reached-offsets=' + self._MERGED_CYGLOG_FILENAME)
       self._step_recorder.RunCommand(
           [self._CYGLOG_TO_ORDERFILE_SCRIPT] + command_args)
     except CommandError:
@@ -688,13 +647,9 @@
             self._instrumented_out_dir,
             self._step_recorder, self._options.arch, self._options.jobs,
             self._options.max_load, self._options.use_goma,
-            self._options.goma_dir,
-            self._options.lightweight_instrumentation)
-        self._RunCygprofileUnitTests()
-        if self._options.lightweight_instrumentation:
-          _EnsureOrderfileStartsWithAnchorSection(self._GetPathToOrderfile())
-        self._compiler.CompileChromeApk(
-            True, self._options.lightweight_instrumentation)
+            self._options.goma_dir)
+        _EnsureOrderfileStartsWithAnchorSection(self._GetPathToOrderfile())
+        self._compiler.CompileChromeApk(True)
         self._GenerateAndProcessProfile()
         self._MaybeArchiveOrderfile(self._GetUnpatchedOrderfileFilename())
         profile_uploaded = True
@@ -710,8 +665,7 @@
         self._compiler = ClankCompiler(
             self._uninstrumented_out_dir, self._step_recorder,
             self._options.arch, self._options.jobs, self._options.max_load,
-            self._options.use_goma, self._options.goma_dir,
-            self._options.lightweight_instrumentation)
+            self._options.use_goma, self._options.goma_dir)
         self._compiler.CompileLibchrome(False)
         self._PatchOrderfile()
         # Because identical code folding is a bit different with and without
@@ -748,10 +702,6 @@
   """Creates and returns the argument parser."""
   parser = argparse.ArgumentParser()
   parser.add_argument(
-      '--regular-instrumentation', action='store_false',
-      dest='lightweight_instrumentation',
-      help='Use the regular instrumentation path')
-  parser.add_argument(
       '--buildbot', action='store_true',
       help='If true, the script expects to be run on a buildbot')
   parser.add_argument(
diff --git a/tools/cygprofile/profile_android_startup.py b/tools/cygprofile/profile_android_startup.py
index ba96bce8..c71fb53 100755
--- a/tools/cygprofile/profile_android_startup.py
+++ b/tools/cygprofile/profile_android_startup.py
@@ -393,6 +393,9 @@
       cyglog_dir = os.path.join(self._host_cyglog_dir, 'cyglog')
       files = os.listdir(cyglog_dir)
 
+    if len(files) == 0:
+      raise NoCyglogDataError('No cyglog data was collected')
+
     return [os.path.join(cyglog_dir, x) for x in files]
 
 
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index bb90bf4..e5105caef 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -25712,6 +25712,7 @@
   <int value="-1868284723" label="DirectManipulationStylus:disabled"/>
   <int value="-1867382602" label="WebRTC-H264WithOpenH264FFmpeg:enabled"/>
   <int value="-1867342522" label="MaterialDesignHistory:enabled"/>
+  <int value="-1863962664" label="LockScreenNotifications:enabled"/>
   <int value="-1861814223" label="MidiManagerDynamicInstantiation:enabled"/>
   <int value="-1860481724" label="ChromeHomeExpandButton:enabled"/>
   <int value="-1859095876" label="Previews:disabled"/>
@@ -26059,6 +26060,7 @@
   <int value="-1033738911" label="enable-mac-views-dialogs"/>
   <int value="-1029920490" label="IdleTimeSpellChecking:enabled"/>
   <int value="-1028733699" label="MacViewsWebUIDialogs:disabled"/>
+  <int value="-1027254093" label="LockScreenNotifications:disabled"/>
   <int value="-1027124889" label="NtlmV2Enabled:enabled"/>
   <int value="-1022971520" label="enable-search-button-in-omnibox-for-str"/>
   <int value="-1022165708" label="BreakingNewsPush:disabled"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 91c3e01..b7db1f6 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -80416,6 +80416,18 @@
   </summary>
 </histogram>
 
+<histogram name="Security.SecurityLevel.DownloadStarted" enum="SecurityLevel">
+  <owner>cthomp@chromium.org</owner>
+  <summary>
+    Records the security level of the page that initiated a download (rather
+    than the security state of the connection to the download URL itself). The
+    recorded security level is the level of the page the download was initiated
+    from, not that of the download URL. This histogram is not recorded for
+    downloads that are initiated in a new tab or window, as the security level
+    of the initiating page cannot be tracked.
+  </summary>
+</histogram>
+
 <histogram name="Security.SecurityLevel.FormSubmission" enum="SecurityLevel">
   <owner>carlosil@chromium.org</owner>
   <owner>cthomp@chromium.org</owner>
diff --git a/tools/perf/process_perf_results.py b/tools/perf/process_perf_results.py
index 1bd7bbd6..5184774 100755
--- a/tools/perf/process_perf_results.py
+++ b/tools/perf/process_perf_results.py
@@ -90,21 +90,35 @@
       for f in listdir(join(task_output_dir, directory))
     ]
 
+  # We need to keep track of disabled benchmarks so we don't try to
+  # upload the results.
+  disabled_benchmarks = []
   test_results_list = []
   tmpfile_dir = tempfile.mkdtemp('resultscache')
   try:
     for directory in benchmark_directory_list:
-      if '.reference' in directory:
-        # We don't need to upload reference build data to the
-        # flakiness dashboard since we don't monitor the ref build
-        continue
       with open(join(directory, 'test_results.json')) as json_data:
-        test_results_list.append(json.load(json_data))
+        json_results = json.load(json_data)
+        if json_results.get('version') == 3:
+          # Non-telemetry tests don't have written json results but
+          # if they are executing then they are enabled and will generate
+          # chartjson results.
+          if not bool(json_results.get('tests')):
+            disabled_benchmarks.append(directory)
+        if '.reference' in directory:
+          # We don't need to upload reference build data to the
+          # flakiness dashboard since we don't monitor the ref build
+          continue
+        test_results_list.append(json_results)
     _merge_json_output(output_json, test_results_list)
 
     with oauth_api.with_access_token(service_account_file) as oauth_file:
       for directory in benchmark_directory_list:
         print 'Uploading perf results from %s benchmark' % directory
+        if directory in disabled_benchmarks:
+          # We don't upload disabled benchmarks
+          print 'Benchmark %s disabled' % directory
+          continue
         _upload_perf_results(join(directory, 'perf_results.json'),
             directory, configuration_name, build_properties,
             oauth_file, tmpfile_dir)
diff --git a/ui/base/ui_base_features.cc b/ui/base/ui_base_features.cc
index c227b35..2ff84fc 100644
--- a/ui/base/ui_base_features.cc
+++ b/ui/base/ui_base_features.cc
@@ -73,4 +73,17 @@
 #endif
 }
 
+#if defined(OS_MACOSX) && BUILDFLAG(MAC_VIEWS_BROWSER)
+// Causes Views browser builds to use Views browser windows by default rather
+// than Cocoa browser windows.
+const base::Feature kViewsBrowserWindows{"ViewsBrowserWindows",
+                                         base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Returns whether a Views-capable browser build should use the Cocoa browser
+// UI.
+bool IsViewsBrowserCocoa() {
+  return !base::FeatureList::IsEnabled(kViewsBrowserWindows);
+}
+#endif  //  defined(OS_MACOSX) && BUILDFLAG(MAC_VIEWS_BROWSER)
+
 }  // namespace features
diff --git a/ui/base/ui_base_features.h b/ui/base/ui_base_features.h
index f21fb22..c7d20168e 100644
--- a/ui/base/ui_base_features.h
+++ b/ui/base/ui_base_features.h
@@ -8,6 +8,7 @@
 #include "base/feature_list.h"
 #include "build/build_config.h"
 #include "ui/base/ui_base_export.h"
+#include "ui/base/ui_features.h"
 
 namespace features {
 
@@ -39,6 +40,14 @@
 // TODO(sky): rename this to IsWindowServiceEnabled().
 UI_BASE_EXPORT bool IsMusEnabled();
 
+#if defined(OS_MACOSX) && BUILDFLAG(MAC_VIEWS_BROWSER)
+UI_BASE_EXPORT extern const base::Feature kViewsBrowserWindows;
+
+// Returns whether a Views-capable browser build should use the Cocoa browser
+// UI.
+UI_BASE_EXPORT bool IsViewsBrowserCocoa();
+#endif  //  defined(OS_MACOSX) && BUILDFLAG(MAC_VIEWS_BROWSER)
+
 }  // namespace features
 
 #endif  // UI_BASE_UI_BASE_FEATURES_H_
diff --git a/ui/base/win/on_screen_keyboard_display_manager_tab_tip.cc b/ui/base/win/on_screen_keyboard_display_manager_tab_tip.cc
index 23b0379..e4c4a6d0 100644
--- a/ui/base/win/on_screen_keyboard_display_manager_tab_tip.cc
+++ b/ui/base/win/on_screen_keyboard_display_manager_tab_tip.cc
@@ -22,7 +22,7 @@
 #include "base/win/windows_version.h"
 #include "ui/base/win/hidden_window.h"
 #include "ui/base/win/osk_display_observer.h"
-#include "ui/display/win/dpi.h"
+#include "ui/display/win/screen_win.h"
 #include "ui/gfx/geometry/dip_util.h"
 
 namespace {
@@ -66,10 +66,13 @@
   void AddObserver(OnScreenKeyboardObserver* observer);
   void RemoveObserver(OnScreenKeyboardObserver* observer);
 
-  // Returns true if the osk is visible. Sets osk bounding rect if non-null
-  static bool IsKeyboardVisible(gfx::Rect* osk_bounding_rect);
+  // Returns true if the osk is visible.
+  static bool IsKeyboardVisible();
 
  private:
+  // Returns the occluded rect in dips.
+  gfx::Rect GetOccludedRect();
+
   // Executes as a task and detects if the on screen keyboard is displayed.
   // Once the keyboard is displayed it schedules the HideIfNecessary() task to
   // detect when the keyboard is or should be hidden.
@@ -82,7 +85,7 @@
   // Notifies observers that the keyboard was displayed.
   // A recurring task HideIfNecessary() is started to detect when the OSK
   // disappears.
-  void HandleKeyboardVisible();
+  void HandleKeyboardVisible(const gfx::Rect& occluded_rect);
 
   // Notifies observers that the keyboard was hidden.
   // The observer list is cleared out after this notification.
@@ -97,9 +100,6 @@
   // Tracks if the keyboard was displayed.
   bool osk_visible_notification_received_ = false;
 
-  // The keyboard dimensions in pixels.
-  gfx::Rect osk_rect_pixels_;
-
   // Set to true if a call to DetectKeyboard() was made.
   bool keyboard_detect_requested_ = false;
 
@@ -178,22 +178,39 @@
 }
 
 // static
-bool OnScreenKeyboardDetector::IsKeyboardVisible(gfx::Rect* osk_bounding_rect) {
+bool OnScreenKeyboardDetector::IsKeyboardVisible() {
   HWND osk = ::FindWindow(kOSKClassName, nullptr);
   if (!::IsWindow(osk))
     return false;
-  if (osk_bounding_rect) {
-    RECT osk_rect = {};
-    ::GetWindowRect(osk, &osk_rect);
-    *osk_bounding_rect = gfx::Rect(osk_rect);
-  }
   return ::IsWindowVisible(osk) && ::IsWindowEnabled(osk);
 }
 
+gfx::Rect OnScreenKeyboardDetector::GetOccludedRect() {
+  gfx::Rect occluded_rect;
+  HWND osk = ::FindWindow(kOSKClassName, nullptr);
+  if (!::IsWindow(osk) || !::IsWindowVisible(osk) || !::IsWindowEnabled(osk))
+    return occluded_rect;
+
+  RECT osk_rect = {};
+  RECT main_window_rect = {};
+  if (!::GetWindowRect(osk, &osk_rect) ||
+      !::GetWindowRect(main_window_, &main_window_rect)) {
+    return occluded_rect;
+  }
+
+  gfx::Rect gfx_osk_rect(osk_rect);
+  gfx::Rect gfx_main_window_rect(main_window_rect);
+
+  gfx_osk_rect.Intersect(gfx_main_window_rect);
+
+  return display::win::ScreenWin::ScreenToDIPRect(main_window_, gfx_osk_rect);
+}
+
 void OnScreenKeyboardDetector::CheckIfKeyboardVisible() {
-  if (IsKeyboardVisible(&osk_rect_pixels_)) {
+  gfx::Rect occluded_rect = GetOccludedRect();
+  if (!occluded_rect.IsEmpty()) {
     if (!osk_visible_notification_received_)
-      HandleKeyboardVisible();
+      HandleKeyboardVisible(occluded_rect);
   } else {
     DVLOG(1) << "OSK did not come up. Something wrong.";
   }
@@ -233,12 +250,13 @@
   }
 }
 
-void OnScreenKeyboardDetector::HandleKeyboardVisible() {
+void OnScreenKeyboardDetector::HandleKeyboardVisible(
+    const gfx::Rect& occluded_rect) {
   DCHECK(!osk_visible_notification_received_);
   osk_visible_notification_received_ = true;
 
   for (OnScreenKeyboardObserver& observer : observers_)
-    observer.OnKeyboardVisible(osk_rect_pixels_);
+    observer.OnKeyboardVisible(occluded_rect);
 
   // Now that the keyboard is visible, run the task to detect if it was hidden.
   base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
@@ -251,7 +269,7 @@
 void OnScreenKeyboardDetector::HandleKeyboardHidden() {
   osk_visible_notification_received_ = false;
   for (OnScreenKeyboardObserver& observer : observers_)
-    observer.OnKeyboardHidden(osk_rect_pixels_);
+    observer.OnKeyboardHidden();
   ClearObservers();
 }
 
@@ -368,7 +386,7 @@
 }
 
 bool OnScreenKeyboardDisplayManagerTabTip::IsKeyboardVisible() const {
-  return OnScreenKeyboardDetector::IsKeyboardVisible(nullptr);
+  return OnScreenKeyboardDetector::IsKeyboardVisible();
 }
 
 }  // namespace ui
diff --git a/ui/base/win/osk_display_observer.h b/ui/base/win/osk_display_observer.h
index 8c5d092..16d341a 100644
--- a/ui/base/win/osk_display_observer.h
+++ b/ui/base/win/osk_display_observer.h
@@ -17,10 +17,9 @@
  public:
   virtual ~OnScreenKeyboardObserver() {}
 
-  // The |keyboard_rect| parameter contains the bounds of the keyboard in
-  // pixels.
-  virtual void OnKeyboardVisible(const gfx::Rect& keyboard_rect_in_pixels) {}
-  virtual void OnKeyboardHidden(const gfx::Rect& keyboard_rect_in_pixels) {}
+  // The |keyboard_rect| parameter contains the bounds of the keyboard in dips.
+  virtual void OnKeyboardVisible(const gfx::Rect& keyboard_rect) {}
+  virtual void OnKeyboardHidden() {}
 };
 
 }  // namespace ui
diff --git a/ui/gfx/x/x11.h b/ui/gfx/x/x11.h
index eb53d6d..4bce2bc 100644
--- a/ui/gfx/x/x11.h
+++ b/ui/gfx/x/x11.h
@@ -89,6 +89,7 @@
 #undef Bool           // Defined by X11/Xlib.h to int
 #undef RootWindow     // Defined by X11/Xlib.h
 #undef DestroyAll     // Defined by X11/X.h to 0
+#undef AddToList      // Defined by X11/extensions/XI.h to 0
 #undef COUNT          // Defined by X11/extensions/XI.h to 0
 #undef CREATE         // Defined by X11/extensions/XI.h to 1
 #undef DeviceAdded    // Defined by X11/extensions/XI.h to 0
diff --git a/ui/views/controls/button/checkbox.cc b/ui/views/controls/button/checkbox.cc
index 84684604..ecdcda3d 100644
--- a/ui/views/controls/button/checkbox.cc
+++ b/ui/views/controls/button/checkbox.cc
@@ -16,6 +16,7 @@
 #include "ui/gfx/color_utils.h"
 #include "ui/gfx/paint_vector_icon.h"
 #include "ui/native_theme/native_theme.h"
+#include "ui/views/accessibility/view_accessibility.h"
 #include "ui/views/animation/ink_drop_impl.h"
 #include "ui/views/animation/ink_drop_ripple.h"
 #include "ui/views/controls/button/label_button_border.h"
@@ -76,6 +77,7 @@
 Checkbox::Checkbox(const base::string16& label, bool force_md)
     : LabelButton(NULL, label),
       checked_(false),
+      label_ax_id_(0),
       use_md_(force_md ||
               ui::MaterialDesignController::IsSecondaryUiMaterial()) {
   SetHorizontalAlignment(gfx::ALIGN_LEFT);
@@ -152,6 +154,18 @@
   label()->SetMultiLine(multi_line);
 }
 
+void Checkbox::SetAssociatedLabel(View* labelling_view) {
+  DCHECK(labelling_view);
+  label_ax_id_ = labelling_view->GetViewAccessibility().GetUniqueId().Get();
+  ui::AXNodeData node_data;
+  labelling_view->GetAccessibleNodeData(&node_data);
+  // TODO(aleventhal) automatically handle setting the name from the related
+  // label in view_accessibility and have it update the name if the text of the
+  // associated label changes.
+  SetAccessibleName(
+      node_data.GetString16Attribute(ax::mojom::StringAttribute::kName));
+}
+
 // TODO(tetsui): Remove this method and |use_md_| when MD for secondary UI
 // becomes default and IsSecondaryUiMaterial() is tautology.
 bool Checkbox::UseMd() const {
@@ -176,6 +190,10 @@
       node_data->SetDefaultActionVerb(ax::mojom::DefaultActionVerb::kCheck);
     }
   }
+  if (label_ax_id_) {
+    node_data->AddIntListAttribute(ax::mojom::IntListAttribute::kLabelledbyIds,
+                                   {label_ax_id_});
+  }
 }
 
 void Checkbox::OnFocus() {
diff --git a/ui/views/controls/button/checkbox.h b/ui/views/controls/button/checkbox.h
index f6605e8d..cec15a8 100644
--- a/ui/views/controls/button/checkbox.h
+++ b/ui/views/controls/button/checkbox.h
@@ -39,6 +39,12 @@
 
   void SetMultiLine(bool multi_line);
 
+  // If the accessible name should be the same as the labelling view's text,
+  // use this. It will set the accessible label relationship and copy the
+  // accessible name from the labelling views's accessible name. Any view with
+  // an accessible name can be used, e.g. a Label, StyledLabel or Link.
+  void SetAssociatedLabel(View* labelling_view);
+
  protected:
   // Returns whether MD is enabled. Returns true if |force_md| in the
   // constructor or --secondary-ui-md flag is set.
@@ -95,6 +101,9 @@
   // The images for each button node_data.
   gfx::ImageSkia images_[2][2][STATE_COUNT];
 
+  // The unique id for the associated label's accessible object.
+  int32_t label_ax_id_;
+
   bool use_md_;
 
   DISALLOW_COPY_AND_ASSIGN(Checkbox);
diff --git a/ui/views/controls/styled_label.cc b/ui/views/controls/styled_label.cc
index e99c027..51ae7229 100644
--- a/ui/views/controls/styled_label.cc
+++ b/ui/views/controls/styled_label.cc
@@ -13,6 +13,7 @@
 
 #include "base/i18n/rtl.h"
 #include "base/strings/string_util.h"
+#include "ui/accessibility/ax_node_data.h"
 #include "ui/gfx/font_list.h"
 #include "ui/gfx/text_elider.h"
 #include "ui/gfx/text_utils.h"
@@ -225,6 +226,15 @@
   return insets;
 }
 
+void StyledLabel::GetAccessibleNodeData(ui::AXNodeData* node_data) {
+  if (text_context_ == style::CONTEXT_DIALOG_TITLE)
+    node_data->role = ax::mojom::Role::kTitleBar;
+  else
+    node_data->role = ax::mojom::Role::kStaticText;
+
+  node_data->SetName(text());
+}
+
 gfx::Size StyledLabel::CalculatePreferredSize() const {
   return calculated_size_;
 }
diff --git a/ui/views/controls/styled_label.h b/ui/views/controls/styled_label.h
index e32c6f6..14a76375 100644
--- a/ui/views/controls/styled_label.h
+++ b/ui/views/controls/styled_label.h
@@ -127,6 +127,7 @@
   // View:
   const char* GetClassName() const override;
   gfx::Insets GetInsets() const override;
+  void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
   gfx::Size CalculatePreferredSize() const override;
   int GetHeightForWidth(int w) const override;
   void Layout() override;
diff --git a/ui/views/controls/textfield/textfield.cc b/ui/views/controls/textfield/textfield.cc
index be15588..51c15f6 100644
--- a/ui/views/controls/textfield/textfield.cc
+++ b/ui/views/controls/textfield/textfield.cc
@@ -319,9 +319,16 @@
   }
 }
 
-void Textfield::SetAssociatedLabel(Label* label) {
-  label_ax_id_ = label->GetViewAccessibility().GetUniqueId().Get();
-  accessible_name_ = label->text();
+void Textfield::SetAssociatedLabel(View* labelling_view) {
+  DCHECK(labelling_view);
+  label_ax_id_ = labelling_view->GetViewAccessibility().GetUniqueId().Get();
+  ui::AXNodeData node_data;
+  labelling_view->GetAccessibleNodeData(&node_data);
+  // TODO(aleventhal) automatically handle setting the name from the related
+  // label in view_accessibility and have it update the name if the text of the
+  // associated label changes.
+  SetAccessibleName(
+      node_data.GetString16Attribute(ax::mojom::StringAttribute::kName));
 }
 
 void Textfield::SetReadOnly(bool read_only) {
diff --git a/ui/views/controls/textfield/textfield.h b/ui/views/controls/textfield/textfield.h
index db30abd..5ab239d 100644
--- a/ui/views/controls/textfield/textfield.h
+++ b/ui/views/controls/textfield/textfield.h
@@ -224,10 +224,11 @@
   // label, use SetAssociatedLabel() instead.
   void SetAccessibleName(const base::string16& name);
 
-  // If the accessible name should be the same as the label text, use this. It
-  // will set both the accessible label relationship and the accessible name
-  // from the contents of the label.
-  void SetAssociatedLabel(Label* label);
+  // If the accessible name should be the same as the labelling view's text,
+  // use this. It will set the accessible label relationship and copy the
+  // accessible name from the labelling views's accessible name. Any view with
+  // an accessible name can be used, typically a Label, StyledLabel or Link.
+  void SetAssociatedLabel(View* labelling_view);
 
   // Set extra spacing placed between glyphs; used for obscured text styling.
   void SetGlyphSpacing(int spacing);