diff --git a/DEPS b/DEPS
index 8fa0a3d..446c6ed 100644
--- a/DEPS
+++ b/DEPS
@@ -145,7 +145,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': 'eb0770211a6c6914b9bf064bb14bb891d64f1fdc',
+  'skia_revision': '88681ddd1d38613649045bf07ac87a5cc4ac3319',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -157,7 +157,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': '7c8928d0a054da47dddb2dd06d4dd292d40a343d',
+  'angle_revision': '74ec0afe01ec39860a942ffd19f8f032ba6b54d6',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -165,7 +165,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': '77548ac65167a273c34e0e7c4d8eaf77eb8e0bb7',
+  'pdfium_revision': 'c9edc556eae15379bd56a91829d12f088f7739bc',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
@@ -208,7 +208,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '698405a9f62a8f11c0f6ca0d06cd050b8c8f32ec',
+  'catapult_revision': '131b9f32457cd29628f34617d84dfa41fccbdc47',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -809,7 +809,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '8be476e7a4e0f6e49ba88504aa47bc6f5d08b9aa',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '385c64442a09fbdbbec481cdb7012c4c54603da3',
       'condition': 'checkout_linux',
   },
 
@@ -824,7 +824,7 @@
 
   # For Linux and Chromium OS.
   'src/third_party/cros_system_api': {
-      'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + '206270625a4ac391aada9ac5f0c32a4e66e9f59c',
+      'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + 'c59652b94a7e9157193b5d631f3f061ccd282553',
       'condition': 'checkout_linux',
   },
 
@@ -834,7 +834,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '921f6a17514698ebc9b037f1f1e8696b6c359fdd',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '36756e4590417a41f3a9054527219294f02fead1',
 
   'src/third_party/devtools-node-modules':
     Var('chromium_git') + '/external/github.com/ChromeDevTools/devtools-node-modules' + '@' + Var('devtools_node_modules_revision'),
@@ -1375,7 +1375,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'abaae129d9a0c6e1e092067e0b105475df43352e',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '074f0d2d282d5d99a6aa380158da4d7441576590',
+    Var('webrtc_git') + '/src.git' + '@' + '7ba3b81ff5da33d845cbf3d11b5340bad07a9582',
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
@@ -1416,7 +1416,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@f399ecdef769fc56f838bcffae99296b81ea9ad5',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@f3e8b89c4fe8e11cf0d21209280884b5923fe591',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/WATCHLISTS b/WATCHLISTS
index 719cc12..fcc1e20 100644
--- a/WATCHLISTS
+++ b/WATCHLISTS
@@ -119,9 +119,6 @@
     'arc_auth': {
       'filepath': 'chrome/browser/chromeos/arc/arc_auth'
     },
-    'arc_common': {
-      'filepath': 'components/arc/common/',
-    },
     'arc_ime': {
       'filepath': 'chrome/browser/chromeos/arc/input_method_manager/'\
                   '|components/arc/ime/'
@@ -131,6 +128,9 @@
                   '|components/arc/kiosk/'\
                   '|arc_kiosk'
     },
+    'arc_mojom': {
+      'filepath': 'components/arc/mojom/',
+    },
     'arc_net': {
       'filepath': 'components/arc/net/',
     },
@@ -1015,7 +1015,7 @@
                   'extensions/browser/api/guest_view|'\
                   'extensions/browser/guest_view|'\
                   'extensions/common/guest_view|'\
-                  'extensions/common/mojo/guest_view.mojom|'\
+                  'extensions/common/mojom/guest_view.mojom|'\
                   'extensions/common/api/*view*.json|'\
                   'extensions/renderer/guest_view',
     },
@@ -1168,7 +1168,7 @@
     'media_remoting': {
       'filepath': 'chrome/browser/media/cast_remoting'\
                   '|media/blink/webmediaplayer_'\
-                  '|media/mojo/interfaces/remoting.mojom'\
+                  '|media/mojo/mojom/remoting.mojom'\
                   '|media/remoting/',
     },
     'media_router': {
@@ -1663,7 +1663,7 @@
         '|media/audio/(audio_output_controller|fake_audio_|virtual_audio_)'\
         '|media/base/video_frame\.h'\
         '|media/capture/'\
-        '|services/viz/privileged/interfaces/compositing/frame_sink',
+        '|services/viz/privileged/mojom/compositing/frame_sink',
     },
     'tab_contents': {
       'filepath': 'chrome/browser/tab_contents/|'\
@@ -1814,7 +1814,7 @@
       'filepath': 'wake_lock',
     },
     'wallpapers': {
-      'filepath': 'ash/public/interfaces/wallpaper.mojom'\
+      'filepath': 'components/arc/common/wallpaper.mojom'\
                   '|ash/wallpaper/'\
                   '|chrome/browser/resources/chromeos/wallpaper_manager/',
     },
@@ -1952,9 +1952,9 @@
             'yusukes+watch@chromium.org',
             'arc-reviews+chromium@google.com'],
     'arc_auth': ['khmel+watch@chromium.org'],
-    'arc_common': ['hashimoto+watch@chromium.org'],
     'arc_ime': ['yhanada+watch@chromium.org'],
     'arc_kiosk': ['poromov+watch@chromium.org'],
+    'arc_mojom': ['hashimoto+watch@chromium.org'],
     'arc_net': ['abhishekbh@chromium.org',
                 'cernekee@chromium.org',
                 'snanda@chromium.org'],
diff --git a/base/test/android/java/src/org/chromium/base/MultiprocessTestClientLauncher.java b/base/test/android/java/src/org/chromium/base/MultiprocessTestClientLauncher.java
index 0b4cbd6..711b1ef 100644
--- a/base/test/android/java/src/org/chromium/base/MultiprocessTestClientLauncher.java
+++ b/base/test/android/java/src/org/chromium/base/MultiprocessTestClientLauncher.java
@@ -200,6 +200,8 @@
     @CalledByNative
     private static int launchClient(
             final String[] commandLine, final FileDescriptorInfo[] filesToMap) {
+        assert Looper.myLooper() != Looper.getMainLooper();
+
         initLauncherThread();
 
         final MultiprocessTestClientLauncher launcher =
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index f7aa1939..6cd66dc6 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-8905936316590074976
\ No newline at end of file
+8905910019240628560
\ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index 71038d1..52f0f15 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-8905940684687891088
\ No newline at end of file
+8905916651051958496
\ No newline at end of file
diff --git a/chrome/BUILD.gn b/chrome/BUILD.gn
index 4224fe2..4234f227 100644
--- a/chrome/BUILD.gn
+++ b/chrome/BUILD.gn
@@ -1666,7 +1666,7 @@
   }
 
   if (!is_android && !is_chromeos) {
-    public_deps += [ "//chrome/browser/resources:welcome_resources" ]
+    public_deps += [ "//chrome/browser/resources:onboarding_welcome_resources" ]
   }
 
   if (enable_extensions) {
@@ -1939,11 +1939,11 @@
   if (is_official_build) {
     group("linux_symbols") {
       deps = [
-        ":angle_egl_symbols",
-        ":angle_gles_symbols",
         ":chrome_symbols",
         ":swiftshader_egl_symbols",
         ":swiftshader_gles_symbols",
+        ":angle_egl_symbols",
+        ":angle_gles_symbols",
       ]
     }
     extract_symbols("chrome_symbols") {
diff --git a/chrome/VERSION b/chrome/VERSION
index dc65ebe..fe2f221 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=78
 MINOR=0
-BUILD=3875
+BUILD=3876
 PATCH=0
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni
index 1f66d99..6ad1fc1 100644
--- a/chrome/android/chrome_java_sources.gni
+++ b/chrome/android/chrome_java_sources.gni
@@ -193,6 +193,7 @@
   "java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelContentViewDelegate.java",
   "java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelInflater.java",
   "java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelManager.java",
+  "java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelRepaddingTextView.java",
   "java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelTextViewInflater.java",
   "java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchBarBannerControl.java",
   "java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchBarControl.java",
@@ -450,6 +451,7 @@
   "java/src/org/chromium/chrome/browser/directactions/DirectActionHandler.java",
   "java/src/org/chromium/chrome/browser/directactions/DirectActionInitializer.java",
   "java/src/org/chromium/chrome/browser/directactions/DirectActionReporter.java",
+  "java/src/org/chromium/chrome/browser/directactions/DirectActionUsageHistogram.java",
   "java/src/org/chromium/chrome/browser/directactions/GoBackDirectActionHandler.java",
   "java/src/org/chromium/chrome/browser/directactions/CloseTabDirectActionHandler.java",
   "java/src/org/chromium/chrome/browser/directactions/SimpleDirectActionHandler.java",
diff --git a/chrome/android/java/res/layout/contextual_search_term_view.xml b/chrome/android/java/res/layout/contextual_search_term_view.xml
index 1eefacd..2ca028a 100644
--- a/chrome/android/java/res/layout/contextual_search_term_view.xml
+++ b/chrome/android/java/res/layout/contextual_search_term_view.xml
@@ -16,4 +16,4 @@
         android:background="@color/overlay_panel_bar_background_color"
         android:layout_marginStart="7dp"
         android:layout_marginEnd="7dp" />
-</FrameLayout>
\ No newline at end of file
+</FrameLayout>
diff --git a/chrome/android/java/res/layout/ephemeral_tab_text_view.xml b/chrome/android/java/res/layout/ephemeral_tab_text_view.xml
index 681ae4a..20de658 100644
--- a/chrome/android/java/res/layout/ephemeral_tab_text_view.xml
+++ b/chrome/android/java/res/layout/ephemeral_tab_text_view.xml
@@ -4,14 +4,13 @@
      found in the LICENSE file. -->
 
 <!-- Ephemeral Tab bar text -->
-<!-- TODO(jinsukkim): Define Ephemeral Tab's own text view style -->
 <FrameLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/ephemeral_tab_text_view"
-    style="@style/ContextualSearchTextViewLayout" >
+    style="@style/OverlayPanelTextViewLayout" >
     <TextView
         android:id="@+id/ephemeral_tab_text"
-        style="@style/ContextualSearchTextView"
+        style="@style/OverlayPanelTextView"
         android:layout_width="match_parent"
         android:layout_gravity="bottom"
         android:background="@color/overlay_panel_bar_background_color"
diff --git a/chrome/android/java/res/values-v17/styles.xml b/chrome/android/java/res/values-v17/styles.xml
index 3d824f90..26c624d 100644
--- a/chrome/android/java/res/values-v17/styles.xml
+++ b/chrome/android/java/res/values-v17/styles.xml
@@ -580,8 +580,8 @@
         <item name="android:alpha">0.6</item>
     </style>
 
-    <!-- Contextual Search styles -->
-    <style name="ContextualSearchTextViewLayout">
+    <!-- Generic Overlay Panel styles -->
+    <style name="OverlayPanelTextViewLayout">
         <item name="android:layout_width">match_parent</item>
         <item name="android:layout_height">wrap_content</item>
         <item name="android:layout_gravity">bottom</item>
@@ -589,14 +589,21 @@
         <item name="android:visibility">invisible</item>
         <!-- 60dp padding minus 7dp for fading edge -->
         <item name="android:paddingStart">53dp</item>
-        <item name="android:paddingEnd">53dp</item>
+        <!-- padding for icons that can appear on the right end of the Bar. -->
+        <item name="android:paddingEnd">@dimen/overlay_panel_end_buttons_width</item>
     </style>
-    <style name="ContextualSearchTextView" parent="@style/TextAppearance.BlackTitle1">
+    <style name="OverlayPanelTextView" parent="@style/TextAppearance.BlackTitle1">
         <item name="android:layout_height">match_parent</item>
         <item name="android:ellipsize">end</item>
         <item name="android:includeFontPadding">false</item>
         <item name="android:singleLine">true</item>
     </style>
+
+    <!-- Contextual Search Overlay styles -->
+    <style name="ContextualSearchTextViewLayout" parent="@style/OverlayPanelTextViewLayout">
+        <item name="android:paddingEnd">@dimen/contextual_search_end_padding</item>
+    </style>
+    <style name="ContextualSearchTextView" parent="@style/OverlayPanelTextView" />
     <style name="ContextualSearchContextTextView">
         <item name="android:layout_width">0dp</item>
         <item name="android:layout_height">match_parent</item>
diff --git a/chrome/android/java/res/values/dimens.xml b/chrome/android/java/res/values/dimens.xml
index a0a37da..b9c96686 100644
--- a/chrome/android/java/res/values/dimens.xml
+++ b/chrome/android/java/res/values/dimens.xml
@@ -110,20 +110,30 @@
     <dimen name="infobar_translate_fade_edge_length">18dp</dimen>
     <dimen name="infobar_translate_menu_width">260dp</dimen>
 
-    <!-- Contextual search dimensions -->
+    <!-- Overlay Panel dimensions -->
+    <dimen name="overlay_panel_end_buttons_width">94dp</dimen>
+    <dimen name="overlay_panel_padded_button_width">41dp</dimen>
+    <dimen name="overlay_panel_text_layer_min_height">38dp</dimen>
+    <dimen name="overlay_panel_button_padding">12dp</dimen>
+    <dimen name="overlay_panel_caption_spacing">1.5dp</dimen>
+
+    <!-- Contextual Search dimensions -->
     <dimen name="contextual_search_bar_banner_padding">12dp</dimen>
     <dimen name="contextual_search_bar_image_size">36dp</dimen>
-    <!-- The following two dimensions were taking from the UI specs for contextual search, where
-    they were 36dp and 3dp respectively, but have been updated to allow for padding around
-    TextViews that we cannot get rid of. -->
-    <dimen name="contextual_search_text_layer_min_height">38dp</dimen>
-    <dimen name="contextual_search_term_caption_spacing">1.5dp</dimen>
-    <!-- This is the offset of the divider from the end of the bar. -->
-    <dimen name="contextual_search_end_button_width">48dp</dimen>
-    <!-- Width of multiple buttons at the end of the Bar. -->
-    <dimen name="contextual_search_end_buttons_width">96dp</dimen>
+    <dimen name="contextual_search_text_layer_min_height">
+        @dimen/overlay_panel_text_layer_min_height
+    </dimen>
+    <dimen name="contextual_search_term_caption_spacing">
+        @dimen/overlay_panel_caption_spacing
+    </dimen>
+    <dimen name="contextual_search_padded_button_width">36dp</dimen>
+    <dimen name="contextual_search_end_buttons_width">
+      @dimen/overlay_panel_end_buttons_width
+    </dimen>
     <dimen name="contextual_search_divider_line_width">1dp</dimen>
     <dimen name="contextual_search_divider_line_height">24dp</dimen>
+    <!-- Padding at the end of the Bar. -->
+    <dimen name="contextual_search_end_padding">7dp</dimen>
     <dimen name="contextual_search_bubble_y_inset">-3dp</dimen>
 
     <!-- Overlay panel dimensions -->
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/DeviceConditions.java b/chrome/android/java/src/org/chromium/chrome/browser/DeviceConditions.java
index 21dd30a..c8dd1db 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/DeviceConditions.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/DeviceConditions.java
@@ -117,6 +117,23 @@
     }
 
     /**
+     * @return Whether the device is in idle / doze mode. This feature is only available in M and
+     * later versions of Android devices so it will return false for earlier versions.
+     */
+    public static boolean isCurrentlyInIdleMode(Context context) {
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
+            return false;
+        }
+        return isCurrentlyInIdleModeM(context);
+    }
+
+    @TargetApi(Build.VERSION_CODES.M)
+    private static boolean isCurrentlyInIdleModeM(Context context) {
+        PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+        return powerManager.isDeviceIdleMode();
+    }
+
+    /**
      * @return Network connection type, where possible values are defined by
      *     org.chromium.net.ConnectionType.
      */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanel.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanel.java
index d149f0d..da75293 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanel.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanel.java
@@ -28,7 +28,6 @@
 import org.chromium.chrome.browser.compositor.overlays.SceneOverlay;
 import org.chromium.chrome.browser.compositor.scene_layer.SceneOverlayLayer;
 import org.chromium.chrome.browser.multiwindow.MultiWindowUtils;
-import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.TabBrowserControlsState;
 import org.chromium.content_public.browser.SelectionPopupController;
 import org.chromium.content_public.browser.WebContents;
@@ -46,9 +45,6 @@
 public class OverlayPanel extends OverlayPanelAnimation implements ActivityStateListener,
         EdgeSwipeHandler, GestureHandler, OverlayPanelContentFactory, SceneOverlay {
 
-    /** The extra dp added around the close button touch target. */
-    private static final int CLOSE_BUTTON_TOUCH_SLOP_DP = 5;
-
     /** The delay after which the hide progress will be hidden. */
     private static final long HIDE_PROGRESS_BAR_DELAY_MS = 1000 / 60 * 4;
 
@@ -154,7 +150,6 @@
     /**
      * @param context The current Android {@link Context}.
      * @param updateHost The {@link LayoutUpdateHost} used to request updates in the Layout.
-     * @param eventHost The {@link EventFilterHost} used to propagate events.
      * @param panelManager The {@link OverlayPanelManager} responsible for showing panels.
      */
     public OverlayPanel(
@@ -643,9 +638,9 @@
      */
     protected boolean isCoordinateInsideCloseButton(float x) {
         if (LocalizationUtils.isLayoutRtl()) {
-            return x <= (getCloseIconX() + getCloseIconDimension() + CLOSE_BUTTON_TOUCH_SLOP_DP);
+            return x <= (getCloseIconX() + getCloseIconDimension() + mButtonPaddingDps);
         } else {
-            return x >= (getCloseIconX() - CLOSE_BUTTON_TOUCH_SLOP_DP);
+            return x >= (getCloseIconX() - mButtonPaddingDps);
         }
     }
 
@@ -654,9 +649,8 @@
      * @return Whether the given |x| coordinate is inside the close button.
      */
     protected boolean isCoordinateInsideOpenTabButton(float x) {
-        float width = getOpenTabIconDimension() + CLOSE_BUTTON_TOUCH_SLOP_DP;
-        return getOpenTabIconX() - CLOSE_BUTTON_TOUCH_SLOP_DP <= x
-                && x <= getOpenTabIconX() + width;
+        float width = getOpenTabIconDimension() + 2 * mButtonPaddingDps;
+        return getOpenTabIconX() - mButtonPaddingDps <= x && x <= getOpenTabIconX() + width;
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelBase.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelBase.java
index 1661b45..5f5fd39 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelBase.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelBase.java
@@ -15,6 +15,7 @@
 import org.chromium.base.VisibleForTesting;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeActivity;
+import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel.PanelState;
 import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel.StateChangeReason;
 import org.chromium.chrome.browser.util.MathUtils;
@@ -62,6 +63,7 @@
 
     /** The opacity of the arrow icon when the Panel is expanded. */
     private static final float ARROW_ICON_OPACITY_STATE_EXPANDED = 0.f;
+    private static final float ARROW_ICON_OPACITY_TRANSPARENT = 0.f;
 
     /** The opacity of the arrow icon when the Panel is maximized. */
     private static final float ARROW_ICON_OPACITY_STATE_MAXIMIZED = 0.f;
@@ -69,6 +71,15 @@
     /** The rotation of the arrow icon. */
     private static final float ARROW_ICON_ROTATION = -90.f;
 
+    /** The opacity of the Open-Tab icon when the Panel is peeking. */
+    private static final float OPEN_TAB_ICON_OPACITY_STATE_PEEKED = 1.f;
+
+    /** The opacity of the Open-Tab icon when the Panel is expanded. */
+    private static final float OPEN_TAB_ICON_OPACITY_STATE_EXPANDED = 0.f;
+
+    /** The opacity of the Open-Tab icon when the Panel is maximized. */
+    private static final float OPEN_TAB_ICON_OPACITY_STATE_MAXIMIZED = 0.f;
+
     /** The opacity of the close icon when the Panel is peeking. */
     private static final float CLOSE_ICON_OPACITY_STATE_PEEKED = 0.f;
 
@@ -111,7 +122,7 @@
     /** The background color of the Bar. */
     private final @ColorInt int mBarBackgroundColor;
 
-    /** The tint used for icons (e.g. arrow icon, close icon). */
+    /** The tint used for icons (e.g. close icon, etc). */
     private final @ColorInt int mIconColor;
 
     /** The tint used for drag handlebar. */
@@ -129,6 +140,9 @@
     /** The current state of the Overlay Panel. */
     private @PanelState int mPanelState = PanelState.UNDEFINED;
 
+    /** The padding on each side of the close and open-tab icons. */
+    protected final int mButtonPaddingDps;
+
     // ============================================================================================
     // Constructor
     // ============================================================================================
@@ -159,6 +173,8 @@
         mIconColor = ApiCompatibilityUtils.getColor(resources, R.color.default_icon_color);
         mDragHandlebarColor =
                 ApiCompatibilityUtils.getColor(resources, R.color.drag_handlebar_color);
+        mButtonPaddingDps =
+                (int) (mPxToDp * resources.getDimension(R.dimen.overlay_panel_button_padding));
     }
 
     // ============================================================================================
@@ -405,8 +421,8 @@
     // --------------------------------------------------------------------------------------------
     // Panel Bar states
     // --------------------------------------------------------------------------------------------
-    private float mBarMarginSide;
-    private float mBarMarginTop;
+    private final float mBarMarginSide;
+    private final float mBarMarginTop;
     private float mBarHeight;
     private boolean mIsBarBorderVisible;
     private float mBarBorderHeight;
@@ -495,7 +511,9 @@
      * @return The opacity of the arrow icon.
      */
     public float getArrowIconOpacity() {
-        return mArrowIconOpacity;
+        return ChromeFeatureList.isEnabled(ChromeFeatureList.OVERLAY_NEW_LAYOUT)
+                ? ARROW_ICON_OPACITY_TRANSPARENT
+                : mArrowIconOpacity;
     }
 
     /**
@@ -550,7 +568,7 @@
      * @return The left X coordinate of the open new tab icon.
      */
     public float getOpenTabIconX() {
-        float offset = getCloseIconDimension() + getBarMarginSide();
+        float offset = getCloseIconDimension() + 2 * mButtonPaddingDps;
         if (LocalizationUtils.isLayoutRtl()) {
             return getCloseIconX() + offset;
         } else {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelRepaddingTextView.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelRepaddingTextView.java
new file mode 100644
index 0000000..f05515b
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelRepaddingTextView.java
@@ -0,0 +1,94 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.compositor.bottombar;
+
+import android.content.Context;
+import android.view.View;
+import android.view.ViewGroup;
+
+import org.chromium.ui.resources.dynamics.DynamicResourceLoader;
+
+/**
+ * Provides a TextView whose end padding can be adjusted between a short and long size.
+ * This implementation simply does a binary transition when the panel is 50% of the way
+ * between peek and expanded states.
+ */
+public abstract class OverlayPanelRepaddingTextView extends OverlayPanelInflater {
+    private static final float REPADDING_THRESHOLD = 0.5f;
+
+    private final float mPeekedEndButtonsWidth;
+    private final float mExpandedEndButtonsWidth;
+
+    private int mPaddingStart;
+    private int mPaddingTop;
+    private int mPaddingBottom;
+
+    private boolean mIsPanelExpandedBeyondHalf;
+    private boolean mWasPanelExpandedBeyondHalf;
+
+    /**
+     * @param panel             The panel.
+     * @param layoutResource    The Layout that contains the Text View we're managing.
+     * @param layoutId          The resource ID of the layout.
+     * @param context           The Android Context used to inflate the View.
+     * @param container         The container View used to inflate the View.
+     * @param resourceLoader    The resource loader that will handle the snapshot capturing.
+     * @param peekedDimension   The dimension resource for the padding when the Overlay is Peeked.
+     * @param expandedDimension The dimension resource for the padding when the Overlay is Expanded.
+     */
+    public OverlayPanelRepaddingTextView(OverlayPanel panel, int layoutResource, int layoutId,
+            Context context, ViewGroup container, DynamicResourceLoader resourceLoader,
+            int peekedDimension, int expandedDimension) {
+        super(panel, layoutResource, layoutId, context, container, resourceLoader);
+        mPeekedEndButtonsWidth =
+                peekedDimension == 0 ? 0 : context.getResources().getDimension(peekedDimension);
+        mExpandedEndButtonsWidth =
+                expandedDimension == 0 ? 0 : context.getResources().getDimension(expandedDimension);
+    }
+
+    /**
+     * Updates the text view during the transition of the Overlay from Peeked to Expanded states.
+     * @param percentage A value from 0 to 1 that indicates the degree to which the panel has
+     *        been expanded.
+     */
+    public void onUpdateFromPeekToExpand(float percentage) {
+        mIsPanelExpandedBeyondHalf = percentage > REPADDING_THRESHOLD;
+        invalidateIfNeeded(false);
+    }
+
+    @Override
+    public void invalidate() {
+        invalidateIfNeeded(true);
+    }
+
+    /**
+     * Invalidates the view, if needed.  Checks the {@code mIsPanelExpandedBeyondHalf} private
+     * member to see if the panel is beyond a threshold that's part way between peek and expanded
+     * states.
+     * @param alwaysInvalidate When {@code true}, makes sure that {@link #invalidate} is called.
+     */
+    protected void invalidateIfNeeded(boolean alwaysInvalidate) {
+        View view = getView();
+        if (view == null
+                || !alwaysInvalidate && mIsPanelExpandedBeyondHalf == mWasPanelExpandedBeyondHalf) {
+            return;
+        }
+
+        mWasPanelExpandedBeyondHalf = mIsPanelExpandedBeyondHalf;
+        int barPaddingWidth = (int) (mIsPanelExpandedBeyondHalf ? mExpandedEndButtonsWidth
+                                                                : mPeekedEndButtonsWidth);
+        view.setPaddingRelative(mPaddingStart, mPaddingTop, barPaddingWidth, mPaddingBottom);
+        super.invalidate();
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        View view = getView();
+        mPaddingStart = view.getPaddingStart();
+        mPaddingTop = view.getPaddingTop();
+        mPaddingBottom = view.getPaddingBottom();
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelTextViewInflater.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelTextViewInflater.java
index c7c7fd7..ad1a6af 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelTextViewInflater.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelTextViewInflater.java
@@ -21,19 +21,45 @@
  * Details in this issue: crbug.com/651389.
  */
 public abstract class OverlayPanelTextViewInflater
-        extends OverlayPanelInflater implements OnLayoutChangeListener {
+        extends OverlayPanelRepaddingTextView implements OnLayoutChangeListener {
     private static final float SHORTNESS_FACTOR = 0.5f;
 
     private boolean mDidAdjustViewDirection;
 
     /**
-     * Constructs an instance similar to an {@link OverlayPanelInflater} that can adjust the RTL/LTR
-     * ordering of text fragments whose initial values are considered short relative to the width
-     * of the view.
+     * Constructs an instance similar to an {@link OverlayPanelRepaddingTextView} that can adjust
+     * the RTL/LTR ordering of text fragments whose initial values are considered short relative to
+     * the width of the view.
+     * @param panel             The panel.
+     * @param layoutId          The resource ID of the layout.
+     * @param viewId            The resource ID of the text view.
+     * @param context           The Android Context used to inflate the View.
+     * @param container         The container View used to inflate the View.
+     * @param resourceLoader    The resource loader that will handle the snapshot capturing.
+     * @param peekedDimension   The dimension resource for the padding when the Overlay is Peeked.
+     * @param expandedDimension The dimension resource for the padding when the Overlay is Expanded.
+     */
+    public OverlayPanelTextViewInflater(OverlayPanel panel, int layoutId, int viewId,
+            Context context, ViewGroup container, DynamicResourceLoader resourceLoader,
+            int peekedDimension, int expandedDimension) {
+        super(panel, layoutId, viewId, context, container, resourceLoader, peekedDimension,
+                expandedDimension);
+    }
+
+    /**
+     * Constructs an instance similar to an {@link OverlayPanelRepaddingTextView} that can adjust
+     * the RTL/LTR ordering of text fragments whose initial values are considered short relative to
+     * the width of the view.
+     * @param panel             The panel.
+     * @param layoutId          The resource ID of the layout.
+     * @param viewId            The resource ID of the text view.
+     * @param context           The Android Context used to inflate the View.
+     * @param container         The container View used to inflate the View.
+     * @param resourceLoader    The resource loader that will handle the snapshot capturing.
      */
     public OverlayPanelTextViewInflater(OverlayPanel panel, int layoutId, int viewId,
             Context context, ViewGroup container, DynamicResourceLoader resourceLoader) {
-        super(panel, layoutId, viewId, context, container, resourceLoader);
+        super(panel, layoutId, viewId, context, container, resourceLoader, 0, 0);
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchBarControl.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchBarControl.java
index e9aec8ff..3740d30 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchBarControl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchBarControl.java
@@ -15,6 +15,7 @@
 import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.compositor.animation.CompositorAnimator;
 import org.chromium.chrome.browser.compositor.bottombar.OverlayPanelAnimation;
+import org.chromium.chrome.browser.contextualsearch.QuickActionCategory;
 import org.chromium.ui.base.LocalizationUtils;
 import org.chromium.ui.resources.dynamics.DynamicResourceLoader;
 
@@ -28,9 +29,6 @@
     /** Transparent opacity -- completely transparent (not visible). */
     private static final float TRANSPARENT_OPACITY = 0.0f;
 
-    /** The opacity of the divider line when using the generic UX. */
-    private static final float DIVIDER_LINE_OPACITY_GENERIC = FULL_OPACITY;
-
     /**
      * The panel used to get information about the panel layout.
      */
@@ -62,6 +60,12 @@
      */
     private final ContextualSearchCardIconControl mCardIconControl;
 
+    /** The width of our icons, including padding, in pixels. */
+    private final float mPaddedIconWidthPx;
+
+    /** The start offset of the middle icon in the Bar, in pixels. */
+    private final int mMiddleIconStartPx;
+
     /**
      * The {@link ContextualSearchImageControl} for the panel.
      */
@@ -165,11 +169,18 @@
                 R.dimen.contextual_search_divider_line_height);
         mDividerLineColor = ApiCompatibilityUtils.getColor(
                 context.getResources(), R.color.contextual_search_divider_line_color);
+
         int endButtonsWidthDimension =
                 ChromeFeatureList.isEnabled(ChromeFeatureList.OVERLAY_NEW_LAYOUT)
                 ? R.dimen.contextual_search_end_buttons_width
-                : R.dimen.contextual_search_end_button_width;
-        mEndButtonWidth = context.getResources().getDimension(endButtonsWidthDimension);
+                : R.dimen.contextual_search_padded_button_width;
+        mEndButtonWidth = context.getResources().getDimension(endButtonsWidthDimension)
+                + context.getResources().getDimension(R.dimen.overlay_panel_button_padding);
+        // Number of pixels from the end of the Bar.
+        mMiddleIconStartPx = context.getResources().getDimensionPixelSize(
+                R.dimen.overlay_panel_end_buttons_width);
+        mPaddedIconWidthPx =
+                context.getResources().getDimension(R.dimen.overlay_panel_padded_button_width);
         mDpToPx = context.getResources().getDisplayMetrics().density;
     }
 
@@ -232,11 +243,14 @@
 
         // If there is a quick action, the divider line's appearance was animated when the quick
         // action was set.
-        if (!getQuickActionControl().hasQuickAction()) {
+        if (!getQuickActionControl().hasQuickAction()
+                && !ChromeFeatureList.isEnabled(ChromeFeatureList.OVERLAY_NEW_LAYOUT)) {
             mDividerLineVisibilityPercentage = percentage;
         }
         getImageControl().onUpdateFromPeekToExpand(percentage);
         mCaptionControl.onUpdateFromPeekToExpand(percentage);
+        mSearchTermControl.onUpdateFromPeekToExpand(percentage);
+        mContextControl.onUpdateFromPeekToExpand(percentage);
     }
 
     /**
@@ -357,8 +371,8 @@
      * @param toolbarBackgroundColor The current toolbar background color. This may be used for
      *                               icon tinting.
      */
-    public void setQuickAction(
-            String quickActionUri, int quickActionCategory, int toolbarBackgroundColor) {
+    public void setQuickAction(String quickActionUri, @QuickActionCategory int quickActionCategory,
+            int toolbarBackgroundColor) {
         mQuickActionControl.setQuickAction(
                 quickActionUri, quickActionCategory, toolbarBackgroundColor);
         if (mQuickActionControl.hasQuickAction()) {
@@ -450,6 +464,8 @@
      * @param visible Whether the divider line should be made visible.
      */
     private void animateDividerLine(boolean visible) {
+        if (ChromeFeatureList.isEnabled(ChromeFeatureList.OVERLAY_NEW_LAYOUT)) return;
+
         float endValue = visible ? FULL_OPACITY : TRANSPARENT_OPACITY;
         if (mDividerLineVisibilityPercentage == endValue) return;
         if (mDividerLineVisibilityAnimation != null) mDividerLineVisibilityAnimation.cancel();
@@ -480,6 +496,12 @@
      */
     private boolean mWasDividerVisibleOnTouch;
 
+    /** Where the touch highlight should start, in pixels. */
+    private float mTouchHighlightXOffsetPx;
+
+    /** The width of the touch highlight, in pixels. */
+    private float mTouchHighlightWidthPx;
+
     /**
      * @return Whether the touch highlight is visible.
      */
@@ -491,6 +513,10 @@
      * @return The x-offset of the touch highlight in pixels.
      */
     public float getTouchHighlightXOffsetPx() {
+        if (ChromeFeatureList.isEnabled(ChromeFeatureList.OVERLAY_NEW_LAYOUT)) {
+            return mTouchHighlightXOffsetPx;
+        }
+
         if (mWasDividerVisibleOnTouch
                 && ((mWasTouchOnEndButton && !LocalizationUtils.isLayoutRtl())
                 || (!mWasTouchOnEndButton && LocalizationUtils.isLayoutRtl()))) {
@@ -508,6 +534,10 @@
      * @return The width of the touch highlight in pixels.
      */
     public float getTouchHighlightWidthPx() {
+        if (ChromeFeatureList.isEnabled(ChromeFeatureList.OVERLAY_NEW_LAYOUT)) {
+            return mTouchHighlightWidthPx;
+        }
+
         if (mWasDividerVisibleOnTouch) {
             // The touch was on the end button so the touch highlight should cover the end button.
             if (mWasTouchOnEndButton) return mEndButtonWidth;
@@ -525,19 +555,58 @@
 
     /**
      * Should be called when the Bar is clicked.
-     * @param x The x-position of the click in px.
+     * @param xDps The x-position of the click in DPs.
      */
-    public void onSearchBarClick(float x) {
-        showTouchHighlight(x);
+    public void onSearchBarClick(float xDps) {
+        showTouchHighlight(xDps * mDpToPx);
     }
 
     /**
      * Should be called when an onShowPress() event occurs on the Bar.
-     * See {@link GestureDetector.SimpleOnGestureListener#onShowPress()}.
-     * @param x The x-position of the touch in px.
+     * See {@code GestureDetector.SimpleOnGestureListener#onShowPress()}.
+     * @param xDps The x-position of the touch in DPs.
      */
-    public void onShowPress(float x) {
-        showTouchHighlight(x);
+    public void onShowPress(float xDps) {
+        showTouchHighlight(xDps * mDpToPx);
+    }
+
+    /**
+     * Classifies the give x position in pixels and computes the highlight offset and width.
+     * @param xPx The x-coordinate of a touch location, in pixels.
+     */
+    private void classifyTouchLocation(float xPx) {
+        assert ChromeFeatureList.isEnabled(ChromeFeatureList.OVERLAY_NEW_LAYOUT);
+
+        // There are 4 cases:
+        // 1) The whole Bar minus icons (when 2 icons present)
+        // 2) The middle icon
+        // 3) The end icon
+        // 4) The whole Bar (without any icons)
+        boolean wereIconsVisibleOnTouch = !mContextualSearchPanel.isPeeking();
+        int panelWidth = mContextualSearchPanel.getContentViewWidthPx();
+        if (wereIconsVisibleOnTouch) {
+            int barWidthMinusIcons = panelWidth - mMiddleIconStartPx;
+            if (xPx < barWidthMinusIcons) {
+                // Case 1 - whole Bar minus icons.
+                mTouchHighlightXOffsetPx = 0;
+                mTouchHighlightWidthPx = barWidthMinusIcons;
+            } else if (xPx < barWidthMinusIcons + mPaddedIconWidthPx) {
+                // Case 2 - middle icon.
+                mTouchHighlightXOffsetPx = barWidthMinusIcons;
+                mTouchHighlightWidthPx = mPaddedIconWidthPx;
+            } else {
+                // Case 3 - end icon.
+                mTouchHighlightXOffsetPx = barWidthMinusIcons + mPaddedIconWidthPx;
+                mTouchHighlightWidthPx = panelWidth - mTouchHighlightXOffsetPx;
+            }
+        } else {
+            // Case 4 - whole Bar.
+            mTouchHighlightXOffsetPx = 0;
+            mTouchHighlightWidthPx = panelWidth;
+        }
+        if (LocalizationUtils.isLayoutRtl()) {
+            mTouchHighlightXOffsetPx = panelWidth - mTouchHighlightXOffsetPx;
+        }
     }
 
     /**
@@ -550,17 +619,20 @@
         mWasTouchOnEndButton = isTouchOnEndButton(x);
 
         // If the panel is expanded or maximized and the panel content cannot be promoted to a new
-        // tab, then tapping anywhere besides the end button does nothing. In this case, the touch
+        // tab, then tapping anywhere besides the end buttons does nothing. In this case, the touch
         // highlight should not be shown.
-        if (!mWasTouchOnEndButton && !mContextualSearchPanel.isPeeking() && !mCanPromoteToNewTab)
-            return;
+        if (!mContextualSearchPanel.isPeeking() && !mCanPromoteToNewTab) return;
 
-        mWasDividerVisibleOnTouch = getDividerLineVisibilityPercentage() > TRANSPARENT_OPACITY;
+        if (ChromeFeatureList.isEnabled(ChromeFeatureList.OVERLAY_NEW_LAYOUT)) {
+            classifyTouchLocation(x);
+        } else {
+            mWasDividerVisibleOnTouch = getDividerLineVisibilityPercentage() > TRANSPARENT_OPACITY;
+        }
         mTouchHighlightVisible = true;
 
         // The touch highlight animation is used to ensure the touch highlight is visible for at
         // least OverlayPanelAnimation.BASE_ANIMATION_DURATION_MS.
-        // TODO(twellington): Add a material ripple to this animation.
+        // TODO(donnd): Add a material ripple to this animation.
         if (mTouchHighlightAnimation == null) {
             mTouchHighlightAnimation =
                     new CompositorAnimator(mContextualSearchPanel.getAnimationHandler());
@@ -577,13 +649,12 @@
     }
 
     /**
-     * @param x The x-position of the touch in px.
+     * @param xPx The x-position of the touch in px.
      * @return Whether the touch occurred on the search Bar's end button.
      */
-    private boolean isTouchOnEndButton(float x) {
+    private boolean isTouchOnEndButton(float xPx) {
         if (getDividerLineVisibilityPercentage() == TRANSPARENT_OPACITY) return false;
 
-        float xPx = x * mDpToPx;
         if (LocalizationUtils.isLayoutRtl()) return xPx <= getDividerLineXOffset();
         return xPx > getDividerLineXOffset();
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchCaptionControl.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchCaptionControl.java
index 02f8456..774b758 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchCaptionControl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchCaptionControl.java
@@ -90,7 +90,13 @@
     public ContextualSearchCaptionControl(OverlayPanel panel, Context context, ViewGroup container,
             DynamicResourceLoader resourceLoader, boolean shouldShowExpandedCaption) {
         super(panel, R.layout.contextual_search_caption_view, R.id.contextual_search_caption_view,
-                context, container, resourceLoader);
+                context, container, resourceLoader,
+                (ChromeFeatureList.isEnabled(ChromeFeatureList.OVERLAY_NEW_LAYOUT)
+                                ? R.dimen.contextual_search_end_padding
+                                : R.dimen.overlay_panel_padded_button_width),
+                (ChromeFeatureList.isEnabled(ChromeFeatureList.OVERLAY_NEW_LAYOUT)
+                                ? R.dimen.contextual_search_end_buttons_width
+                                : R.dimen.overlay_panel_padded_button_width));
         mShouldShowExpandedCaption = shouldShowExpandedCaption;
     }
 
@@ -122,6 +128,7 @@
      * Updates the caption when in transition between peeked to expanded states.
      * @param percentage The percentage to the more opened state.
      */
+    @Override
     public void onUpdateFromPeekToExpand(float percentage) {
         if (ChromeFeatureList.isEnabled(ChromeFeatureList.OVERLAY_NEW_LAYOUT)) {
             if (mHasPeekingCaption) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchContextControl.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchContextControl.java
index cc344760..48da9104 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchContextControl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchContextControl.java
@@ -10,14 +10,15 @@
 import android.widget.TextView;
 
 import org.chromium.chrome.R;
+import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel;
-import org.chromium.chrome.browser.compositor.bottombar.OverlayPanelInflater;
+import org.chromium.chrome.browser.compositor.bottombar.OverlayPanelRepaddingTextView;
 import org.chromium.ui.resources.dynamics.DynamicResourceLoader;
 
 /**
  * Controls the Search Context View that is used as a dynamic resource.
  */
-public class ContextualSearchContextControl extends OverlayPanelInflater {
+public class ContextualSearchContextControl extends OverlayPanelRepaddingTextView {
     /**
      * The selected text View.
      */
@@ -39,7 +40,13 @@
                                           ViewGroup container,
                                           DynamicResourceLoader resourceLoader) {
         super(panel, R.layout.contextual_search_context_view, R.id.contextual_search_context_view,
-                context, container, resourceLoader);
+                context, container, resourceLoader,
+                (ChromeFeatureList.isEnabled(ChromeFeatureList.OVERLAY_NEW_LAYOUT)
+                                ? R.dimen.contextual_search_end_padding
+                                : R.dimen.overlay_panel_padded_button_width),
+                (ChromeFeatureList.isEnabled(ChromeFeatureList.OVERLAY_NEW_LAYOUT)
+                                ? R.dimen.contextual_search_end_buttons_width
+                                : R.dimen.overlay_panel_padded_button_width));
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanel.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanel.java
index 73950f431..16bf4c47 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanel.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanel.java
@@ -99,7 +99,7 @@
         int endButtonsWidthDimension =
                 ChromeFeatureList.isEnabled(ChromeFeatureList.OVERLAY_NEW_LAYOUT)
                 ? R.dimen.contextual_search_end_buttons_width
-                : R.dimen.contextual_search_end_button_width;
+                : R.dimen.contextual_search_padded_button_width;
         mEndButtonWidthDp =
                 mPxToDp * mContext.getResources().getDimensionPixelSize(endButtonsWidthDimension);
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchTermControl.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchTermControl.java
index aa221e1..4a0e263 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchTermControl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchTermControl.java
@@ -10,6 +10,7 @@
 import android.widget.TextView;
 
 import org.chromium.chrome.R;
+import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel;
 import org.chromium.chrome.browser.compositor.bottombar.OverlayPanelTextViewInflater;
 import org.chromium.ui.resources.dynamics.DynamicResourceLoader;
@@ -34,7 +35,13 @@
                                           ViewGroup container,
                                           DynamicResourceLoader resourceLoader) {
         super(panel, R.layout.contextual_search_term_view, R.id.contextual_search_term_view,
-                context, container, resourceLoader);
+                context, container, resourceLoader,
+                (ChromeFeatureList.isEnabled(ChromeFeatureList.OVERLAY_NEW_LAYOUT)
+                                ? R.dimen.contextual_search_end_padding
+                                : R.dimen.overlay_panel_padded_button_width),
+                (ChromeFeatureList.isEnabled(ChromeFeatureList.OVERLAY_NEW_LAYOUT)
+                                ? R.dimen.contextual_search_end_buttons_width
+                                : R.dimen.overlay_panel_padded_button_width));
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabBarControl.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabBarControl.java
index c21c03a..74124a7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabBarControl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabBarControl.java
@@ -40,8 +40,8 @@
         mCaption = panel.canPromoteToNewTab()
                 ? new EphemeralTabCaptionControl(panel, context, container, loader)
                 : null;
-        mTextLayerMinHeight = context.getResources().getDimension(
-                R.dimen.contextual_search_text_layer_min_height);
+        mTextLayerMinHeight =
+                context.getResources().getDimension(R.dimen.overlay_panel_text_layer_min_height);
         mTitleCaptionSpacing =
                 context.getResources().getDimension(R.dimen.contextual_search_term_caption_spacing);
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabCaptionControl.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabCaptionControl.java
index 9f07e901..fd7a960 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabCaptionControl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabCaptionControl.java
@@ -10,6 +10,7 @@
 import android.widget.TextView;
 
 import org.chromium.chrome.R;
+import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel;
 import org.chromium.chrome.browser.compositor.bottombar.OverlayPanelTextViewInflater;
 import org.chromium.ui.resources.dynamics.DynamicResourceLoader;
@@ -43,7 +44,13 @@
     public EphemeralTabCaptionControl(OverlayPanel panel, Context context, ViewGroup container,
             DynamicResourceLoader resourceLoader) {
         super(panel, R.layout.ephemeral_tab_caption_view, R.id.ephemeral_tab_caption_view, context,
-                container, resourceLoader);
+                container, resourceLoader,
+                (ChromeFeatureList.isEnabled(ChromeFeatureList.OVERLAY_NEW_LAYOUT)
+                                ? R.dimen.overlay_panel_end_buttons_width
+                                : R.dimen.overlay_panel_padded_button_width),
+                (ChromeFeatureList.isEnabled(ChromeFeatureList.OVERLAY_NEW_LAYOUT)
+                                ? R.dimen.overlay_panel_end_buttons_width
+                                : R.dimen.overlay_panel_padded_button_width));
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabTitleControl.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabTitleControl.java
index 09d68aa..9feedf9a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabTitleControl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabTitleControl.java
@@ -9,6 +9,7 @@
 import android.widget.TextView;
 
 import org.chromium.chrome.R;
+import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel;
 import org.chromium.chrome.browser.compositor.bottombar.OverlayPanelTextViewInflater;
 import org.chromium.ui.resources.dynamics.DynamicResourceLoader;
@@ -28,7 +29,13 @@
     public EphemeralTabTitleControl(OverlayPanel panel, Context context, ViewGroup container,
             DynamicResourceLoader resourceLoader) {
         super(panel, R.layout.ephemeral_tab_text_view, R.id.ephemeral_tab_text_view, context,
-                container, resourceLoader);
+                container, resourceLoader,
+                (ChromeFeatureList.isEnabled(ChromeFeatureList.OVERLAY_NEW_LAYOUT)
+                                ? R.dimen.overlay_panel_end_buttons_width
+                                : R.dimen.overlay_panel_padded_button_width),
+                (ChromeFeatureList.isEnabled(ChromeFeatureList.OVERLAY_NEW_LAYOUT)
+                                ? R.dimen.overlay_panel_end_buttons_width
+                                : R.dimen.overlay_panel_padded_button_width));
         invalidate();
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/directactions/ChromeDirectActionIds.java b/chrome/android/java/src/org/chromium/chrome/browser/directactions/ChromeDirectActionIds.java
index dd7ca86..876281d3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/directactions/ChromeDirectActionIds.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/directactions/ChromeDirectActionIds.java
@@ -46,6 +46,9 @@
     // Close all tabs
     public static final String CLOSE_ALL_TABS = "close_all_tabs";
 
+    // If you add a new action to this list, consider extending ChromeDirectActionUsageHistogram to
+    // track usage of the new action.
+
     private ChromeDirectActionIds() {
         // This is a utility class. It is not meant to be instantiated.
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/directactions/DirectActionCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/directactions/DirectActionCoordinator.java
index 4cf02f3..d127893 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/directactions/DirectActionCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/directactions/DirectActionCoordinator.java
@@ -9,6 +9,7 @@
 import android.support.annotation.NonNull;
 
 import org.chromium.base.Callback;
+import org.chromium.base.metrics.CachedMetrics;
 
 import java.util.LinkedHashSet;
 import java.util.List;
@@ -25,6 +26,15 @@
  */
 @TargetApi(29)
 public abstract class DirectActionCoordinator {
+    /**
+     * Tracks calls to {@link #onGetDirectActions}.
+     *
+     * <p>This corresponds to a user triggering the assist app while a Chrome activity is in the
+     * foreground.
+     */
+    private static final CachedMetrics.ActionEvent LIST_ACTION_EVENT =
+            new CachedMetrics.ActionEvent("Android.DirectAction.List");
+
     private final Set<DirectActionHandler> mHandlers = new LinkedHashSet<>();
 
     /**
@@ -53,6 +63,7 @@
             }
         }
         reporter.report();
+        LIST_ACTION_EVENT.record();
     }
 
     /** Performs an action and reports the result to the callback. */
@@ -60,9 +71,18 @@
             String actionId, Bundle arguments, Consumer<Bundle> consumer) {
         if (!mIsEnabled.get()) return;
 
+        boolean performedAction = false;
         Callback<Bundle> callback = (result) -> consumer.accept(result);
         for (DirectActionHandler handler : mHandlers) {
-            if (handler.performDirectAction(actionId, arguments, callback)) return;
+            if (handler.performDirectAction(actionId, arguments, callback)) {
+                performedAction = true;
+                break;
+            }
+        }
+        if (performedAction) {
+            DirectActionUsageHistogram.record(actionId);
+        } else {
+            DirectActionUsageHistogram.recordUnknown();
         }
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/directactions/DirectActionUsageHistogram.java b/chrome/android/java/src/org/chromium/chrome/browser/directactions/DirectActionUsageHistogram.java
new file mode 100644
index 0000000..6e0e0b23
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/directactions/DirectActionUsageHistogram.java
@@ -0,0 +1,95 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.directactions;
+
+import android.support.annotation.IntDef;
+
+import org.chromium.base.VisibleForTesting;
+import org.chromium.base.metrics.CachedMetrics.EnumeratedHistogramSample;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A histogram that tracks calls to {@link ChromeActivity#onPerformDirectAction} and, when possible,
+ * the specific action that was performed.
+ */
+class DirectActionUsageHistogram {
+    private static final EnumeratedHistogramSample PERFORM_HISTOGRAM =
+            new EnumeratedHistogramSample(
+                    "Android.DirectAction.Perform", DirectActionId.NUM_ENTRIES);
+
+    /** A map that convert known string ids to enum value for the histogram. */
+    private static final Map<String, Integer> ACTION_ID_MAP;
+    static {
+        Map<String, Integer> map = new HashMap<>();
+        map.put(ChromeDirectActionIds.GO_BACK, DirectActionId.GO_BACK);
+        map.put(ChromeDirectActionIds.RELOAD, DirectActionId.RELOAD);
+        map.put(ChromeDirectActionIds.GO_FORWARD, DirectActionId.GO_FORWARD);
+        map.put(ChromeDirectActionIds.BOOKMARK_THIS_PAGE, DirectActionId.BOOKMARK_THIS_PAGE);
+        map.put(ChromeDirectActionIds.DOWNLOADS, DirectActionId.DOWNLOADS);
+        map.put(ChromeDirectActionIds.PREFERENCES, DirectActionId.PREFERENCES);
+        map.put(ChromeDirectActionIds.OPEN_HISTORY, DirectActionId.OPEN_HISTORY);
+        map.put(ChromeDirectActionIds.HELP, DirectActionId.HELP);
+        map.put(ChromeDirectActionIds.NEW_TAB, DirectActionId.NEW_TAB);
+        map.put(ChromeDirectActionIds.CLOSE_TAB, DirectActionId.CLOSE_TAB);
+        map.put(ChromeDirectActionIds.CLOSE_ALL_TABS, DirectActionId.CLOSE_ALL_TABS);
+        ACTION_ID_MAP = Collections.unmodifiableMap(map);
+    }
+
+    /**
+     * Enum defined in tools/metrics/histograms/enums.xml.
+     */
+    @VisibleForTesting
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({DirectActionId.GO_BACK, DirectActionId.RELOAD, DirectActionId.GO_FORWARD,
+            DirectActionId.BOOKMARK_THIS_PAGE, DirectActionId.DOWNLOADS, DirectActionId.PREFERENCES,
+            DirectActionId.OPEN_HISTORY, DirectActionId.HELP, DirectActionId.NEW_TAB,
+            DirectActionId.CLOSE_TAB, DirectActionId.CLOSE_ALL_TABS, DirectActionId.NUM_ENTRIES})
+    @interface DirectActionId {
+        /** No action was executed. */
+        int UNKNOWN = 0;
+
+        /** An action was executed that isn't in this enum. */
+        int OTHER = 1;
+
+        // Actions from ChromeDirectActionIds.
+        int GO_BACK = 2;
+        int RELOAD = 3;
+        int GO_FORWARD = 4;
+        int BOOKMARK_THIS_PAGE = 5;
+        int DOWNLOADS = 6;
+        int PREFERENCES = 7;
+        int OPEN_HISTORY = 8;
+        int HELP = 9;
+        int NEW_TAB = 10;
+        int CLOSE_TAB = 11;
+        int CLOSE_ALL_TABS = 12;
+
+        int NUM_ENTRIES = 13;
+    }
+
+    /**
+     * Records an attempt to execute a direct action that was rejected as unknown.
+     */
+    static void recordUnknown() {
+        PERFORM_HISTOGRAM.record(DirectActionId.UNKNOWN);
+    }
+
+    /**
+     * Records direct action usage.
+     *
+     * @param actionId The string id of the direct action that was executed.
+     */
+    static void record(String actionId) {
+        Integer histogramId = ACTION_ID_MAP.get(actionId);
+        if (histogramId == null) histogramId = DirectActionId.OTHER;
+
+        PERFORM_HISTOGRAM.record(histogramId);
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/password_manager/PasswordGenerationDialogViewBinder.java b/chrome/android/java/src/org/chromium/chrome/browser/password_manager/PasswordGenerationDialogViewBinder.java
index 697bcd350..6e49294 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/password_manager/PasswordGenerationDialogViewBinder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/password_manager/PasswordGenerationDialogViewBinder.java
@@ -4,42 +4,10 @@
 
 package org.chromium.chrome.browser.password_manager;
 
-import org.chromium.base.Callback;
-import org.chromium.ui.modaldialog.ModalDialogProperties;
-import org.chromium.ui.modelutil.PropertyModel;
-
 /** Class responsible for binding the model and the view. On bind, it lazily initializes the view
  * since all the needed data was made available at this point.
  */
 public class PasswordGenerationDialogViewBinder {
-    private static class PasswordGenerationDialogController
-            implements ModalDialogProperties.Controller {
-        private final Callback<Boolean> mPasswordActionCallback;
-
-        public PasswordGenerationDialogController(Callback<Boolean> passwordActionCallback) {
-            mPasswordActionCallback = passwordActionCallback;
-        }
-
-        @Override
-        public void onClick(PropertyModel model, int buttonType) {
-            switch (buttonType) {
-                case ModalDialogProperties.ButtonType.POSITIVE:
-                    mPasswordActionCallback.onResult(true);
-                    break;
-                case ModalDialogProperties.ButtonType.NEGATIVE:
-                    mPasswordActionCallback.onResult(false);
-                    break;
-                default:
-                    assert false : "Unexpected button pressed in dialog: " + buttonType;
-            }
-        }
-
-        @Override
-        public void onDismiss(PropertyModel model, int dismissalCause) {
-            mPasswordActionCallback.onResult(false);
-        }
-    }
-
     public static void bind(
             PasswordGenerationDialogModel model, PasswordGenerationDialogCustomView viewHolder) {
         viewHolder.setGeneratedPassword(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordManagerHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordManagerHandler.java
index 419735f..55f25d1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordManagerHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordManagerHandler.java
@@ -59,6 +59,14 @@
     void removeSavedPasswordEntry(int index);
 
     /**
+     * Change saved password entry at index.
+     * @param index of password entry to change.
+     * @param new_username is the username after a change.
+     * @param new_password is the password after a change.
+     */
+    void changeSavedPasswordEntry(int index, String newUsername, String newPassword);
+
+    /**
      * Remove saved exception entry at index.
      *
      * @param index of exception entry.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordUIView.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordUIView.java
index e24cfc6..39cd3f5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordUIView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordUIView.java
@@ -68,6 +68,12 @@
     }
 
     @Override
+    public void changeSavedPasswordEntry(int index, String newUsername, String newPassword) {
+        nativeHandleChangeSavedPasswordEntry(
+                mNativePasswordUIViewAndroid, index, newUsername, newPassword);
+    }
+
+    @Override
     public void removeSavedPasswordException(int index) {
         nativeHandleRemoveSavedPasswordException(mNativePasswordUIViewAndroid, index);
     }
@@ -111,6 +117,9 @@
     private native void nativeHandleRemoveSavedPasswordEntry(
             long nativePasswordUIViewAndroid, int index);
 
+    private native void nativeHandleChangeSavedPasswordEntry(
+            long nativePasswordUIViewAndroid, int index, String newUsername, String newPassword);
+
     private native void nativeHandleRemoveSavedPasswordException(
             long nativePasswordUIViewAndroid, int index);
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/services/gcm/ChromeGcmListenerService.java b/chrome/android/java/src/org/chromium/chrome/browser/services/gcm/ChromeGcmListenerService.java
index 7ef3970..450b8caa 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/services/gcm/ChromeGcmListenerService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/services/gcm/ChromeGcmListenerService.java
@@ -19,8 +19,8 @@
 import org.chromium.base.Log;
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.library_loader.ProcessInitException;
-import org.chromium.base.metrics.CachedMetrics;
 import org.chromium.base.task.PostTask;
+import org.chromium.chrome.browser.DeviceConditions;
 import org.chromium.chrome.browser.init.ChromeBrowserInitializer;
 import org.chromium.chrome.browser.init.ProcessInitializationHandler;
 import org.chromium.components.background_task_scheduler.BackgroundTaskSchedulerFactory;
@@ -145,10 +145,7 @@
             LazySubscriptionsManager.persistMessage(subscriptionId, message);
         }
 
-        // Use {@link CachedMetrics} so this gets reported when native is
-        // loaded instead of calling native right away.
-        new CachedMetrics.TimesHistogramSample("PushMessaging.TimeToCheckIfSubscriptionLazy")
-                .record(SystemClock.elapsedRealtime() - time);
+        GcmUma.recordSubscriptionLazyCheckTime(SystemClock.elapsedRealtime() - time);
 
         return shouldPersistMessage;
     }
@@ -167,6 +164,23 @@
                 ContextUtils.getApplicationContext(), backgroundTask);
     }
 
+    private static void recordWebPushMetrics(GCMMessage message) {
+        Context context = ContextUtils.getApplicationContext();
+        boolean inIdleMode = DeviceConditions.isCurrentlyInIdleMode(context);
+        boolean isHighPriority = message.getOriginalPriority() == GCMMessage.Priority.HIGH;
+
+        @GcmUma.WebPushDeviceState
+        int state;
+        if (inIdleMode) {
+            state = isHighPriority ? GcmUma.WebPushDeviceState.IDLE_HIGH_PRIORITY
+                                   : GcmUma.WebPushDeviceState.IDLE_NOT_HIGH_PRIORITY;
+        } else {
+            state = isHighPriority ? GcmUma.WebPushDeviceState.NOT_IDLE_HIGH_PRIORITY
+                                   : GcmUma.WebPushDeviceState.NOT_IDLE_NOT_HIGH_PRIORITY;
+        }
+        GcmUma.recordWebPushReceivedDeviceState(state);
+    }
+
     /**
      * If Chrome is backgrounded, messages coming from lazy subscriptions are
      * persisted on disk and replayed next time Chrome is forgrounded. If Chrome is forgrounded or
@@ -180,6 +194,11 @@
     static void scheduleOrDispatchMessageToDriver(GCMMessage message) {
         ThreadUtils.assertOnUiThread();
 
+        // GCMMessage#getAppId never returns null.
+        if (message.getAppId().startsWith("wp:")) {
+            recordWebPushMetrics(message);
+        }
+
         // Check if we should only persist the message for now.
         if (maybePersistLazyMessage(message)) {
             return;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/services/gcm/GcmUma.java b/chrome/android/java/src/org/chromium/chrome/browser/services/gcm/GcmUma.java
index ef39d8c0..a3838f00 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/services/gcm/GcmUma.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/services/gcm/GcmUma.java
@@ -5,14 +5,19 @@
 package org.chromium.chrome.browser.services.gcm;
 
 import android.content.Context;
+import android.support.annotation.IntDef;
 
 import org.chromium.base.library_loader.LibraryProcessType;
+import org.chromium.base.metrics.CachedMetrics;
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.task.PostTask;
 import org.chromium.content_public.browser.BrowserStartupController;
 import org.chromium.content_public.browser.BrowserStartupController.StartupCallback;
 import org.chromium.content_public.browser.UiThreadTaskTraits;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * Helper Class for GCM UMA Collection.
  */
@@ -24,6 +29,19 @@
     public static final int UMA_UPSTREAM_SEND_FAILED = 3;
     public static final int UMA_UPSTREAM_COUNT = 4;
 
+    // Keep in sync with the WebPushDeviceState enum in enums.xml.
+    @IntDef({WebPushDeviceState.NOT_IDLE_NOT_HIGH_PRIORITY,
+            WebPushDeviceState.NOT_IDLE_HIGH_PRIORITY, WebPushDeviceState.IDLE_NOT_HIGH_PRIORITY,
+            WebPushDeviceState.IDLE_HIGH_PRIORITY})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface WebPushDeviceState {
+        int NOT_IDLE_NOT_HIGH_PRIORITY = 0;
+        int NOT_IDLE_HIGH_PRIORITY = 1;
+        int IDLE_NOT_HIGH_PRIORITY = 2;
+        int IDLE_HIGH_PRIORITY = 3;
+        int NUM_ENTRIES = 4;
+    }
+
     public static void recordDataMessageReceived(Context context, final boolean hasCollapseKey) {
         onNativeLaunched(context, new Runnable() {
             @Override public void run() {
@@ -59,6 +77,22 @@
         });
     }
 
+    public static void recordSubscriptionLazyCheckTime(long time) {
+        // Use {@link CachedMetrics} so this gets reported when native is loaded instead of calling
+        // native right away.
+        new CachedMetrics.TimesHistogramSample("PushMessaging.TimeToCheckIfSubscriptionLazy")
+                .record(time);
+    }
+
+    public static void recordWebPushReceivedDeviceState(@WebPushDeviceState int state) {
+        // Use {@link CachedMetrics} so this gets reported when native is loaded instead of calling
+        // native right away.
+        new CachedMetrics
+                .EnumeratedHistogramSample(
+                        "GCM.WebPushReceived.DeviceState", WebPushDeviceState.NUM_ENTRIES)
+                .record(state);
+    }
+
     private static void onNativeLaunched(final Context context, final Runnable task) {
         PostTask.postTask(UiThreadTaskTraits.DEFAULT, new Runnable() {
             @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/layouts/MockResourcesForLayout.java b/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/layouts/MockResourcesForLayout.java
index 2971623..6672e6d8 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/layouts/MockResourcesForLayout.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/layouts/MockResourcesForLayout.java
@@ -67,7 +67,8 @@
         mFloats.put(org.chromium.chrome.R.dimen.overlay_panel_bar_height, 56.f);
         mFloats.put(org.chromium.chrome.R.dimen.control_container_height, 56.f);
         mFloats.put(org.chromium.chrome.R.dimen.contextual_search_bar_banner_padding, 12.f);
-        mFloats.put(org.chromium.chrome.R.dimen.contextual_search_end_button_width, 48.f);
+        mFloats.put(org.chromium.chrome.R.dimen.contextual_search_end_buttons_width, 48.f);
+        mFloats.put(org.chromium.chrome.R.dimen.overlay_panel_end_buttons_width, 94.f);
         mFloats.put(org.chromium.chrome.R.dimen.toolbar_height_no_shadow, 56.f);
         mIntegers.put(R.color.modern_grey_100, 0xFFF1F3F4);
         mIntegers.put(R.color.modern_primary_color, Color.WHITE);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/directactions/DirectActionsInActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/directactions/DirectActionsInActivityTest.java
index 972a41f..6f5fa42d 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/directactions/DirectActionsInActivityTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/directactions/DirectActionsInActivityTest.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser.directactions;
 
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertThat;
 import static org.junit.Assert.fail;
 
@@ -13,6 +14,7 @@
 import android.support.test.filters.MediumTest;
 
 import org.hamcrest.Matchers;
+import org.junit.After;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -20,7 +22,9 @@
 import org.chromium.base.Callback;
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.Feature;
+import org.chromium.base.test.util.MetricsUtils.HistogramDelta;
 import org.chromium.base.test.util.MinAndroidSdkLevel;
+import org.chromium.base.test.util.UserActionTester;
 import org.chromium.chrome.browser.ChromeActivity;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
@@ -43,10 +47,17 @@
     @Rule
     public DirectActionTestRule mDirectActionRule = new DirectActionTestRule();
 
+    private UserActionTester mActionTester;
+
     private ChromeActivity getActivity() {
         return mActivityTestRule.getActivity();
     }
 
+    @After
+    public void tearDown() throws Exception {
+        if (mActionTester != null) mActionTester.tearDown();
+    }
+
     @Test
     @MediumTest
     @Feature({"DirectActions"})
@@ -89,16 +100,28 @@
             });
         });
 
+        mActionTester = new UserActionTester();
+
         assertThat(DirectActionTestUtils.callOnGetDirectActions(getActivity()),
                 Matchers.hasItem("test"));
+        assertThat(mActionTester.getActions(), Matchers.hasItem("Android.DirectAction.List"));
+
+        HistogramDelta unknownAction = new HistogramDelta(
+                "Android.DirectAction.Perform", DirectActionUsageHistogram.DirectActionId.UNKNOWN);
+        HistogramDelta otherAction = new HistogramDelta(
+                "Android.DirectAction.Perform", DirectActionUsageHistogram.DirectActionId.OTHER);
 
         DirectActionTestUtils.callOnPerformDirectActions(
                 getActivity(), "doesnotexist", (r) -> fail("Unexpected result: " + r));
+        assertEquals(1, unknownAction.getDelta());
+        assertEquals(0, otherAction.getDelta());
 
         Bundle result = new Bundle();
         DirectActionTestUtils.callOnPerformDirectActions(
                 getActivity(), "test", (r) -> result.putAll((Bundle) r));
         assertThat(result.keySet(), Matchers.contains("ran_test"));
+        assertEquals(1, unknownAction.getDelta());
+        assertEquals(1, otherAction.getDelta());
     }
 
     @Test
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/password/SavePasswordsPreferencesTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/password/SavePasswordsPreferencesTest.java
index 0dd895ef..e4adde6b 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/password/SavePasswordsPreferencesTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/preferences/password/SavePasswordsPreferencesTest.java
@@ -186,17 +186,18 @@
         }
 
         @Override
+        public void changeSavedPasswordEntry(int index, String newUsername, String newPassword) {
+            assert false : "Define this method before starting to use it in tests.";
+        }
+
+        @Override
         public void removeSavedPasswordEntry(int index) {
-            // Define this method before starting to use it in tests.
-            assert false;
-            return;
+            assert false : "Define this method before starting to use it in tests.";
         }
 
         @Override
         public void removeSavedPasswordException(int index) {
-            // Define this method before starting to use it in tests.
-            assert false;
-            return;
+            assert false : "Define this method before starting to use it in tests.";
         }
 
         @Override
diff --git a/chrome/app/BUILD.gn b/chrome/app/BUILD.gn
index 413eb35..b4fba68 100644
--- a/chrome/app/BUILD.gn
+++ b/chrome/app/BUILD.gn
@@ -555,7 +555,6 @@
     "//base",
     "//chrome/common:buildflags",
     "//chrome/common:mojo_bindings",
-    "//chrome/services/file_util/public/cpp:manifest",
     "//components/services/quarantine",
     "//components/services/quarantine/public/cpp:manifest",
     "//components/startup_metric_utils/common:interfaces",
diff --git a/chrome/app/OWNERS b/chrome/app/OWNERS
index 25c0e849..2b82288 100644
--- a/chrome/app/OWNERS
+++ b/chrome/app/OWNERS
@@ -21,7 +21,7 @@
 
 per-file media_router_strings.grdp=file://chrome/browser/media/router/OWNERS
 
-per-file welcome_strings.grdp=file://chrome/browser/ui/webui/welcome/OWNERS
+per-file onboarding_welcome_strings.grdp=file://chrome/browser/ui/webui/welcome/OWNERS
 
 per-file printing_strings.grdp=file://printing/OWNERS
 
diff --git a/chrome/app/builtin_service_manifests.cc b/chrome/app/builtin_service_manifests.cc
index b9cbc3b..3b7dcf2e 100644
--- a/chrome/app/builtin_service_manifests.cc
+++ b/chrome/app/builtin_service_manifests.cc
@@ -7,7 +7,6 @@
 #include "base/no_destructor.h"
 #include "build/build_config.h"
 #include "chrome/common/buildflags.h"
-#include "chrome/services/file_util/public/cpp/manifest.h"
 #include "components/services/quarantine/public/cpp/manifest.h"
 #include "device/vr/buildflags/buildflags.h"
 #include "extensions/buildflags/buildflags.h"
@@ -59,7 +58,6 @@
 const std::vector<service_manager::Manifest>&
 GetChromeBuiltinServiceManifests() {
   static base::NoDestructor<std::vector<service_manager::Manifest>> manifests{{
-      GetFileUtilManifest(),
       quarantine::GetQuarantineManifest(),
 #if BUILDFLAG(ENABLE_EXTENSIONS)
       GetRemovableStorageWriterManifest(),
diff --git a/chrome/app/chrome_content_browser_overlay_manifest.cc b/chrome/app/chrome_content_browser_overlay_manifest.cc
index 05d1d49..b6f7695 100644
--- a/chrome/app/chrome_content_browser_overlay_manifest.cc
+++ b/chrome/app/chrome_content_browser_overlay_manifest.cc
@@ -127,8 +127,6 @@
         .RequireCapability("device", "device:geolocation_control")
         .RequireCapability("device", "device:ip_geolocator")
         .RequireCapability("device_sync", "device_sync")
-        .RequireCapability("file_util", "analyze_archive")
-        .RequireCapability("file_util", "zip_file")
         .RequireCapability("identity", "identity_accessor")
         .RequireCapability(image_annotation::mojom::kServiceName,
                            image_annotation::mojom::kAnnotationCapability)
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 8b1e59d..af9303c 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -213,9 +213,9 @@
         <part file="extensions_strings.grdp" />
       </if>
 
-      <!-- Welcome strings -->
+      <!-- NUX Welcome onboarding experience strings -->
       <if expr="not chromeos and not is_android">
-        <part file="welcome_strings.grdp" />
+        <part file="onboarding_welcome_strings.grdp" />
       </if>
 
       <!-- Printing specific strings -->
diff --git a/chrome/app/onboarding_welcome_strings.grdp b/chrome/app/onboarding_welcome_strings.grdp
new file mode 100644
index 0000000..ca34a69
--- /dev/null
+++ b/chrome/app/onboarding_welcome_strings.grdp
@@ -0,0 +1,118 @@
+<?xml version="1.0" encoding="utf-8"?>
+<grit-part>
+  <!-- Shared strings -->
+  <message name="IDS_ONBOARDING_WELCOME_NEXT" desc="Label for a button to confirm and continue from the current onboarding step.">
+    Next
+  </message>
+  <message name="IDS_ONBOARDING_WELCOME_SKIP" desc="Label for a button to skip the current onboarding step.">
+    Skip
+  </message>
+  <message name="IDS_ONBOARDING_WELCOME_BOOKMARK_ADDED" desc="String read for accessibility to inform the user a bookmark was added.">
+    Bookmark added
+  </message>
+  <message name="IDS_ONBOARDING_WELCOME_BOOKMARKS_ADDED" desc="String read for accessibility to inform the user that several bookmarks were added.">
+    Bookmarks added
+  </message>
+  <message name="IDS_ONBOARDING_WELCOME_BOOKMARK_REMOVED" desc="String read for accessibility to inform the user a bookmark was removed.">
+    Bookmark removed
+  </message>
+  <message name="IDS_ONBOARDING_WELCOME_BOOKMARKS_REMOVED" desc="String read for accessibility to inform the user that several bookmarks were removed.">
+    Bookmarks removed
+  </message>
+  <message name="IDS_ONBOARDING_DEFAULT_BROWSER_CHANGED" desc="text notifying users that their default browser is successfully changed to Chrome">
+    Chrome is your default browser
+  </message>
+
+  <!-- NUX Google apps selection module -->
+  <message name="IDS_ONBOARDING_WELCOME_NUX_GOOGLE_APPS_DESCRIPTION" desc="Description of what this section in the onboarding workflow does.">
+    Add bookmarks to your favorite Google Apps
+  </message>
+  <if expr="_google_chrome">
+    <message name="IDS_ONBOARDING_WELCOME_NUX_GOOGLE_SEARCH" desc="Label for a button that creates a bookmark to google.com, this should be the name of the brand.">
+      Google
+    </message>
+  </if>
+  <message name="IDS_ONBOARDING_WELCOME_NUX_GOOGLE_GMAIL" desc="Label for a button that creates a bookmark to gmail.com, this should be the name of the brand.">
+    Gmail
+  </message>
+  <message name="IDS_ONBOARDING_WELCOME_NUX_GOOGLE_APPS_MAPS" desc="Label for a button that creates a bookmark to maps.google.com, this should be the name of the brand.">
+    Maps
+  </message>
+  <message name="IDS_ONBOARDING_WELCOME_NUX_GOOGLE_APPS_NEWS" desc="Label for a button that creates a bookmark to news.google.com, this should be the name of the brand.">
+    News
+  </message>
+  <message name="IDS_ONBOARDING_WELCOME_NUX_GOOGLE_APPS_TRANSLATE" desc="Label for a button that creates a bookmark to translate.google.com, this should be the name of the brand.">
+    Translate
+  </message>
+  <message name="IDS_ONBOARDING_WELCOME_NUX_GOOGLE_APPS_YOUTUBE" desc="Label for a button that creates a bookmark to youtube.com, this should be the name of the brand.">
+    YouTube
+  </message>
+
+  <!-- NUX NTP background selection module -->
+  <message name="IDS_ONBOARDING_WELCOME_NTP_BACKGROUND_DESCRIPTION" desc="Description of what this section in the onboarding workflow does. This section lets a user change the background for the New Tab Page">
+    Pick a background
+  </message>
+  <message name="IDS_ONBOARDING_WELCOME_NTP_BACKGROUND_DEFAULT_TITLE" desc="Label for the default option when selecting a background. The default is to not have a background.">
+    Default
+  </message>
+  <message name="IDS_ONBOARDING_WELCOME_NTP_BACKGROUND_ART_TITLE" desc="Label for choosing a background/wallpaper from the 'Art' category">
+    Art
+  </message>
+  <message name="IDS_ONBOARDING_WELCOME_NTP_BACKGROUND_LANDSCAPE_TITLE" desc="Label for choosing a background/wallpaper from the 'Landscape' category, as in a category of photos of scenery and large outdoor spaces.">
+    Landscape
+  </message>
+  <message name="IDS_ONBOARDING_WELCOME_NTP_BACKGROUND_CITYSCAPE_TITLE" desc="Label for choosing a background/wallpaper from the 'Cityscape' category">
+    Cityscape
+  </message>
+  <message name="IDS_ONBOARDING_WELCOME_NTP_BACKGROUND_EARTH_TITLE" desc="Label for choosing a background/wallpaper from the 'Earth' category, as in a category of photos of planets and outer space.">
+    Earth
+  </message>
+  <message name="IDS_ONBOARDING_WELCOME_NTP_BACKGROUND_GEOMETRIC_SHAPES_TITLE" desc="Label for choosing a background/wallpaper from the 'Geometric Shapes' category">
+    Geometric shapes
+  </message>
+  <message name="IDS_ONBOARDING_WELCOME_NTP_BACKGROUND_PHOTO_BY_LABEL" desc="Label indicating who the background/wallpaper is created or photographed by">
+    Photo by <ph name="NAME">$1<ex>John Doe</ex></ph>
+  </message>
+  <message name="IDS_ONBOARDING_WELCOME_NTP_BACKGROUND_PREVIEW_UPDATED" desc="String read for accessibility to inform the user that the background of the New Tab Page (referred to as 'start page') has been changed to a specific photo.">
+    Start page background has been changed to <ph name="CATEGORY">$1<ex>Geometric shapes</ex></ph>.
+  </message>
+  <message name="IDS_ONBOARDING_WELCOME_NTP_BACKGROUND_RESET" desc="String read for accessibility to inform the user that the background of the New Tab Page (referred to as 'start page') has been reset to the default background.">
+    Start page background has been reset to the default background.
+  </message>
+
+  <!-- NUX set default module -->
+  <message name="IDS_ONBOARDING_WELCOME_NUX_SET_AS_DEFAULT_HEADER" desc="Header for the page that prompts user to set Chrome as their default browser.">
+    Set Chrome as your default browser
+  </message>
+  <message name="IDS_ONBOARDING_WELCOME_NUX_SET_AS_DEFAULT_SUB_HEADER" desc="Sub-header for the page that prompts user to set Chrome as their default browser.">
+    Get Google Search and Google smarts everytime you browse
+  </message>
+  <message name="IDS_ONBOARDING_WELCOME_NUX_SET_AS_DEFAULT_SET_AS_DEFAULT" desc="The label for a button to confirm setting Chrome as their default browser.">
+    Set as default
+  </message>
+
+  <!-- Landing view -->
+  <message name="IDS_ONBOARDING_WELCOME_LANDING_TITLE" desc="Title for the page that prompts user to start setting up their new Chrome.">
+    Make Chrome your own
+  </message>
+  <message name="IDS_ONBOARDING_WELCOME_LANDING_DESCRIPTION" desc="Description for the page that prompts user to start setting up their new Chrome.">
+    Set up your browser in a few simple steps
+  </message>
+  <message name="IDS_ONBOARDING_WELCOME_LANDING_NEW_USER" desc="Label for a button that prompts new users to start setting up their new Chrome.">
+    Get Started
+  </message>
+  <message name="IDS_ONBOARDING_WELCOME_LANDING_EXISTING_USER" desc="Label for a button that prompts existing users to sign in.">
+    Already a Chrome user? Sign in
+  </message>
+
+  <!-- Sign-in view -->
+  <message name="IDS_ONBOARDING_WELCOME_SIGNIN_VIEW_HEADER" desc="Header for the page that prompts user to sign in to chrome.">
+    Your Chrome, Everywhere
+  </message>
+  <message name="IDS_ONBOARDING_WELCOME_SIGNIN_VIEW_SUB_HEADER" desc="Sub-header for the page that prompts user to sign in to chrome.">
+    Sign in and turn on sync to get your bookmarks, passwords and more on all devices
+  </message>
+  <message name="IDS_ONBOARDING_WELCOME_SIGNIN_VIEW_SIGNIN" desc="The label for a button to let users sign in to chrome.">
+    Continue
+  </message>
+</grit-part>
diff --git a/chrome/app/welcome_strings.grdp b/chrome/app/welcome_strings.grdp
deleted file mode 100644
index 6e37085..0000000
--- a/chrome/app/welcome_strings.grdp
+++ /dev/null
@@ -1,118 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<grit-part>
-  <!-- Shared strings -->
-  <message name="IDS_WELCOME_NEXT" desc="Label for a button to confirm and continue from the current welcome step.">
-    Next
-  </message>
-  <message name="IDS_WELCOME_SKIP" desc="Label for a button to skip the current welcome step.">
-    Skip
-  </message>
-  <message name="IDS_WELCOME_BOOKMARK_ADDED" desc="String read for accessibility to inform the user a bookmark was added.">
-    Bookmark added
-  </message>
-  <message name="IDS_WELCOME_BOOKMARKS_ADDED" desc="String read for accessibility to inform the user that several bookmarks were added.">
-    Bookmarks added
-  </message>
-  <message name="IDS_WELCOME_BOOKMARK_REMOVED" desc="String read for accessibility to inform the user a bookmark was removed.">
-    Bookmark removed
-  </message>
-  <message name="IDS_WELCOME_BOOKMARKS_REMOVED" desc="String read for accessibility to inform the user that several bookmarks were removed.">
-    Bookmarks removed
-  </message>
-  <message name="IDS_DEFAULT_BROWSER_CHANGED" desc="text notifying users that their default browser is successfully changed to Chrome">
-    Chrome is your default browser
-  </message>
-
-  <!-- Google apps selection module -->
-  <message name="IDS_WELCOME_GOOGLE_APPS_DESCRIPTION" desc="Description of what this section does in the welcome workflow. This section lets a user bookmark popular Google apps.">
-    Add bookmarks to your favorite Google Apps
-  </message>
-  <if expr="_google_chrome">
-    <message name="IDS_WELCOME_GOOGLE_SEARCH" desc="Label for a button that creates a bookmark to google.com, this should be the name of the brand.">
-      Google
-    </message>
-  </if>
-  <message name="IDS_WELCOME_GOOGLE_GMAIL" desc="Label for a button that creates a bookmark to gmail.com, this should be the name of the brand.">
-    Gmail
-  </message>
-  <message name="IDS_WELCOME_GOOGLE_APPS_MAPS" desc="Label for a button that creates a bookmark to maps.google.com, this should be the name of the brand.">
-    Maps
-  </message>
-  <message name="IDS_WELCOME_GOOGLE_APPS_NEWS" desc="Label for a button that creates a bookmark to news.google.com, this should be the name of the brand.">
-    News
-  </message>
-  <message name="IDS_WELCOME_GOOGLE_APPS_TRANSLATE" desc="Label for a button that creates a bookmark to translate.google.com, this should be the name of the brand.">
-    Translate
-  </message>
-  <message name="IDS_WELCOME_GOOGLE_APPS_YOUTUBE" desc="Label for a button that creates a bookmark to youtube.com, this should be the name of the brand.">
-    YouTube
-  </message>
-
-  <!-- NTP background selection module -->
-  <message name="IDS_WELCOME_NTP_BACKGROUND_DESCRIPTION" desc="Description of what this section does in the welcome workflow. This section lets a user change the background for the New Tab Page">
-    Pick a background
-  </message>
-  <message name="IDS_WELCOME_NTP_BACKGROUND_DEFAULT_TITLE" desc="Label for the default option when selecting a background. The default is to not have a background.">
-    Default
-  </message>
-  <message name="IDS_WELCOME_NTP_BACKGROUND_ART_TITLE" desc="Label for choosing a background/wallpaper from the 'Art' category">
-    Art
-  </message>
-  <message name="IDS_WELCOME_NTP_BACKGROUND_LANDSCAPE_TITLE" desc="Label for choosing a background/wallpaper from the 'Landscape' category, as in a category of photos of scenery and large outdoor spaces.">
-    Landscape
-  </message>
-  <message name="IDS_WELCOME_NTP_BACKGROUND_CITYSCAPE_TITLE" desc="Label for choosing a background/wallpaper from the 'Cityscape' category">
-    Cityscape
-  </message>
-  <message name="IDS_WELCOME_NTP_BACKGROUND_EARTH_TITLE" desc="Label for choosing a background/wallpaper from the 'Earth' category, as in a category of photos of planets and outer space.">
-    Earth
-  </message>
-  <message name="IDS_WELCOME_NTP_BACKGROUND_GEOMETRIC_SHAPES_TITLE" desc="Label for choosing a background/wallpaper from the 'Geometric Shapes' category">
-    Geometric shapes
-  </message>
-  <message name="IDS_WELCOME_NTP_BACKGROUND_PHOTO_BY_LABEL" desc="Label indicating who the background/wallpaper is created or photographed by">
-    Photo by <ph name="NAME">$1<ex>John Doe</ex></ph>
-  </message>
-  <message name="IDS_WELCOME_NTP_BACKGROUND_PREVIEW_UPDATED" desc="String read for accessibility to inform the user that the background of the New Tab Page (referred to as 'start page') has been changed to a specific photo.">
-    Start page background has been changed to <ph name="CATEGORY">$1<ex>Geometric shapes</ex></ph>.
-  </message>
-  <message name="IDS_WELCOME_NTP_BACKGROUND_RESET" desc="String read for accessibility to inform the user that the background of the New Tab Page (referred to as 'start page') has been reset to the default background.">
-    Start page background has been reset to the default background.
-  </message>
-
-  <!-- set default module -->
-  <message name="IDS_WELCOME_SET_AS_DEFAULT_HEADER" desc="Header for the page that prompts user to set Chrome as their default browser.">
-    Set Chrome as your default browser
-  </message>
-  <message name="IDS_WELCOME_SET_AS_DEFAULT_SUB_HEADER" desc="Sub-header for the page that prompts user to set Chrome as their default browser.">
-    Get Google Search and Google smarts everytime you browse
-  </message>
-  <message name="IDS_WELCOME_SET_AS_DEFAULT_SET_AS_DEFAULT" desc="The label for a button to confirm setting Chrome as their default browser.">
-    Set as default
-  </message>
-
-  <!-- Landing view -->
-  <message name="IDS_WELCOME_LANDING_TITLE" desc="Title for the page that prompts user to start setting up their new Chrome.">
-    Make Chrome your own
-  </message>
-  <message name="IDS_WELCOME_LANDING_DESCRIPTION" desc="Description for the page that prompts user to start setting up their new Chrome.">
-    Set up your browser in a few simple steps
-  </message>
-  <message name="IDS_WELCOME_LANDING_NEW_USER" desc="Label for a button that prompts new users to start setting up their new Chrome.">
-    Get Started
-  </message>
-  <message name="IDS_WELCOME_LANDING_EXISTING_USER" desc="Label for a button that prompts existing users to sign in.">
-    Already a Chrome user? Sign in
-  </message>
-
-  <!-- Sign-in view -->
-  <message name="IDS_WELCOME_SIGNIN_VIEW_HEADER" desc="Header for the page that prompts user to sign in to chrome.">
-    Your Chrome, Everywhere
-  </message>
-  <message name="IDS_WELCOME_SIGNIN_VIEW_SUB_HEADER" desc="Sub-header for the page that prompts user to sign in to chrome.">
-    Sign in and turn on sync to get your bookmarks, passwords and more on all devices
-  </message>
-  <message name="IDS_WELCOME_SIGNIN_VIEW_SIGNIN" desc="The label for a button to let users sign in to chrome.">
-    Continue
-  </message>
-</grit-part>
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 3e9731f..a7e3ea8b 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -507,6 +507,8 @@
     "file_select_helper_contacts_android.cc",
     "file_select_helper_contacts_android.h",
     "file_select_helper_mac.mm",
+    "file_util_service.cc",
+    "file_util_service.h",
     "flag_descriptions.cc",
     "flag_descriptions.h",
     "font_pref_change_notifier.cc",
@@ -1873,6 +1875,7 @@
   public_deps = [
     "//base",
     "//chrome/common",
+    "//chrome/services/file_util/public/mojom",
     "//components/account_id",
     "//components/autofill/core/browser",
     "//components/nacl/common:buildflags",
@@ -3293,8 +3296,8 @@
       "search/background/ntp_background_service_factory.cc",
       "search/background/ntp_background_service_factory.h",
       "search/background/ntp_background_service_observer.h",
-      "search/background/ntp_backgrounds.cc",
-      "search/background/ntp_backgrounds.h",
+      "search/background/onboarding_ntp_backgrounds.cc",
+      "search/background/onboarding_ntp_backgrounds.h",
       "search/chrome_colors/chrome_colors_factory.cc",
       "search/chrome_colors/chrome_colors_factory.h",
       "search/chrome_colors/chrome_colors_service.cc",
diff --git a/chrome/browser/android/compositor/layer/overlay_panel_layer.cc b/chrome/browser/android/compositor/layer/overlay_panel_layer.cc
index ef4040b..278a4953 100644
--- a/chrome/browser/android/compositor/layer/overlay_panel_layer.cc
+++ b/chrome/browser/android/compositor/layer/overlay_panel_layer.cc
@@ -217,8 +217,9 @@
     // Positions the icon at the end of the bar.
     float open_tab_top = close_icon_top;
     float open_tab_left;
+    float spacing_between_icons = 2 * bar_margin_side;
     float margin_from_close_icon =
-        close_icon_resource->size().width() + bar_margin_side;
+        close_icon_resource->size().width() + spacing_between_icons;
     if (is_rtl) {
       open_tab_left = close_icon_left + margin_from_close_icon;
     } else {
diff --git a/chrome/browser/android/password_ui_view_android.cc b/chrome/browser/android/password_ui_view_android.cc
index 2b10041..f32b0ba2d 100644
--- a/chrome/browser/android/password_ui_view_android.cc
+++ b/chrome/browser/android/password_ui_view_android.cc
@@ -142,6 +142,18 @@
   password_manager_presenter_.RemovePasswordException(index);
 }
 
+void PasswordUIViewAndroid::HandleChangeSavedPasswordEntry(
+    JNIEnv* env,
+    const base::android::JavaRef<jobject>&,
+    int index,
+    const JavaRef<jstring>& new_username,
+    const JavaRef<jstring>& new_password) {
+  DCHECK_EQ(State::ALIVE, state_);
+  password_manager_presenter_.ChangeSavedPassword(
+      index, ConvertJavaStringToUTF16(env, new_username),
+      ConvertJavaStringToUTF16(env, new_password));
+}
+
 void PasswordUIViewAndroid::HandleSerializePasswords(
     JNIEnv* env,
     const JavaRef<jobject>&,
diff --git a/chrome/browser/android/password_ui_view_android.h b/chrome/browser/android/password_ui_view_android.h
index 8ae6891..ac320505 100644
--- a/chrome/browser/android/password_ui_view_android.h
+++ b/chrome/browser/android/password_ui_view_android.h
@@ -74,6 +74,12 @@
       JNIEnv* env,
       const base::android::JavaRef<jobject>&,
       int index);
+  void HandleChangeSavedPasswordEntry(
+      JNIEnv* env,
+      const base::android::JavaRef<jobject>&,
+      int index,
+      const base::android::JavaRef<jstring>& new_username,
+      const base::android::JavaRef<jstring>& new_password);
   void HandleSerializePasswords(
       JNIEnv* env,
       const base::android::JavaRef<jobject>&,
diff --git a/chrome/browser/app_controller_mac_browsertest.mm b/chrome/browser/app_controller_mac_browsertest.mm
index f728b392..a3ae2b5 100644
--- a/chrome/browser/app_controller_mac_browsertest.mm
+++ b/chrome/browser/app_controller_mac_browsertest.mm
@@ -472,7 +472,8 @@
 class AppControllerOpenShortcutBrowserTest : public InProcessBrowserTest {
  protected:
   AppControllerOpenShortcutBrowserTest() {
-    scoped_feature_list_.InitWithFeatures({welcome::kForceEnabled}, {});
+    scoped_feature_list_.InitWithFeatures({welcome::kOnboardingForceEnabled},
+                                          {});
   }
 
   void SetUpInProcessBrowserTestFixture() override {
diff --git a/chrome/browser/background_sync/periodic_background_sync_permission_context.cc b/chrome/browser/background_sync/periodic_background_sync_permission_context.cc
index cb9efe2..79477af0 100644
--- a/chrome/browser/background_sync/periodic_background_sync_permission_context.cc
+++ b/chrome/browser/background_sync/periodic_background_sync_permission_context.cc
@@ -10,7 +10,6 @@
 #include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
-#include "content/public/common/content_features.h"
 
 #if defined(OS_ANDROID)
 #include "base/android/jni_string.h"
@@ -62,9 +61,6 @@
     const GURL& embedding_origin) const {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
-  if (!base::FeatureList::IsEnabled(features::kPeriodicBackgroundSync))
-    return CONTENT_SETTING_BLOCK;
-
 #if defined(OS_ANDROID)
   if (IsTwaInstalled(requesting_origin))
     return CONTENT_SETTING_ALLOW;
diff --git a/chrome/browser/background_sync/periodic_background_sync_permission_context_unittest.cc b/chrome/browser/background_sync/periodic_background_sync_permission_context_unittest.cc
index 9ff079c..ec88e561 100644
--- a/chrome/browser/background_sync/periodic_background_sync_permission_context_unittest.cc
+++ b/chrome/browser/background_sync/periodic_background_sync_permission_context_unittest.cc
@@ -7,7 +7,6 @@
 #include <string>
 
 #include "base/macros.h"
-#include "base/test/scoped_feature_list.h"
 #include "build/build_config.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
 #include "chrome/common/web_application_info.h"
@@ -17,7 +16,6 @@
 #include "components/content_settings/core/common/content_settings.h"
 #include "components/content_settings/core/common/content_settings_types.h"
 #include "content/public/browser/web_contents.h"
-#include "content/public/common/content_features.h"
 #include "content/public/test/web_contents_tester.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -119,8 +117,6 @@
 }
 
 TEST_F(PeriodicBackgroundSyncPermissionContextTest, DenyForInsecureOrigin) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(features::kPeriodicBackgroundSync);
   GURL url("http://example.com");
   SetBackgroundSyncContentSetting(url, CONTENT_SETTING_ALLOW);
   EXPECT_EQ(GetPermissionStatus(url, /* with_frame= */ false),
@@ -128,8 +124,6 @@
 }
 
 TEST_F(PeriodicBackgroundSyncPermissionContextTest, AllowWithFrame) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(features::kPeriodicBackgroundSync);
   GURL url("https://example.com");
   SetUpPwaAndContentSettings(url);
   SetBackgroundSyncContentSetting(url, CONTENT_SETTING_ALLOW);
@@ -139,8 +133,6 @@
 }
 
 TEST_F(PeriodicBackgroundSyncPermissionContextTest, AllowWithoutFrame) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(features::kPeriodicBackgroundSync);
   GURL url("https://example.com");
   SetUpPwaAndContentSettings(url);
 
@@ -149,8 +141,6 @@
 }
 
 TEST_F(PeriodicBackgroundSyncPermissionContextTest, DesktopPwa) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(features::kPeriodicBackgroundSync);
   GURL url("https://example.com");
   SetUpPwaAndContentSettings(url);
 
@@ -163,8 +153,6 @@
 
 #if defined(OS_ANDROID)
 TEST_F(PeriodicBackgroundSyncPermissionContextTest, Twa) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(features::kPeriodicBackgroundSync);
   GURL url("https://example.com");
 
   // No TWA or PWA installed.
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
index 0d06e4a6..5cd1aaa 100644
--- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
+++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
@@ -2139,11 +2139,11 @@
   base::Time one_hour_ago = base::Time::Now() - base::TimeDelta::FromHours(1);
   base::Time yesterday = base::Time::Now() - base::TimeDelta::FromDays(1);
   registry->OnAcceptRegisterProtocolHandler(
-      ProtocolHandler::CreateProtocolHandler("test1", kOrigin1));
+      ProtocolHandler::CreateProtocolHandler("news", kOrigin1));
   registry->OnAcceptRegisterProtocolHandler(
-      ProtocolHandler("test2", kOrigin1, yesterday));
-  EXPECT_TRUE(registry->IsHandledProtocol("test1"));
-  EXPECT_TRUE(registry->IsHandledProtocol("test2"));
+      ProtocolHandler("mailto", kOrigin1, yesterday));
+  EXPECT_TRUE(registry->IsHandledProtocol("news"));
+  EXPECT_TRUE(registry->IsHandledProtocol("mailto"));
   EXPECT_EQ(
       2U,
       registry->GetUserDefinedHandlers(base::Time(), base::Time::Max()).size());
@@ -2151,8 +2151,8 @@
   BlockUntilBrowsingDataRemoved(
       one_hour_ago, base::Time::Max(),
       ChromeBrowsingDataRemoverDelegate::DATA_TYPE_CONTENT_SETTINGS, false);
-  EXPECT_FALSE(registry->IsHandledProtocol("test1"));
-  EXPECT_TRUE(registry->IsHandledProtocol("test2"));
+  EXPECT_FALSE(registry->IsHandledProtocol("news"));
+  EXPECT_TRUE(registry->IsHandledProtocol("mailto"));
   EXPECT_EQ(
       1U,
       registry->GetUserDefinedHandlers(base::Time(), base::Time::Max()).size());
@@ -2160,8 +2160,8 @@
   BlockUntilBrowsingDataRemoved(
       base::Time(), base::Time::Max(),
       ChromeBrowsingDataRemoverDelegate::DATA_TYPE_CONTENT_SETTINGS, false);
-  EXPECT_FALSE(registry->IsHandledProtocol("test1"));
-  EXPECT_FALSE(registry->IsHandledProtocol("test2"));
+  EXPECT_FALSE(registry->IsHandledProtocol("news"));
+  EXPECT_FALSE(registry->IsHandledProtocol("mailto"));
   EXPECT_EQ(
       0U,
       registry->GetUserDefinedHandlers(base::Time(), base::Time::Max()).size());
diff --git a/chrome/browser/browsing_data/counters/site_settings_counter_unittest.cc b/chrome/browser/browsing_data/counters/site_settings_counter_unittest.cc
index ef359ac1..dbed6a1 100644
--- a/chrome/browser/browsing_data/counters/site_settings_counter_unittest.cc
+++ b/chrome/browser/browsing_data/counters/site_settings_counter_unittest.cc
@@ -236,11 +236,11 @@
 
   base::Time now = base::Time::Now();
   handler_registry()->OnAcceptRegisterProtocolHandler(
-      ProtocolHandler("test1", GURL("http://www.google.com"), now));
+      ProtocolHandler("news", GURL("http://www.google.com"), now));
   handler_registry()->OnAcceptRegisterProtocolHandler(
-      ProtocolHandler("test1", GURL("http://docs.google.com"), now));
+      ProtocolHandler("news", GURL("http://docs.google.com"), now));
   handler_registry()->OnAcceptRegisterProtocolHandler(
-      ProtocolHandler("test1", GURL("http://slides.google.com"), now));
+      ProtocolHandler("news", GURL("http://slides.google.com"), now));
 
   auto translate_prefs =
       ChromeTranslateClient::CreateTranslatePrefs(profile()->GetPrefs());
@@ -256,12 +256,12 @@
   base::Time now = base::Time::Now();
 
   handler_registry()->OnAcceptRegisterProtocolHandler(
-      ProtocolHandler("test1", GURL("http://www.google.com"), now));
+      ProtocolHandler("news", GURL("http://www.google.com"), now));
   handler_registry()->OnAcceptRegisterProtocolHandler(
-      ProtocolHandler("test2", GURL("http://maps.google.com"),
+      ProtocolHandler("mailto", GURL("http://maps.google.com"),
                       now - base::TimeDelta::FromMinutes(90)));
-  EXPECT_TRUE(handler_registry()->IsHandledProtocol("test1"));
-  EXPECT_TRUE(handler_registry()->IsHandledProtocol("test2"));
+  EXPECT_TRUE(handler_registry()->IsHandledProtocol("news"));
+  EXPECT_TRUE(handler_registry()->IsHandledProtocol("mailto"));
 
   SetDeletionPeriodPref(browsing_data::TimePeriod::ALL_TIME);
   EXPECT_EQ(2, GetResult());
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index a96a66a..8baa99ff 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -609,10 +609,6 @@
 #include "chrome/browser/safe_browsing/chrome_password_protection_service.h"
 #endif
 
-#if BUILDFLAG(FULL_SAFE_BROWSING) || defined(OS_CHROMEOS)
-#include "chrome/services/file_util/public/mojom/constants.mojom.h"
-#endif
-
 #if BUILDFLAG(ENABLE_OFFLINE_PAGES)
 #include "chrome/browser/offline_pages/offline_page_tab_helper.h"
 #include "chrome/browser/offline_pages/offline_page_url_loader_request_interceptor.h"
diff --git a/chrome/browser/chrome_content_browser_client_browsertest.cc b/chrome/browser/chrome_content_browser_client_browsertest.cc
index 3e2c454..e2540c90 100644
--- a/chrome/browser/chrome_content_browser_client_browsertest.cc
+++ b/chrome/browser/chrome_content_browser_client_browsertest.cc
@@ -774,9 +774,9 @@
 };
 
 IN_PROC_BROWSER_TEST_F(ProtocolHandlerTest, CustomHandler) {
-  AddProtocolHandler("abc", "https://abc.xyz/?url=%s");
+  AddProtocolHandler("news", "https://abc.xyz/?url=%s");
 
-  ui_test_utils::NavigateToURL(browser(), GURL("abc:something"));
+  ui_test_utils::NavigateToURL(browser(), GURL("news:something"));
 
   base::string16 expected_title = base::ASCIIToUTF16("abc.xyz");
   content::TitleWatcher title_watcher(
@@ -786,10 +786,10 @@
 
 // This is a regression test for crbug.com/969177.
 IN_PROC_BROWSER_TEST_F(ProtocolHandlerTest, HandlersIgnoredWhenDisabled) {
-  AddProtocolHandler("abc", "https://abc.xyz/?url=%s");
+  AddProtocolHandler("bitcoin", "https://abc.xyz/?url=%s");
   protocol_handler_registry()->Disable();
 
-  ui_test_utils::NavigateToURL(browser(), GURL("abc:something"));
+  ui_test_utils::NavigateToURL(browser(), GURL("bitcoin:something"));
 
   base::string16 tab_title;
   ASSERT_TRUE(ui_test_utils::GetCurrentTabTitle(browser(), &tab_title));
diff --git a/chrome/browser/chromeos/accessibility/accessibility_manager.cc b/chrome/browser/chromeos/accessibility/accessibility_manager.cc
index 5eacf83..10fdbe0 100644
--- a/chrome/browser/chromeos/accessibility/accessibility_manager.cc
+++ b/chrome/browser/chromeos/accessibility/accessibility_manager.cc
@@ -153,7 +153,7 @@
 // brltty.
 void RestartBrltty(const std::string& address) {
   chromeos::UpstartClient* client = chromeos::UpstartClient::Get();
-  client->StopJob(kBrlttyUpstartJobName, EmptyVoidDBusMethodCallback());
+  client->StopJob(kBrlttyUpstartJobName, {}, EmptyVoidDBusMethodCallback());
 
   std::vector<std::string> args;
   if (address.empty())
@@ -1403,7 +1403,7 @@
 void AccessibilityManager::PostUnloadChromeVox() {
   // Do any teardown work needed immediately after ChromeVox actually unloads.
   // Stop brltty.
-  chromeos::UpstartClient::Get()->StopJob(kBrlttyUpstartJobName,
+  chromeos::UpstartClient::Get()->StopJob(kBrlttyUpstartJobName, {},
                                           EmptyVoidDBusMethodCallback());
 
   PlayEarcon(SOUND_SPOKEN_FEEDBACK_DISABLED, PlaySoundOption::ALWAYS);
diff --git a/chrome/browser/chromeos/apps/intent_helper/OWNERS b/chrome/browser/chromeos/apps/intent_helper/OWNERS
new file mode 100644
index 0000000..be3430d
--- /dev/null
+++ b/chrome/browser/chromeos/apps/intent_helper/OWNERS
@@ -0,0 +1,3 @@
+mxcai@chromium.org
+
+# COMPONENT: Platform>Apps>Foundation
\ No newline at end of file
diff --git a/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge.cc b/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge.cc
index b184c5f..15bc2e0 100644
--- a/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge.cc
+++ b/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge.cc
@@ -240,6 +240,10 @@
     surface_manager->RemoveObserver(this);
 }
 
+extensions::EventRouter* ArcAccessibilityHelperBridge::GetEventRouter() const {
+  return extensions::EventRouter::Get(profile_);
+}
+
 void ArcAccessibilityHelperBridge::OnAccessibilityEvent(
     mojom::AccessibilityEventDataPtr event_data) {
   arc::mojom::AccessibilityFilterType filter_type =
@@ -250,6 +254,25 @@
       arc::mojom::AccessibilityFilterType::WHITELISTED_PACKAGE_NAME_DEPRECATED);
 
   if (filter_type == arc::mojom::AccessibilityFilterType::ALL) {
+    if (event_data->event_type ==
+        arc::mojom::AccessibilityEventType::ANNOUNCEMENT) {
+      if (!event_data->eventText.has_value())
+        return;
+
+      extensions::EventRouter* event_router = GetEventRouter();
+      std::unique_ptr<base::ListValue> event_args(
+          extensions::api::accessibility_private::OnAnnounceForAccessibility::
+              Create(*(event_data->eventText)));
+      std::unique_ptr<extensions::Event> event(new extensions::Event(
+          extensions::events::
+              ACCESSIBILITY_PRIVATE_ON_ANNOUNCE_FOR_ACCESSIBILITY,
+          extensions::api::accessibility_private::OnAnnounceForAccessibility::
+              kEventName,
+          std::move(event_args)));
+      event_router->BroadcastEvent(std::move(event));
+      return;
+    }
+
     if (event_data->node_data.empty())
       return;
 
@@ -279,21 +302,6 @@
       }
 
       tree_source = input_method_tree_.get();
-    } else if (event_data->event_type ==
-                   arc::mojom::AccessibilityEventType::ANNOUNCEMENT &&
-               event_data->eventText.has_value()) {
-      extensions::EventRouter* event_router =
-          extensions::EventRouter::Get(profile_);
-      std::unique_ptr<base::ListValue> event_args(
-          extensions::api::accessibility_private::OnAnnounceForAccessibility::
-              Create(*(event_data->eventText)));
-      std::unique_ptr<extensions::Event> event(new extensions::Event(
-          extensions::events::
-              ACCESSIBILITY_PRIVATE_ON_ANNOUNCE_FOR_ACCESSIBILITY,
-          extensions::api::accessibility_private::OnAnnounceForAccessibility::
-              kEventName,
-          std::move(event_args)));
-      event_router->BroadcastEvent(std::move(event));
     } else {
       if (event_data->task_id == kNoTaskId)
         return;
diff --git a/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge.h b/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge.h
index bd136340..d85294c 100644
--- a/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge.h
+++ b/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge.h
@@ -111,6 +111,7 @@
 
  protected:
   virtual aura::Window* GetActiveWindow();
+  virtual extensions::EventRouter* GetEventRouter() const;
 
  private:
   // wm::ActivationChangeObserver overrides.
diff --git a/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge_unittest.cc b/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge_unittest.cc
index 1e2a28d..ef885bd 100644
--- a/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge_unittest.cc
+++ b/chrome/browser/chromeos/arc/accessibility/arc_accessibility_helper_bridge_unittest.cc
@@ -18,6 +18,7 @@
 #include "base/command_line.h"
 #include "base/observer_list.h"
 #include "base/strings/utf_string_conversions.h"
+#include "chrome/common/extensions/api/accessibility_private.h"
 #include "chrome/test/base/testing_profile.h"
 #include "chrome/test/views/chrome_views_test_base.h"
 #include "chromeos/constants/chromeos_switches.h"
@@ -25,6 +26,7 @@
 #include "components/arc/session/arc_bridge_service.h"
 #include "components/exo/shell_surface.h"
 #include "components/exo/shell_surface_util.h"
+#include "extensions/browser/test_event_router.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/aura/window.h"
 #include "ui/display/display.h"
@@ -55,7 +57,9 @@
     TestArcAccessibilityHelperBridge(content::BrowserContext* browser_context,
                                      ArcBridgeService* arc_bridge_service)
         : ArcAccessibilityHelperBridge(browser_context, arc_bridge_service),
-          window_(new aura::Window(nullptr)) {
+          window_(new aura::Window(nullptr)),
+          event_router_(
+              extensions::CreateAndUseTestEventRouter(browser_context)) {
       window_->Init(ui::LAYER_NOT_DRAWN);
     }
 
@@ -65,11 +69,19 @@
       exo::SetShellApplicationId(window_.get(), id);
     }
 
+    int GetEventCount(const std::string& event_name) const {
+      return event_router_->GetEventCount(event_name);
+    }
+
    protected:
     aura::Window* GetActiveWindow() override { return window_.get(); }
+    extensions::EventRouter* GetEventRouter() const override {
+      return event_router_;
+    }
 
    private:
     std::unique_ptr<aura::Window> window_;
+    extensions::TestEventRouter* const event_router_;
 
     DISALLOW_COPY_AND_ASSIGN(TestArcAccessibilityHelperBridge);
   };
@@ -258,6 +270,24 @@
   ASSERT_EQ(0U, task_id_to_tree.size());
 }
 
+TEST_F(ArcAccessibilityHelperBridgeTest, EventAnnoucement) {
+  TestArcAccessibilityHelperBridge* helper_bridge =
+      accessibility_helper_bridge();
+  helper_bridge->set_filter_type_all_for_test();
+
+  std::vector<std::string> text({"Str"});
+  auto event = arc::mojom::AccessibilityEventData::New();
+  event->event_type = arc::mojom::AccessibilityEventType::ANNOUNCEMENT;
+  event->eventText =
+      base::make_optional<std::vector<std::string>>(std::move(text));
+
+  helper_bridge->OnAccessibilityEvent(event.Clone());
+
+  ASSERT_EQ(1, helper_bridge->GetEventCount(
+                   extensions::api::accessibility_private::
+                       OnAnnounceForAccessibility::kEventName));
+}
+
 // Accessibility event and surface creation/removal are sent in different
 // channels, mojo and wayland. Order of those events can be changed. This is the
 // case where mojo events arrive earlier than surface creation/removal.
diff --git a/chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc.cc b/chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc.cc
index 2f473e08..8423331 100644
--- a/chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc.cc
+++ b/chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc.cc
@@ -164,7 +164,10 @@
   if (focused_id_ < 0) {
     if (root_id_ >= 0) {
       ArcAccessibilityInfoData* root = GetRoot();
-      if (root->IsNode()) {
+      // TODO (sarakato): Add proper fix once cause of invalid node is known.
+      if (!IsValid(root)) {
+        return;
+      } else if (root->IsNode()) {
         focused_id_ = root_id_;
       } else {
         std::vector<ArcAccessibilityInfoData*> children;
diff --git a/chrome/browser/chromeos/extensions/OWNERS b/chrome/browser/chromeos/extensions/OWNERS
index d5fa58b..a17d079 100644
--- a/chrome/browser/chromeos/extensions/OWNERS
+++ b/chrome/browser/chromeos/extensions/OWNERS
@@ -3,6 +3,11 @@
 # Additional ChromeOS-specific reviewers
 tbarzic@chromium.org
 
+per-file default_app*=dominickn@chromium.org
+per-file default_app*=jshikaram@chromium.org
+per-file default_web_app_ids.h=dominickn@chromium.org
+per-file default_web_app_ids.h=jshikaram@chromium.org
+
 per-file *wallpaper*=file://ash/wallpaper/OWNERS
 
 # input method related reviewers. shuchen@ is primary, and googleo@ is backup.
diff --git a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc
index c853822..54195d7 100644
--- a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc
+++ b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc
@@ -11,7 +11,9 @@
 #include "ash/public/cpp/ash_pref_names.h"
 #include "ash/public/cpp/login_screen.h"
 #include "ash/public/cpp/shelf_item.h"
+#include "ash/public/cpp/shelf_model.h"
 #include "ash/public/cpp/shelf_prefs.h"
+#include "ash/public/cpp/shelf_types.h"
 #include "ash/public/cpp/tablet_mode.h"
 #include "ash/public/cpp/window_properties.h"
 #include "ash/public/mojom/constants.mojom.h"
@@ -190,6 +192,39 @@
   }
 }
 
+api::autotest_private::ShelfItemType GetShelfItemType(ash::ShelfItemType type) {
+  switch (type) {
+    case ash::TYPE_APP:
+      return api::autotest_private::ShelfItemType::SHELF_ITEM_TYPE_APP;
+    case ash::TYPE_PINNED_APP:
+      return api::autotest_private::ShelfItemType::SHELF_ITEM_TYPE_PINNEDAPP;
+    case ash::TYPE_BROWSER_SHORTCUT:
+      return api::autotest_private::ShelfItemType::
+          SHELF_ITEM_TYPE_BROWSERSHORTCUT;
+    case ash::TYPE_DIALOG:
+      return api::autotest_private::ShelfItemType::SHELF_ITEM_TYPE_DIALOG;
+    case ash::TYPE_UNDEFINED:
+      return api::autotest_private::ShelfItemType::SHELF_ITEM_TYPE_NONE;
+  }
+  NOTREACHED();
+  return api::autotest_private::ShelfItemType::SHELF_ITEM_TYPE_NONE;
+}
+
+api::autotest_private::ShelfItemStatus GetShelfItemStatus(
+    ash::ShelfItemStatus status) {
+  switch (status) {
+    case ash::STATUS_CLOSED:
+      return api::autotest_private::ShelfItemStatus::SHELF_ITEM_STATUS_CLOSED;
+    case ash::STATUS_RUNNING:
+      return api::autotest_private::ShelfItemStatus::SHELF_ITEM_STATUS_RUNNING;
+    case ash::STATUS_ATTENTION:
+      return api::autotest_private::ShelfItemStatus::
+          SHELF_ITEM_STATUS_ATTENTION;
+  }
+  NOTREACHED();
+  return api::autotest_private::ShelfItemStatus::SHELF_ITEM_STATUS_NONE;
+}
+
 // Helper function to set whitelisted user pref based on |pref_name| with any
 // specific pref validations. Returns error messages if any.
 std::string SetWhitelistedPref(Profile* profile,
@@ -1699,6 +1734,41 @@
 }
 
 ///////////////////////////////////////////////////////////////////////////////
+// AutotestPrivateGetShelfItemsFunction
+///////////////////////////////////////////////////////////////////////////////
+AutotestPrivateGetShelfItemsFunction::AutotestPrivateGetShelfItemsFunction() =
+    default;
+
+AutotestPrivateGetShelfItemsFunction::~AutotestPrivateGetShelfItemsFunction() =
+    default;
+
+ExtensionFunction::ResponseAction AutotestPrivateGetShelfItemsFunction::Run() {
+  DVLOG(1) << "AutotestPrivateGetShelfItemsFunction";
+
+  ChromeLauncherController* const controller =
+      ChromeLauncherController::instance();
+  if (!controller)
+    return RespondNow(Error("Controller not available"));
+
+  std::vector<api::autotest_private::ShelfItem> result_items;
+  for (const auto& item : controller->shelf_model()->items()) {
+    api::autotest_private::ShelfItem result_item;
+    result_item.app_id = item.id.app_id;
+    result_item.launch_id = item.id.launch_id;
+    result_item.title = base::UTF16ToUTF8(item.title);
+    result_item.type = GetShelfItemType(item.type);
+    result_item.status = GetShelfItemStatus(item.status);
+    result_item.shows_tooltip = item.shows_tooltip;
+    result_item.pinned_by_policy = item.pinned_by_policy;
+    result_item.has_notification = item.has_notification;
+    result_items.emplace_back(std::move(result_item));
+  }
+
+  return RespondNow(ArgumentList(
+      api::autotest_private::GetShelfItems::Results::Create(result_items)));
+}
+
+///////////////////////////////////////////////////////////////////////////////
 // AutotestPrivateGetShelfAutoHideBehaviorFunction
 ///////////////////////////////////////////////////////////////////////////////
 
diff --git a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.h b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.h
index 3bfc0f8..0235421 100644
--- a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.h
+++ b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.h
@@ -603,6 +603,18 @@
   ResponseAction Run() override;
 };
 
+// Returns a list of all shelf items
+class AutotestPrivateGetShelfItemsFunction : public ExtensionFunction {
+ public:
+  AutotestPrivateGetShelfItemsFunction();
+  DECLARE_EXTENSION_FUNCTION("autotestPrivate.getShelfItems",
+                             AUTOTESTPRIVATE_GETSHELFITEMS)
+
+ private:
+  ~AutotestPrivateGetShelfItemsFunction() override;
+  ResponseAction Run() override;
+};
+
 // Returns the shelf auto hide behavior.
 class AutotestPrivateGetShelfAutoHideBehaviorFunction
     : public ExtensionFunction {
diff --git a/chrome/browser/chromeos/extensions/default_app_order.cc b/chrome/browser/chromeos/extensions/default_app_order.cc
index 68e338f..cf54b2d2 100644
--- a/chrome/browser/chromeos/extensions/default_app_order.cc
+++ b/chrome/browser/chromeos/extensions/default_app_order.cc
@@ -60,6 +60,7 @@
     app_list::kInternalAppIdCamera,
     extension_misc::kCameraAppId,
     extension_misc::kGooglePhotosAppId,
+    arc::kGoogleDuo,
     app_list::kDefaultPageBreak1,  // First default page break
     extension_misc::kGoogleMapsAppId,
     app_list::kInternalAppIdSettings,
@@ -70,7 +71,6 @@
     extension_misc::kCalculatorAppId,
     default_web_apps::kCanvasAppId,
     extension_misc::kTextEditorAppId,
-    arc::kGoogleDuo,
     default_web_apps::kYoutubeTVAppId,
     arc::kLightRoom,
     arc::kInfinitePainter,
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc
index 580ee22a..684bf992 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc
@@ -40,6 +40,7 @@
 #include "chrome/browser/chromeos/settings/cros_settings.h"
 #include "chrome/browser/devtools/devtools_window.h"
 #include "chrome/browser/extensions/devtools_util.h"
+#include "chrome/browser/file_util_service.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
 #include "chrome/browser/net/system_network_context_manager.h"
 #include "chrome/browser/profiles/profile.h"
@@ -66,7 +67,6 @@
 #include "components/signin/public/identity_manager/identity_manager.h"
 #include "components/user_manager/user_manager.h"
 #include "components/zoom/page_zoom.h"
-#include "content/public/browser/system_connector.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/page_zoom.h"
 #include "extensions/browser/api/file_handlers/mime_util.h"
@@ -342,7 +342,7 @@
        base::Bind(&FileManagerPrivateInternalZipSelectionFunction::OnZipDone,
                   this),
        src_dir, src_relative_paths, dest_file))
-      ->Start(content::GetSystemConnector());
+      ->Start(LaunchFileUtilService());
   return RespondLater();
 }
 
diff --git a/chrome/browser/custom_handlers/protocol_handler_registry.cc b/chrome/browser/custom_handlers/protocol_handler_registry.cc
index 62646ec..f1551c6 100644
--- a/chrome/browser/custom_handlers/protocol_handler_registry.cc
+++ b/chrome/browser/custom_handlers/protocol_handler_registry.cc
@@ -144,7 +144,8 @@
 void ProtocolHandlerRegistry::OnAcceptRegisterProtocolHandler(
     const ProtocolHandler& handler) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  RegisterProtocolHandler(handler, USER);
+  if (!RegisterProtocolHandler(handler, USER))
+    return;
   SetDefault(handler);
   Save();
   NotifyChanged();
@@ -647,23 +648,29 @@
     observer.OnProtocolHandlerRegistryChanged();
 }
 
-void ProtocolHandlerRegistry::RegisterProtocolHandler(
+bool ProtocolHandlerRegistry::RegisterProtocolHandler(
     const ProtocolHandler& handler,
     const HandlerSource source) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK(CanSchemeBeOverridden(handler.protocol()));
   DCHECK(!handler.IsEmpty());
+
+  // Ignore invalid handlers.
+  if (!handler.IsValid())
+    return false;
+
   ProtocolHandlerMultiMap& map =
       (source == POLICY) ? policy_protocol_handlers_ : user_protocol_handlers_;
   ProtocolHandlerList& list = map[handler.protocol()];
   if (!HandlerExists(handler, list))
     list.push_back(handler);
   if (IsRegistered(handler)) {
-    return;
+    return true;
   }
   if (enabled_ && !delegate_->IsExternalHandlerRegistered(handler.protocol()))
     delegate_->RegisterExternalHandler(handler.protocol());
   InsertHandler(handler);
+  return true;
 }
 
 std::vector<const base::DictionaryValue*>
@@ -699,7 +706,8 @@
        p != registered_handlers.end();
        ++p) {
     ProtocolHandler handler = ProtocolHandler::CreateProtocolHandler(*p);
-    RegisterProtocolHandler(handler, source);
+    if (!RegisterProtocolHandler(handler, source))
+      continue;
     bool is_default = false;
     if ((*p)->GetBoolean("default", &is_default) && is_default) {
       SetDefault(handler);
diff --git a/chrome/browser/custom_handlers/protocol_handler_registry.h b/chrome/browser/custom_handlers/protocol_handler_registry.h
index b73dbceb5..614b1b0 100644
--- a/chrome/browser/custom_handlers/protocol_handler_registry.h
+++ b/chrome/browser/custom_handlers/protocol_handler_registry.h
@@ -242,7 +242,7 @@
   void NotifyChanged();
 
   // Registers a new protocol handler.
-  void RegisterProtocolHandler(const ProtocolHandler& handler,
+  bool RegisterProtocolHandler(const ProtocolHandler& handler,
                                const HandlerSource source);
 
   // Registers protocol handlers from the preference.
diff --git a/chrome/browser/custom_handlers/protocol_handler_registry_browsertest.cc b/chrome/browser/custom_handlers/protocol_handler_registry_browsertest.cc
index 1535f5e..647b1054 100644
--- a/chrome/browser/custom_handlers/protocol_handler_registry_browsertest.cc
+++ b/chrome/browser/custom_handlers/protocol_handler_registry_browsertest.cc
@@ -52,8 +52,7 @@
     return menu;
   }
 
-  void AddProtocolHandler(const std::string& protocol,
-                          const GURL& url) {
+  void AddProtocolHandler(const std::string& protocol, const GURL& url) {
     ProtocolHandler handler = ProtocolHandler::CreateProtocolHandler(protocol,
                                                                      url);
     ProtocolHandlerRegistry* registry =
@@ -120,17 +119,17 @@
 
 IN_PROC_BROWSER_TEST_F(RegisterProtocolHandlerBrowserTest, CustomHandler) {
   ASSERT_TRUE(embedded_test_server()->Start());
-  GURL handler_url = embedded_test_server()->GetURL("/custom_handler_foo.html");
-  AddProtocolHandler("foo", handler_url);
+  GURL handler_url = embedded_test_server()->GetURL("/custom_handler.html");
+  AddProtocolHandler("news", handler_url);
 
-  ui_test_utils::NavigateToURL(browser(), GURL("foo:test"));
+  ui_test_utils::NavigateToURL(browser(), GURL("news:test"));
 
   ASSERT_EQ(handler_url,
             browser()->tab_strip_model()->GetActiveWebContents()->GetURL());
 
   // Also check redirects.
   GURL redirect_url =
-      embedded_test_server()->GetURL("/server-redirect?foo:test");
+      embedded_test_server()->GetURL("/server-redirect?news:test");
   ui_test_utils::NavigateToURL(browser(), redirect_url);
 
   ASSERT_EQ(handler_url,
diff --git a/chrome/browser/custom_handlers/protocol_handler_registry_unittest.cc b/chrome/browser/custom_handlers/protocol_handler_registry_unittest.cc
index f6fe7772..a59e06c 100644
--- a/chrome/browser/custom_handlers/protocol_handler_registry_unittest.cc
+++ b/chrome/browser/custom_handlers/protocol_handler_registry_unittest.cc
@@ -197,7 +197,7 @@
 class ProtocolHandlerRegistryTest : public testing::Test {
  protected:
   ProtocolHandlerRegistryTest()
-      : test_protocol_handler_(CreateProtocolHandler("test", "test")) {}
+      : test_protocol_handler_(CreateProtocolHandler("news", "news")) {}
 
   FakeDelegate* delegate() const { return delegate_; }
   ProtocolHandlerRegistry* registry() { return registry_.get(); }
@@ -268,7 +268,7 @@
     CHECK(profile_->GetPrefs());
     SetUpRegistry(true);
     test_protocol_handler_ =
-        CreateProtocolHandler("test", GURL("http://test.com/%s"));
+        CreateProtocolHandler("news", GURL("http://test.com/%s"));
   }
 
   void TearDown() override { TeadDownRegistry(); }
@@ -283,34 +283,34 @@
 };
 
 TEST_F(ProtocolHandlerRegistryTest, AcceptProtocolHandlerHandlesProtocol) {
-  ASSERT_FALSE(registry()->IsHandledProtocol("test"));
+  ASSERT_FALSE(registry()->IsHandledProtocol("news"));
   registry()->OnAcceptRegisterProtocolHandler(test_protocol_handler());
-  ASSERT_TRUE(registry()->IsHandledProtocol("test"));
+  ASSERT_TRUE(registry()->IsHandledProtocol("news"));
 }
 
 TEST_F(ProtocolHandlerRegistryTest, DeniedProtocolIsntHandledUntilAccepted) {
   registry()->OnDenyRegisterProtocolHandler(test_protocol_handler());
-  ASSERT_FALSE(registry()->IsHandledProtocol("test"));
+  ASSERT_FALSE(registry()->IsHandledProtocol("news"));
   registry()->OnAcceptRegisterProtocolHandler(test_protocol_handler());
-  ASSERT_TRUE(registry()->IsHandledProtocol("test"));
+  ASSERT_TRUE(registry()->IsHandledProtocol("news"));
 }
 
 TEST_F(ProtocolHandlerRegistryTest, ClearDefaultMakesProtocolNotHandled) {
   registry()->OnAcceptRegisterProtocolHandler(test_protocol_handler());
-  registry()->ClearDefault("test");
-  ASSERT_FALSE(registry()->IsHandledProtocol("test"));
-  ASSERT_TRUE(registry()->GetHandlerFor("test").IsEmpty());
+  registry()->ClearDefault("news");
+  ASSERT_FALSE(registry()->IsHandledProtocol("news"));
+  ASSERT_TRUE(registry()->GetHandlerFor("news").IsEmpty());
 }
 
 TEST_F(ProtocolHandlerRegistryTest, DisableDeregistersProtocolHandlers) {
-  ASSERT_FALSE(delegate()->IsExternalHandlerRegistered("test"));
+  ASSERT_FALSE(delegate()->IsExternalHandlerRegistered("news"));
   registry()->OnAcceptRegisterProtocolHandler(test_protocol_handler());
-  ASSERT_TRUE(delegate()->IsExternalHandlerRegistered("test"));
+  ASSERT_TRUE(delegate()->IsExternalHandlerRegistered("news"));
 
   registry()->Disable();
-  ASSERT_FALSE(delegate()->IsExternalHandlerRegistered("test"));
+  ASSERT_FALSE(delegate()->IsExternalHandlerRegistered("news"));
   registry()->Enable();
-  ASSERT_TRUE(delegate()->IsExternalHandlerRegistered("test"));
+  ASSERT_TRUE(delegate()->IsExternalHandlerRegistered("news"));
 }
 
 TEST_F(ProtocolHandlerRegistryTest, IgnoreProtocolHandler) {
@@ -322,8 +322,8 @@
 }
 
 TEST_F(ProtocolHandlerRegistryTest, IgnoreEquivalentProtocolHandler) {
-  ProtocolHandler ph1 = CreateProtocolHandler("test", GURL("http://test/%s"));
-  ProtocolHandler ph2 = CreateProtocolHandler("test", GURL("http://test/%s"));
+  ProtocolHandler ph1 = CreateProtocolHandler("news", GURL("http://test/%s"));
+  ProtocolHandler ph2 = CreateProtocolHandler("news", GURL("http://test/%s"));
 
   registry()->OnIgnoreRegisterProtocolHandler(ph1);
   ASSERT_TRUE(registry()->IsIgnored(ph1));
@@ -340,21 +340,21 @@
   registry()->OnAcceptRegisterProtocolHandler(test_protocol_handler());
   registry()->OnIgnoreRegisterProtocolHandler(stuff_protocol_handler);
 
-  ASSERT_TRUE(registry()->IsHandledProtocol("test"));
+  ASSERT_TRUE(registry()->IsHandledProtocol("news"));
   ASSERT_TRUE(registry()->IsIgnored(stuff_protocol_handler));
   delegate()->Reset();
   RecreateRegistry(true);
-  ASSERT_TRUE(registry()->IsHandledProtocol("test"));
+  ASSERT_TRUE(registry()->IsHandledProtocol("news"));
   ASSERT_TRUE(registry()->IsIgnored(stuff_protocol_handler));
 }
 
 TEST_F(ProtocolHandlerRegistryTest, Encode) {
   base::Time now = base::Time::Now();
-  ProtocolHandler handler("test", GURL("http://example.com"), now);
+  ProtocolHandler handler("news", GURL("http://example.com"), now);
   auto value = handler.Encode();
   ProtocolHandler recreated =
       ProtocolHandler::CreateProtocolHandler(value.get());
-  EXPECT_EQ("test", recreated.protocol());
+  EXPECT_EQ("news", recreated.protocol());
   EXPECT_EQ(GURL("http://example.com"), recreated.url());
   EXPECT_EQ(now, recreated.last_modified());
 }
@@ -363,9 +363,10 @@
   base::Time now = base::Time::Now();
   base::Time one_hour_ago = now - base::TimeDelta::FromHours(1);
   base::Time two_hours_ago = now - base::TimeDelta::FromHours(2);
-  ProtocolHandler handler1("test1", GURL("http://example.com"), two_hours_ago);
-  ProtocolHandler handler2("test2", GURL("http://example.com"), one_hour_ago);
-  ProtocolHandler handler3("test3", GURL("http://example.com"), now);
+  ProtocolHandler handler1("bitcoin", GURL("http://example.com"),
+                           two_hours_ago);
+  ProtocolHandler handler2("geo", GURL("http://example.com"), one_hour_ago);
+  ProtocolHandler handler3("im", GURL("http://example.com"), now);
   registry()->OnAcceptRegisterProtocolHandler(handler1);
   registry()->OnAcceptRegisterProtocolHandler(handler2);
   registry()->OnAcceptRegisterProtocolHandler(handler3);
@@ -385,12 +386,12 @@
   base::Time one_hour_ago = now - base::TimeDelta::FromHours(1);
   base::Time two_hours_ago = now - base::TimeDelta::FromHours(2);
   GURL url("http://example.com");
-  ProtocolHandler handler1("test1", url, two_hours_ago);
-  ProtocolHandler handler2("test2", url, one_hour_ago);
-  ProtocolHandler handler3("test3", url, now);
-  ProtocolHandler ignored1("ignored1", url, two_hours_ago);
-  ProtocolHandler ignored2("ignored2", url, one_hour_ago);
-  ProtocolHandler ignored3("ignored3", url, now);
+  ProtocolHandler handler1("bitcoin", url, two_hours_ago);
+  ProtocolHandler handler2("geo", url, one_hour_ago);
+  ProtocolHandler handler3("im", url, now);
+  ProtocolHandler ignored1("irc", url, two_hours_ago);
+  ProtocolHandler ignored2("ircs", url, one_hour_ago);
+  ProtocolHandler ignored3("magnet", url, now);
   registry()->OnAcceptRegisterProtocolHandler(handler1);
   registry()->OnAcceptRegisterProtocolHandler(handler2);
   registry()->OnAcceptRegisterProtocolHandler(handler3);
@@ -398,27 +399,27 @@
   registry()->OnIgnoreRegisterProtocolHandler(ignored2);
   registry()->OnIgnoreRegisterProtocolHandler(ignored3);
 
-  EXPECT_TRUE(registry()->IsHandledProtocol("test1"));
-  EXPECT_TRUE(registry()->IsHandledProtocol("test2"));
-  EXPECT_TRUE(registry()->IsHandledProtocol("test3"));
+  EXPECT_TRUE(registry()->IsHandledProtocol("bitcoin"));
+  EXPECT_TRUE(registry()->IsHandledProtocol("geo"));
+  EXPECT_TRUE(registry()->IsHandledProtocol("im"));
   EXPECT_TRUE(registry()->IsIgnored(ignored1));
   EXPECT_TRUE(registry()->IsIgnored(ignored2));
   EXPECT_TRUE(registry()->IsIgnored(ignored3));
 
   // Delete handler2 and ignored2.
   registry()->ClearUserDefinedHandlers(one_hour_ago, now);
-  EXPECT_TRUE(registry()->IsHandledProtocol("test1"));
-  EXPECT_FALSE(registry()->IsHandledProtocol("test2"));
-  EXPECT_TRUE(registry()->IsHandledProtocol("test3"));
+  EXPECT_TRUE(registry()->IsHandledProtocol("bitcoin"));
+  EXPECT_FALSE(registry()->IsHandledProtocol("geo"));
+  EXPECT_TRUE(registry()->IsHandledProtocol("im"));
   EXPECT_TRUE(registry()->IsIgnored(ignored1));
   EXPECT_FALSE(registry()->IsIgnored(ignored2));
   EXPECT_TRUE(registry()->IsIgnored(ignored3));
 
   // Delete all.
   registry()->ClearUserDefinedHandlers(base::Time(), base::Time::Max());
-  EXPECT_FALSE(registry()->IsHandledProtocol("test1"));
-  EXPECT_FALSE(registry()->IsHandledProtocol("test2"));
-  EXPECT_FALSE(registry()->IsHandledProtocol("test3"));
+  EXPECT_FALSE(registry()->IsHandledProtocol("bitcoin"));
+  EXPECT_FALSE(registry()->IsHandledProtocol("geo"));
+  EXPECT_FALSE(registry()->IsHandledProtocol("im"));
   EXPECT_FALSE(registry()->IsIgnored(ignored1));
   EXPECT_FALSE(registry()->IsIgnored(ignored2));
   EXPECT_FALSE(registry()->IsIgnored(ignored3));
@@ -433,15 +434,15 @@
 
 TEST_F(ProtocolHandlerRegistryTest,
     DisallowRegisteringExternallyHandledProtocols) {
-  delegate()->RegisterExternalHandler("test");
-  ASSERT_FALSE(registry()->CanSchemeBeOverridden("test"));
+  delegate()->RegisterExternalHandler("news");
+  ASSERT_FALSE(registry()->CanSchemeBeOverridden("news"));
 }
 
 TEST_F(ProtocolHandlerRegistryTest, RemovingHandlerMeansItCanBeAddedAgain) {
   registry()->OnAcceptRegisterProtocolHandler(test_protocol_handler());
-  ASSERT_TRUE(registry()->CanSchemeBeOverridden("test"));
+  ASSERT_TRUE(registry()->CanSchemeBeOverridden("news"));
   registry()->RemoveHandler(test_protocol_handler());
-  ASSERT_TRUE(registry()->CanSchemeBeOverridden("test"));
+  ASSERT_TRUE(registry()->CanSchemeBeOverridden("news"));
 }
 
 TEST_F(ProtocolHandlerRegistryTest, TestStartsAsDefault) {
@@ -450,31 +451,31 @@
 }
 
 TEST_F(ProtocolHandlerRegistryTest, TestClearDefault) {
-  ProtocolHandler ph1 = CreateProtocolHandler("test", "test1");
-  ProtocolHandler ph2 = CreateProtocolHandler("test", "test2");
+  ProtocolHandler ph1 = CreateProtocolHandler("news", "test1");
+  ProtocolHandler ph2 = CreateProtocolHandler("news", "test2");
   registry()->OnAcceptRegisterProtocolHandler(ph1);
   registry()->OnAcceptRegisterProtocolHandler(ph2);
 
   registry()->OnAcceptRegisterProtocolHandler(ph1);
-  registry()->ClearDefault("test");
+  registry()->ClearDefault("news");
   ASSERT_FALSE(registry()->IsDefault(ph1));
   ASSERT_FALSE(registry()->IsDefault(ph2));
 }
 
 TEST_F(ProtocolHandlerRegistryTest, TestGetHandlerFor) {
-  ProtocolHandler ph1 = CreateProtocolHandler("test", "test1");
-  ProtocolHandler ph2 = CreateProtocolHandler("test", "test2");
+  ProtocolHandler ph1 = CreateProtocolHandler("news", "test1");
+  ProtocolHandler ph2 = CreateProtocolHandler("news", "test2");
   registry()->OnAcceptRegisterProtocolHandler(ph1);
   registry()->OnAcceptRegisterProtocolHandler(ph2);
 
   registry()->OnAcceptRegisterProtocolHandler(ph2);
-  ASSERT_EQ(ph2, registry()->GetHandlerFor("test"));
-  ASSERT_TRUE(registry()->IsHandledProtocol("test"));
+  ASSERT_EQ(ph2, registry()->GetHandlerFor("news"));
+  ASSERT_TRUE(registry()->IsHandledProtocol("news"));
 }
 
 TEST_F(ProtocolHandlerRegistryTest, TestMostRecentHandlerIsDefault) {
-  ProtocolHandler ph1 = CreateProtocolHandler("test", "test1");
-  ProtocolHandler ph2 = CreateProtocolHandler("test", "test2");
+  ProtocolHandler ph1 = CreateProtocolHandler("news", "test1");
+  ProtocolHandler ph2 = CreateProtocolHandler("news", "test2");
   registry()->OnAcceptRegisterProtocolHandler(ph1);
   registry()->OnAcceptRegisterProtocolHandler(ph2);
   ASSERT_FALSE(registry()->IsDefault(ph1));
@@ -482,8 +483,8 @@
 }
 
 TEST_F(ProtocolHandlerRegistryTest, TestOnAcceptRegisterProtocolHandler) {
-  ProtocolHandler ph1 = CreateProtocolHandler("test", "test1");
-  ProtocolHandler ph2 = CreateProtocolHandler("test", "test2");
+  ProtocolHandler ph1 = CreateProtocolHandler("news", "test1");
+  ProtocolHandler ph2 = CreateProtocolHandler("news", "test2");
   registry()->OnAcceptRegisterProtocolHandler(ph1);
   registry()->OnAcceptRegisterProtocolHandler(ph2);
 
@@ -497,8 +498,8 @@
 }
 
 TEST_F(ProtocolHandlerRegistryTest, TestDefaultSaveLoad) {
-  ProtocolHandler ph1 = CreateProtocolHandler("test", "test1");
-  ProtocolHandler ph2 = CreateProtocolHandler("test", "test2");
+  ProtocolHandler ph1 = CreateProtocolHandler("news", "test1");
+  ProtocolHandler ph2 = CreateProtocolHandler("news", "test2");
   registry()->OnDenyRegisterProtocolHandler(ph1);
   registry()->OnDenyRegisterProtocolHandler(ph2);
 
@@ -517,13 +518,13 @@
 }
 
 TEST_F(ProtocolHandlerRegistryTest, TestRemoveHandler) {
-  ProtocolHandler ph1 = CreateProtocolHandler("test", "test1");
+  ProtocolHandler ph1 = CreateProtocolHandler("news", "test1");
   registry()->OnAcceptRegisterProtocolHandler(ph1);
   registry()->OnAcceptRegisterProtocolHandler(ph1);
 
   registry()->RemoveHandler(ph1);
   ASSERT_FALSE(registry()->IsRegistered(ph1));
-  ASSERT_FALSE(registry()->IsHandledProtocol("test"));
+  ASSERT_FALSE(registry()->IsHandledProtocol("news"));
 
   registry()->OnIgnoreRegisterProtocolHandler(ph1);
   ASSERT_FALSE(registry()->IsRegistered(ph1));
@@ -535,8 +536,8 @@
 }
 
 TEST_F(ProtocolHandlerRegistryTest, TestIsRegistered) {
-  ProtocolHandler ph1 = CreateProtocolHandler("test", "test1");
-  ProtocolHandler ph2 = CreateProtocolHandler("test", "test2");
+  ProtocolHandler ph1 = CreateProtocolHandler("news", "test1");
+  ProtocolHandler ph2 = CreateProtocolHandler("news", "test2");
   registry()->OnAcceptRegisterProtocolHandler(ph1);
   registry()->OnAcceptRegisterProtocolHandler(ph2);
 
@@ -544,8 +545,8 @@
 }
 
 TEST_F(ProtocolHandlerRegistryTest, TestIsEquivalentRegistered) {
-  ProtocolHandler ph1 = CreateProtocolHandler("test", GURL("http://test/%s"));
-  ProtocolHandler ph2 = CreateProtocolHandler("test", GURL("http://test/%s"));
+  ProtocolHandler ph1 = CreateProtocolHandler("news", GURL("http://test/%s"));
+  ProtocolHandler ph2 = CreateProtocolHandler("news", GURL("http://test/%s"));
   registry()->OnAcceptRegisterProtocolHandler(ph1);
 
   ASSERT_TRUE(registry()->IsRegistered(ph1));
@@ -553,8 +554,8 @@
 }
 
 TEST_F(ProtocolHandlerRegistryTest, TestSilentlyRegisterHandler) {
-  ProtocolHandler ph1 = CreateProtocolHandler("test", GURL("http://test/1/%s"));
-  ProtocolHandler ph2 = CreateProtocolHandler("test", GURL("http://test/2/%s"));
+  ProtocolHandler ph1 = CreateProtocolHandler("news", GURL("http://test/1/%s"));
+  ProtocolHandler ph2 = CreateProtocolHandler("news", GURL("http://test/2/%s"));
   ProtocolHandler ph3 = CreateProtocolHandler("ignore", GURL("http://test/%s"));
   ProtocolHandler ph4 = CreateProtocolHandler("ignore", GURL("http://test/%s"));
 
@@ -581,9 +582,9 @@
 }
 
 TEST_F(ProtocolHandlerRegistryTest, TestRemoveHandlerRemovesDefault) {
-  ProtocolHandler ph1 = CreateProtocolHandler("test", "test1");
-  ProtocolHandler ph2 = CreateProtocolHandler("test", "test2");
-  ProtocolHandler ph3 = CreateProtocolHandler("test", "test3");
+  ProtocolHandler ph1 = CreateProtocolHandler("news", "test1");
+  ProtocolHandler ph2 = CreateProtocolHandler("news", "test2");
+  ProtocolHandler ph3 = CreateProtocolHandler("news", "test3");
 
   registry()->OnAcceptRegisterProtocolHandler(ph1);
   registry()->OnAcceptRegisterProtocolHandler(ph2);
@@ -595,15 +596,15 @@
 }
 
 TEST_F(ProtocolHandlerRegistryTest, TestGetHandlersFor) {
-  ProtocolHandler ph1 = CreateProtocolHandler("test", "test1");
-  ProtocolHandler ph2 = CreateProtocolHandler("test", "test2");
-  ProtocolHandler ph3 = CreateProtocolHandler("test", "test3");
+  ProtocolHandler ph1 = CreateProtocolHandler("news", "test1");
+  ProtocolHandler ph2 = CreateProtocolHandler("news", "test2");
+  ProtocolHandler ph3 = CreateProtocolHandler("news", "test3");
   registry()->OnAcceptRegisterProtocolHandler(ph1);
   registry()->OnAcceptRegisterProtocolHandler(ph2);
   registry()->OnAcceptRegisterProtocolHandler(ph3);
 
   ProtocolHandlerRegistry::ProtocolHandlerList handlers =
-      registry()->GetHandlersFor("test");
+      registry()->GetHandlersFor("news");
   ASSERT_EQ(static_cast<size_t>(3), handlers.size());
 
   ASSERT_EQ(ph3, handlers[0]);
@@ -616,7 +617,7 @@
   registry()->GetRegisteredProtocols(&protocols);
   ASSERT_EQ(static_cast<size_t>(0), protocols.size());
 
-  registry()->GetHandlersFor("test");
+  registry()->GetHandlersFor("news");
 
   protocols.clear();
   registry()->GetRegisteredProtocols(&protocols);
@@ -624,12 +625,12 @@
 }
 
 TEST_F(ProtocolHandlerRegistryTest, TestIsHandledProtocol) {
-  registry()->GetHandlersFor("test");
-  ASSERT_FALSE(registry()->IsHandledProtocol("test"));
+  registry()->GetHandlersFor("news");
+  ASSERT_FALSE(registry()->IsHandledProtocol("news"));
 }
 
 TEST_F(ProtocolHandlerRegistryTest, TestObserver) {
-  ProtocolHandler ph1 = CreateProtocolHandler("test", "test1");
+  ProtocolHandler ph1 = CreateProtocolHandler("news", "test1");
   ProtocolHandlerChangeListener counter(registry());
 
   registry()->OnAcceptRegisterProtocolHandler(ph1);
@@ -651,43 +652,43 @@
 
 TEST_F(ProtocolHandlerRegistryTest, TestReentrantObserver) {
   QueryProtocolHandlerOnChange queryer(registry());
-  ProtocolHandler ph1 = CreateProtocolHandler("test", "test1");
+  ProtocolHandler ph1 = CreateProtocolHandler("news", "test1");
   registry()->OnAcceptRegisterProtocolHandler(ph1);
   ASSERT_TRUE(queryer.called());
 }
 
 TEST_F(ProtocolHandlerRegistryTest, TestProtocolsWithNoDefaultAreHandled) {
-  ProtocolHandler ph1 = CreateProtocolHandler("test", "test1");
+  ProtocolHandler ph1 = CreateProtocolHandler("news", "test1");
   registry()->OnAcceptRegisterProtocolHandler(ph1);
-  registry()->ClearDefault("test");
+  registry()->ClearDefault("news");
   std::vector<std::string> handled_protocols;
   registry()->GetRegisteredProtocols(&handled_protocols);
   ASSERT_EQ(static_cast<size_t>(1), handled_protocols.size());
-  ASSERT_EQ("test", handled_protocols[0]);
+  ASSERT_EQ("news", handled_protocols[0]);
 }
 
 TEST_F(ProtocolHandlerRegistryTest, TestDisablePreventsHandling) {
-  ProtocolHandler ph1 = CreateProtocolHandler("test", "test1");
+  ProtocolHandler ph1 = CreateProtocolHandler("news", "test1");
   registry()->OnAcceptRegisterProtocolHandler(ph1);
-  ASSERT_TRUE(registry()->IsHandledProtocol("test"));
+  ASSERT_TRUE(registry()->IsHandledProtocol("news"));
   registry()->Disable();
-  ASSERT_FALSE(registry()->IsHandledProtocol("test"));
+  ASSERT_FALSE(registry()->IsHandledProtocol("news"));
 }
 
 TEST_F(ProtocolHandlerRegistryTest, TestOSRegistration) {
-  ProtocolHandler ph_do1 = CreateProtocolHandler("do", "test1");
-  ProtocolHandler ph_do2 = CreateProtocolHandler("do", "test2");
-  ProtocolHandler ph_dont = CreateProtocolHandler("dont", "test");
+  ProtocolHandler ph_do1 = CreateProtocolHandler("news", "test1");
+  ProtocolHandler ph_do2 = CreateProtocolHandler("news", "test2");
+  ProtocolHandler ph_dont = CreateProtocolHandler("im", "test3");
 
-  ASSERT_FALSE(delegate()->IsFakeRegisteredWithOS("do"));
-  ASSERT_FALSE(delegate()->IsFakeRegisteredWithOS("dont"));
+  ASSERT_FALSE(delegate()->IsFakeRegisteredWithOS("news"));
+  ASSERT_FALSE(delegate()->IsFakeRegisteredWithOS("im"));
 
   registry()->OnAcceptRegisterProtocolHandler(ph_do1);
   registry()->OnDenyRegisterProtocolHandler(ph_dont);
   base::RunLoop().RunUntilIdle();
 
-  ASSERT_TRUE(delegate()->IsFakeRegisteredWithOS("do"));
-  ASSERT_FALSE(delegate()->IsFakeRegisteredWithOS("dont"));
+  ASSERT_TRUE(delegate()->IsFakeRegisteredWithOS("news"));
+  ASSERT_FALSE(delegate()->IsFakeRegisteredWithOS("im"));
 
   // This should not register with the OS, if it does the delegate
   // will assert for us. We don't need to wait for the message loop
@@ -704,11 +705,11 @@
 #endif
 
 TEST_F(ProtocolHandlerRegistryTest, MAYBE_TestOSRegistrationFailure) {
-  ProtocolHandler ph_do = CreateProtocolHandler("do", "test1");
-  ProtocolHandler ph_dont = CreateProtocolHandler("dont", "test");
+  ProtocolHandler ph_do = CreateProtocolHandler("news", "test1");
+  ProtocolHandler ph_dont = CreateProtocolHandler("im", "test2");
 
-  ASSERT_FALSE(registry()->IsHandledProtocol("do"));
-  ASSERT_FALSE(registry()->IsHandledProtocol("dont"));
+  ASSERT_FALSE(registry()->IsHandledProtocol("news"));
+  ASSERT_FALSE(registry()->IsHandledProtocol("im"));
 
   registry()->OnAcceptRegisterProtocolHandler(ph_do);
   base::RunLoop().RunUntilIdle();
@@ -717,10 +718,10 @@
   registry()->OnAcceptRegisterProtocolHandler(ph_dont);
   base::RunLoop().RunUntilIdle();
 
-  ASSERT_TRUE(registry()->IsHandledProtocol("do"));
-  ASSERT_EQ(static_cast<size_t>(1), registry()->GetHandlersFor("do").size());
-  ASSERT_FALSE(registry()->IsHandledProtocol("dont"));
-  ASSERT_EQ(static_cast<size_t>(1), registry()->GetHandlersFor("dont").size());
+  ASSERT_TRUE(registry()->IsHandledProtocol("news"));
+  ASSERT_EQ(static_cast<size_t>(1), registry()->GetHandlersFor("news").size());
+  ASSERT_FALSE(registry()->IsHandledProtocol("im"));
+  ASSERT_EQ(static_cast<size_t>(1), registry()->GetHandlersFor("im").size());
 }
 
 TEST_F(ProtocolHandlerRegistryTest, TestRemovingDefaultFallsBackToOldDefault) {
@@ -822,17 +823,17 @@
 TEST_F(ProtocolHandlerRegistryTest, TestInstallDefaultHandler) {
   RecreateRegistry(false);
   registry()->AddPredefinedHandler(
-      CreateProtocolHandler("test", GURL("http://test.com/%s")));
+      CreateProtocolHandler("news", GURL("http://test.com/%s")));
   registry()->InitProtocolSettings();
   std::vector<std::string> protocols;
   registry()->GetRegisteredProtocols(&protocols);
   ASSERT_EQ(static_cast<size_t>(1), protocols.size());
-  EXPECT_TRUE(registry()->IsHandledProtocol("test"));
+  EXPECT_TRUE(registry()->IsHandledProtocol("news"));
   auto handlers =
       registry()->GetUserDefinedHandlers(base::Time(), base::Time::Max());
   EXPECT_TRUE(handlers.empty());
   registry()->ClearUserDefinedHandlers(base::Time(), base::Time::Max());
-  EXPECT_TRUE(registry()->IsHandledProtocol("test"));
+  EXPECT_TRUE(registry()->IsHandledProtocol("news"));
 }
 
 #define URL_p1u1 "http://p1u1.com/%s"
@@ -847,16 +848,16 @@
   base::ListValue handlers_registered_by_policy;
 
   handlers_registered_by_pref.Append(
-      GetProtocolHandlerValueWithDefault("p1", URL_p1u2, true));
+      GetProtocolHandlerValueWithDefault("news", URL_p1u2, true));
   handlers_registered_by_pref.Append(
-      GetProtocolHandlerValueWithDefault("p1", URL_p1u1, true));
+      GetProtocolHandlerValueWithDefault("news", URL_p1u1, true));
   handlers_registered_by_pref.Append(
-      GetProtocolHandlerValueWithDefault("p1", URL_p1u2, false));
+      GetProtocolHandlerValueWithDefault("news", URL_p1u2, false));
 
   handlers_registered_by_policy.Append(
-      GetProtocolHandlerValueWithDefault("p1", URL_p1u1, false));
+      GetProtocolHandlerValueWithDefault("news", URL_p1u1, false));
   handlers_registered_by_policy.Append(
-      GetProtocolHandlerValueWithDefault("p3", URL_p3u1, true));
+      GetProtocolHandlerValueWithDefault("mailto", URL_p3u1, true));
 
   profile()->GetPrefs()->Set(prefs::kRegisteredProtocolHandlers,
                              handlers_registered_by_pref);
@@ -865,14 +866,14 @@
   registry()->InitProtocolSettings();
 
   // Duplicate p1u2 eliminated in memory but not yet saved in pref
-  ProtocolHandler p1u1 = CreateProtocolHandler("p1", GURL(URL_p1u1));
-  ProtocolHandler p1u2 = CreateProtocolHandler("p1", GURL(URL_p1u2));
+  ProtocolHandler p1u1 = CreateProtocolHandler("news", GURL(URL_p1u1));
+  ProtocolHandler p1u2 = CreateProtocolHandler("news", GURL(URL_p1u2));
   ASSERT_EQ(InPrefHandlerCount(), 3);
   ASSERT_EQ(InMemoryHandlerCount(), 3);
   ASSERT_TRUE(registry()->IsDefault(p1u1));
   ASSERT_FALSE(registry()->IsDefault(p1u2));
 
-  ProtocolHandler p2u1 = CreateProtocolHandler("p2", GURL(URL_p2u1));
+  ProtocolHandler p2u1 = CreateProtocolHandler("im", GURL(URL_p2u1));
   registry()->OnDenyRegisterProtocolHandler(p2u1);
 
   // Duplicate p1u2 saved in pref and a new handler added to pref and memory
@@ -887,7 +888,7 @@
   ASSERT_EQ(InMemoryHandlerCount(), 4);
   ASSERT_TRUE(registry()->IsDefault(p1u1));
 
-  ProtocolHandler p3u1 = CreateProtocolHandler("p3", GURL(URL_p3u1));
+  ProtocolHandler p3u1 = CreateProtocolHandler("mailto", GURL(URL_p3u1));
   registry()->RemoveHandler(p3u1);
 
   // p3u1 not removed from memory due to policy and it was never in pref.
@@ -902,7 +903,7 @@
   ASSERT_EQ(InMemoryHandlerCount(), 3);
   ASSERT_TRUE(registry()->IsDefault(p1u1));
 
-  ProtocolHandler p1u3 = CreateProtocolHandler("p1", GURL(URL_p1u3));
+  ProtocolHandler p1u3 = CreateProtocolHandler("news", GURL(URL_p1u3));
   registry()->OnAcceptRegisterProtocolHandler(p1u3);
 
   // p1u3 added to pref and memory.
@@ -926,14 +927,14 @@
   base::ListValue handlers_ignored_by_pref;
   base::ListValue handlers_ignored_by_policy;
 
-  handlers_ignored_by_pref.Append(GetProtocolHandlerValue("p1", URL_p1u1));
-  handlers_ignored_by_pref.Append(GetProtocolHandlerValue("p1", URL_p1u2));
-  handlers_ignored_by_pref.Append(GetProtocolHandlerValue("p1", URL_p1u2));
-  handlers_ignored_by_pref.Append(GetProtocolHandlerValue("p3", URL_p3u1));
+  handlers_ignored_by_pref.Append(GetProtocolHandlerValue("news", URL_p1u1));
+  handlers_ignored_by_pref.Append(GetProtocolHandlerValue("news", URL_p1u2));
+  handlers_ignored_by_pref.Append(GetProtocolHandlerValue("news", URL_p1u2));
+  handlers_ignored_by_pref.Append(GetProtocolHandlerValue("mailto", URL_p3u1));
 
-  handlers_ignored_by_policy.Append(GetProtocolHandlerValue("p1", URL_p1u2));
-  handlers_ignored_by_policy.Append(GetProtocolHandlerValue("p1", URL_p1u3));
-  handlers_ignored_by_policy.Append(GetProtocolHandlerValue("p2", URL_p2u1));
+  handlers_ignored_by_policy.Append(GetProtocolHandlerValue("news", URL_p1u2));
+  handlers_ignored_by_policy.Append(GetProtocolHandlerValue("news", URL_p1u3));
+  handlers_ignored_by_policy.Append(GetProtocolHandlerValue("im", URL_p2u1));
 
   profile()->GetPrefs()->Set(prefs::kIgnoredProtocolHandlers,
                              handlers_ignored_by_pref);
@@ -945,21 +946,21 @@
   ASSERT_EQ(InPrefIgnoredHandlerCount(), 4);
   ASSERT_EQ(InMemoryIgnoredHandlerCount(), 5);
 
-  ProtocolHandler p2u2 = CreateProtocolHandler("p2", GURL(URL_p2u2));
+  ProtocolHandler p2u2 = CreateProtocolHandler("im", GURL(URL_p2u2));
   registry()->OnIgnoreRegisterProtocolHandler(p2u2);
 
   // Duplicate p1u2 eliminated in pref, p2u2 added to pref and memory.
   ASSERT_EQ(InPrefIgnoredHandlerCount(), 4);
   ASSERT_EQ(InMemoryIgnoredHandlerCount(), 6);
 
-  ProtocolHandler p2u1 = CreateProtocolHandler("p2", GURL(URL_p2u1));
+  ProtocolHandler p2u1 = CreateProtocolHandler("im", GURL(URL_p2u1));
   registry()->RemoveIgnoredHandler(p2u1);
 
   // p2u1 installed by policy so cant be removed.
   ASSERT_EQ(InPrefIgnoredHandlerCount(), 4);
   ASSERT_EQ(InMemoryIgnoredHandlerCount(), 6);
 
-  ProtocolHandler p1u2 = CreateProtocolHandler("p1", GURL(URL_p1u2));
+  ProtocolHandler p1u2 = CreateProtocolHandler("news", GURL(URL_p1u2));
   registry()->RemoveIgnoredHandler(p1u2);
 
   // p1u2 installed by policy and pref so it is removed from pref and not from
@@ -967,7 +968,7 @@
   ASSERT_EQ(InPrefIgnoredHandlerCount(), 3);
   ASSERT_EQ(InMemoryIgnoredHandlerCount(), 6);
 
-  ProtocolHandler p1u1 = CreateProtocolHandler("p1", GURL(URL_p1u1));
+  ProtocolHandler p1u1 = CreateProtocolHandler("news", GURL(URL_p1u1));
   registry()->RemoveIgnoredHandler(p1u1);
 
   // p1u1 installed by pref so it is removed from pref and memory.
@@ -1060,7 +1061,7 @@
 
 TEST_F(ProtocolHandlerRegistryTest, TestMultiplePlaceholders) {
   ProtocolHandler ph =
-      CreateProtocolHandler("test", GURL("http://example.com/%s/url=%s"));
+      CreateProtocolHandler("news", GURL("http://example.com/%s/url=%s"));
   registry()->OnAcceptRegisterProtocolHandler(ph);
 
   GURL translated_url = ph.TranslateUrl(GURL("test:duplicated_placeholders"));
@@ -1070,3 +1071,42 @@
   ASSERT_EQ(translated_url,
             GURL("http://example.com/test%3Aduplicated_placeholders/url=%s"));
 }
+
+TEST_F(ProtocolHandlerRegistryTest, InvalidHandlers) {
+  // Invalid protocol.
+  registry()->OnAcceptRegisterProtocolHandler(
+      CreateProtocolHandler("foo", GURL("https://www.google.com/handler%s")));
+  ASSERT_FALSE(registry()->IsHandledProtocol("foo"));
+  registry()->OnAcceptRegisterProtocolHandler(
+      CreateProtocolHandler("web", GURL("https://www.google.com/handler%s")));
+  ASSERT_FALSE(registry()->IsHandledProtocol("web"));
+  registry()->OnAcceptRegisterProtocolHandler(
+      CreateProtocolHandler("web+", GURL("https://www.google.com/handler%s")));
+  ASSERT_FALSE(registry()->IsHandledProtocol("web+"));
+  registry()->OnAcceptRegisterProtocolHandler(
+      CreateProtocolHandler("https", GURL("https://www.google.com/handler%s")));
+  ASSERT_FALSE(registry()->IsHandledProtocol("https"));
+
+  // Invalid handler URL.
+  // data: URL.
+  registry()->OnAcceptRegisterProtocolHandler(CreateProtocolHandler(
+      "news",
+      GURL("data:text/html,<html><body><b>hello world</b></body></html>%s")));
+  ASSERT_FALSE(registry()->IsHandledProtocol("news"));
+  // ftp:// URL.
+  registry()->OnAcceptRegisterProtocolHandler(
+      CreateProtocolHandler("news", GURL("ftp://www.google.com/handler%s")));
+  ASSERT_FALSE(registry()->IsHandledProtocol("news"));
+  // blob:// URL
+  registry()->OnAcceptRegisterProtocolHandler(CreateProtocolHandler(
+      "news", GURL("blob:https://www.google.com/"
+                   "f2d8c47d-17d0-4bf5-8f0a-76e42cbed3bf/%s")));
+  ASSERT_FALSE(registry()->IsHandledProtocol("news"));
+}
+
+TEST_F(ProtocolHandlerRegistryTest, ExtensionHandler) {
+  registry()->OnAcceptRegisterProtocolHandler(CreateProtocolHandler(
+      "news",
+      GURL("chrome-extension://abcdefghijklmnopqrstuvwxyzabcdef/test.html")));
+  ASSERT_TRUE(registry()->IsHandledProtocol("news"));
+}
diff --git a/chrome/browser/file_util_service.cc b/chrome/browser/file_util_service.cc
new file mode 100644
index 0000000..75e813b
--- /dev/null
+++ b/chrome/browser/file_util_service.cc
@@ -0,0 +1,20 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/file_util_service.h"
+
+#include "chrome/grit/generated_resources.h"
+#include "components/strings/grit/components_strings.h"
+#include "content/public/browser/service_process_host.h"
+
+mojo::PendingRemote<chrome::mojom::FileUtilService> LaunchFileUtilService() {
+  mojo::PendingRemote<chrome::mojom::FileUtilService> remote;
+  content::ServiceProcessHost::Launch<chrome::mojom::FileUtilService>(
+      remote.InitWithNewPipeAndPassReceiver(),
+      content::ServiceProcessHost::Options()
+          .WithSandboxType(service_manager::SANDBOX_TYPE_UTILITY)
+          .WithDisplayName(IDS_UTILITY_PROCESS_FILE_UTILITY_NAME)
+          .Pass());
+  return remote;
+}
diff --git a/chrome/browser/file_util_service.h b/chrome/browser/file_util_service.h
new file mode 100644
index 0000000..9029816
--- /dev/null
+++ b/chrome/browser/file_util_service.h
@@ -0,0 +1,16 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_FILE_UTIL_SERVICE_H_
+#define CHROME_BROWSER_FILE_UTIL_SERVICE_H_
+
+#include "chrome/services/file_util/public/mojom/file_util_service.mojom.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+
+// Launches a new instance of the FileUtil service in an isolated, sandboxed
+// process and returns a remote interface to control the service. The lifetime
+// of the process is tied to that of the remote. May be called from any thread.
+mojo::PendingRemote<chrome::mojom::FileUtilService> LaunchFileUtilService();
+
+#endif  // CHROME_BROWSER_FILE_UTIL_SERVICE_H_
diff --git a/chrome/browser/notifications/scheduler/internal/display_decider.cc b/chrome/browser/notifications/scheduler/internal/display_decider.cc
index 6e7a8e0..39bbb30a 100644
--- a/chrome/browser/notifications/scheduler/internal/display_decider.cc
+++ b/chrome/browser/notifications/scheduler/internal/display_decider.cc
@@ -25,7 +25,7 @@
  public:
   DecisionHelper(const SchedulerConfig* config,
                  const std::vector<SchedulerClientType>& clients,
-                 std::unique_ptr<DistributionPolicy> distribution_policy,
+                 DistributionPolicy* distribution_policy,
                  SchedulerTaskTime task_start_time,
                  Notifications notifications,
                  ClientStates client_states)
@@ -34,7 +34,7 @@
         client_states_(std::move(client_states)),
         config_(config),
         clients_(clients),
-        policy_(std::move(distribution_policy)),
+        policy_(distribution_policy),
         daily_max_to_show_all_types_(0),
         last_shown_type_(SchedulerClientType::kUnknown),
         shown_(0) {}
@@ -146,7 +146,7 @@
   const ClientStates client_states_;
   const SchedulerConfig* config_;
   const std::vector<SchedulerClientType> clients_;
-  std::unique_ptr<DistributionPolicy> policy_;
+  DistributionPolicy* policy_;
   int daily_max_to_show_all_types_;
 
   SchedulerClientType last_shown_type_;
@@ -158,33 +158,43 @@
 
 class DisplayDeciderImpl : public DisplayDecider {
  public:
-  DisplayDeciderImpl() = default;
+  DisplayDeciderImpl(const SchedulerConfig* config,
+                     std::vector<SchedulerClientType> clients,
+                     std::unique_ptr<DistributionPolicy> distribution_policy)
+      : config_(config),
+        clients_(std::move(clients)),
+        distribution_policy_(std::move(distribution_policy)) {}
   ~DisplayDeciderImpl() override = default;
 
  private:
   // DisplayDecider implementation.
   void FindNotificationsToShow(
-      const SchedulerConfig* config,
-      std::vector<SchedulerClientType> clients,
-      std::unique_ptr<DistributionPolicy> distribution_policy,
       SchedulerTaskTime task_start_time,
       Notifications notifications,
       ClientStates client_states,
       Results* results) override {
     auto helper = std::make_unique<DecisionHelper>(
-        config, std::move(clients), std::move(distribution_policy),
-        task_start_time, std::move(notifications), std::move(client_states));
+        config_, clients_, distribution_policy_.get(), task_start_time,
+        std::move(notifications), std::move(client_states));
     helper->DecideNotificationToShow(results);
   }
 
+  const SchedulerConfig* config_;
+  const std::vector<SchedulerClientType> clients_;
+  std::unique_ptr<DistributionPolicy> distribution_policy_;
+
   DISALLOW_COPY_AND_ASSIGN(DisplayDeciderImpl);
 };
 
 }  // namespace
 
 // static
-std::unique_ptr<DisplayDecider> DisplayDecider::Create() {
-  return std::make_unique<DisplayDeciderImpl>();
+std::unique_ptr<DisplayDecider> DisplayDecider::Create(
+    const SchedulerConfig* config,
+    std::vector<SchedulerClientType> clients,
+    std::unique_ptr<DistributionPolicy> distribution_policy) {
+  return std::make_unique<DisplayDeciderImpl>(config, std::move(clients),
+                                              std::move(distribution_policy));
 }
 
 }  // namespace notifications
diff --git a/chrome/browser/notifications/scheduler/internal/display_decider.h b/chrome/browser/notifications/scheduler/internal/display_decider.h
index cacb5df1..393596a 100644
--- a/chrome/browser/notifications/scheduler/internal/display_decider.h
+++ b/chrome/browser/notifications/scheduler/internal/display_decider.h
@@ -34,16 +34,16 @@
   using Results = std::set<std::string>;
 
   // Creates the decider to determine notifications to show.
-  static std::unique_ptr<DisplayDecider> Create();
+  static std::unique_ptr<DisplayDecider> Create(
+      const SchedulerConfig* config,
+      std::vector<SchedulerClientType> clients,
+      std::unique_ptr<DistributionPolicy> distribution_policy);
 
   DisplayDecider() = default;
   virtual ~DisplayDecider() = default;
 
   // Finds notifications to show. Returns a list of notification guids.
   virtual void FindNotificationsToShow(
-      const SchedulerConfig* config,
-      std::vector<SchedulerClientType> clients,
-      std::unique_ptr<DistributionPolicy> distribution_policy,
       SchedulerTaskTime task_start_time,
       Notifications notifications,
       ClientStates client_states,
diff --git a/chrome/browser/notifications/scheduler/internal/display_decider_unittest.cc b/chrome/browser/notifications/scheduler/internal/display_decider_unittest.cc
index da5bc05..24593da 100644
--- a/chrome/browser/notifications/scheduler/internal/display_decider_unittest.cc
+++ b/chrome/browser/notifications/scheduler/internal/display_decider_unittest.cc
@@ -100,9 +100,9 @@
     }
 
     // Copy test inputs into |decider_|.
-    decider_ = DisplayDecider::Create();
+    decider_ =
+        DisplayDecider::Create(&config_, clients, DistributionPolicy::Create());
     decider_->FindNotificationsToShow(
-        &config_, std::move(clients), DistributionPolicy::Create(),
         test_data_.task_start_time, std::move(notifications),
         std::move(client_states), &results_);
 
diff --git a/chrome/browser/notifications/scheduler/internal/notification_scheduler.cc b/chrome/browser/notifications/scheduler/internal/notification_scheduler.cc
index 9866270..6642241 100644
--- a/chrome/browser/notifications/scheduler/internal/notification_scheduler.cc
+++ b/chrome/browser/notifications/scheduler/internal/notification_scheduler.cc
@@ -16,7 +16,6 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/notifications/scheduler/internal/background_task_coordinator.h"
 #include "chrome/browser/notifications/scheduler/internal/display_decider.h"
-#include "chrome/browser/notifications/scheduler/internal/distribution_policy.h"
 #include "chrome/browser/notifications/scheduler/internal/impression_history_tracker.h"
 #include "chrome/browser/notifications/scheduler/internal/notification_entry.h"
 #include "chrome/browser/notifications/scheduler/internal/notification_scheduler_context.h"
@@ -251,7 +250,6 @@
     context_->client_registrar()->GetRegisteredClients(&clients);
 
     context_->display_decider()->FindNotificationsToShow(
-        context_->config(), std::move(clients), DistributionPolicy::Create(),
         task_start_time, std::move(notifications), std::move(client_states),
         &results);
 
diff --git a/chrome/browser/notifications/scheduler/internal/notification_scheduler_unittest.cc b/chrome/browser/notifications/scheduler/internal/notification_scheduler_unittest.cc
index 5d6f591c..e424a22 100644
--- a/chrome/browser/notifications/scheduler/internal/notification_scheduler_unittest.cc
+++ b/chrome/browser/notifications/scheduler/internal/notification_scheduler_unittest.cc
@@ -255,8 +255,8 @@
 
   // No notification picked to show.
   DisplayDecider::Results result;
-  EXPECT_CALL(*display_decider(), FindNotificationsToShow(_, _, _, _, _, _, _))
-      .WillOnce(SetArgPointee<6>(result));
+  EXPECT_CALL(*display_decider(), FindNotificationsToShow(_, _, _, _))
+      .WillOnce(SetArgPointee<3>(result));
 
   EXPECT_CALL(*display_agent(), ShowNotification(_, _)).Times(0);
   EXPECT_CALL(*notification_manager(), DisplayNotification(_)).Times(0);
@@ -289,8 +289,8 @@
       ShowNotification(NotifcationDataEq(kTitle),
                        SystemDataEq(SchedulerClientType::kTest1, kGuid)));
   DisplayDecider::Results result({kGuid});
-  EXPECT_CALL(*display_decider(), FindNotificationsToShow(_, _, _, _, _, _, _))
-      .WillOnce(SetArgPointee<6>(result));
+  EXPECT_CALL(*display_decider(), FindNotificationsToShow(_, _, _, _))
+      .WillOnce(SetArgPointee<3>(result));
   EXPECT_CALL(*impression_tracker(), AddImpression(_, _));
 
   EXPECT_CALL(*client(), BeforeShowNotification(_, _))
diff --git a/chrome/browser/notifications/scheduler/schedule_service_factory_helper.cc b/chrome/browser/notifications/scheduler/schedule_service_factory_helper.cc
index 342b224..4da3677 100644
--- a/chrome/browser/notifications/scheduler/schedule_service_factory_helper.cc
+++ b/chrome/browser/notifications/scheduler/schedule_service_factory_helper.cc
@@ -12,6 +12,7 @@
 #include "base/time/default_clock.h"
 #include "chrome/browser/notifications/scheduler/internal/background_task_coordinator.h"
 #include "chrome/browser/notifications/scheduler/internal/display_decider.h"
+#include "chrome/browser/notifications/scheduler/internal/distribution_policy.h"
 #include "chrome/browser/notifications/scheduler/internal/icon_store.h"
 #include "chrome/browser/notifications/scheduler/internal/impression_history_tracker.h"
 #include "chrome/browser/notifications/scheduler/internal/impression_store.h"
@@ -96,10 +97,12 @@
                           config->background_task_random_time_window),
       base::DefaultClock::GetInstance());
 
+  auto display_decider = DisplayDecider::Create(
+      config.get(), registered_clients, DistributionPolicy::Create());
   auto context = std::make_unique<NotificationSchedulerContext>(
       std::move(client_registrar), std::move(background_task_coordinator),
       std::move(impression_tracker), std::move(notification_manager),
-      std::move(display_agent), DisplayDecider::Create(), std::move(config));
+      std::move(display_agent), std::move(display_decider), std::move(config));
 
   auto scheduler = NotificationScheduler::Create(std::move(context));
   auto init_aware_scheduler =
diff --git a/chrome/browser/notifications/scheduler/test/mock_display_decider.h b/chrome/browser/notifications/scheduler/test/mock_display_decider.h
index 385811d0..dfdd41f 100644
--- a/chrome/browser/notifications/scheduler/test/mock_display_decider.h
+++ b/chrome/browser/notifications/scheduler/test/mock_display_decider.h
@@ -16,14 +16,8 @@
  public:
   MockDisplayDecider();
   ~MockDisplayDecider() override;
-  MOCK_METHOD7(FindNotificationsToShow,
-               void(const SchedulerConfig*,
-                    std::vector<SchedulerClientType>,
-                    std::unique_ptr<DistributionPolicy>,
-                    SchedulerTaskTime,
-                    Notifications,
-                    ClientStates,
-                    Results*));
+  MOCK_METHOD4(FindNotificationsToShow,
+               void(SchedulerTaskTime, Notifications, ClientStates, Results*));
 };
 
 }  // namespace test
diff --git a/chrome/browser/password_manager/chrome_password_manager_client.cc b/chrome/browser/password_manager/chrome_password_manager_client.cc
index 98871ac..757f1e8 100644
--- a/chrome/browser/password_manager/chrome_password_manager_client.cc
+++ b/chrome/browser/password_manager/chrome_password_manager_client.cc
@@ -972,6 +972,12 @@
   return IdentityManagerFactory::GetForProfile(profile_->GetOriginalProfile());
 }
 
+scoped_refptr<network::SharedURLLoaderFactory>
+ChromePasswordManagerClient::GetURLLoaderFactory() {
+  return content::BrowserContext::GetDefaultStoragePartition(profile_)
+      ->GetURLLoaderFactoryForBrowserProcess();
+}
+
 bool ChromePasswordManagerClient::IsUnderAdvancedProtection() const {
 #if BUILDFLAG(FULL_SAFE_BROWSING)
   return safe_browsing::AdvancedProtectionStatusManagerFactory::GetForProfile(
diff --git a/chrome/browser/password_manager/chrome_password_manager_client.h b/chrome/browser/password_manager/chrome_password_manager_client.h
index 7d7e7dd..ae04413 100644
--- a/chrome/browser/password_manager/chrome_password_manager_client.h
+++ b/chrome/browser/password_manager/chrome_password_manager_client.h
@@ -139,6 +139,7 @@
   GetPasswordRequirementsService() override;
   favicon::FaviconService* GetFaviconService() override;
   signin::IdentityManager* GetIdentityManager() override;
+  scoped_refptr<network::SharedURLLoaderFactory> GetURLLoaderFactory() override;
   bool IsUnderAdvancedProtection() const override;
   void UpdateFormManagers() override;
   void NavigateToManagePasswordsPage(
diff --git a/chrome/browser/policy/policy_browsertest.cc b/chrome/browser/policy/policy_browsertest.cc
index bdb2446..35376ff 100644
--- a/chrome/browser/policy/policy_browsertest.cc
+++ b/chrome/browser/policy/policy_browsertest.cc
@@ -6703,7 +6703,8 @@
       public testing::WithParamInterface<BooleanPolicy> {
  protected:
   PromotionalTabsEnabledPolicyTest() {
-    scoped_feature_list_.InitWithFeatures({welcome::kForceEnabled}, {});
+    scoped_feature_list_.InitWithFeatures({welcome::kOnboardingForceEnabled},
+                                          {});
   }
   ~PromotionalTabsEnabledPolicyTest() = default;
 
diff --git a/chrome/browser/resources/BUILD.gn b/chrome/browser/resources/BUILD.gn
index d8b6bb5..1423615 100644
--- a/chrome/browser/resources/BUILD.gn
+++ b/chrome/browser/resources/BUILD.gn
@@ -224,15 +224,15 @@
 }
 
 if (!is_android && !is_chromeos) {
-  grit("welcome_resources") {
-    source = "welcome/welcome_resources.grd"
+  grit("onboarding_welcome_resources") {
+    source = "welcome/onboarding_welcome_resources.grd"
 
     defines = chrome_grit_defines
     outputs = [
-      "grit/welcome_resources.h",
-      "grit/welcome_resources_map.cc",
-      "grit/welcome_resources_map.h",
-      "welcome_resources.pak",
+      "grit/onboarding_welcome_resources.h",
+      "grit/onboarding_welcome_resources_map.cc",
+      "grit/onboarding_welcome_resources_map.h",
+      "onboarding_welcome_resources.pak",
     ]
     output_dir = "$root_gen_dir/chrome"
   }
diff --git a/chrome/browser/resources/app_management/OWNERS b/chrome/browser/resources/app_management/OWNERS
index 54640cb..94b2e07 100644
--- a/chrome/browser/resources/app_management/OWNERS
+++ b/chrome/browser/resources/app_management/OWNERS
@@ -1,5 +1,4 @@
-calamity@chromium.org
 dominickn@chromium.org
-ericwilligers@chromium.org
+jshikaram@chromium.org
 
-# COMPONENT: Platform>Apps>Foundation
\ No newline at end of file
+# COMPONENT: Platform>Apps>Foundation
diff --git a/chrome/browser/resources/settings/privacy_page/BUILD.gn b/chrome/browser/resources/settings/privacy_page/BUILD.gn
index a77c34a..6db1f51 100644
--- a/chrome/browser/resources/settings/privacy_page/BUILD.gn
+++ b/chrome/browser/resources/settings/privacy_page/BUILD.gn
@@ -76,6 +76,7 @@
 js_library("security_keys_set_pin_dialog") {
   deps = [
     ":security_keys_browser_proxy",
+    "//third_party/polymer/v1_0/components-chromium/iron-a11y-announcer:iron-a11y-announcer-extracted",
     "//ui/webui/resources/js:i18n_behavior",
   ]
   externs_list = [ "$externs_path/settings_private.js" ]
diff --git a/chrome/browser/resources/settings/privacy_page/security_keys_set_pin_dialog.html b/chrome/browser/resources/settings/privacy_page/security_keys_set_pin_dialog.html
index 2e6c0a49..94f201d 100644
--- a/chrome/browser/resources/settings/privacy_page/security_keys_set_pin_dialog.html
+++ b/chrome/browser/resources/settings/privacy_page/security_keys_set_pin_dialog.html
@@ -6,6 +6,7 @@
 <link rel="import" href="chrome://resources/cr_elements/cr_icons_css.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_input/cr_input.html">
 <link rel="import" href="chrome://resources/html/i18n_behavior.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-a11y-announcer/iron-a11y-announcer.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-pages/iron-pages.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-spinner/paper-spinner-lite.html">
 <link rel="import" href="../i18n_setup.html">
diff --git a/chrome/browser/resources/settings/privacy_page/security_keys_set_pin_dialog.js b/chrome/browser/resources/settings/privacy_page/security_keys_set_pin_dialog.js
index 4cadbca..69f476c0 100644
--- a/chrome/browser/resources/settings/privacy_page/security_keys_set_pin_dialog.js
+++ b/chrome/browser/resources/settings/privacy_page/security_keys_set_pin_dialog.js
@@ -149,6 +149,10 @@
     this.browserProxy_ = settings.SecurityKeysPINBrowserProxyImpl.getInstance();
     this.$.dialog.showModal();
 
+    Polymer.RenderStatus.afterNextRender(this, function() {
+      Polymer.IronA11yAnnouncer.requestAvailability();
+    });
+
     this.browserProxy_.startSetPIN().then(([success, errorCode]) => {
       if (success) {
         // Operation is complete. errorCode is a CTAP error code. See
@@ -335,6 +339,7 @@
       this.currentPINError_ = this.isValidPIN_(this.currentPIN_);
       if (this.currentPINError_ != '') {
         this.focusOn_(this.$.currentPIN);
+        this.fire('iron-announce', {message: this.currentPINError_});
         this.fire('ui-ready');  // for test synchronization.
         return;
       }
@@ -343,6 +348,7 @@
     this.newPINError_ = this.isValidPIN_(this.newPIN_);
     if (this.newPINError_ != '') {
       this.focusOn_(this.$.newPIN);
+      this.fire('iron-announce', {message: this.newPINError_});
       this.fire('ui-ready');  // for test synchronization.
       return;
     }
@@ -350,6 +356,7 @@
     if (this.newPIN_ != this.confirmPIN_) {
       this.confirmPINError_ = this.i18n('securityKeysPINMismatch');
       this.focusOn_(this.$.confirmPIN);
+      this.fire('iron-announce', {message: this.confirmPINError_});
       this.fire('ui-ready');  // for test synchronization.
       return;
     }
@@ -374,6 +381,7 @@
         this.currentPINError_ = this.mismatchError_(this.retries_);
         this.setPINButtonValid_ = true;
         this.focusOn_(this.$.currentPIN);
+        this.fire('iron-announce', {message: this.currentPINError_});
         this.fire('ui-ready');  // for test synchronization.
       } else {
         // Unknown error.
diff --git a/chrome/browser/resources/welcome/google_apps/nux_google_apps.html b/chrome/browser/resources/welcome/google_apps/nux_google_apps.html
index fd03465..a5d31e1 100644
--- a/chrome/browser/resources/welcome/google_apps/nux_google_apps.html
+++ b/chrome/browser/resources/welcome/google_apps/nux_google_apps.html
@@ -143,38 +143,38 @@
       /* App Icons */
       .gmail {
         content: -webkit-image-set(
-            url(chrome://theme/IDS_WELCOME_GMAIL@1x) 1x,
-            url(chrome://theme/IDS_WELCOME_GMAIL@2x) 2x);
+            url(chrome://theme/IDS_ONBOARDING_WELCOME_GMAIL@1x) 1x,
+            url(chrome://theme/IDS_ONBOARDING_WELCOME_GMAIL@2x) 2x);
       }
 
       .youtube {
         content: -webkit-image-set(
-            url(chrome://theme/IDS_WELCOME_YOUTUBE@1x) 1x,
-            url(chrome://theme/IDS_WELCOME_YOUTUBE@2x) 2x);
+            url(chrome://theme/IDS_ONBOARDING_WELCOME_YOUTUBE@1x) 1x,
+            url(chrome://theme/IDS_ONBOARDING_WELCOME_YOUTUBE@2x) 2x);
       }
 
       .maps {
         content: -webkit-image-set(
-            url(chrome://theme/IDS_WELCOME_MAPS@1x) 1x,
-            url(chrome://theme/IDS_WELCOME_MAPS@2x) 2x);
+            url(chrome://theme/IDS_ONBOARDING_WELCOME_MAPS@1x) 1x,
+            url(chrome://theme/IDS_ONBOARDING_WELCOME_MAPS@2x) 2x);
       }
 
       .translate {
         content: -webkit-image-set(
-            url(chrome://theme/IDS_WELCOME_TRANSLATE@1x) 1x,
-            url(chrome://theme/IDS_WELCOME_TRANSLATE@2x) 2x);
+            url(chrome://theme/IDS_ONBOARDING_WELCOME_TRANSLATE@1x) 1x,
+            url(chrome://theme/IDS_ONBOARDING_WELCOME_TRANSLATE@2x) 2x);
       }
 
       .news {
         content: -webkit-image-set(
-            url(chrome://theme/IDS_WELCOME_NEWS@1x) 1x,
-            url(chrome://theme/IDS_WELCOME_NEWS@2x) 2x);
+            url(chrome://theme/IDS_ONBOARDING_WELCOME_NEWS@1x) 1x,
+            url(chrome://theme/IDS_ONBOARDING_WELCOME_NEWS@2x) 2x);
       }
 
       .search {
         content: -webkit-image-set(
-            url(chrome://theme/IDS_WELCOME_SEARCH@1x) 1x,
-            url(chrome://theme/IDS_WELCOME_SEARCH@2x) 2x);
+            url(chrome://theme/IDS_ONBOARDING_WELCOME_SEARCH@1x) 1x,
+            url(chrome://theme/IDS_ONBOARDING_WELCOME_SEARCH@2x) 2x);
       }
     </style>
     <div class="apps-ask">
diff --git a/chrome/browser/resources/welcome/welcome_resources.grd b/chrome/browser/resources/welcome/onboarding_welcome_resources.grd
similarity index 66%
rename from chrome/browser/resources/welcome/welcome_resources.grd
rename to chrome/browser/resources/welcome/onboarding_welcome_resources.grd
index cc67d33..011b9b1 100644
--- a/chrome/browser/resources/welcome/welcome_resources.grd
+++ b/chrome/browser/resources/welcome/onboarding_welcome_resources.grd
@@ -1,199 +1,199 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <grit latest_public_release="0" current_release="1" output_all_resource_defines="false">
   <outputs>
-    <output filename="grit/welcome_resources.h"
+    <output filename="grit/onboarding_welcome_resources.h"
             type="rc_header">
       <emit emit_type='prepend'></emit>
     </output>
-    <output filename="grit/welcome_resources_map.cc"
+    <output filename="grit/onboarding_welcome_resources_map.cc"
             type="resource_file_map_source" />
-    <output filename="grit/welcome_resources_map.h"
+    <output filename="grit/onboarding_welcome_resources_map.h"
             type="resource_map_header" />
-    <output filename="welcome_resources.pak"
+    <output filename="onboarding_welcome_resources.pak"
             type="data_package" />
   </outputs>
   <release seq="1">
     <includes>
-      <include name="IDR_WELCOME_IMAGES_BACKGROUND_SVGS_BLUE_CIRCLE_SVG"
+      <include name="IDR_WELCOME_ONBOARDING_WELCOME_IMAGES_BACKGROUND_SVGS_BLUE_CIRCLE_SVG"
                file="images/background_svgs/blue_circle.svg"
                compress="gzip"
                type="BINDATA" />
-      <include name="IDR_WELCOME_IMAGES_BACKGROUND_SVGS_GREEN_RECTANGLE_SVG"
+      <include name="IDR_WELCOME_ONBOARDING_WELCOME_IMAGES_BACKGROUND_SVGS_GREEN_RECTANGLE_SVG"
                file="images/background_svgs/green_rectangle.svg"
                compress="gzip"
                type="BINDATA" />
-      <include name="IDR_WELCOME_IMAGES_BACKGROUND_SVGS_GREY_OVAL_SVG"
+      <include name="IDR_WELCOME_ONBOARDING_WELCOME_IMAGES_BACKGROUND_SVGS_GREY_OVAL_SVG"
                file="images/background_svgs/grey_oval.svg"
                compress="gzip"
                type="BINDATA" />
-      <include name="IDR_WELCOME_IMAGES_BACKGROUND_SVGS_GREY_ROUNDED_RECTANGLE_SVG"
+      <include name="IDR_WELCOME_ONBOARDING_WELCOME_IMAGES_BACKGROUND_SVGS_GREY_ROUNDED_RECTANGLE_SVG"
                file="images/background_svgs/grey_rounded_rectangle.svg"
                compress="gzip"
                type="BINDATA" />
-      <include name="IDR_WELCOME_IMAGES_BACKGROUND_SVGS_RED_TRIANGLE_SVG"
+      <include name="IDR_WELCOME_ONBOARDING_WELCOME_IMAGES_BACKGROUND_SVGS_RED_TRIANGLE_SVG"
                file="images/background_svgs/red_triangle.svg"
                compress="gzip"
                type="BINDATA" />
-      <include name="IDR_WELCOME_IMAGES_BACKGROUND_SVGS_YELLOW_DOTS_SVG"
+      <include name="IDR_WELCOME_ONBOARDING_WELCOME_IMAGES_BACKGROUND_SVGS_YELLOW_DOTS_SVG"
                file="images/background_svgs/yellow_dots.svg"
                compress="gzip"
                type="BINDATA" />
-      <include name="IDR_WELCOME_IMAGES_BACKGROUND_SVGS_YELLOW_SEMICIRCLE_SVG"
+      <include name="IDR_WELCOME_ONBOARDING_WELCOME_IMAGES_BACKGROUND_SVGS_YELLOW_SEMICIRCLE_SVG"
                file="images/background_svgs/yellow_semicircle.svg"
                compress="gzip"
                type="BINDATA" />
     </includes>
     <structures>
-      <structure name="IDR_WELCOME_LANDING_VIEW_HTML"
+      <structure name="IDR_WELCOME_ONBOARDING_WELCOME_LANDING_VIEW_HTML"
                  file="landing_view.html"
                  type="chrome_html"
                  compress="gzip"
                  preprocess="true"/>
-      <structure name="IDR_WELCOME_LANDING_VIEW_JS"
+      <structure name="IDR_WELCOME_ONBOARDING_WELCOME_LANDING_VIEW_JS"
                  file="landing_view.js"
                  type="chrome_html"
                  compress="gzip"
                  preprocess="true"/>
-      <structure name="IDR_WELCOME_LANDING_VIEW_PROXY_HTML"
+      <structure name="IDR_WELCOME_ONBOARDING_WELCOME_LANDING_VIEW_PROXY_HTML"
                  file="landing_view_proxy.html"
                  type="chrome_html"
                  compress="gzip"
                  preprocess="true"/>
-      <structure name="IDR_WELCOME_LANDING_VIEW_PROXY_JS"
+      <structure name="IDR_WELCOME_ONBOARDING_WELCOME_LANDING_VIEW_PROXY_JS"
                  file="landing_view_proxy.js"
                  type="chrome_html"
                  compress="gzip"
                  preprocess="true"/>
-      <structure name="IDR_WELCOME_NAVIGATION_BEHAVIOR_HTML"
+      <structure name="IDR_WELCOME_ONBOARDING_WELCOME_NAVIGATION_BEHAVIOR_HTML"
                  file="navigation_behavior.html"
                  type="chrome_html"
                  compress="gzip"
                  preprocess="true"/>
-      <structure name="IDR_WELCOME_NAVIGATION_BEHAVIOR_JS"
+      <structure name="IDR_WELCOME_ONBOARDING_WELCOME_NAVIGATION_BEHAVIOR_JS"
                  file="navigation_behavior.js"
                  type="chrome_html"
                  compress="gzip"
                  preprocess="true"/>
-      <structure name="IDR_WELCOME_SHARED_ACTION_LINK_STYLE_JS"
+      <structure name="IDR_WELCOME_ONBOARDING_WELCOME_SHARED_ACTION_LINK_STYLE_JS"
                  file="shared/action_link_style.js"
                  compress="gzip"
                  type="chrome_html" />
-      <structure name="IDR_WELCOME_SHARED_ACTION_LINK_STYLE_CSS_HTML"
+      <structure name="IDR_WELCOME_ONBOARDING_WELCOME_SHARED_ACTION_LINK_STYLE_CSS_HTML"
                  file="shared/action_link_style_css.html"
                  compress="gzip"
                  type="chrome_html" />
-      <structure name="IDR_WELCOME_SHARED_ANIMATIONS_CSS"
+      <structure name="IDR_WELCOME_ONBOARDING_WELCOME_SHARED_ANIMATIONS_CSS"
                  file="shared/animations_css.html"
                  compress="gzip"
                  type="chrome_html" />
-      <structure name="IDR_WELCOME_SHARED_BOOKMARK_PROXY_HTML"
+      <structure name="IDR_WELCOME_ONBOARDING_WELCOME_SHARED_BOOKMARK_PROXY_HTML"
                  file="shared/bookmark_proxy.html"
                  compress="gzip"
                  type="chrome_html" />
-      <structure name="IDR_WELCOME_SHARED_BOOKMARK_PROXY_JS"
+      <structure name="IDR_WELCOME_ONBOARDING_WELCOME_SHARED_BOOKMARK_PROXY_JS"
                  file="shared/bookmark_proxy.js"
                  compress="gzip"
                  type="chrome_html" />
-      <structure name="IDR_WELCOME_SHARED_CHOOSER_SHARED_CSS"
+      <structure name="IDR_WELCOME_ONBOARDING_WELCOME_SHARED_CHOOSER_SHARED_CSS"
                  file="shared/chooser_shared_css.html"
                  compress="gzip"
                  type="chrome_html" />
-      <structure name="IDR_WELCOME_SHARED_I18N_SETUP_HTML"
+      <structure name="IDR_WELCOME_ONBOARDING_WELCOME_SHARED_I18N_SETUP_HTML"
                  file="shared/i18n_setup.html"
                  compress="gzip"
                  type="chrome_html" />
-      <structure name="IDR_WELCOME_SHARED_MODULE_METRICS_PROXY_HTML"
+      <structure name="IDR_WELCOME_ONBOARDING_WELCOME_SHARED_MODULE_METRICS_PROXY_HTML"
                  file="shared/module_metrics_proxy.html"
                  compress="gzip"
                  type="chrome_html" />
-      <structure name="IDR_WELCOME_SHARED_MODULE_METRICS_PROXY_JS"
+      <structure name="IDR_WELCOME_ONBOARDING_WELCOME_SHARED_MODULE_METRICS_PROXY_JS"
                  file="shared/module_metrics_proxy.js"
                  compress="gzip"
                  type="chrome_html" />
-      <structure name="IDR_WELCOME_SHARED_NAVI_COLORS_CSS"
+      <structure name="IDR_WELCOME_ONBOARDING_WELCOME_SHARED_NAVI_COLORS_CSS"
                  file="shared/navi_colors_css.html"
                  compress="gzip"
                  type="chrome_html" />
-      <structure name="IDR_WELCOME_SHARED_ONBOARDING_BACKGROUND_HTML"
+      <structure name="IDR_WELCOME_ONBOARDING_WELCOME_SHARED_ONBOARDING_BACKGROUND_HTML"
                  file="shared/onboarding_background.html"
                  compress="gzip"
                  type="chrome_html" />
-      <structure name="IDR_WELCOME_SHARED_ONBOARDING_BACKGROUND_JS"
+      <structure name="IDR_WELCOME_ONBOARDING_WELCOME_SHARED_ONBOARDING_BACKGROUND_JS"
                  file="shared/onboarding_background.js"
                  compress="gzip"
                  type="chrome_html" />
-      <structure name="IDR_WELCOME_SHARED_STEP_INDICATOR_HTML"
+      <structure name="IDR_WELCOME_ONBOARDING_WELCOME_SHARED_STEP_INDICATOR_HTML"
                  file="shared/step_indicator.html"
                  compress="gzip"
                  type="chrome_html" />
-      <structure name="IDR_WELCOME_SHARED_STEP_INDICATOR_JS"
+      <structure name="IDR_WELCOME_ONBOARDING_WELCOME_SHARED_STEP_INDICATOR_JS"
                  file="shared/step_indicator.js"
                  compress="gzip"
                  type="chrome_html" />
-      <structure name="IDR_WELCOME_SHARED_SPLASH_PAGES_SHARED_CSS"
+      <structure name="IDR_WELCOME_ONBOARDING_WELCOME_SHARED_SPLASH_PAGES_SHARED_CSS"
                  file="shared/splash_pages_shared_css.html"
                  compress="gzip"
                  type="chrome_html" />
-      <structure name="IDR_WELCOME_SIGNIN_VIEW_HTML"
+      <structure name="IDR_WELCOME_ONBOARDING_WELCOME_SIGNIN_VIEW_HTML"
                  file="signin_view.html"
                  type="chrome_html"
                  compress="gzip"
                  preprocess="true"/>
-      <structure name="IDR_WELCOME_SIGNIN_VIEW_JS"
+      <structure name="IDR_WELCOME_ONBOARDING_WELCOME_SIGNIN_VIEW_JS"
                  file="signin_view.js"
                  type="chrome_html"
                  compress="gzip"
                  preprocess="true"/>
-      <structure name="IDR_WELCOME_SIGNIN_VIEW_PROXY_HTML"
+      <structure name="IDR_WELCOME_ONBOARDING_WELCOME_SIGNIN_VIEW_PROXY_HTML"
                  file="signin_view_proxy.html"
                  type="chrome_html"
                  compress="gzip"
                  preprocess="true"/>
-      <structure name="IDR_WELCOME_SIGNIN_VIEW_PROXY_JS"
+      <structure name="IDR_WELCOME_ONBOARDING_WELCOME_SIGNIN_VIEW_PROXY_JS"
                  file="signin_view_proxy.js"
                  type="chrome_html"
                  compress="gzip"
                  preprocess="true"/>
-      <structure name="IDR_WELCOME_APP_HTML"
+      <structure name="IDR_WELCOME_ONBOARDING_WELCOME_WELCOME_APP_HTML"
                  file="welcome_app.html"
                  type="chrome_html"
                  compress="gzip"
                  preprocess="true"/>
-      <structure name="IDR_WELCOME_APP_JS"
+      <structure name="IDR_WELCOME_ONBOARDING_WELCOME_WELCOME_APP_JS"
                  file="welcome_app.js"
                  type="chrome_html"
                  compress="gzip"
                  preprocess="true"/>
-      <structure name="IDR_WELCOME_BROWSER_PROXY_HTML"
+      <structure name="IDR_WELCOME_ONBOARDING_WELCOME_WELCOME_BROWSER_PROXY_HTML"
                  file="welcome_browser_proxy.html"
                  compress="gzip"
                  type="chrome_html"/>
-      <structure name="IDR_WELCOME_BROWSER_PROXY_JS"
+      <structure name="IDR_WELCOME_ONBOARDING_WELCOME_WELCOME_BROWSER_PROXY_JS"
                  file="welcome_browser_proxy.js"
                  compress="gzip"
                  type="chrome_html"/>
-      <structure name="IDR_WELCOME_CSS"
+      <structure name="IDR_WELCOME_ONBOARDING_WELCOME_WELCOME_CSS"
                  file="welcome.css"
                  type="chrome_html"
                  compress="gzip"
                  preprocess="true"/>
-      <structure name="IDR_WELCOME_HTML"
+      <structure name="IDR_WELCOME_ONBOARDING_WELCOME_WELCOME_HTML"
                  file="welcome.html"
                  type="chrome_html"
                  compress="gzip"
                  preprocess="true"/>
-      <structure name="IDR_WELCOME_JS"
+      <structure name="IDR_WELCOME_ONBOARDING_WELCOME_WELCOME_JS"
                  file="welcome.js"
                  type="chrome_html"
                  compress="gzip"
                  preprocess="true"/>
 
-       <!-- Google apps-->
-      <structure name="IDR_GOOGLE_APPS_HTML"
+       <!-- NUX Google apps-->
+      <structure name="IDR_NUX_GOOGLE_APPS_HTML"
                  file="google_apps/nux_google_apps.html"
                  compress="gzip"
                  type="chrome_html" />
-      <structure name="IDR_GOOGLE_APPS_JS"
+      <structure name="IDR_NUX_GOOGLE_APPS_JS"
                  file="google_apps/nux_google_apps.js"
                  compress="gzip"
                  type="chrome_html" />
@@ -205,21 +205,21 @@
                  file="google_apps/google_app_proxy.js"
                  compress="gzip"
                  type="chrome_html" />
-      <structure name="IDR_SET_AS_DEFAULT_HTML"
+      <structure name="IDR_NUX_SET_AS_DEFAULT_HTML"
                  file="set_as_default/nux_set_as_default.html"
                  type="chrome_html"
                  compress="gzip"
                  preprocess="true"/>
-      <structure name="IDR_SET_AS_DEFAULT_JS"
+      <structure name="IDR_NUX_SET_AS_DEFAULT_JS"
                  file="set_as_default/nux_set_as_default.js"
                  type="chrome_html"
                  compress="gzip"
                  preprocess="true"/>
-      <structure name="IDR_SET_AS_DEFAULT_PROXY_HTML"
+      <structure name="IDR_NUX_SET_AS_DEFAULT_PROXY_HTML"
                  file="set_as_default/nux_set_as_default_proxy.html"
                  compress="gzip"
                  type="chrome_html" />
-      <structure name="IDR_SET_AS_DEFAULT_PROXY_JS"
+      <structure name="IDR_NUX_SET_AS_DEFAULT_PROXY_JS"
                  file="set_as_default/nux_set_as_default_proxy.js"
                  compress="gzip"
                  type="chrome_html" />
@@ -232,28 +232,28 @@
                  compress="gzip"
                  type="chrome_html" />
 
-      <!-- NTP background-->
-      <structure name="IDR_NTP_BACKGROUND_HTML"
+      <!-- NUX NTP background-->
+      <structure name="IDR_NUX_NTP_BACKGROUND_HTML"
                  file="ntp_background/nux_ntp_background.html"
                  compress="gzip"
                  type="chrome_html" />
-      <structure name="IDR_NTP_BACKGROUND_JS"
+      <structure name="IDR_NUX_NTP_BACKGROUND_JS"
                  file="ntp_background/nux_ntp_background.js"
                  compress="gzip"
                  type="chrome_html" />
-      <structure name="IDR_NTP_BACKGROUND_PROXY_HTML"
+      <structure name="IDR_NUX_NTP_BACKGROUND_PROXY_HTML"
                  file="ntp_background/ntp_background_proxy.html"
                  compress="gzip"
                  type="chrome_html" />
-      <structure name="IDR_NTP_BACKGROUND_PROXY_JS"
+      <structure name="IDR_NUX_NTP_BACKGROUND_PROXY_JS"
                  file="ntp_background/ntp_background_proxy.js"
                  compress="gzip"
                  type="chrome_html" />
-      <structure name="IDR_NTP_BACKGROUND_METRICS_PROXY_HTML"
+      <structure name="IDR_NUX_NTP_BACKGROUND_METRICS_PROXY_HTML"
                  file="ntp_background/ntp_background_metrics_proxy.html"
                  compress="gzip"
                  type="chrome_html" />
-      <structure name="IDR_NTP_BACKGROUND_METRICS_PROXY_JS"
+      <structure name="IDR_NUX_NTP_BACKGROUND_METRICS_PROXY_JS"
                  file="ntp_background/ntp_background_metrics_proxy.js"
                  compress="gzip"
                  type="chrome_html" />
diff --git a/chrome/browser/safe_browsing/download_protection/file_analyzer.cc b/chrome/browser/safe_browsing/download_protection/file_analyzer.cc
index 4d67e7e..0d09573 100644
--- a/chrome/browser/safe_browsing/download_protection/file_analyzer.cc
+++ b/chrome/browser/safe_browsing/download_protection/file_analyzer.cc
@@ -10,12 +10,12 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/task/post_task.h"
 #include "base/task/task_traits.h"
+#include "chrome/browser/file_util_service.h"
 #include "chrome/common/safe_browsing/archive_analyzer_results.h"
 #include "chrome/common/safe_browsing/download_type_util.h"
 #include "chrome/common/safe_browsing/file_type_policies.h"
 #include "components/safe_browsing/features.h"
 #include "content/public/browser/browser_thread.h"
-#include "content/public/browser/system_connector.h"
 
 namespace safe_browsing {
 
@@ -149,7 +149,7 @@
       tmp_path_,
       base::BindRepeating(&FileAnalyzer::OnZipAnalysisFinished,
                           weakptr_factory_.GetWeakPtr()),
-      content::GetSystemConnector());
+      LaunchFileUtilService());
   zip_analyzer_->Start();
 }
 
@@ -222,7 +222,7 @@
       tmp_path_,
       base::BindRepeating(&FileAnalyzer::OnRarAnalysisFinished,
                           weakptr_factory_.GetWeakPtr()),
-      content::GetSystemConnector());
+      LaunchFileUtilService());
   rar_analyzer_->Start();
 }
 
@@ -285,7 +285,7 @@
       FileTypePolicies::GetInstance()->GetMaxFileSizeToAnalyze("dmg"),
       base::BindRepeating(&FileAnalyzer::OnDmgAnalysisFinished,
                           weakptr_factory_.GetWeakPtr()),
-      content::GetSystemConnector());
+      LaunchFileUtilService());
   dmg_analyzer_->Start();
   dmg_analysis_start_time_ = base::TimeTicks::Now();
 }
diff --git a/chrome/browser/safe_browsing/threat_details_unittest.cc b/chrome/browser/safe_browsing/threat_details_unittest.cc
index 3ebf528..0d4265e 100644
--- a/chrome/browser/safe_browsing/threat_details_unittest.cc
+++ b/chrome/browser/safe_browsing/threat_details_unittest.cc
@@ -872,8 +872,6 @@
 //   \- <frame src=kDataURL>
 //        \- <script src=kDOMChildURL2>
 TEST_F(ThreatDetailsTest, ThreatDOMDetails_AmbiguousDOM) {
-  const char kAmbiguousDomMetric[] = "SafeBrowsing.ThreatReport.DomIsAmbiguous";
-
   // Create a child renderer inside the main frame to house the inner iframe.
   // Perform the navigation first in order to manipulate the frame tree.
   content::WebContentsTester::For(web_contents())
@@ -989,9 +987,6 @@
   ClientSafeBrowsingReportRequest actual;
   actual.ParseFromString(serialized);
   VerifyResults(actual, expected);
-
-  // This DOM should be ambiguous, expect the UMA metric to be incremented.
-  histograms.ExpectTotalCount(kAmbiguousDomMetric, 1);
 }
 
 // Tests creating a threat report when receiving data from multiple renderers
diff --git a/chrome/browser/search/background/ntp_background_service.cc b/chrome/browser/search/background/ntp_background_service.cc
index 7577222..2832da0f 100644
--- a/chrome/browser/search/background/ntp_background_service.cc
+++ b/chrome/browser/search/background/ntp_background_service.cc
@@ -9,7 +9,7 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/net/system_network_context_manager.h"
 #include "chrome/browser/search/background/ntp_background.pb.h"
-#include "chrome/browser/search/background/ntp_backgrounds.h"
+#include "chrome/browser/search/background/onboarding_ntp_backgrounds.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
 #include "net/base/load_flags.h"
@@ -348,8 +348,8 @@
 }
 
 bool NtpBackgroundService::IsValidBackdropUrl(const GURL& url) const {
-  for (auto& ntp_background : GetNtpBackgrounds()) {
-    if (ntp_background == url) {
+  for (auto& onboarding_background : GetOnboardingNtpBackgrounds()) {
+    if (onboarding_background == url) {
       return true;
     }
   }
diff --git a/chrome/browser/search/background/ntp_backgrounds.cc b/chrome/browser/search/background/ntp_backgrounds.cc
deleted file mode 100644
index ef327f6..0000000
--- a/chrome/browser/search/background/ntp_backgrounds.cc
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/search/background/ntp_backgrounds.h"
-
-#include "url/gurl.h"
-
-std::array<GURL, kNtpBackgroundsCount> GetNtpBackgrounds() {
-  // A set of whitelisted NTP background image URLs that are always considered
-  // to be valid URLs that are shown to the user as part of the welcome flow.
-  // These backgrounds were handpicked from the Backdrop API based on popularity
-  // and those requiring minimum maintenance and translation work. This list
-  // matches with chrome/browser/ui/webui/welcome/nux/ntp_background_handler.cc.
-  const std::array<GURL, kNtpBackgroundsCount> kNtpBackgrounds = {{
-      // Art
-      GURL("https://lh5.googleusercontent.com/proxy/"
-           "E60bugMrz3Jw0Ty3vD1HqfrrabnAQGlHzIJjRadV1kDS_"
-           "XSE0AtWuMnjW9VPvq1YeyPJK13gZw63TQYvh2RlaZq_"
-           "aQm5xskpsgWW1l67gg3mkYaZr07BQqMV47onKA=w3840-h2160-p-k-no-nd-"
-           "mv"),
-
-      // Cityscape
-      GURL("https://lh4.googleusercontent.com/proxy/"
-           "UOhQwfclsAK8TnXZqoTkh9szHvYOJ3auDH07hZBZeVaaRWvzGaXpaYl60MfCRuW"
-           "_S57gvzBw859pj5Xl2pW_GpfG8k2GhE9LUFNKwA=w3840-h2160-p-k-no-nd-"
-           "mv"),
-
-      // Earth
-      GURL("https://lh5.googleusercontent.com/proxy/"
-           "xvtq6_782kBajCBr0GISHpujOb51XLKUeEOJ2lLPKh12-"
-           "xNBTCtsoHT14NQcaH9l4JhatcXEMBkqgUeCWhb3XhdLnD1BiNzQ_LVydwg="
-           "w3840-h2160-p-k-no-nd-mv"),
-
-      // Geometric Shapes
-      GURL("https://lh3.googleusercontent.com/proxy/"
-           "FWOBAVfQYasxV3KURX1VVKem1yOC2iazWAb8csOmqCDwI1CCzAA1zCpnAxR-"
-           "wL2rbfZNcRHbI5b-SZfLASmF7uhJnzrksBWougEGlkw_-4U=w3840-h2160-p-"
-           "k-no-nd-mv"),
-
-      // Landscapes
-      GURL("https://lh3.googleusercontent.com/proxy/"
-           "nMIspgHzTUU0GzmiadmPphBelzF2xy9-tIiejZg3VvJTITxUb-1vILxf-"
-           "IsCfyl94VSn6YvHa8_PiIyR9d3rwD8ZhNdQ1C1rnblP6zy3OaI=w3840-h2160-"
-           "p-k-no-nd-mv"),
-  }};
-  return kNtpBackgrounds;
-}
diff --git a/chrome/browser/search/background/ntp_backgrounds.h b/chrome/browser/search/background/ntp_backgrounds.h
deleted file mode 100644
index 7afc0a23..0000000
--- a/chrome/browser/search/background/ntp_backgrounds.h
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_SEARCH_BACKGROUND_NTP_BACKGROUNDS_H_
-#define CHROME_BROWSER_SEARCH_BACKGROUND_NTP_BACKGROUNDS_H_
-
-#include <array>
-
-class GURL;
-
-const size_t kNtpBackgroundsCount = 5;
-std::array<GURL, kNtpBackgroundsCount> GetNtpBackgrounds();
-
-#endif  // CHROME_BROWSER_SEARCH_BACKGROUND_NTP_BACKGROUNDS_H_
diff --git a/chrome/browser/search/background/onboarding_ntp_backgrounds.cc b/chrome/browser/search/background/onboarding_ntp_backgrounds.cc
new file mode 100644
index 0000000..d36cda5
--- /dev/null
+++ b/chrome/browser/search/background/onboarding_ntp_backgrounds.cc
@@ -0,0 +1,49 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/search/background/onboarding_ntp_backgrounds.h"
+
+#include "url/gurl.h"
+
+std::array<GURL, kOnboardingNtpBackgroundsCount> GetOnboardingNtpBackgrounds() {
+  // A set of whitelisted NTP background image URLs that are always considered
+  // to be valid URLs that are shown to the user as part of the Onboarding flow.
+  // These backgrounds were handpicked from the Backdrop API based on popularity
+  // and those requiring minimum maintenance and translation work. This list
+  // matches with chrome/browser/ui/webui/welcome/nux/ntp_background_handler.cc.
+  const std::array<GURL, kOnboardingNtpBackgroundsCount>
+      kOnboardingNtpBackgrounds = {{
+          // Art
+          GURL("https://lh5.googleusercontent.com/proxy/"
+               "E60bugMrz3Jw0Ty3vD1HqfrrabnAQGlHzIJjRadV1kDS_"
+               "XSE0AtWuMnjW9VPvq1YeyPJK13gZw63TQYvh2RlaZq_"
+               "aQm5xskpsgWW1l67gg3mkYaZr07BQqMV47onKA=w3840-h2160-p-k-no-nd-"
+               "mv"),
+
+          // Cityscape
+          GURL("https://lh4.googleusercontent.com/proxy/"
+               "UOhQwfclsAK8TnXZqoTkh9szHvYOJ3auDH07hZBZeVaaRWvzGaXpaYl60MfCRuW"
+               "_S57gvzBw859pj5Xl2pW_GpfG8k2GhE9LUFNKwA=w3840-h2160-p-k-no-nd-"
+               "mv"),
+
+          // Earth
+          GURL("https://lh5.googleusercontent.com/proxy/"
+               "xvtq6_782kBajCBr0GISHpujOb51XLKUeEOJ2lLPKh12-"
+               "xNBTCtsoHT14NQcaH9l4JhatcXEMBkqgUeCWhb3XhdLnD1BiNzQ_LVydwg="
+               "w3840-h2160-p-k-no-nd-mv"),
+
+          // Geometric Shapes
+          GURL("https://lh3.googleusercontent.com/proxy/"
+               "FWOBAVfQYasxV3KURX1VVKem1yOC2iazWAb8csOmqCDwI1CCzAA1zCpnAxR-"
+               "wL2rbfZNcRHbI5b-SZfLASmF7uhJnzrksBWougEGlkw_-4U=w3840-h2160-p-"
+               "k-no-nd-mv"),
+
+          // Landscapes
+          GURL("https://lh3.googleusercontent.com/proxy/"
+               "nMIspgHzTUU0GzmiadmPphBelzF2xy9-tIiejZg3VvJTITxUb-1vILxf-"
+               "IsCfyl94VSn6YvHa8_PiIyR9d3rwD8ZhNdQ1C1rnblP6zy3OaI=w3840-h2160-"
+               "p-k-no-nd-mv"),
+      }};
+  return kOnboardingNtpBackgrounds;
+}
diff --git a/chrome/browser/search/background/onboarding_ntp_backgrounds.h b/chrome/browser/search/background/onboarding_ntp_backgrounds.h
new file mode 100644
index 0000000..b5570db
--- /dev/null
+++ b/chrome/browser/search/background/onboarding_ntp_backgrounds.h
@@ -0,0 +1,15 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_SEARCH_BACKGROUND_ONBOARDING_NTP_BACKGROUNDS_H_
+#define CHROME_BROWSER_SEARCH_BACKGROUND_ONBOARDING_NTP_BACKGROUNDS_H_
+
+#include <array>
+
+#include "url/gurl.h"
+
+const size_t kOnboardingNtpBackgroundsCount = 5;
+std::array<GURL, kOnboardingNtpBackgroundsCount> GetOnboardingNtpBackgrounds();
+
+#endif  // CHROME_BROWSER_SEARCH_BACKGROUND_ONBOARDING_NTP_BACKGROUNDS_H_
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 14c24d0..58a5497 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -2400,6 +2400,8 @@
       "views/first_run_dialog.cc",
       "views/first_run_dialog.h",
       "views/frame/browser_desktop_window_tree_host.h",
+      "views/frame/desktop_browser_frame_aura_linux.cc",
+      "views/frame/desktop_browser_frame_aura_linux.h",
       "views/status_icons/status_icon_linux_wrapper.cc",
       "views/status_icons/status_icon_linux_wrapper.h",
       "webui/help/version_updater_basic.cc",
@@ -2429,8 +2431,6 @@
       sources += [
         "views/frame/browser_desktop_window_tree_host_x11.cc",
         "views/frame/browser_desktop_window_tree_host_x11.h",
-        "views/frame/desktop_browser_frame_aurax11.cc",
-        "views/frame/desktop_browser_frame_aurax11.h",
         "views/frame/global_menu_bar_registrar_x11.cc",
         "views/frame/global_menu_bar_registrar_x11.h",
         "views/frame/global_menu_bar_x11.cc",
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
index 3a4c010b..17f680a 100644
--- a/chrome/browser/ui/browser.cc
+++ b/chrome/browser/ui/browser.cc
@@ -1724,6 +1724,9 @@
   ProtocolHandler handler =
       ProtocolHandler::CreateProtocolHandler(protocol, url);
 
+  if (!handler.IsValid())
+    return;
+
   ProtocolHandlerRegistry* registry =
       ProtocolHandlerRegistryFactory::GetForBrowserContext(context);
   if (registry->SilentlyHandleRegisterHandlerRequest(handler))
diff --git a/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc b/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc
index 240f837..bbbb7b7 100644
--- a/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator_browsertest.cc
@@ -1026,7 +1026,8 @@
 class StartupBrowserCreatorFirstRunTest : public InProcessBrowserTest {
  public:
   StartupBrowserCreatorFirstRunTest() {
-    scoped_feature_list_.InitWithFeatures({welcome::kForceEnabled}, {});
+    scoped_feature_list_.InitWithFeatures({welcome::kOnboardingForceEnabled},
+                                          {});
   }
 
  protected:
diff --git a/chrome/browser/ui/startup/startup_browser_creator_impl.cc b/chrome/browser/ui/startup/startup_browser_creator_impl.cc
index 61eef2c3..59bca8cd 100644
--- a/chrome/browser/ui/startup/startup_browser_creator_impl.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator_impl.cc
@@ -628,16 +628,17 @@
         !SessionStartupPref::TypeHasRecommendedValue(profile_->GetPrefs());
   }
 
-  bool welcome_enabled = true;
+  bool onboarding_enabled = true;
 #if !defined(OS_CHROMEOS)
-  welcome_enabled =
-      welcome::IsEnabled(profile_) && welcome::HasModulesToShow(profile_);
+  onboarding_enabled = welcome::IsOnboardingEnabled(profile_) &&
+                       welcome::DoesOnboardingHaveModulesToShow(profile_);
 #endif  // !defined(OS_CHROMEOS)
 
-  StartupTabs tabs = DetermineStartupTabs(
-      StartupTabProviderImpl(), cmd_line_tabs, process_startup,
-      is_incognito_or_guest, is_post_crash_launch,
-      has_incompatible_applications, promotional_tabs_enabled, welcome_enabled);
+  StartupTabs tabs =
+      DetermineStartupTabs(StartupTabProviderImpl(), cmd_line_tabs,
+                           process_startup, is_incognito_or_guest,
+                           is_post_crash_launch, has_incompatible_applications,
+                           promotional_tabs_enabled, onboarding_enabled);
 
   // Return immediately if we start an async restore, since the remainder of
   // that process is self-contained.
@@ -689,7 +690,7 @@
     bool is_post_crash_launch,
     bool has_incompatible_applications,
     bool promotional_tabs_enabled,
-    bool welcome_enabled) {
+    bool onboarding_enabled) {
   // Only the New Tab Page or command line URLs may be shown in incognito mode.
   // A similar policy exists for crash recovery launches, to prevent getting the
   // user stuck in a crash loop.
@@ -738,8 +739,8 @@
         profile_, browser_creator_, process_startup);
     AppendTabs(welcome_back_tabs, &tabs);
 
-    if (welcome_enabled) {
-      // Policies for welcome (e.g., first run) may show promotional and
+    if (onboarding_enabled) {
+      // Policies for onboarding (e.g., first run) may show promotional and
       // introductory content depending on a number of system status factors,
       // including OS and whether or not this is First Run.
       onboarding_tabs = provider.GetOnboardingTabs(profile_);
diff --git a/chrome/browser/ui/startup/startup_browser_creator_impl.h b/chrome/browser/ui/startup/startup_browser_creator_impl.h
index d76da10..ebc0cac 100644
--- a/chrome/browser/ui/startup/startup_browser_creator_impl.h
+++ b/chrome/browser/ui/startup/startup_browser_creator_impl.h
@@ -135,7 +135,7 @@
   bool OpenApplicationTab(Profile* profile);
 
   // Determines the URLs to be shown at startup by way of various policies
-  // (welcome, pinned tabs, etc.), determines whether a session restore
+  // (onboarding, pinned tabs, etc.), determines whether a session restore
   // is necessary, and opens the URLs in a new or restored browser accordingly.
   void DetermineURLsAndLaunch(bool process_startup,
                               const std::vector<GURL>& cmd_line_urls);
@@ -150,7 +150,7 @@
                                    bool is_post_crash_launch,
                                    bool has_incompatible_applications,
                                    bool promotional_tabs_enabled,
-                                   bool welcome_enabled);
+                                   bool onboarding_enabled);
 
   // Begins an asynchronous session restore if current state allows it (e.g.,
   // this is not process startup) and SessionService indicates that one is
diff --git a/chrome/browser/ui/startup/startup_browser_policy_unittest.cc b/chrome/browser/ui/startup/startup_browser_policy_unittest.cc
index 3703280f..7b850a1 100644
--- a/chrome/browser/ui/startup/startup_browser_policy_unittest.cc
+++ b/chrome/browser/ui/startup/startup_browser_policy_unittest.cc
@@ -104,13 +104,13 @@
   content::TestBrowserThreadBundle thread_bundle;
   auto profile = builder.Build();
 
-  EXPECT_TRUE(welcome::HasModulesToShow(profile.get()));
+  EXPECT_TRUE(welcome::DoesOnboardingHaveModulesToShow(profile.get()));
 
   SetPolicy(policy_map, policy::key::kForceEphemeralProfiles, true);
-  EXPECT_FALSE(welcome::HasModulesToShow(profile.get()));
+  EXPECT_FALSE(welcome::DoesOnboardingHaveModulesToShow(profile.get()));
 
   SetPolicy(policy_map, policy::key::kForceEphemeralProfiles, false);
-  EXPECT_TRUE(welcome::HasModulesToShow(profile.get()));
+  EXPECT_TRUE(welcome::DoesOnboardingHaveModulesToShow(profile.get()));
 }
 
 TEST_F(StartupBrowserPolicyUnitTest, NewTabPageLocation) {
diff --git a/chrome/browser/ui/startup/startup_tab_provider.cc b/chrome/browser/ui/startup/startup_tab_provider.cc
index 72cde142..b8321209 100644
--- a/chrome/browser/ui/startup/startup_tab_provider.cc
+++ b/chrome/browser/ui/startup/startup_tab_provider.cc
@@ -44,7 +44,7 @@
 }  // namespace
 
 StartupTabs StartupTabProviderImpl::GetOnboardingTabs(Profile* profile) const {
-// Chrome OS has its own welcome flow provided by OOBE.
+// Onboarding content has not been launched on Chrome OS.
 #if defined(OS_CHROMEOS)
   return StartupTabs();
 #else
diff --git a/chrome/browser/ui/startup/startup_tab_provider.h b/chrome/browser/ui/startup/startup_tab_provider.h
index 045f916..ff71dc5 100644
--- a/chrome/browser/ui/startup/startup_tab_provider.h
+++ b/chrome/browser/ui/startup/startup_tab_provider.h
@@ -133,7 +133,6 @@
   // URL parameter will be appended so as to access the variant page used when
   // onboarding occurs after the first Chrome execution (e.g., when creating an
   // additional profile).
-  // TODO(hcarmona): it might be possible to deprecate use_later_run_variant.
   static GURL GetWelcomePageUrl(bool use_later_run_variant);
 
 #if defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD)
diff --git a/chrome/browser/ui/views/frame/desktop_browser_frame_aurax11.cc b/chrome/browser/ui/views/frame/desktop_browser_frame_aura_linux.cc
similarity index 79%
rename from chrome/browser/ui/views/frame/desktop_browser_frame_aurax11.cc
rename to chrome/browser/ui/views/frame/desktop_browser_frame_aura_linux.cc
index a163fb8..57c6ad21 100644
--- a/chrome/browser/ui/views/frame/desktop_browser_frame_aurax11.cc
+++ b/chrome/browser/ui/views/frame/desktop_browser_frame_aura_linux.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/ui/views/frame/desktop_browser_frame_aurax11.h"
+#include "chrome/browser/ui/views/frame/desktop_browser_frame_aura_linux.h"
 
 #include "base/bind.h"
 #include "base/command_line.h"
@@ -13,21 +13,20 @@
 #include "chrome/common/pref_names.h"
 #include "ui/views/widget/widget.h"
 
-DesktopBrowserFrameAuraX11::DesktopBrowserFrameAuraX11(
+DesktopBrowserFrameAuraLinux::DesktopBrowserFrameAuraLinux(
     BrowserFrame* browser_frame,
     BrowserView* browser_view)
     : DesktopBrowserFrameAura(browser_frame, browser_view) {
   use_custom_frame_pref_.Init(
       prefs::kUseCustomChromeFrame,
       browser_view->browser()->profile()->GetPrefs(),
-      base::Bind(&DesktopBrowserFrameAuraX11::OnUseCustomChromeFrameChanged,
+      base::Bind(&DesktopBrowserFrameAuraLinux::OnUseCustomChromeFrameChanged,
                  base::Unretained(this)));
 }
 
-DesktopBrowserFrameAuraX11::~DesktopBrowserFrameAuraX11() {
-}
+DesktopBrowserFrameAuraLinux::~DesktopBrowserFrameAuraLinux() {}
 
-views::Widget::InitParams DesktopBrowserFrameAuraX11::GetWidgetParams() {
+views::Widget::InitParams DesktopBrowserFrameAuraLinux::GetWidgetParams() {
   views::Widget::InitParams params;
   params.native_widget = this;
 
@@ -53,7 +52,7 @@
   return params;
 }
 
-bool DesktopBrowserFrameAuraX11::UseCustomFrame() const {
+bool DesktopBrowserFrameAuraLinux::UseCustomFrame() const {
   // Normal browser windows get a custom frame (per the user's preference).
   if (use_custom_frame_pref_.GetValue() &&
       browser_view()->IsBrowserTypeNormal()) {
@@ -68,10 +67,10 @@
   return false;
 }
 
-void DesktopBrowserFrameAuraX11::OnUseCustomChromeFrameChanged() {
+void DesktopBrowserFrameAuraLinux::OnUseCustomChromeFrameChanged() {
   // Tell the window manager to add or remove system borders.
-  browser_frame()->set_frame_type(
-      UseCustomFrame() ? views::Widget::FRAME_TYPE_FORCE_CUSTOM
-                       : views::Widget::FRAME_TYPE_FORCE_NATIVE);
+  browser_frame()->set_frame_type(UseCustomFrame()
+                                      ? views::Widget::FRAME_TYPE_FORCE_CUSTOM
+                                      : views::Widget::FRAME_TYPE_FORCE_NATIVE);
   browser_frame()->FrameTypeChanged();
 }
diff --git a/chrome/browser/ui/views/frame/desktop_browser_frame_aurax11.h b/chrome/browser/ui/views/frame/desktop_browser_frame_aura_linux.h
similarity index 74%
rename from chrome/browser/ui/views/frame/desktop_browser_frame_aurax11.h
rename to chrome/browser/ui/views/frame/desktop_browser_frame_aura_linux.h
index 08e63f5..39e94ba 100644
--- a/chrome/browser/ui/views/frame/desktop_browser_frame_aurax11.h
+++ b/chrome/browser/ui/views/frame/desktop_browser_frame_aura_linux.h
@@ -2,21 +2,21 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_UI_VIEWS_FRAME_DESKTOP_BROWSER_FRAME_AURAX11_H_
-#define CHROME_BROWSER_UI_VIEWS_FRAME_DESKTOP_BROWSER_FRAME_AURAX11_H_
+#ifndef CHROME_BROWSER_UI_VIEWS_FRAME_DESKTOP_BROWSER_FRAME_AURA_LINUX_H_
+#define CHROME_BROWSER_UI_VIEWS_FRAME_DESKTOP_BROWSER_FRAME_AURA_LINUX_H_
 
 #include "base/macros.h"
 #include "chrome/browser/ui/views/frame/desktop_browser_frame_aura.h"
 #include "components/prefs/pref_member.h"
 
 // Provides the window frame for the Chrome browser window on Desktop Linux/X11.
-class DesktopBrowserFrameAuraX11 : public DesktopBrowserFrameAura {
+class DesktopBrowserFrameAuraLinux : public DesktopBrowserFrameAura {
  public:
-  DesktopBrowserFrameAuraX11(BrowserFrame* browser_frame,
-                             BrowserView* browser_view);
+  DesktopBrowserFrameAuraLinux(BrowserFrame* browser_frame,
+                               BrowserView* browser_view);
 
  protected:
-  ~DesktopBrowserFrameAuraX11() override;
+  ~DesktopBrowserFrameAuraLinux() override;
 
   // Overridden from NativeBrowserFrame:
   views::Widget::InitParams GetWidgetParams() override;
@@ -29,7 +29,7 @@
   // Whether the custom Chrome frame preference is set.
   BooleanPrefMember use_custom_frame_pref_;
 
-  DISALLOW_COPY_AND_ASSIGN(DesktopBrowserFrameAuraX11);
+  DISALLOW_COPY_AND_ASSIGN(DesktopBrowserFrameAuraLinux);
 };
 
-#endif  // CHROME_BROWSER_UI_VIEWS_FRAME_DESKTOP_BROWSER_FRAME_AURAX11_H_
+#endif  // CHROME_BROWSER_UI_VIEWS_FRAME_DESKTOP_BROWSER_FRAME_AURA_LINUX_H_
diff --git a/chrome/browser/ui/views/frame/native_browser_frame_factory_aurax11.cc b/chrome/browser/ui/views/frame/native_browser_frame_factory_aurax11.cc
index 21096248c..af5ab5d 100644
--- a/chrome/browser/ui/views/frame/native_browser_frame_factory_aurax11.cc
+++ b/chrome/browser/ui/views/frame/native_browser_frame_factory_aurax11.cc
@@ -4,10 +4,10 @@
 
 #include "chrome/browser/ui/views/frame/native_browser_frame_factory.h"
 
-#include "chrome/browser/ui/views/frame/desktop_browser_frame_aurax11.h"
+#include "chrome/browser/ui/views/frame/desktop_browser_frame_aura_linux.h"
 
 NativeBrowserFrame* NativeBrowserFrameFactory::Create(
     BrowserFrame* browser_frame,
     BrowserView* browser_view) {
-  return new DesktopBrowserFrameAuraX11(browser_frame, browser_view);
+  return new DesktopBrowserFrameAuraLinux(browser_frame, browser_view);
 }
diff --git a/chrome/browser/ui/views/frame/native_browser_frame_factory_ozone.cc b/chrome/browser/ui/views/frame/native_browser_frame_factory_ozone.cc
index 06be688c..f77c6c7c 100644
--- a/chrome/browser/ui/views/frame/native_browser_frame_factory_ozone.cc
+++ b/chrome/browser/ui/views/frame/native_browser_frame_factory_ozone.cc
@@ -4,10 +4,10 @@
 
 #include "chrome/browser/ui/views/frame/native_browser_frame_factory.h"
 
-#include "chrome/browser/ui/views/frame/desktop_browser_frame_aura.h"
+#include "chrome/browser/ui/views/frame/desktop_browser_frame_aura_linux.h"
 
 NativeBrowserFrame* NativeBrowserFrameFactory::Create(
     BrowserFrame* browser_frame,
     BrowserView* browser_view) {
-  return new DesktopBrowserFrameAura(browser_frame, browser_view);
+  return new DesktopBrowserFrameAuraLinux(browser_frame, browser_view);
 }
diff --git a/chrome/browser/ui/webui/app_management/OWNERS b/chrome/browser/ui/webui/app_management/OWNERS
index 4829e5d..3b25536 100644
--- a/chrome/browser/ui/webui/app_management/OWNERS
+++ b/chrome/browser/ui/webui/app_management/OWNERS
@@ -1,6 +1,5 @@
 per-file *.mojom=set noparent
 per-file *.mojom=file://ipc/SECURITY_OWNERS
 
-calamity@chromium.org
 dominickn@chromium.org
-ericwilligers@chromium.org
+jshikaram@chromium.org
diff --git a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
index af42771..27d8865 100644
--- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
+++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
@@ -632,7 +632,7 @@
       !profile->IsOffTheRecord())
     return &NewWebUI<SigninEmailConfirmationUI>;
   if (url.host_piece() == chrome::kChromeUIWelcomeHost &&
-      welcome::IsEnabled(profile))
+      welcome::IsOnboardingEnabled(profile))
     return &NewWebUI<WelcomeUI>;
 #endif
 
diff --git a/chrome/browser/ui/webui/chromeos/drive_internals_ui.cc b/chrome/browser/ui/webui/chromeos/drive_internals_ui.cc
index cce737b..5aa085a6 100644
--- a/chrome/browser/ui/webui/chromeos/drive_internals_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/drive_internals_ui.cc
@@ -34,6 +34,7 @@
 #include "chrome/browser/chromeos/drive/file_system_util.h"
 #include "chrome/browser/chromeos/file_manager/path_util.h"
 #include "chrome/browser/drive/drive_notification_manager_factory.h"
+#include "chrome/browser/file_util_service.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
@@ -53,7 +54,6 @@
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/navigation_controller.h"
-#include "content/public/browser/system_connector.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_ui.h"
 #include "content/public/browser/web_ui_data_source.h"
@@ -997,7 +997,7 @@
     (new ZipFileCreator(
          base::BindRepeating(&LogsZipper::OnZipDone, base::Unretained(this)),
          logs_directory_, files, zip_path_))
-        ->Start(content::GetSystemConnector());
+        ->Start(LaunchFileUtilService());
   }
 
   static std::vector<base::FilePath> EnumerateLogFiles(
diff --git a/chrome/browser/ui/webui/welcome/google_apps_handler.cc b/chrome/browser/ui/webui/welcome/google_apps_handler.cc
index 1a8f2ed..fd26cf38 100644
--- a/chrome/browser/ui/webui/welcome/google_apps_handler.cc
+++ b/chrome/browser/ui/webui/welcome/google_apps_handler.cc
@@ -14,7 +14,7 @@
 #include "chrome/browser/ui/webui/welcome/helpers.h"
 #include "chrome/grit/chrome_unscaled_resources.h"
 #include "chrome/grit/generated_resources.h"
-#include "chrome/grit/welcome_resources.h"
+#include "chrome/grit/onboarding_welcome_resources.h"
 #include "components/favicon/core/favicon_service.h"
 #include "components/grit/components_resources.h"
 #include "components/grit/components_scaled_resources.h"
@@ -51,41 +51,43 @@
 
   BookmarkItem gmail = {
       static_cast<int>(GoogleApps::kGmail),
-      l10n_util::GetStringUTF8(IDS_WELCOME_GOOGLE_GMAIL), "gmail",
-      "https://accounts.google.com/b/0/AddMailService", IDS_WELCOME_GMAIL};
+      l10n_util::GetStringUTF8(IDS_ONBOARDING_WELCOME_NUX_GOOGLE_GMAIL),
+      "gmail", "https://accounts.google.com/b/0/AddMailService",
+      IDS_ONBOARDING_WELCOME_GMAIL};
 
   if (IsAppVariationEnabled()) {
-    google_apps_.push_back({static_cast<int>(GoogleApps::kSearch),
-                            l10n_util::GetStringUTF8(IDS_WELCOME_GOOGLE_SEARCH),
-                            "search", "https://google.com",
-                            IDS_WELCOME_SEARCH});
+    google_apps_.push_back(
+        {static_cast<int>(GoogleApps::kSearch),
+         l10n_util::GetStringUTF8(IDS_ONBOARDING_WELCOME_NUX_GOOGLE_SEARCH),
+         "search", "https://google.com", IDS_ONBOARDING_WELCOME_SEARCH});
   } else {
     google_apps_.push_back(gmail);
   }
 
   google_apps_.push_back(
       {static_cast<int>(GoogleApps::kYouTube),
-       l10n_util::GetStringUTF8(IDS_WELCOME_GOOGLE_APPS_YOUTUBE), "youtube",
-       "https://youtube.com", IDS_WELCOME_YOUTUBE});
+       l10n_util::GetStringUTF8(IDS_ONBOARDING_WELCOME_NUX_GOOGLE_APPS_YOUTUBE),
+       "youtube", "https://youtube.com", IDS_ONBOARDING_WELCOME_YOUTUBE});
 
   google_apps_.push_back(
       {static_cast<int>(GoogleApps::kMaps),
-       l10n_util::GetStringUTF8(IDS_WELCOME_GOOGLE_APPS_MAPS), "maps",
-       "https://maps.google.com", IDS_WELCOME_MAPS});
+       l10n_util::GetStringUTF8(IDS_ONBOARDING_WELCOME_NUX_GOOGLE_APPS_MAPS),
+       "maps", "https://maps.google.com", IDS_ONBOARDING_WELCOME_MAPS});
 
   if (IsAppVariationEnabled()) {
     google_apps_.push_back(gmail);
   } else {
     google_apps_.push_back(
         {static_cast<int>(GoogleApps::kNews),
-         l10n_util::GetStringUTF8(IDS_WELCOME_GOOGLE_APPS_NEWS), "news",
-         "https://news.google.com", IDS_WELCOME_NEWS});
+         l10n_util::GetStringUTF8(IDS_ONBOARDING_WELCOME_NUX_GOOGLE_APPS_NEWS),
+         "news", "https://news.google.com", IDS_ONBOARDING_WELCOME_NEWS});
   }
 
-  google_apps_.push_back(
-      {static_cast<int>(GoogleApps::kTranslate),
-       l10n_util::GetStringUTF8(IDS_WELCOME_GOOGLE_APPS_TRANSLATE), "translate",
-       "https://translate.google.com", IDS_WELCOME_TRANSLATE});
+  google_apps_.push_back({static_cast<int>(GoogleApps::kTranslate),
+                          l10n_util::GetStringUTF8(
+                              IDS_ONBOARDING_WELCOME_NUX_GOOGLE_APPS_TRANSLATE),
+                          "translate", "https://translate.google.com",
+                          IDS_ONBOARDING_WELCOME_TRANSLATE});
 #endif  // defined(GOOGLE_CHROME_BUILD)
 }
 
diff --git a/chrome/browser/ui/webui/welcome/helpers.cc b/chrome/browser/ui/webui/welcome/helpers.cc
index 3cac3eb..a15c7586 100644
--- a/chrome/browser/ui/webui/welcome/helpers.cc
+++ b/chrome/browser/ui/webui/welcome/helpers.cc
@@ -35,32 +35,36 @@
 const char kDefaultReturningUserModules[] = "nux-set-as-default";
 
 // Feature flag.
-const base::Feature kFeature{"NuxOnboarding", base::FEATURE_ENABLED_BY_DEFAULT};
+const base::Feature kOnboardingFeature{"NuxOnboarding",
+                                       base::FEATURE_ENABLED_BY_DEFAULT};
 // For testing purposes
-const base::Feature kForceEnabled = {"NuxOnboardingForceEnabled",
-                                     base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kOnboardingForceEnabled = {
+    "NuxOnboardingForceEnabled", base::FEATURE_DISABLED_BY_DEFAULT};
 
 // The value of these FeatureParam values should be a comma-delimited list
 // of element names whitelisted in the MODULES_WHITELIST list, defined in
 // chrome/browser/resources/welcome/welcome_app.js
-const base::FeatureParam<std::string> kNewUserModules{
-    &kFeature, "new-user-modules", kDefaultNewUserModules};
-const base::FeatureParam<std::string> kReturningUserModules{
-    &kFeature, "returning-user-modules", kDefaultReturningUserModules};
+const base::FeatureParam<std::string> kOnboardingNewUserModules{
+    &kOnboardingFeature, "new-user-modules", kDefaultNewUserModules};
+const base::FeatureParam<std::string> kOnboardingReturningUserModules{
+    &kOnboardingFeature, "returning-user-modules",
+    kDefaultReturningUserModules};
 // For testing purposes
-const base::FeatureParam<std::string> kForceEnabledNewUserModules = {
-    &kForceEnabled, "new-user-modules",
+const base::FeatureParam<std::string> kOnboardingForceEnabledNewUserModules = {
+    &kOnboardingForceEnabled, "new-user-modules",
     "nux-google-apps,nux-ntp-background,nux-set-as-default,"
     "signin-view"};
-const base::FeatureParam<std::string> kForceEnabledReturningUserModules = {
-    &kForceEnabled, "returning-user-modules", "nux-set-as-default"};
+const base::FeatureParam<std::string>
+    kOnboardingForceEnabledReturningUserModules = {&kOnboardingForceEnabled,
+                                                   "returning-user-modules",
+                                                   "nux-set-as-default"};
 
 // FeatureParam for app variation.
-const base::FeatureParam<bool> kShowGoogleApp{&kFeature,
-                                              "app-variation-enabled", false};
+const base::FeatureParam<bool> kOnboardingShowGoogleApp{
+    &kOnboardingFeature, "app-variation-enabled", false};
 // For testing purposes
-const base::FeatureParam<bool> kForceEnabledShowGoogleApp = {
-    &kForceEnabled, "app-variation-enabled", false};
+const base::FeatureParam<bool> kOnboardingForceEnabledShowGoogleApp = {
+    &kOnboardingForceEnabled, "app-variation-enabled", false};
 
 bool CanShowGoogleAppModule(const policy::PolicyMap& policies) {
   const base::Value* bookmark_bar_enabled_value =
@@ -123,12 +127,11 @@
     "NaviShortcutVariationEnabled", base::FEATURE_DISABLED_BY_DEFAULT};
 #endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING) && defined(OS_WIN)
 
-// Welcome experiments depend on Google being the default search provider.
+// Onboarding experiments depend on Google being the default search provider.
 bool CanExperimentWithVariations(Profile* profile) {
   return search::DefaultSearchProviderIsGoogle(profile);
 }
 
-#if BUILDFLAG(GOOGLE_CHROME_BRANDING) && defined(OS_WIN)
 // Get the group for users who onboard in this experiment.
 // Groups are:
 //   - Specified by study
@@ -149,52 +152,55 @@
   return base::GetFieldTrialParamValue("NaviOnboarding", "onboarding-group");
 }
 
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING) && defined(OS_WIN)
 void JoinOnboardingGroup(Profile* profile) {
   PrefService* prefs = profile->GetPrefs();
 
-  std::string group;
+  std::string onboard_group;
   if (prefs->GetBoolean(prefs::kHasSeenWelcomePage)) {
-    // Get user's original group.
-    group = prefs->GetString(prefs::kNaviOnboardGroup);
+    // Get user's original onboarding group.
+    onboard_group = prefs->GetString(prefs::kNaviOnboardGroup);
 
-    // Users who onboarded before Navi won't have a group.
-    if (group.empty())
+    // Users who onboarded before Navi won't have an onboarding group.
+    if (onboard_group.empty())
       return;
   } else {
     // Join the latest group if onboarding for the first time!
-    group = GetOnboardingGroup(profile);
-    profile->GetPrefs()->SetString(prefs::kNaviOnboardGroup, group);
+    onboard_group = GetOnboardingGroup(profile);
+    profile->GetPrefs()->SetString(prefs::kNaviOnboardGroup, onboard_group);
   }
 
-  // User will be tied to their original group, even after experiment ends.
+  // User will be tied to their original onboarding group, even after
+  // experiment ends.
   ChromeMetricsServiceAccessor::RegisterSyntheticFieldTrial(
-      "NaviOnboardingSynthetic", group);
+      "NaviOnboardingSynthetic", onboard_group);
 
-  // Check for feature based on group.
+  // Check for feature based on onboarding group.
   // TODO(hcarmona): find a solution that scales better.
-  if (group.compare("ControlSynthetic-008") == 0)
+  if (onboard_group.compare("ControlSynthetic-008") == 0)
     base::FeatureList::IsEnabled(kNaviControlEnabled);
-  else if (group.compare("AppVariationSynthetic-008") == 0)
+  else if (onboard_group.compare("AppVariationSynthetic-008") == 0)
     base::FeatureList::IsEnabled(kNaviAppVariationEnabled);
-  else if (group.compare("NTPVariationSynthetic-008") == 0)
+  else if (onboard_group.compare("NTPVariationSynthetic-008") == 0)
     base::FeatureList::IsEnabled(kNaviNTPVariationEnabled);
-  else if (group.compare("ShortcutVariationSynthetic-008") == 0)
+  else if (onboard_group.compare("ShortcutVariationSynthetic-008") == 0)
     base::FeatureList::IsEnabled(kNaviShortcutVariationEnabled);
 }
 #endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING) && defined(OS_WIN)
 
-bool IsEnabled(Profile* profile) {
+bool IsOnboardingEnabled(Profile* profile) {
 #if defined(GOOGLE_CHROME_BUILD)
-  return base::FeatureList::IsEnabled(welcome::kFeature) ||
-         base::FeatureList::IsEnabled(welcome::kForceEnabled);
+  return base::FeatureList::IsEnabled(welcome::kOnboardingFeature) ||
+         base::FeatureList::IsEnabled(welcome::kOnboardingForceEnabled);
 #else
   // Allow enabling outside official builds for testing purposes.
-  return base::FeatureList::IsEnabled(welcome::kForceEnabled);
+  return base::FeatureList::IsEnabled(welcome::kOnboardingForceEnabled);
 #endif  // defined(GOOGLE_CHROME_BUILD)
 }
 
 bool IsAppVariationEnabled() {
-  return kForceEnabledShowGoogleApp.Get() || kShowGoogleApp.Get();
+  return kOnboardingForceEnabledShowGoogleApp.Get() ||
+         kOnboardingShowGoogleApp.Get();
 }
 
 const policy::PolicyMap& GetPoliciesFromProfile(Profile* profile) {
@@ -221,7 +227,7 @@
   return available_modules;
 }
 
-bool HasModulesToShow(Profile* profile) {
+bool DoesOnboardingHaveModulesToShow(Profile* profile) {
   const base::Value* force_ephemeral_profiles_value =
       GetPoliciesFromProfile(profile).GetValue(
           policy::key::kForceEphemeralProfiles);
@@ -250,19 +256,19 @@
   return base::JoinString(filtered_modules, ",");
 }
 
-base::DictionaryValue GetModules(Profile* profile) {
-  // This function should not be called when feature is not on.
-  DCHECK(welcome::IsEnabled(profile));
+base::DictionaryValue GetOnboardingModules(Profile* profile) {
+  // This function should not be called when nux onboarding feature is not on.
+  DCHECK(welcome::IsOnboardingEnabled(profile));
 
   std::string new_user_modules = kDefaultNewUserModules;
   std::string returning_user_modules = kDefaultReturningUserModules;
 
-  if (base::FeatureList::IsEnabled(welcome::kForceEnabled)) {
-    new_user_modules = kForceEnabledNewUserModules.Get();
-    returning_user_modules = kForceEnabledReturningUserModules.Get();
+  if (base::FeatureList::IsEnabled(welcome::kOnboardingForceEnabled)) {
+    new_user_modules = kOnboardingForceEnabledNewUserModules.Get();
+    returning_user_modules = kOnboardingForceEnabledReturningUserModules.Get();
   } else if (CanExperimentWithVariations(profile)) {
-    new_user_modules = kNewUserModules.Get();
-    returning_user_modules = kReturningUserModules.Get();
+    new_user_modules = kOnboardingNewUserModules.Get();
+    returning_user_modules = kOnboardingReturningUserModules.Get();
   }
 
   std::vector<std::string> available_modules = GetAvailableModules(profile);
diff --git a/chrome/browser/ui/webui/welcome/helpers.h b/chrome/browser/ui/webui/welcome/helpers.h
index 258c956b..33d8e76 100644
--- a/chrome/browser/ui/webui/welcome/helpers.h
+++ b/chrome/browser/ui/webui/welcome/helpers.h
@@ -31,16 +31,16 @@
 void JoinOnboardingGroup(Profile* profile);
 #endif  // defined(GOOGLE_CHROME_BUILD) && defined(OS_WIN)
 
-bool IsEnabled(Profile* profile);
+bool IsOnboardingEnabled(Profile* profile);
 
 bool IsAppVariationEnabled();
 
-bool HasModulesToShow(Profile* profile);
+bool DoesOnboardingHaveModulesToShow(Profile* profile);
 
-base::DictionaryValue GetModules(Profile* profile);
+base::DictionaryValue GetOnboardingModules(Profile* profile);
 
 // Exposed for testing.
-extern const base::Feature kForceEnabled;
+extern const base::Feature kOnboardingForceEnabled;
 
 bool CanShowGoogleAppModuleForTesting(const policy::PolicyMap& policies);
 bool CanShowNTPBackgroundModuleForTesting(const policy::PolicyMap& policies,
diff --git a/chrome/browser/ui/webui/welcome/ntp_background_fetcher.cc b/chrome/browser/ui/webui/welcome/ntp_background_fetcher.cc
index 33ff488..9d5abee 100644
--- a/chrome/browser/ui/webui/welcome/ntp_background_fetcher.cc
+++ b/chrome/browser/ui/webui/welcome/ntp_background_fetcher.cc
@@ -8,7 +8,7 @@
 
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/net/system_network_context_manager.h"
-#include "chrome/browser/search/background/ntp_backgrounds.h"
+#include "chrome/browser/search/background/onboarding_ntp_backgrounds.h"
 #include "net/base/load_flags.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
 #include "net/url_request/url_request.h"
@@ -46,7 +46,7 @@
           policy_exception_justification: "Not implemented."
         })");
 
-  auto backgrounds = GetNtpBackgrounds();
+  auto backgrounds = GetOnboardingNtpBackgrounds();
 
   if (index_ >= backgrounds.size()) {
     OnFetchCompleted(nullptr);
diff --git a/chrome/browser/ui/webui/welcome/ntp_background_handler.cc b/chrome/browser/ui/webui/welcome/ntp_background_handler.cc
index 531501d..13e89d7 100644
--- a/chrome/browser/ui/webui/welcome/ntp_background_handler.cc
+++ b/chrome/browser/ui/webui/welcome/ntp_background_handler.cc
@@ -11,11 +11,11 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/search/background/ntp_backgrounds.h"
+#include "chrome/browser/search/background/onboarding_ntp_backgrounds.h"
 #include "chrome/browser/search/instant_service.h"
 #include "chrome/browser/search/instant_service_factory.h"
 #include "chrome/grit/generated_resources.h"
-#include "chrome/grit/welcome_resources.h"
+#include "chrome/grit/onboarding_welcome_resources.h"
 #include "components/strings/grit/components_strings.h"
 #include "content/public/browser/web_ui.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -64,14 +64,16 @@
   CHECK(args->Get(0, &callback_id));
 
   base::ListValue list_value;
-  std::array<GURL, kNtpBackgroundsCount> NtpBackgrounds = GetNtpBackgrounds();
+  std::array<GURL, kOnboardingNtpBackgroundsCount> onboardingNtpBackgrounds =
+      GetOnboardingNtpBackgrounds();
   const std::string kUrlPrefix = "preview-background.jpg?";
 
   auto element = std::make_unique<base::DictionaryValue>();
   int id = static_cast<int>(NtpBackgrounds::kEarth);
   element->SetInteger("id", id);
-  element->SetString("title", l10n_util::GetStringUTF8(
-                                  IDS_WELCOME_NTP_BACKGROUND_EARTH_TITLE));
+  element->SetString("title",
+                     l10n_util::GetStringUTF8(
+                         IDS_ONBOARDING_WELCOME_NTP_BACKGROUND_EARTH_TITLE));
   element->SetString("imageUrl", kUrlPrefix + base::NumberToString(id));
   element->SetString("thumbnailClass", "earth");
   list_value.Append(std::move(element));
@@ -79,8 +81,9 @@
   element = std::make_unique<base::DictionaryValue>();
   id = static_cast<int>(NtpBackgrounds::kCityscape);
   element->SetInteger("id", id);
-  element->SetString("title", l10n_util::GetStringUTF8(
-                                  IDS_WELCOME_NTP_BACKGROUND_CITYSCAPE_TITLE));
+  element->SetString(
+      "title", l10n_util::GetStringUTF8(
+                   IDS_ONBOARDING_WELCOME_NTP_BACKGROUND_CITYSCAPE_TITLE));
   element->SetString("imageUrl", kUrlPrefix + base::NumberToString(id));
   element->SetString("thumbnailClass", "cityscape");
   list_value.Append(std::move(element));
@@ -88,8 +91,9 @@
   element = std::make_unique<base::DictionaryValue>();
   id = static_cast<int>(NtpBackgrounds::kLandscape);
   element->SetInteger("id", id);
-  element->SetString("title", l10n_util::GetStringUTF8(
-                                  IDS_WELCOME_NTP_BACKGROUND_LANDSCAPE_TITLE));
+  element->SetString(
+      "title", l10n_util::GetStringUTF8(
+                   IDS_ONBOARDING_WELCOME_NTP_BACKGROUND_LANDSCAPE_TITLE));
   element->SetString("imageUrl", kUrlPrefix + base::NumberToString(id));
   element->SetString("thumbnailClass", "landscape");
   list_value.Append(std::move(element));
@@ -97,8 +101,9 @@
   element = std::make_unique<base::DictionaryValue>();
   id = static_cast<int>(NtpBackgrounds::kArt);
   element->SetInteger("id", id);
-  element->SetString(
-      "title", l10n_util::GetStringUTF8(IDS_WELCOME_NTP_BACKGROUND_ART_TITLE));
+  element->SetString("title",
+                     l10n_util::GetStringUTF8(
+                         IDS_ONBOARDING_WELCOME_NTP_BACKGROUND_ART_TITLE));
   element->SetString("imageUrl", kUrlPrefix + base::NumberToString(id));
   element->SetString("thumbnailClass", "art");
   list_value.Append(std::move(element));
@@ -106,9 +111,10 @@
   element = std::make_unique<base::DictionaryValue>();
   id = static_cast<int>(NtpBackgrounds::kGeometricShapes);
   element->SetInteger("id", id);
-  element->SetString("title",
-                     l10n_util::GetStringUTF8(
-                         IDS_WELCOME_NTP_BACKGROUND_GEOMETRIC_SHAPES_TITLE));
+  element->SetString(
+      "title",
+      l10n_util::GetStringUTF8(
+          IDS_ONBOARDING_WELCOME_NTP_BACKGROUND_GEOMETRIC_SHAPES_TITLE));
   element->SetString("imageUrl", kUrlPrefix + base::NumberToString(id));
   element->SetString("thumbnailClass", "geometric-shapes");
   list_value.Append(std::move(element));
@@ -121,22 +127,24 @@
   int backgroundIndex;
   args->GetInteger(0, &backgroundIndex);
 
-  std::array<GURL, kNtpBackgroundsCount> NtpBackgrounds = GetNtpBackgrounds();
+  std::array<GURL, kOnboardingNtpBackgroundsCount> onboardingNtpBackgrounds =
+      GetOnboardingNtpBackgrounds();
   InstantService* instant_service =
       InstantServiceFactory::GetForProfile(Profile::FromWebUI(web_ui()));
 
   switch (backgroundIndex) {
     case static_cast<int>(NtpBackgrounds::kArt):
       instant_service->SetCustomBackgroundInfo(
-          NtpBackgrounds[backgroundIndex], "Universe Cosmic Vacum",
+          onboardingNtpBackgrounds[backgroundIndex], "Universe Cosmic Vacum",
           "Philipp Rietz — Walli",
           GURL("https://walli.shanga.co/image/view/?id=370"), "");
       break;
     case static_cast<int>(NtpBackgrounds::kCityscape):
       instant_service->SetCustomBackgroundInfo(
-          NtpBackgrounds[backgroundIndex],
-          l10n_util::GetStringFUTF8(IDS_WELCOME_NTP_BACKGROUND_PHOTO_BY_LABEL,
-                                    base::UTF8ToUTF16("Ev Tchebotarev")),
+          onboardingNtpBackgrounds[backgroundIndex],
+          l10n_util::GetStringFUTF8(
+              IDS_ONBOARDING_WELCOME_NTP_BACKGROUND_PHOTO_BY_LABEL,
+              base::UTF8ToUTF16("Ev Tchebotarev")),
           "",
           GURL("https://500px.com/photo/135751035/"
                "soulseek-by-%E5%B0%A4%E9%87%91%E5%B0%BC-ev-tchebotarev"),
@@ -144,22 +152,24 @@
       break;
     case static_cast<int>(NtpBackgrounds::kEarth):
       instant_service->SetCustomBackgroundInfo(
-          NtpBackgrounds[backgroundIndex],
-          l10n_util::GetStringFUTF8(IDS_WELCOME_NTP_BACKGROUND_PHOTO_BY_LABEL,
-                                    base::UTF8ToUTF16("NASA Image Library")),
+          onboardingNtpBackgrounds[backgroundIndex],
+          l10n_util::GetStringFUTF8(
+              IDS_ONBOARDING_WELCOME_NTP_BACKGROUND_PHOTO_BY_LABEL,
+              base::UTF8ToUTF16("NASA Image Library")),
           "", GURL("https://www.google.com/sky/"), "");
       break;
     case static_cast<int>(NtpBackgrounds::kGeometricShapes):
       instant_service->SetCustomBackgroundInfo(
-          NtpBackgrounds[backgroundIndex], "Tessellation 15",
+          onboardingNtpBackgrounds[backgroundIndex], "Tessellation 15",
           "Justin Prno — Walli",
           GURL("https://walli.shanga.co/image/view/?id=1375"), "");
       break;
     case static_cast<int>(NtpBackgrounds::kLandscape):
       instant_service->SetCustomBackgroundInfo(
-          NtpBackgrounds[backgroundIndex],
-          l10n_util::GetStringFUTF8(IDS_WELCOME_NTP_BACKGROUND_PHOTO_BY_LABEL,
-                                    base::UTF8ToUTF16("Giulio Rosso Chioso")),
+          onboardingNtpBackgrounds[backgroundIndex],
+          l10n_util::GetStringFUTF8(
+              IDS_ONBOARDING_WELCOME_NTP_BACKGROUND_PHOTO_BY_LABEL,
+              base::UTF8ToUTF16("Giulio Rosso Chioso")),
           "",
           GURL("https://500px.com/photo/41149196/"
                "le-piscine-sunset-by-giulio-rosso-chioso"),
diff --git a/chrome/browser/ui/webui/welcome/welcome_handler.cc b/chrome/browser/ui/webui/welcome/welcome_handler.cc
index 17d4764..222a102 100644
--- a/chrome/browser/ui/webui/welcome/welcome_handler.cc
+++ b/chrome/browser/ui/webui/welcome/welcome_handler.cc
@@ -61,7 +61,7 @@
   if (result != LoginUIService::ABORT_SIGNIN) {
     result_ = WelcomeResult::SIGNED_IN;
 
-    // When signed in from welcome flow, it's possible to come back to
+    // When signed in from NUX onboarding flow, it's possible to come back to
     // chrome://welcome/... after closing sync-confirmation UI. If current URL
     // matches such a case, do not navigate away.
     if (!is_redirected_welcome_impression_) {
@@ -110,7 +110,7 @@
 
 // Override from WebUIMessageHandler.
 void WelcomeHandler::RegisterMessages() {
-  // Check if this instance of WelcomeHandler is spawned by welcome flow
+  // Check if this instance of WelcomeHandler is spawned by onboarding flow
   // redirecting users back to welcome page. This is done here instead of
   // constructor, because web_ui hasn't loaded yet at that time.
   is_redirected_welcome_impression_ = isValidRedirectUrl();
diff --git a/chrome/browser/ui/webui/welcome/welcome_ui.cc b/chrome/browser/ui/webui/welcome/welcome_ui.cc
index e153053..9cd7977 100644
--- a/chrome/browser/ui/webui/welcome/welcome_ui.cc
+++ b/chrome/browser/ui/webui/welcome/welcome_ui.cc
@@ -19,8 +19,8 @@
 #include "chrome/grit/chrome_unscaled_resources.h"
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
-#include "chrome/grit/welcome_resources.h"
-#include "chrome/grit/welcome_resources_map.h"
+#include "chrome/grit/onboarding_welcome_resources.h"
+#include "chrome/grit/onboarding_welcome_resources_map.h"
 #include "components/prefs/pref_service.h"
 #include "components/signin/public/base/signin_pref_names.h"
 #include "components/strings/grit/components_strings.h"
@@ -66,44 +66,49 @@
   weak_ptr->CreateBackgroundFetcher(background_index, callback);
 }
 
-void AddStrings(content::WebUIDataSource* html_source) {
+void AddOnboardingStrings(content::WebUIDataSource* html_source) {
   static constexpr LocalizedString kLocalizedStrings[] = {
       // Shared strings.
-      {"bookmarkAdded", IDS_WELCOME_BOOKMARK_ADDED},
-      {"bookmarksAdded", IDS_WELCOME_BOOKMARKS_ADDED},
-      {"bookmarkRemoved", IDS_WELCOME_BOOKMARK_REMOVED},
-      {"bookmarksRemoved", IDS_WELCOME_BOOKMARKS_REMOVED},
-      {"defaultBrowserChanged", IDS_DEFAULT_BROWSER_CHANGED},
+      {"bookmarkAdded", IDS_ONBOARDING_WELCOME_BOOKMARK_ADDED},
+      {"bookmarksAdded", IDS_ONBOARDING_WELCOME_BOOKMARKS_ADDED},
+      {"bookmarkRemoved", IDS_ONBOARDING_WELCOME_BOOKMARK_REMOVED},
+      {"bookmarksRemoved", IDS_ONBOARDING_WELCOME_BOOKMARKS_REMOVED},
+      {"defaultBrowserChanged", IDS_ONBOARDING_DEFAULT_BROWSER_CHANGED},
       {"headerText", IDS_WELCOME_HEADER},
-      {"next", IDS_WELCOME_NEXT},
+      {"next", IDS_ONBOARDING_WELCOME_NEXT},
       {"noThanks", IDS_NO_THANKS},
-      {"skip", IDS_WELCOME_SKIP},
+      {"skip", IDS_ONBOARDING_WELCOME_SKIP},
 
       // Sign-in view strings.
-      {"signInHeader", IDS_WELCOME_SIGNIN_VIEW_HEADER},
-      {"signInSubHeader", IDS_WELCOME_SIGNIN_VIEW_SUB_HEADER},
-      {"signIn", IDS_WELCOME_SIGNIN_VIEW_SIGNIN},
+      {"signInHeader", IDS_ONBOARDING_WELCOME_SIGNIN_VIEW_HEADER},
+      {"signInSubHeader", IDS_ONBOARDING_WELCOME_SIGNIN_VIEW_SUB_HEADER},
+      {"signIn", IDS_ONBOARDING_WELCOME_SIGNIN_VIEW_SIGNIN},
 
       // Google apps module strings.
-      {"googleAppsDescription", IDS_WELCOME_GOOGLE_APPS_DESCRIPTION},
+      {"googleAppsDescription",
+       IDS_ONBOARDING_WELCOME_NUX_GOOGLE_APPS_DESCRIPTION},
 
       // New Tab Page background module strings.
-      {"ntpBackgroundDescription", IDS_WELCOME_NTP_BACKGROUND_DESCRIPTION},
-      {"ntpBackgroundDefault", IDS_WELCOME_NTP_BACKGROUND_DEFAULT_TITLE},
+      {"ntpBackgroundDescription",
+       IDS_ONBOARDING_WELCOME_NTP_BACKGROUND_DESCRIPTION},
+      {"ntpBackgroundDefault",
+       IDS_ONBOARDING_WELCOME_NTP_BACKGROUND_DEFAULT_TITLE},
       {"ntpBackgroundPreviewUpdated",
-       IDS_WELCOME_NTP_BACKGROUND_PREVIEW_UPDATED},
-      {"ntpBackgroundReset", IDS_WELCOME_NTP_BACKGROUND_RESET},
+       IDS_ONBOARDING_WELCOME_NTP_BACKGROUND_PREVIEW_UPDATED},
+      {"ntpBackgroundReset", IDS_ONBOARDING_WELCOME_NTP_BACKGROUND_RESET},
 
       // Set as default module strings.
-      {"setDefaultHeader", IDS_WELCOME_SET_AS_DEFAULT_HEADER},
-      {"setDefaultSubHeader", IDS_WELCOME_SET_AS_DEFAULT_SUB_HEADER},
-      {"setDefaultConfirm", IDS_WELCOME_SET_AS_DEFAULT_SET_AS_DEFAULT},
+      {"setDefaultHeader", IDS_ONBOARDING_WELCOME_NUX_SET_AS_DEFAULT_HEADER},
+      {"setDefaultSubHeader",
+       IDS_ONBOARDING_WELCOME_NUX_SET_AS_DEFAULT_SUB_HEADER},
+      {"setDefaultConfirm",
+       IDS_ONBOARDING_WELCOME_NUX_SET_AS_DEFAULT_SET_AS_DEFAULT},
 
       // Landing view strings.
-      {"landingTitle", IDS_WELCOME_LANDING_TITLE},
-      {"landingDescription", IDS_WELCOME_LANDING_DESCRIPTION},
-      {"landingNewUser", IDS_WELCOME_LANDING_NEW_USER},
-      {"landingExistingUser", IDS_WELCOME_LANDING_EXISTING_USER},
+      {"landingTitle", IDS_ONBOARDING_WELCOME_LANDING_TITLE},
+      {"landingDescription", IDS_ONBOARDING_WELCOME_LANDING_DESCRIPTION},
+      {"landingNewUser", IDS_ONBOARDING_WELCOME_LANDING_NEW_USER},
+      {"landingExistingUser", IDS_ONBOARDING_WELCOME_LANDING_EXISTING_USER},
   };
   AddLocalizedStringsBulk(html_source, kLocalizedStrings,
                           base::size(kLocalizedStrings));
@@ -128,13 +133,13 @@
   content::WebUIDataSource* html_source =
       content::WebUIDataSource::Create(url.host());
 
-  // Add welcome strings.
-  AddStrings(html_source);
+  // Add Onboarding welcome strings.
+  AddOnboardingStrings(html_source);
 
-  // Add all welcome resources.
-  for (size_t i = 0; i < kWelcomeResourcesSize; ++i) {
-    html_source->AddResourcePath(kWelcomeResources[i].name,
-                                 kWelcomeResources[i].value);
+  // Add all Onboarding resources.
+  for (size_t i = 0; i < kOnboardingWelcomeResourcesSize; ++i) {
+    html_source->AddResourcePath(kOnboardingWelcomeResources[i].name,
+                                 kOnboardingWelcomeResources[i].value);
   }
 
 #if BUILDFLAG(GOOGLE_CHROME_BRANDING)
@@ -168,32 +173,33 @@
 #endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 
   // chrome://welcome
-  html_source->SetDefaultResource(IDR_WELCOME_HTML);
+  html_source->SetDefaultResource(IDR_WELCOME_ONBOARDING_WELCOME_WELCOME_HTML);
 
 #if defined(OS_WIN)
   html_source->AddBoolean("is_win10",
                           base::win::GetVersion() >= base::win::Version::WIN10);
 #endif
 
-  // Add the shared bookmark handler for welcome modules.
+  // Add the shared bookmark handler for onboarding modules.
   web_ui->AddMessageHandler(
       std::make_unique<welcome::BookmarkHandler>(profile->GetPrefs()));
 
-  // Add google apps bookmarking module.
+  // Add google apps bookmarking onboarding module.
   web_ui->AddMessageHandler(std::make_unique<welcome::GoogleAppsHandler>());
 
-  // Add NTP custom background module.
+  // Add NTP custom background onboarding module.
   web_ui->AddMessageHandler(std::make_unique<welcome::NtpBackgroundHandler>());
 
-  // Add set-as-default module.
+  // Add set-as-default onboarding module.
   web_ui->AddMessageHandler(std::make_unique<welcome::SetAsDefaultHandler>());
 
   html_source->AddString(
       "newUserModules",
-      welcome::GetModules(profile).FindKey("new-user")->GetString());
-  html_source->AddString(
-      "returningUserModules",
-      welcome::GetModules(profile).FindKey("returning-user")->GetString());
+      welcome::GetOnboardingModules(profile).FindKey("new-user")->GetString());
+  html_source->AddString("returningUserModules",
+                         welcome::GetOnboardingModules(profile)
+                             .FindKey("returning-user")
+                             ->GetString());
   html_source->AddBoolean(
       "signinAllowed", profile->GetPrefs()->GetBoolean(prefs::kSigninAllowed));
   html_source->SetRequestFilter(
diff --git a/chrome/browser/web_applications/pending_app_install_task.h b/chrome/browser/web_applications/pending_app_install_task.h
index 451ab1e..0a04a9e 100644
--- a/chrome/browser/web_applications/pending_app_install_task.h
+++ b/chrome/browser/web_applications/pending_app_install_task.h
@@ -28,9 +28,8 @@
 enum class InstallResultCode;
 class InstallFinalizer;
 
-// Class to install a BookmarkApp-based Shortcut or WebApp from a WebContents.
-// Can only be called from the UI thread.
-// TODO(loyso): Erase this class and use InstallManager directly.
+// Class to install WebApp from a WebContents. A queue of such tasks is owned by
+// PendingAppManager. Can only be called from the UI thread.
 class PendingAppInstallTask {
  public:
   // TODO(loyso): Use InstallManager::OnceInstallCallback directly.
diff --git a/chrome/browser/web_applications/pending_app_manager_impl.h b/chrome/browser/web_applications/pending_app_manager_impl.h
index 06d780c..2765cdb 100644
--- a/chrome/browser/web_applications/pending_app_manager_impl.h
+++ b/chrome/browser/web_applications/pending_app_manager_impl.h
@@ -29,8 +29,8 @@
 
 namespace web_app {
 
-// WebAppProvider creates an instance of this class and manages its
-// lifetime. This class should only be used from the UI thread.
+// Installs, uninstalls, and updates any External Web Apps. This class should
+// only be used from the UI thread.
 class PendingAppManagerImpl : public PendingAppManager {
  public:
   using WebContentsFactory =
diff --git a/chrome/browser/web_applications/web_app_provider.cc b/chrome/browser/web_applications/web_app_provider.cc
index 5cd19ee..7267b7cf 100644
--- a/chrome/browser/web_applications/web_app_provider.cc
+++ b/chrome/browser/web_applications/web_app_provider.cc
@@ -13,8 +13,6 @@
 #include "chrome/browser/web_applications/components/install_bounce_metric.h"
 #include "chrome/browser/web_applications/components/policy/web_app_policy_manager.h"
 #include "chrome/browser/web_applications/components/web_app_audio_focus_id_map.h"
-#include "chrome/browser/web_applications/components/web_app_constants.h"
-#include "chrome/browser/web_applications/components/web_app_helpers.h"
 #include "chrome/browser/web_applications/components/web_app_ui_manager.h"
 #include "chrome/browser/web_applications/components/web_app_utils.h"
 #include "chrome/browser/web_applications/extensions/bookmark_app_install_finalizer.h"
@@ -103,7 +101,7 @@
 }
 
 WebAppUiManager& WebAppProvider::ui_manager() {
-  DCHECK(ui_manager_);
+  DCHECK_IS_CONNECTED();
   return *ui_manager_;
 }
 
@@ -125,37 +123,27 @@
   audio_focus_id_map_ = std::make_unique<WebAppAudioFocusIdMap>();
   install_manager_ = std::make_unique<WebAppInstallManager>(profile);
   pending_app_manager_ = std::make_unique<PendingAppManagerImpl>(profile);
+  system_web_app_manager_ = std::make_unique<SystemWebAppManager>(profile);
   ui_manager_ = WebAppUiManager::Create(profile);
 }
 
 void WebAppProvider::CreateWebAppsSubsystems(Profile* profile) {
   database_factory_ = std::make_unique<WebAppDatabaseFactory>(profile);
   database_ = std::make_unique<WebAppDatabase>(database_factory_.get());
-  auto web_app_registrar =
-      std::make_unique<WebAppRegistrar>(profile, database_.get());
+  registrar_ = std::make_unique<WebAppRegistrar>(profile, database_.get());
   icon_manager_ = std::make_unique<WebAppIconManager>(
       profile, std::make_unique<FileUtilsWrapper>());
-
   install_finalizer_ =
       std::make_unique<WebAppInstallFinalizer>(icon_manager_.get());
   sync_manager_ = std::make_unique<WebAppSyncManager>();
-
-  system_web_app_manager_ = std::make_unique<SystemWebAppManager>(profile);
-
-  registrar_ = std::move(web_app_registrar);
 }
 
 void WebAppProvider::CreateBookmarkAppsSubsystems(Profile* profile) {
+  registrar_ = std::make_unique<extensions::BookmarkAppRegistrar>(profile);
   install_finalizer_ =
       std::make_unique<extensions::BookmarkAppInstallFinalizer>(profile);
-
   external_web_app_manager_ = std::make_unique<ExternalWebAppManager>(profile);
-
   web_app_policy_manager_ = std::make_unique<WebAppPolicyManager>(profile);
-
-  system_web_app_manager_ = std::make_unique<SystemWebAppManager>(profile);
-
-  registrar_ = std::make_unique<extensions::BookmarkAppRegistrar>(profile);
 }
 
 void WebAppProvider::ConnectSubsystems() {
@@ -163,16 +151,15 @@
 
   install_manager_->SetSubsystems(registrar_.get(), install_finalizer_.get());
   install_finalizer_->SetSubsystems(registrar_.get(), ui_manager_.get());
+  pending_app_manager_->SetSubsystems(registrar_.get(), ui_manager_.get(),
+                                      install_finalizer_.get());
+  system_web_app_manager_->SetSubsystems(pending_app_manager_.get(),
+                                         registrar_.get(), ui_manager_.get());
 
-  // TODO(crbug.com/877898): Port all other managers to support BMO.
   if (!base::FeatureList::IsEnabled(features::kDesktopPWAsWithoutExtensions)) {
-    pending_app_manager_->SetSubsystems(registrar_.get(), ui_manager_.get(),
-                                        install_finalizer_.get());
     external_web_app_manager_->SetSubsystems(pending_app_manager_.get());
     web_app_policy_manager_->SetSubsystems(pending_app_manager_.get());
   }
-  system_web_app_manager_->SetSubsystems(pending_app_manager_.get(),
-                                         registrar_.get(), ui_manager_.get());
 
   connected_ = true;
 }
@@ -185,6 +172,7 @@
 void WebAppProvider::OnRegistryReady() {
   DCHECK(!on_registry_ready_.is_signaled());
 
+  // TODO(crbug.com/877898): Port all these managers to support BMO. Start them.
   if (!base::FeatureList::IsEnabled(features::kDesktopPWAsWithoutExtensions)) {
     external_web_app_manager_->Start();
     web_app_policy_manager_->Start();
diff --git a/chrome/browser/web_applications/web_app_provider.h b/chrome/browser/web_applications/web_app_provider.h
index 0a85c2e0..5d1ef3c 100644
--- a/chrome/browser/web_applications/web_app_provider.h
+++ b/chrome/browser/web_applications/web_app_provider.h
@@ -78,12 +78,11 @@
 
   WebAppDatabaseFactory& database_factory() { return *database_factory_; }
   WebAppSyncManager& sync_manager() { return *sync_manager_; }
+  SystemWebAppManager& system_web_app_manager();
 
   // KeyedService:
   void Shutdown() override;
 
-  SystemWebAppManager& system_web_app_manager();
-
   static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
   static WebAppTabHelperBase* CreateTabHelper(
       content::WebContents* web_contents);
diff --git a/chrome/chrome_paks.gni b/chrome/chrome_paks.gni
index 8610cd3..829a8013 100644
--- a/chrome/chrome_paks.gni
+++ b/chrome/chrome_paks.gni
@@ -176,8 +176,8 @@
       ]
     }
     if (!is_android && !is_chromeos) {
-      sources += [ "$root_gen_dir/chrome/welcome_resources.pak" ]
-      deps += [ "//chrome/browser/resources:welcome_resources" ]
+      sources += [ "$root_gen_dir/chrome/onboarding_welcome_resources.pak" ]
+      deps += [ "//chrome/browser/resources:onboarding_welcome_resources" ]
     }
     if (enable_extensions) {
       sources += [
diff --git a/chrome/common/custom_handlers/protocol_handler.cc b/chrome/common/custom_handlers/protocol_handler.cc
index 19649d5..9afb863f 100644
--- a/chrome/common/custom_handlers/protocol_handler.cc
+++ b/chrome/common/custom_handlers/protocol_handler.cc
@@ -9,6 +9,8 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/value_conversions.h"
 #include "chrome/grit/generated_resources.h"
+#include "content/public/common/origin_util.h"
+#include "extensions/common/constants.h"
 #include "net/base/escape.h"
 #include "ui/base/l10n/l10n_util.h"
 
@@ -34,6 +36,36 @@
   return value->HasKey("protocol") && value->HasKey("url");
 }
 
+bool ProtocolHandler::IsValid() const {
+  // TODO(https://crbug.com/977083): Consider limiting to secure contexts.
+
+  // This matches SupportedSchemes() in blink's NavigatorContentUtils.
+
+  // Although not enforced in the spec the spec gives freedom to do additional
+  // security checks. Bugs have arisen from allowing non-http/https URLs, e.g.
+  // https://crbug.com/971917 so we check this here.
+  if (!url_.SchemeIsHTTPOrHTTPS() &&
+      !url_.SchemeIs(extensions::kExtensionScheme)) {
+    return false;
+  }
+
+  // From:
+  // https://html.spec.whatwg.org/multipage/system-state.html#safelisted-scheme
+  static constexpr const char* const kProtocolSafelist[] = {
+      "bitcoin", "geo",  "im",   "irc",         "ircs", "magnet", "mailto",
+      "mms",     "news", "nntp", "openpgp4fpr", "sip",  "sms",    "smsto",
+      "ssh",     "tel",  "urn",  "webcal",      "wtai", "xmpp"};
+  static constexpr const char kWebPrefix[] = "web+";
+
+  bool has_web_prefix =
+      base::StartsWith(protocol_, kWebPrefix,
+                       base::CompareCase::INSENSITIVE_ASCII) &&
+      protocol_ != kWebPrefix;
+
+  return has_web_prefix ||
+         base::Contains(kProtocolSafelist, base::ToLowerASCII(protocol_));
+}
+
 bool ProtocolHandler::IsSameOrigin(
     const ProtocolHandler& handler) const {
   return handler.url().GetOrigin() == url_.GetOrigin();
diff --git a/chrome/common/custom_handlers/protocol_handler.h b/chrome/common/custom_handlers/protocol_handler.h
index 36b56799..d538705 100644
--- a/chrome/common/custom_handlers/protocol_handler.h
+++ b/chrome/common/custom_handlers/protocol_handler.h
@@ -34,6 +34,9 @@
   // define a ProtocolHandler.
   static bool IsValidDict(const base::DictionaryValue* value);
 
+  // Return true if the protocol handler meets security constraints.
+  bool IsValid() const;
+
   // Returns true if this handler's url has the same origin as the given one.
   bool IsSameOrigin(const ProtocolHandler& handler) const;
 
diff --git a/chrome/common/extensions/api/autotest_private.idl b/chrome/common/extensions/api/autotest_private.idl
index d52f2e0..f1b72de8 100644
--- a/chrome/common/extensions/api/autotest_private.idl
+++ b/chrome/common/extensions/api/autotest_private.idl
@@ -13,6 +13,21 @@
     Bottom, Left, Right
   };
 
+  // A mapping of ash::ShelfItemType.
+  enum ShelfItemType {
+    App,
+    PinnedApp,
+    BrowserShortcut,
+    Dialog
+  };
+
+  // A mapping of ash::ShelfItemStatus.
+  enum ShelfItemStatus {
+    Closed,
+    Running,
+    Attention
+  };
+
   // A subset of Window State types in ash::WindowStateType. We may add more
   // into the set in the future.
   enum WindowStateType {
@@ -202,6 +217,19 @@
 
   callback SetTabletModeEnabledCallback = void(boolean enabled);
 
+  dictionary ShelfItem {
+    DOMString appId;
+    DOMString launchId;
+    DOMString title;
+    ShelfItemType? type;
+    ShelfItemStatus status;
+    boolean showsTooltip;
+    boolean pinnedByPolicy;
+    boolean hasNotification;
+  };
+
+  callback GetShelfItemsCallback = void (ShelfItem[] items);
+
   callback GetShelfAutoHideBehaviorCallback = void (DOMString behavior);
 
   callback GetShelfAlignmentCallback = void (ShelfAlignmentType alignment);
@@ -398,6 +426,9 @@
     static void setTabletModeEnabled(boolean enabled,
         SetTabletModeEnabledCallback callback);
 
+    // Get the list of all shelf items
+    static void getShelfItems(GetShelfItemsCallback callback);
+
     // Get the shelf auto hide behavior.
     // |displayId|: display that contains the shelf.
     // |callback| is invoked with the shelf auto hide behavior. Possible
diff --git a/chrome/common/extensions/docs/templates/intros/webRequest.html b/chrome/common/extensions/docs/templates/intros/webRequest.html
index 93b79c48..23fe70c 100644
--- a/chrome/common/extensions/docs/templates/intros/webRequest.html
+++ b/chrome/common/extensions/docs/templates/intros/webRequest.html
@@ -119,6 +119,15 @@
 </p>
 
 <p>
+<span class="availability">Starting from Chrome 76</span>, header modifications
+affect Cross-Origin Resource Sharing (CORS) checks. If modified headers for
+cross-origin requests do not meet a criteria, it will results in sending a CORS
+preflight to ask the server if such headers can be accepted.
+If you really need to modify headers in a way to violate the CORS protocol, you
+need to specify <code>'extraHeaders'</code> in <code>opt_extraInfoSpec</code>.
+</p>
+
+<p>
 <span class="availability">Starting from Chrome 72</span>, the following request
 headers are <strong>not provided</strong> and cannot be modified or removed
 without specifying <code>'extraHeaders'</code> in
diff --git a/chrome/renderer/safe_browsing/threat_dom_details_browsertest.cc b/chrome/renderer/safe_browsing/threat_dom_details_browsertest.cc
index ac4439b2..f8a0ae5 100644
--- a/chrome/renderer/safe_browsing/threat_dom_details_browsertest.cc
+++ b/chrome/renderer/safe_browsing/threat_dom_details_browsertest.cc
@@ -55,8 +55,6 @@
   safe_browsing::ThreatDOMDetails::kMaxAttributes = 5;
 
   const char kUrlPrefix[] = "data:text/html;charset=utf-8,";
-  const char kMaxNodesExceededMetric[] =
-      "SafeBrowsing.ThreatReport.MaxNodesExceededInFrame";
   {
     // A page with an internal script
     std::string html = "<html><head><script></script></head></html>";
@@ -71,8 +69,6 @@
     EXPECT_EQ(0, param->node_id);
     EXPECT_EQ(0, param->parent_node_id);
     EXPECT_TRUE(param->child_node_ids.empty());
-
-    histograms.ExpectBucketCount(kMaxNodesExceededMetric, false, 1);
   }
 
   {
@@ -219,8 +215,6 @@
       EXPECT_EQ(0, param.parent_node_id);
       EXPECT_TRUE(param.child_node_ids.empty());
     }
-
-    histograms.ExpectBucketCount(kMaxNodesExceededMetric, true, 1);
   }
 
   {
@@ -248,8 +242,6 @@
       EXPECT_EQ(0, param.parent_node_id);
       EXPECT_TRUE(param.child_node_ids.empty());
     }
-
-    histograms.ExpectBucketCount(kMaxNodesExceededMetric, true, 1);
   }
 
   {
@@ -417,8 +409,6 @@
                                               registry_.get()));
 
   const char kUrlPrefix[] = "data:text/html;charset=utf-8,";
-  const char kMaxNodesExceededMetric[] =
-      "SafeBrowsing.ThreatReport.MaxNodesExceededInFrame";
   {
     // A page with a html element without an onclick element, html element with
     // an onclick element, an internal script. Html elements without onclick
@@ -467,7 +457,5 @@
     EXPECT_EQ(0, param->node_id);
     EXPECT_EQ(0, param->parent_node_id);
     EXPECT_TRUE(param->child_node_ids.empty());
-
-    histograms.ExpectBucketCount(kMaxNodesExceededMetric, false, 1);
   }
 }
diff --git a/chrome/services/file_util/BUILD.gn b/chrome/services/file_util/BUILD.gn
index e565880..a8e5c994 100644
--- a/chrome/services/file_util/BUILD.gn
+++ b/chrome/services/file_util/BUILD.gn
@@ -5,7 +5,7 @@
 import("//build/config/features.gni")
 import("//components/safe_browsing/buildflags.gni")
 
-source_set("lib") {
+source_set("file_util") {
   sources = [
     "file_util_service.cc",
     "file_util_service.h",
@@ -19,8 +19,8 @@
 
   public_deps = [
     "//chrome/services/file_util/public/mojom",
+    "//mojo/public/cpp/bindings",
     "//mojo/public/mojom/base",
-    "//services/service_manager/public/cpp",
   ]
 
   if (is_chromeos) {
diff --git a/chrome/services/file_util/file_util_service.cc b/chrome/services/file_util/file_util_service.cc
index 7f35680..7fee5e7 100644
--- a/chrome/services/file_util/file_util_service.cc
+++ b/chrome/services/file_util/file_util_service.cc
@@ -9,7 +9,7 @@
 #include "base/bind.h"
 #include "build/build_config.h"
 #include "components/safe_browsing/buildflags.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "mojo/public/cpp/bindings/self_owned_receiver.h"
 
 #if BUILDFLAG(FULL_SAFE_BROWSING)
 #include "chrome/services/file_util/safe_archive_analyzer.h"
@@ -19,49 +19,24 @@
 #include "chrome/services/file_util/zip_file_creator.h"
 #endif
 
-namespace {
-
-#if BUILDFLAG(FULL_SAFE_BROWSING)
-void OnSafeArchiveAnalyzerRequest(
-    service_manager::ServiceKeepalive* keepalive,
-    chrome::mojom::SafeArchiveAnalyzerRequest request) {
-  mojo::MakeStrongBinding(
-      std::make_unique<SafeArchiveAnalyzer>(keepalive->CreateRef()),
-      std::move(request));
-}
-#endif
-
-#if defined(OS_CHROMEOS)
-void OnZipFileCreatorRequest(service_manager::ServiceKeepalive* keepalive,
-                             chrome::mojom::ZipFileCreatorRequest request) {
-  mojo::MakeStrongBinding(
-      std::make_unique<chrome::ZipFileCreator>(keepalive->CreateRef()),
-      std::move(request));
-}
-#endif
-
-}  // namespace
-
-FileUtilService::FileUtilService(service_manager::mojom::ServiceRequest request)
-    : service_binding_(this, std::move(request)),
-      service_keepalive_(&service_binding_, base::TimeDelta()) {}
+FileUtilService::FileUtilService(
+    mojo::PendingReceiver<chrome::mojom::FileUtilService> receiver)
+    : receiver_(this, std::move(receiver)) {}
 
 FileUtilService::~FileUtilService() = default;
 
-void FileUtilService::OnStart() {
 #if defined(OS_CHROMEOS)
-  registry_.AddInterface(
-      base::BindRepeating(&OnZipFileCreatorRequest, &service_keepalive_));
-#endif
-#if BUILDFLAG(FULL_SAFE_BROWSING)
-  registry_.AddInterface(
-      base::BindRepeating(&OnSafeArchiveAnalyzerRequest, &service_keepalive_));
-#endif
+void FileUtilService::BindZipFileCreator(
+    mojo::PendingReceiver<chrome::mojom::ZipFileCreator> receiver) {
+  mojo::MakeSelfOwnedReceiver(std::make_unique<chrome::ZipFileCreator>(),
+                              std::move(receiver));
 }
+#endif
 
-void FileUtilService::OnBindInterface(
-    const service_manager::BindSourceInfo& source_info,
-    const std::string& interface_name,
-    mojo::ScopedMessagePipeHandle interface_pipe) {
-  registry_.BindInterface(interface_name, std::move(interface_pipe));
+#if BUILDFLAG(FULL_SAFE_BROWSING)
+void FileUtilService::BindSafeArchiveAnalyzer(
+    mojo::PendingReceiver<chrome::mojom::SafeArchiveAnalyzer> receiver) {
+  mojo::MakeSelfOwnedReceiver(std::make_unique<SafeArchiveAnalyzer>(),
+                              std::move(receiver));
 }
+#endif
diff --git a/chrome/services/file_util/file_util_service.h b/chrome/services/file_util/file_util_service.h
index 316522d..db054a7 100644
--- a/chrome/services/file_util/file_util_service.h
+++ b/chrome/services/file_util/file_util_service.h
@@ -5,26 +5,32 @@
 #ifndef CHROME_SERVICES_FILE_UTIL_FILE_UTIL_SERVICE_H_
 #define CHROME_SERVICES_FILE_UTIL_FILE_UTIL_SERVICE_H_
 
-#include "services/service_manager/public/cpp/binder_registry.h"
-#include "services/service_manager/public/cpp/service.h"
-#include "services/service_manager/public/cpp/service_binding.h"
-#include "services/service_manager/public/cpp/service_keepalive.h"
+#include "build/build_config.h"
+#include "chrome/services/file_util/public/mojom/file_util_service.mojom.h"
+#include "components/safe_browsing/buildflags.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/receiver.h"
 
-class FileUtilService : public service_manager::Service {
+class FileUtilService : public chrome::mojom::FileUtilService {
  public:
-  explicit FileUtilService(service_manager::mojom::ServiceRequest request);
+  explicit FileUtilService(
+      mojo::PendingReceiver<chrome::mojom::FileUtilService> receiver);
   ~FileUtilService() override;
 
-  // Lifescycle events that occur after the service has started to spinup.
-  void OnStart() override;
-  void OnBindInterface(const service_manager::BindSourceInfo& source_info,
-                       const std::string& interface_name,
-                       mojo::ScopedMessagePipeHandle interface_pipe) override;
-
  private:
-  service_manager::ServiceBinding service_binding_;
-  service_manager::ServiceKeepalive service_keepalive_;
-  service_manager::BinderRegistry registry_;
+  // chrome::mojom::FileUtilService implementation:
+#if defined(OS_CHROMEOS)
+  void BindZipFileCreator(
+      mojo::PendingReceiver<chrome::mojom::ZipFileCreator> receiver) override;
+#endif
+
+#if BUILDFLAG(FULL_SAFE_BROWSING)
+  void BindSafeArchiveAnalyzer(
+      mojo::PendingReceiver<chrome::mojom::SafeArchiveAnalyzer> receiver)
+      override;
+#endif
+
+  mojo::Receiver<chrome::mojom::FileUtilService> receiver_;
 
   DISALLOW_COPY_AND_ASSIGN(FileUtilService);
 };
diff --git a/chrome/services/file_util/public/cpp/BUILD.gn b/chrome/services/file_util/public/cpp/BUILD.gn
index c57a73c..7c7aff4 100644
--- a/chrome/services/file_util/public/cpp/BUILD.gn
+++ b/chrome/services/file_util/public/cpp/BUILD.gn
@@ -8,7 +8,6 @@
 source_set("cpp") {
   public_deps = [
     "//chrome/services/file_util/public/mojom",
-    "//services/service_manager/public/cpp",
   ]
 
   if (safe_browsing_mode == 1) {
@@ -31,21 +30,6 @@
   }
 }
 
-source_set("manifest") {
-  sources = [
-    "manifest.cc",
-    "manifest.h",
-  ]
-
-  deps = [
-    "//base",
-    "//chrome:strings",
-    "//chrome/services/file_util/public/mojom",
-    "//components/safe_browsing:buildflags",
-    "//services/service_manager/public/cpp",
-  ]
-}
-
 if (safe_browsing_mode == 1) {
   source_set("unit_tests") {
     testonly = true
@@ -58,9 +42,8 @@
 
     deps = [
       ":cpp",
-      "//chrome/services/file_util:lib",
+      "//chrome/services/file_util",
       "//crypto:platform",
-      "//services/service_manager/public/cpp/test:test_support",
       "//skia",
       "//testing/gmock",
       "//testing/gtest",
@@ -80,6 +63,7 @@
     deps = [
       "//base",
       "//chrome/test:test_support",
+      "//content/public/browser",
       "//content/public/common",
       "//content/test:test_support",
       "//testing/gtest",
diff --git a/chrome/services/file_util/public/cpp/manifest.cc b/chrome/services/file_util/public/cpp/manifest.cc
deleted file mode 100644
index 3033d15..0000000
--- a/chrome/services/file_util/public/cpp/manifest.cc
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/services/file_util/public/cpp/manifest.h"
-
-#include "base/no_destructor.h"
-#include "build/build_config.h"
-#include "chrome/grit/generated_resources.h"
-#include "chrome/services/file_util/public/mojom/constants.mojom.h"
-#include "components/safe_browsing/buildflags.h"
-#include "services/service_manager/public/cpp/manifest_builder.h"
-
-#if defined(OS_CHROMEOS)
-#include "chrome/services/file_util/public/mojom/zip_file_creator.mojom.h"
-#endif
-
-#if BUILDFLAG(FULL_SAFE_BROWSING)
-#include "chrome/services/file_util/public/mojom/safe_archive_analyzer.mojom.h"
-#endif
-
-const service_manager::Manifest& GetFileUtilManifest() {
-  static base::NoDestructor<service_manager::Manifest> manifest {
-    service_manager::ManifestBuilder()
-        .WithServiceName(chrome::mojom::kFileUtilServiceName)
-        .WithDisplayName(IDS_UTILITY_PROCESS_FILE_UTILITY_NAME)
-        .WithOptions(
-            service_manager::ManifestOptionsBuilder()
-                .WithExecutionMode(service_manager::Manifest::ExecutionMode::
-                                       kOutOfProcessBuiltin)
-                .WithSandboxType("utility")
-                .WithInstanceSharingPolicy(
-                    service_manager::Manifest::InstanceSharingPolicy::
-                        kSharedAcrossGroups)
-                .Build())
-#if defined(OS_CHROMEOS)
-        .ExposeCapability("zip_file", service_manager::Manifest::InterfaceList<
-                                          chrome::mojom::ZipFileCreator>())
-#endif
-#if BUILDFLAG(FULL_SAFE_BROWSING)
-        .ExposeCapability("analyze_archive",
-                          service_manager::Manifest::InterfaceList<
-                              chrome::mojom::SafeArchiveAnalyzer>())
-#endif
-        .Build()
-  };
-  return *manifest;
-}
diff --git a/chrome/services/file_util/public/cpp/manifest.h b/chrome/services/file_util/public/cpp/manifest.h
deleted file mode 100644
index 392e496..0000000
--- a/chrome/services/file_util/public/cpp/manifest.h
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_SERVICES_FILE_UTIL_PUBLIC_CPP_MANIFEST_H_
-#define CHROME_SERVICES_FILE_UTIL_PUBLIC_CPP_MANIFEST_H_
-
-#include "services/service_manager/public/cpp/manifest.h"
-
-const service_manager::Manifest& GetFileUtilManifest();
-
-#endif  // CHROME_SERVICES_FILE_UTIL_PUBLIC_CPP_MANIFEST_H_
diff --git a/chrome/services/file_util/public/cpp/sandboxed_dmg_analyzer_mac.cc b/chrome/services/file_util/public/cpp/sandboxed_dmg_analyzer_mac.cc
index 37e8398..e1c6c9e4 100644
--- a/chrome/services/file_util/public/cpp/sandboxed_dmg_analyzer_mac.cc
+++ b/chrome/services/file_util/public/cpp/sandboxed_dmg_analyzer_mac.cc
@@ -10,21 +10,24 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/task/post_task.h"
 #include "chrome/common/safe_browsing/archive_analyzer_results.h"
-#include "chrome/services/file_util/public/mojom/constants.mojom.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
-#include "services/service_manager/public/cpp/connector.h"
 
 SandboxedDMGAnalyzer::SandboxedDMGAnalyzer(
     const base::FilePath& dmg_file,
     const uint64_t max_size,
     const ResultCallback& callback,
-    service_manager::Connector* connector)
+    mojo::PendingRemote<chrome::mojom::FileUtilService> service)
     : file_path_(dmg_file),
       max_size_(max_size),
       callback_(callback),
-      connector_(connector) {
+      service_(std::move(service)) {
   DCHECK(callback);
+  service_->BindSafeArchiveAnalyzer(
+      remote_analyzer_.BindNewPipeAndPassReceiver());
+  remote_analyzer_.set_disconnect_handler(base::BindOnce(
+      &SandboxedDMGAnalyzer::AnalyzeFileDone, base::Unretained(this),
+      safe_browsing::ArchiveAnalyzerResults()));
 }
 
 void SandboxedDMGAnalyzer::Start() {
@@ -66,7 +69,6 @@
 
 void SandboxedDMGAnalyzer::ReportFileFailure() {
   DCHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
-  DCHECK(!analyzer_ptr_);
 
   base::PostTask(
       FROM_HERE, {content::BrowserThread::UI},
@@ -75,22 +77,15 @@
 
 void SandboxedDMGAnalyzer::AnalyzeFile(base::File file) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  DCHECK(!analyzer_ptr_);
-
-  connector_->BindInterface(chrome::mojom::kFileUtilServiceName,
-                            mojo::MakeRequest(&analyzer_ptr_));
-  analyzer_ptr_.set_connection_error_handler(
-      base::Bind(&SandboxedDMGAnalyzer::AnalyzeFileDone, base::Unretained(this),
-                 safe_browsing::ArchiveAnalyzerResults()));
-  analyzer_ptr_->AnalyzeDmgFile(
+  remote_analyzer_->AnalyzeDmgFile(
       std::move(file),
-      base::Bind(&SandboxedDMGAnalyzer::AnalyzeFileDone, this));
+      base::BindOnce(&SandboxedDMGAnalyzer::AnalyzeFileDone, this));
 }
 
 void SandboxedDMGAnalyzer::AnalyzeFileDone(
     const safe_browsing::ArchiveAnalyzerResults& results) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
-  analyzer_ptr_.reset();
+  remote_analyzer_.reset();
   callback_.Run(results);
 }
diff --git a/chrome/services/file_util/public/cpp/sandboxed_dmg_analyzer_mac.h b/chrome/services/file_util/public/cpp/sandboxed_dmg_analyzer_mac.h
index f8c790c..de4f41e2 100644
--- a/chrome/services/file_util/public/cpp/sandboxed_dmg_analyzer_mac.h
+++ b/chrome/services/file_util/public/cpp/sandboxed_dmg_analyzer_mac.h
@@ -10,16 +10,15 @@
 #include "base/files/file_path.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
+#include "chrome/services/file_util/public/mojom/file_util_service.mojom.h"
 #include "chrome/services/file_util/public/mojom/safe_archive_analyzer.mojom.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/remote.h"
 
 namespace safe_browsing {
 struct ArchiveAnalyzerResults;
 }
 
-namespace service_manager {
-class Connector;
-}
-
 // This class is used to analyze DMG files in a sandboxed utility process
 // for file download protection. This class lives on the UI thread, which
 // is where the result callback will be invoked.
@@ -29,10 +28,11 @@
   using ResultCallback =
       base::Callback<void(const safe_browsing::ArchiveAnalyzerResults&)>;
 
-  SandboxedDMGAnalyzer(const base::FilePath& dmg_file,
-                       const uint64_t max_size,
-                       const ResultCallback& callback,
-                       service_manager::Connector* connector);
+  SandboxedDMGAnalyzer(
+      const base::FilePath& dmg_file,
+      const uint64_t max_size,
+      const ResultCallback& callback,
+      mojo::PendingRemote<chrome::mojom::FileUtilService> service);
 
   // Starts the analysis. Must be called on the UI thread.
   void Start();
@@ -63,11 +63,9 @@
   // Callback invoked on the UI thread with the file analyze results.
   const ResultCallback callback_;
 
-  // The connector to the service manager, only used on the UI thread.
-  service_manager::Connector* connector_;
-
-  // Pointer to the SafeArchiveAnalyzer interface. Only used from the UI thread.
-  chrome::mojom::SafeArchiveAnalyzerPtr analyzer_ptr_;
+  // Remote interfaces to the file util service. Only used from the UI thread.
+  mojo::Remote<chrome::mojom::FileUtilService> service_;
+  mojo::Remote<chrome::mojom::SafeArchiveAnalyzer> remote_analyzer_;
 
   DISALLOW_COPY_AND_ASSIGN(SandboxedDMGAnalyzer);
 };
diff --git a/chrome/services/file_util/public/cpp/sandboxed_dmg_analyzer_mac_unittest.cc b/chrome/services/file_util/public/cpp/sandboxed_dmg_analyzer_mac_unittest.cc
index bd35d0a..6f9117c 100644
--- a/chrome/services/file_util/public/cpp/sandboxed_dmg_analyzer_mac_unittest.cc
+++ b/chrome/services/file_util/public/cpp/sandboxed_dmg_analyzer_mac_unittest.cc
@@ -18,10 +18,9 @@
 #include "chrome/common/safe_browsing/archive_analyzer_results.h"
 #include "chrome/common/safe_browsing/file_type_policies.h"
 #include "chrome/services/file_util/file_util_service.h"
-#include "chrome/services/file_util/public/mojom/constants.mojom.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "content/public/test/test_utils.h"
-#include "services/service_manager/public/cpp/test/test_connector_factory.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace {
@@ -29,20 +28,19 @@
 class SandboxedDMGAnalyzerTest : public testing::Test {
  public:
   SandboxedDMGAnalyzerTest()
-      : browser_thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP),
-        file_util_service_(test_connector_factory_.RegisterInstance(
-            chrome::mojom::kFileUtilServiceName)) {}
+      : browser_thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) {}
 
   void AnalyzeFile(const base::FilePath& path,
                    safe_browsing::ArchiveAnalyzerResults* results) {
+    mojo::PendingRemote<chrome::mojom::FileUtilService> remote;
+    FileUtilService service(remote.InitWithNewPipeAndPassReceiver());
     base::RunLoop run_loop;
     ResultsGetter results_getter(run_loop.QuitClosure(), results);
     scoped_refptr<SandboxedDMGAnalyzer> analyzer(new SandboxedDMGAnalyzer(
         path,
         safe_browsing::FileTypePolicies::GetInstance()->GetMaxFileSizeToAnalyze(
             "dmg"),
-        results_getter.GetCallback(),
-        test_connector_factory_.GetDefaultConnector()));
+        results_getter.GetCallback(), std::move(remote)));
     analyzer->Start();
     run_loop.Run();
   }
@@ -83,9 +81,6 @@
   };
 
   content::TestBrowserThreadBundle browser_thread_bundle_;
-  content::InProcessUtilityThreadHelper utility_thread_helper_;
-  service_manager::TestConnectorFactory test_connector_factory_;
-  FileUtilService file_util_service_;
 };
 
 TEST_F(SandboxedDMGAnalyzerTest, AnalyzeDMG) {
diff --git a/chrome/services/file_util/public/cpp/sandboxed_rar_analyzer.cc b/chrome/services/file_util/public/cpp/sandboxed_rar_analyzer.cc
index 8e74c1c..a0a9e46 100644
--- a/chrome/services/file_util/public/cpp/sandboxed_rar_analyzer.cc
+++ b/chrome/services/file_util/public/cpp/sandboxed_rar_analyzer.cc
@@ -12,19 +12,24 @@
 #include "base/strings/stringprintf.h"
 #include "base/task/post_task.h"
 #include "chrome/common/safe_browsing/archive_analyzer_results.h"
-#include "chrome/services/file_util/public/mojom/constants.mojom.h"
 #include "chrome/services/file_util/public/mojom/safe_archive_analyzer.mojom.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
-#include "services/service_manager/public/cpp/connector.h"
 
 SandboxedRarAnalyzer::SandboxedRarAnalyzer(
     const base::FilePath& rar_file_path,
     const ResultCallback& callback,
-    service_manager::Connector* connector)
-    : file_path_(rar_file_path), callback_(callback), connector_(connector) {
+    mojo::PendingRemote<chrome::mojom::FileUtilService> service)
+    : file_path_(rar_file_path),
+      callback_(callback),
+      service_(std::move(service)) {
   DCHECK(callback);
   DCHECK(!file_path_.value().empty());
+  service_->BindSafeArchiveAnalyzer(
+      remote_analyzer_.BindNewPipeAndPassReceiver());
+  remote_analyzer_.set_disconnect_handler(base::BindOnce(
+      &SandboxedRarAnalyzer::AnalyzeFileDone, base::Unretained(this),
+      safe_browsing::ArchiveAnalyzerResults()));
 }
 
 void SandboxedRarAnalyzer::Start() {
@@ -41,15 +46,8 @@
 
 void SandboxedRarAnalyzer::AnalyzeFile(base::File file, base::File temp_file) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  DCHECK(!analyzer_ptr_);
   DCHECK(!file_path_.value().empty());
-
-  connector_->BindInterface(chrome::mojom::kFileUtilServiceName,
-                            mojo::MakeRequest(&analyzer_ptr_));
-  analyzer_ptr_.set_connection_error_handler(base::BindOnce(
-      &SandboxedRarAnalyzer::AnalyzeFileDone, base::Unretained(this),
-      safe_browsing::ArchiveAnalyzerResults()));
-  analyzer_ptr_->AnalyzeRarFile(
+  remote_analyzer_->AnalyzeRarFile(
       std::move(file), std::move(temp_file),
       base::BindOnce(&SandboxedRarAnalyzer::AnalyzeFileDone, this));
 }
@@ -57,7 +55,7 @@
 void SandboxedRarAnalyzer::AnalyzeFileDone(
     const safe_browsing::ArchiveAnalyzerResults& results) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  analyzer_ptr_.reset();
+  remote_analyzer_.reset();
   callback_.Run(results);
 }
 
@@ -98,15 +96,15 @@
 }
 
 void SandboxedRarAnalyzer::ReportFileFailure() {
-  DCHECK(!analyzer_ptr_);
   base::PostTask(
       FROM_HERE, {content::BrowserThread::UI},
       base::BindOnce(callback_, safe_browsing::ArchiveAnalyzerResults()));
 }
 
 std::string SandboxedRarAnalyzer::DebugString() const {
-  return base::StringPrintf("path: %" PRFilePath "; analyzer_ptr_: %p",
-                            file_path_.value().c_str(), analyzer_ptr_.get());
+  return base::StringPrintf("path: %" PRFilePath "; connected_: %d",
+                            file_path_.value().c_str(),
+                            remote_analyzer_.is_connected());
 }
 
 std::ostream& operator<<(std::ostream& os,
diff --git a/chrome/services/file_util/public/cpp/sandboxed_rar_analyzer.h b/chrome/services/file_util/public/cpp/sandboxed_rar_analyzer.h
index fb10f7ab..20d9e3b 100644
--- a/chrome/services/file_util/public/cpp/sandboxed_rar_analyzer.h
+++ b/chrome/services/file_util/public/cpp/sandboxed_rar_analyzer.h
@@ -9,16 +9,15 @@
 #include "base/files/file_path.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
+#include "chrome/services/file_util/public/mojom/file_util_service.mojom.h"
 #include "chrome/services/file_util/public/mojom/safe_archive_analyzer.mojom.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/remote.h"
 
 namespace safe_browsing {
 struct ArchiveAnalyzerResults;
 }
 
-namespace service_manager {
-class Connector;
-}
-
 // This class is used to analyze rar files in a sandbox for file download
 // protection. This class lives on the UI thread, which is where the result
 // callback will be invoked.
@@ -28,9 +27,10 @@
   using ResultCallback = base::RepeatingCallback<void(
       const safe_browsing::ArchiveAnalyzerResults&)>;
 
-  SandboxedRarAnalyzer(const base::FilePath& rar_file_path,
-                       const ResultCallback& callback,
-                       service_manager::Connector* connector);
+  SandboxedRarAnalyzer(
+      const base::FilePath& rar_file_path,
+      const ResultCallback& callback,
+      mojo::PendingRemote<chrome::mojom::FileUtilService> service);
 
   // Starts the analysis. Must be called on the UI thread.
   void Start();
@@ -62,11 +62,9 @@
   // Callback invoked on the UI thread with the file analyze results.
   const ResultCallback callback_;
 
-  // The connector to the service manager, only used on the UI thread.
-  service_manager::Connector* connector_;
-
-  // Pointer to the SafeArchiveAnalyzer interface. Only used from the UI thread.
-  chrome::mojom::SafeArchiveAnalyzerPtr analyzer_ptr_;
+  // Remote interfaces to the file util service. Only used from the UI thread.
+  mojo::Remote<chrome::mojom::FileUtilService> service_;
+  mojo::Remote<chrome::mojom::SafeArchiveAnalyzer> remote_analyzer_;
 
   DISALLOW_COPY_AND_ASSIGN(SandboxedRarAnalyzer);
 };
diff --git a/chrome/services/file_util/public/cpp/sandboxed_rar_analyzer_unittest.cc b/chrome/services/file_util/public/cpp/sandboxed_rar_analyzer_unittest.cc
index 9a1245a..9e4453f 100644
--- a/chrome/services/file_util/public/cpp/sandboxed_rar_analyzer_unittest.cc
+++ b/chrome/services/file_util/public/cpp/sandboxed_rar_analyzer_unittest.cc
@@ -18,12 +18,11 @@
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/safe_browsing/archive_analyzer_results.h"
 #include "chrome/services/file_util/file_util_service.h"
-#include "chrome/services/file_util/public/mojom/constants.mojom.h"
 #include "components/safe_browsing/features.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "content/public/test/test_utils.h"
 #include "crypto/sha2.h"
-#include "services/service_manager/public/cpp/test/test_connector_factory.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -48,17 +47,16 @@
 
  public:
   SandboxedRarAnalyzerTest()
-      : browser_thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP),
-        file_util_service_(test_connector_factory_.RegisterInstance(
-            chrome::mojom::kFileUtilServiceName)) {}
+      : browser_thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) {}
 
   void AnalyzeFile(const base::FilePath& path,
                    safe_browsing::ArchiveAnalyzerResults* results) {
+    mojo::PendingRemote<chrome::mojom::FileUtilService> remote;
+    FileUtilService service(remote.InitWithNewPipeAndPassReceiver());
     base::RunLoop run_loop;
     ResultsGetter results_getter(run_loop.QuitClosure(), results);
     scoped_refptr<SandboxedRarAnalyzer> analyzer(new SandboxedRarAnalyzer(
-        path, results_getter.GetCallback(),
-        test_connector_factory_.GetDefaultConnector()));
+        path, results_getter.GetCallback(), std::move(remote)));
     analyzer->Start();
     run_loop.Run();
   }
@@ -124,9 +122,6 @@
   };
 
   content::TestBrowserThreadBundle browser_thread_bundle_;
-  content::InProcessUtilityThreadHelper utility_thread_helper_;
-  service_manager::TestConnectorFactory test_connector_factory_;
-  FileUtilService file_util_service_;
 };
 
 // static
diff --git a/chrome/services/file_util/public/cpp/sandboxed_zip_analyzer.cc b/chrome/services/file_util/public/cpp/sandboxed_zip_analyzer.cc
index b0cf14a..962a7a0 100644
--- a/chrome/services/file_util/public/cpp/sandboxed_zip_analyzer.cc
+++ b/chrome/services/file_util/public/cpp/sandboxed_zip_analyzer.cc
@@ -10,18 +10,21 @@
 #include "base/files/file_util.h"
 #include "base/task/post_task.h"
 #include "chrome/common/safe_browsing/archive_analyzer_results.h"
-#include "chrome/services/file_util/public/mojom/constants.mojom.h"
 #include "chrome/services/file_util/public/mojom/safe_archive_analyzer.mojom.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
-#include "services/service_manager/public/cpp/connector.h"
 
 SandboxedZipAnalyzer::SandboxedZipAnalyzer(
     const base::FilePath& zip_file,
     const ResultCallback& callback,
-    service_manager::Connector* connector)
-    : file_path_(zip_file), callback_(callback), connector_(connector) {
+    mojo::PendingRemote<chrome::mojom::FileUtilService> service)
+    : file_path_(zip_file), callback_(callback), service_(std::move(service)) {
   DCHECK(callback);
+  service_->BindSafeArchiveAnalyzer(
+      remote_analyzer_.BindNewPipeAndPassReceiver());
+  remote_analyzer_.set_disconnect_handler(base::BindOnce(
+      &SandboxedZipAnalyzer::AnalyzeFileDone, base::Unretained(this),
+      safe_browsing::ArchiveAnalyzerResults()));
 }
 
 void SandboxedZipAnalyzer::Start() {
@@ -66,8 +69,6 @@
 }
 
 void SandboxedZipAnalyzer::ReportFileFailure() {
-  DCHECK(!analyzer_ptr_);
-
   base::PostTask(
       FROM_HERE, {content::BrowserThread::UI},
       base::BindOnce(callback_, safe_browsing::ArchiveAnalyzerResults()));
@@ -75,22 +76,15 @@
 
 void SandboxedZipAnalyzer::AnalyzeFile(base::File file, base::File temp_file) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  DCHECK(!analyzer_ptr_);
-
-  connector_->BindInterface(chrome::mojom::kFileUtilServiceName,
-                            mojo::MakeRequest(&analyzer_ptr_));
-  analyzer_ptr_.set_connection_error_handler(
-      base::Bind(&SandboxedZipAnalyzer::AnalyzeFileDone, base::Unretained(this),
-                 safe_browsing::ArchiveAnalyzerResults()));
-  analyzer_ptr_->AnalyzeZipFile(
+  remote_analyzer_->AnalyzeZipFile(
       std::move(file), std::move(temp_file),
-      base::Bind(&SandboxedZipAnalyzer::AnalyzeFileDone, this));
+      base::BindOnce(&SandboxedZipAnalyzer::AnalyzeFileDone, this));
 }
 
 void SandboxedZipAnalyzer::AnalyzeFileDone(
     const safe_browsing::ArchiveAnalyzerResults& results) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
-  analyzer_ptr_.reset();
+  remote_analyzer_.reset();
   callback_.Run(results);
 }
diff --git a/chrome/services/file_util/public/cpp/sandboxed_zip_analyzer.h b/chrome/services/file_util/public/cpp/sandboxed_zip_analyzer.h
index 59ea36b..74cc44a5 100644
--- a/chrome/services/file_util/public/cpp/sandboxed_zip_analyzer.h
+++ b/chrome/services/file_util/public/cpp/sandboxed_zip_analyzer.h
@@ -10,16 +10,15 @@
 #include "base/files/file_path.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
+#include "chrome/services/file_util/public/mojom/file_util_service.mojom.h"
 #include "chrome/services/file_util/public/mojom/safe_archive_analyzer.mojom.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/remote.h"
 
 namespace safe_browsing {
 struct ArchiveAnalyzerResults;
 }
 
-namespace service_manager {
-class Connector;
-}
-
 // This class is used to analyze zip files in a sandboxed utility process for
 // file download protection. This class lives on the UI thread, which is where
 // the result callback will be invoked.
@@ -29,9 +28,10 @@
   using ResultCallback =
       base::Callback<void(const safe_browsing::ArchiveAnalyzerResults&)>;
 
-  SandboxedZipAnalyzer(const base::FilePath& zip_file,
-                       const ResultCallback& callback,
-                       service_manager::Connector* connector);
+  SandboxedZipAnalyzer(
+      const base::FilePath& zip_file,
+      const ResultCallback& callback,
+      mojo::PendingRemote<chrome::mojom::FileUtilService> service);
 
   // Starts the analysis. Must be called on the UI thread.
   void Start();
@@ -59,11 +59,9 @@
   // Callback invoked on the UI thread with the file analyze results.
   const ResultCallback callback_;
 
-  // The connector to the service manager, only used on the UI thread.
-  service_manager::Connector* connector_;
-
-  // Pointer to the SafeArchiveAnalyzer interface. Only used from the UI thread.
-  chrome::mojom::SafeArchiveAnalyzerPtr analyzer_ptr_;
+  // Remote interfaces to the file util service. Only used from the UI thread.
+  mojo::Remote<chrome::mojom::FileUtilService> service_;
+  mojo::Remote<chrome::mojom::SafeArchiveAnalyzer> remote_analyzer_;
 
   DISALLOW_COPY_AND_ASSIGN(SandboxedZipAnalyzer);
 };
diff --git a/chrome/services/file_util/public/cpp/sandboxed_zip_analyzer_unittest.cc b/chrome/services/file_util/public/cpp/sandboxed_zip_analyzer_unittest.cc
index 55d41f6d..596431e3 100644
--- a/chrome/services/file_util/public/cpp/sandboxed_zip_analyzer_unittest.cc
+++ b/chrome/services/file_util/public/cpp/sandboxed_zip_analyzer_unittest.cc
@@ -17,11 +17,10 @@
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/safe_browsing/archive_analyzer_results.h"
 #include "chrome/services/file_util/file_util_service.h"
-#include "chrome/services/file_util/public/mojom/constants.mojom.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "content/public/test/test_utils.h"
 #include "crypto/sha2.h"
-#include "services/service_manager/public/cpp/test/test_connector_factory.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -74,9 +73,7 @@
   };
 
   SandboxedZipAnalyzerTest()
-      : browser_thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP),
-        file_util_service_(test_connector_factory_.RegisterInstance(
-            chrome::mojom::kFileUtilServiceName)) {}
+      : browser_thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) {}
 
   void SetUp() override {
     ASSERT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &dir_test_data_));
@@ -88,11 +85,12 @@
   void RunAnalyzer(const base::FilePath& file_path,
                    safe_browsing::ArchiveAnalyzerResults* results) {
     DCHECK(results);
+    mojo::PendingRemote<chrome::mojom::FileUtilService> remote;
+    FileUtilService service(remote.InitWithNewPipeAndPassReceiver());
     base::RunLoop run_loop;
     ResultsGetter results_getter(run_loop.QuitClosure(), results);
     scoped_refptr<SandboxedZipAnalyzer> analyzer(new SandboxedZipAnalyzer(
-        file_path, results_getter.GetCallback(),
-        test_connector_factory_.GetDefaultConnector()));
+        file_path, results_getter.GetCallback(), std::move(remote)));
     analyzer->Start();
     run_loop.Run();
   }
@@ -185,9 +183,6 @@
 
   base::FilePath dir_test_data_;
   content::TestBrowserThreadBundle browser_thread_bundle_;
-  content::InProcessUtilityThreadHelper utility_thread_helper_;
-  service_manager::TestConnectorFactory test_connector_factory_;
-  FileUtilService file_util_service_;
 };
 
 // static
diff --git a/chrome/services/file_util/public/cpp/zip_file_creator.cc b/chrome/services/file_util/public/cpp/zip_file_creator.cc
index cf1e7c5..69402bd 100644
--- a/chrome/services/file_util/public/cpp/zip_file_creator.cc
+++ b/chrome/services/file_util/public/cpp/zip_file_creator.cc
@@ -8,12 +8,10 @@
 
 #include "base/bind.h"
 #include "base/task/post_task.h"
-#include "chrome/services/file_util/public/mojom/constants.mojom.h"
 #include "components/services/filesystem/directory_impl.h"
 #include "components/services/filesystem/lock_table.h"
 #include "content/public/browser/browser_thread.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
-#include "services/service_manager/public/cpp/connector.h"
+#include "mojo/public/cpp/bindings/self_owned_receiver.h"
 
 namespace {
 
@@ -24,44 +22,46 @@
 
 void BindDirectoryInBackground(
     const base::FilePath& src_dir,
-    mojo::InterfaceRequest<filesystem::mojom::Directory> request) {
+    mojo::PendingReceiver<filesystem::mojom::Directory> receiver) {
   auto directory_impl = std::make_unique<filesystem::DirectoryImpl>(
       src_dir, /*temp_dir=*/nullptr, /*lock_table=*/nullptr);
-  mojo::MakeStrongBinding(std::move(directory_impl), std::move(request));
+  mojo::MakeSelfOwnedReceiver(std::move(directory_impl), std::move(receiver));
 }
 
 }  // namespace
 
 ZipFileCreator::ZipFileCreator(
-    const ResultCallback& callback,
+    ResultCallback callback,
     const base::FilePath& src_dir,
     const std::vector<base::FilePath>& src_relative_paths,
     const base::FilePath& dest_file)
-    : callback_(callback),
+    : callback_(std::move(callback)),
       src_dir_(src_dir),
       src_relative_paths_(src_relative_paths),
       dest_file_(dest_file) {
-  DCHECK(!callback_.is_null());
+  DCHECK(callback_);
 }
 
-void ZipFileCreator::Start(service_manager::Connector* connector) {
+void ZipFileCreator::Start(
+    mojo::PendingRemote<chrome::mojom::FileUtilService> service) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
   // Note this class owns itself (it self-deletes when finished in ReportDone),
   // so it is safe to use base::Unretained(this).
   base::PostTaskAndReplyWithResult(
       FROM_HERE, {base::ThreadPool(), base::MayBlock()},
-      base::Bind(&OpenFileHandleAsync, dest_file_),
-      base::Bind(&ZipFileCreator::CreateZipFile, base::Unretained(this),
-                 base::Unretained(connector)));
+      base::BindOnce(&OpenFileHandleAsync, dest_file_),
+      base::BindOnce(&ZipFileCreator::CreateZipFile, base::Unretained(this),
+                     std::move(service)));
 }
 
 ZipFileCreator::~ZipFileCreator() = default;
 
-void ZipFileCreator::CreateZipFile(service_manager::Connector* connector,
-                                   base::File file) {
+void ZipFileCreator::CreateZipFile(
+    mojo::PendingRemote<chrome::mojom::FileUtilService> service,
+    base::File file) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  DCHECK(!zip_file_creator_ptr_);
+  DCHECK(!remote_zip_file_creator_);
 
   if (!file.IsValid()) {
     LOG(ERROR) << "Failed to create dest zip file " << dest_file_.value();
@@ -76,27 +76,27 @@
          base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN});
   }
 
-  filesystem::mojom::DirectoryPtr directory_ptr;
-  mojo::InterfaceRequest<filesystem::mojom::Directory> request =
-      mojo::MakeRequest(&directory_ptr);
+  mojo::PendingRemote<filesystem::mojom::Directory> directory;
   directory_task_runner_->PostTask(
       FROM_HERE, base::BindOnce(&BindDirectoryInBackground, src_dir_,
-                                base::Passed(&request)));
+                                directory.InitWithNewPipeAndPassReceiver()));
 
-  connector->BindInterface(chrome::mojom::kFileUtilServiceName,
-                           mojo::MakeRequest(&zip_file_creator_ptr_));
+  service_.Bind(std::move(service));
+  service_->BindZipFileCreator(
+      remote_zip_file_creator_.BindNewPipeAndPassReceiver());
+
   // See comment in Start() on why using base::Unretained(this) is safe.
-  zip_file_creator_ptr_.set_connection_error_handler(
-      base::Bind(&ZipFileCreator::ReportDone, base::Unretained(this), false));
-  zip_file_creator_ptr_->CreateZipFile(
-      std::move(directory_ptr), src_dir_, src_relative_paths_, std::move(file),
-      base::Bind(&ZipFileCreator::ReportDone, base::Unretained(this)));
+  remote_zip_file_creator_.set_disconnect_handler(base::BindOnce(
+      &ZipFileCreator::ReportDone, base::Unretained(this), false));
+  remote_zip_file_creator_->CreateZipFile(
+      std::move(directory), src_dir_, src_relative_paths_, std::move(file),
+      base::BindOnce(&ZipFileCreator::ReportDone, base::Unretained(this)));
 }
 
 void ZipFileCreator::ReportDone(bool success) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
-  zip_file_creator_ptr_.reset();
+  remote_zip_file_creator_.reset();
   std::move(callback_).Run(success);
 
   delete this;
diff --git a/chrome/services/file_util/public/cpp/zip_file_creator.h b/chrome/services/file_util/public/cpp/zip_file_creator.h
index 64f98e45..f650275 100644
--- a/chrome/services/file_util/public/cpp/zip_file_creator.h
+++ b/chrome/services/file_util/public/cpp/zip_file_creator.h
@@ -11,11 +11,10 @@
 #include "base/files/file.h"
 #include "base/files/file_path.h"
 #include "base/task/post_task.h"
+#include "chrome/services/file_util/public/mojom/file_util_service.mojom.h"
 #include "chrome/services/file_util/public/mojom/zip_file_creator.mojom.h"
-
-namespace service_manager {
-class Connector;
-}
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/remote.h"
 
 // ZipFileCreator creates a ZIP file from a specified list of files and
 // directories under a common parent directory. This is done in a sandboxed
@@ -25,25 +24,28 @@
 // specified in the constructor (and should be heap allocated).
 class ZipFileCreator {
  public:
-  typedef base::Callback<void(bool)> ResultCallback;
+  using ResultCallback = base::OnceCallback<void(bool)>;
 
   // Creates a zip file from the specified list of files and directories.
-  ZipFileCreator(const ResultCallback& callback,
+  ZipFileCreator(ResultCallback callback,
                  const base::FilePath& src_dir,
                  const std::vector<base::FilePath>& src_relative_paths,
                  const base::FilePath& dest_file);
 
-  // Starts creating the zip file. Must be called from the UI thread.
+  // Starts creating the zip file.
+  //
   // The result will be passed to |callback|. After the task is finished
   // and |callback| is run, ZipFileCreator instance is deleted.
-  void Start(service_manager::Connector* connector);
+  void Start(mojo::PendingRemote<chrome::mojom::FileUtilService> service);
 
  private:
   ~ZipFileCreator();
 
   // Called after the dest_file |file| is opened on the blocking pool to
   // create the zip file in it using a sandboxed utility process.
-  void CreateZipFile(service_manager::Connector* connector, base::File file);
+  void CreateZipFile(
+      mojo::PendingRemote<chrome::mojom::FileUtilService> service,
+      base::File file);
 
   // Notifies by calling |callback| specified in the constructor the end of the
   // ZIP operation. Deletes this.
@@ -64,7 +66,9 @@
   // The output zip file.
   base::FilePath dest_file_;
 
-  chrome::mojom::ZipFileCreatorPtr zip_file_creator_ptr_;
+  // Remote interfaces to the file util service. Only used from the UI thread.
+  mojo::Remote<chrome::mojom::FileUtilService> service_;
+  mojo::Remote<chrome::mojom::ZipFileCreator> remote_zip_file_creator_;
 
   DISALLOW_COPY_AND_ASSIGN(ZipFileCreator);
 };
diff --git a/chrome/services/file_util/public/cpp/zip_file_creator_browsertest.cc b/chrome/services/file_util/public/cpp/zip_file_creator_browsertest.cc
index 3ac753f..d249381 100644
--- a/chrome/services/file_util/public/cpp/zip_file_creator_browsertest.cc
+++ b/chrome/services/file_util/public/cpp/zip_file_creator_browsertest.cc
@@ -15,16 +15,16 @@
 #include "base/run_loop.h"
 #include "base/threading/thread_restrictions.h"
 #include "chrome/test/base/in_process_browser_test.h"
-#include "content/public/browser/system_connector.h"
+#include "content/public/browser/service_process_host.h"
 #include "content/public/test/test_utils.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/zlib/google/zip_reader.h"
 
 namespace {
 
-void TestCallback(bool* out_success, const base::Closure& quit, bool success) {
+void TestCallback(bool* out_success, base::OnceClosure quit, bool success) {
   *out_success = success;
-  quit.Run();
+  std::move(quit).Run();
 }
 
 bool CreateFile(const base::FilePath& file, const std::string& content) {
@@ -47,6 +47,13 @@
     return dir_.GetPath().AppendASCII("files");
   }
 
+  mojo::PendingRemote<chrome::mojom::FileUtilService> LaunchService() {
+    mojo::PendingRemote<chrome::mojom::FileUtilService> service;
+    content::ServiceProcessHost::Launch(
+        service.InitWithNewPipeAndPassReceiver());
+    return service;
+  }
+
  protected:
   base::ScopedTempDir dir_;
 };
@@ -60,12 +67,11 @@
   std::vector<base::FilePath> paths;
   paths.push_back(base::FilePath(FILE_PATH_LITERAL("not.exist")));
   (new ZipFileCreator(
-       base::Bind(&TestCallback, &success,
-                  content::GetDeferredQuitTaskForRunLoop(&run_loop)),
+       base::BindOnce(&TestCallback, &success, run_loop.QuitClosure()),
        zip_base_dir(), paths, zip_archive_path()))
-      ->Start(content::GetSystemConnector());
+      ->Start(LaunchService());
 
-  content::RunThisRunLoop(&run_loop);
+  run_loop.Run();
   EXPECT_FALSE(success);
 }
 
@@ -92,12 +98,11 @@
   paths.push_back(kFile1);
   paths.push_back(kFile2);
   (new ZipFileCreator(
-       base::Bind(&TestCallback, &success,
-                  content::GetDeferredQuitTaskForRunLoop(&run_loop)),
+       base::BindOnce(&TestCallback, &success, run_loop.QuitClosure()),
        zip_base_dir(), paths, zip_archive_path()))
-      ->Start(content::GetSystemConnector());
+      ->Start(LaunchService());
 
-  content::RunThisRunLoop(&run_loop);
+  run_loop.Run();
   EXPECT_TRUE(success);
 
   base::ScopedAllowBlockingForTesting allow_io;
@@ -187,12 +192,13 @@
   bool success = false;
   base::RunLoop run_loop;
   (new ZipFileCreator(
-       base::Bind(&TestCallback, &success, run_loop.QuitClosure()), root_dir,
+       base::BindOnce(&TestCallback, &success, run_loop.QuitClosure()),
+       root_dir,
        std::vector<base::FilePath>(),  // Empty means zip everything in dir.
        zip_archive_path()))
-      ->Start(content::GetSystemConnector());
+      ->Start(LaunchService());
 
-  content::RunThisRunLoop(&run_loop);
+  run_loop.Run();
   EXPECT_TRUE(success);
 
   // Check the archive content.
diff --git a/chrome/services/file_util/public/mojom/BUILD.gn b/chrome/services/file_util/public/mojom/BUILD.gn
index 19344c3..10d8410c 100644
--- a/chrome/services/file_util/public/mojom/BUILD.gn
+++ b/chrome/services/file_util/public/mojom/BUILD.gn
@@ -8,11 +8,12 @@
 
 mojom("mojom") {
   sources = [
-    "constants.mojom",
+    "file_util_service.mojom",
   ]
 
   if (safe_browsing_mode == 1) {
     sources += [ "safe_archive_analyzer.mojom" ]
+    enabled_features = [ "full_safe_browsing" ]
   }
 
   public_deps = [
diff --git a/chrome/services/file_util/public/mojom/constants.mojom b/chrome/services/file_util/public/mojom/constants.mojom
deleted file mode 100644
index cf32245..0000000
--- a/chrome/services/file_util/public/mojom/constants.mojom
+++ /dev/null
@@ -1,7 +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.
-
-module chrome.mojom;
-
-const string kFileUtilServiceName = "file_util";
diff --git a/chrome/services/file_util/public/mojom/file_util_service.mojom b/chrome/services/file_util/public/mojom/file_util_service.mojom
new file mode 100644
index 0000000..e10f5db
--- /dev/null
+++ b/chrome/services/file_util/public/mojom/file_util_service.mojom
@@ -0,0 +1,23 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module chrome.mojom;
+
+[EnableIf=full_safe_browsing]
+import "chrome/services/file_util/public/mojom/safe_archive_analyzer.mojom";
+
+[EnableIf=is_chromeos]
+import "chrome/services/file_util/public/mojom/zip_file_creator.mojom";
+
+// The main interface to the file utility service. Binds any of various
+// specific utility receivers.
+interface FileUtilService {
+  // Binds an instance of the ZipFileCreator interface.
+  [EnableIf=is_chromeos]
+  BindZipFileCreator(pending_receiver<ZipFileCreator> receiver);
+
+  // Binds an instance of the SafeArchiveAnalyzer interface.
+  [EnableIf=full_safe_browsing]
+  BindSafeArchiveAnalyzer(pending_receiver<SafeArchiveAnalyzer> receiver);
+};
diff --git a/chrome/services/file_util/public/mojom/zip_file_creator.mojom b/chrome/services/file_util/public/mojom/zip_file_creator.mojom
index 92017e2..5b4511e 100644
--- a/chrome/services/file_util/public/mojom/zip_file_creator.mojom
+++ b/chrome/services/file_util/public/mojom/zip_file_creator.mojom
@@ -13,7 +13,7 @@
 
 interface ZipFileCreator {
   // OS_CHROMEOS: Create a |zip_file| from a list of source files.
-  CreateZipFile(filesystem.mojom.Directory source_dir_mojo,
+  CreateZipFile(pending_remote<filesystem.mojom.Directory> source_dir_mojo,
                 mojo_base.mojom.FilePath source_dir,
                 array<mojo_base.mojom.FilePath> source_relative_paths,
                 mojo_base.mojom.File zip_file)
diff --git a/chrome/services/file_util/safe_archive_analyzer.cc b/chrome/services/file_util/safe_archive_analyzer.cc
index a58249e8..042fd290 100644
--- a/chrome/services/file_util/safe_archive_analyzer.cc
+++ b/chrome/services/file_util/safe_archive_analyzer.cc
@@ -15,9 +15,7 @@
 #include "chrome/utility/safe_browsing/mac/dmg_analyzer.h"
 #endif
 
-SafeArchiveAnalyzer::SafeArchiveAnalyzer(
-    std::unique_ptr<service_manager::ServiceContextRef> service_ref)
-    : service_ref_(std::move(service_ref)) {}
+SafeArchiveAnalyzer::SafeArchiveAnalyzer() = default;
 
 SafeArchiveAnalyzer::~SafeArchiveAnalyzer() = default;
 
diff --git a/chrome/services/file_util/safe_archive_analyzer.h b/chrome/services/file_util/safe_archive_analyzer.h
index 94d6ec0e..ad52f310 100644
--- a/chrome/services/file_util/safe_archive_analyzer.h
+++ b/chrome/services/file_util/safe_archive_analyzer.h
@@ -6,7 +6,6 @@
 #define CHROME_SERVICES_FILE_UTIL_SAFE_ARCHIVE_ANALYZER_H_
 
 #include "chrome/services/file_util/public/mojom/safe_archive_analyzer.mojom.h"
-#include "services/service_manager/public/cpp/service_context_ref.h"
 
 namespace base {
 class File;
@@ -14,8 +13,7 @@
 
 class SafeArchiveAnalyzer : public chrome::mojom::SafeArchiveAnalyzer {
  public:
-  explicit SafeArchiveAnalyzer(
-      std::unique_ptr<service_manager::ServiceContextRef> service_ref);
+  SafeArchiveAnalyzer();
   ~SafeArchiveAnalyzer() override;
 
  private:
@@ -29,8 +27,6 @@
                       base::File temporary_file,
                       AnalyzeRarFileCallback callback) override;
 
-  const std::unique_ptr<service_manager::ServiceContextRef> service_ref_;
-
   DISALLOW_COPY_AND_ASSIGN(SafeArchiveAnalyzer);
 };
 
diff --git a/chrome/services/file_util/zip_file_creator.cc b/chrome/services/file_util/zip_file_creator.cc
index 1782e534..d05bd38b 100644
--- a/chrome/services/file_util/zip_file_creator.cc
+++ b/chrome/services/file_util/zip_file_creator.cc
@@ -10,7 +10,7 @@
 #include "base/files/file.h"
 #include "base/files/file_path.h"
 #include "components/services/filesystem/public/mojom/types.mojom-shared.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "third_party/zlib/google/zip.h"
 
 namespace chrome {
@@ -23,9 +23,11 @@
 // converted to relative when calling filesystem::mojom::Directory APIs.
 class MojoFileAccessor : public zip::FileAccessor {
  public:
-  MojoFileAccessor(const base::FilePath& source_dir,
-                   filesystem::mojom::DirectoryPtr source_dir_mojo)
-      : source_dir_(source_dir), source_dir_mojo_(std::move(source_dir_mojo)) {}
+  MojoFileAccessor(
+      const base::FilePath& source_dir,
+      mojo::PendingRemote<filesystem::mojom::Directory> source_dir_remote)
+      : source_dir_(source_dir),
+        source_dir_remote_(std::move(source_dir_remote)) {}
   ~MojoFileAccessor() override = default;
 
  private:
@@ -50,7 +52,7 @@
       details.push_back(std::move(open_details));
     }
     std::vector<filesystem::mojom::FileOpenResultPtr> results;
-    if (!source_dir_mojo_->OpenFileHandles(std::move(details), &results))
+    if (!source_dir_remote_->OpenFileHandles(std::move(details), &results))
       return std::vector<base::File>();
 
     std::vector<base::File> files;
@@ -69,32 +71,32 @@
     DCHECK(dir_path.IsAbsolute());
 
     std::vector<DirectoryContentEntry> results;
-    // dir_mojo_ptr is the  directory that is open if |dir_path| is not the
+    // |dir_remote| is the  directory that is open if |dir_path| is not the
     // source dir. Note that it must be defined outside of the else block so it
-    // does not get deleted before dir_mojo is used (which would make dir_mojo
+    // does not get deleted before |dir| is used (which would make |dir|
     // invalid).
-    filesystem::mojom::DirectoryPtr dir_mojo_ptr;
-    filesystem::mojom::Directory* dir_mojo = nullptr;
+    mojo::Remote<filesystem::mojom::Directory> dir_remote;
+    filesystem::mojom::Directory* dir = nullptr;
     if (source_dir_ == dir_path) {
-      dir_mojo = source_dir_mojo_.get();
+      dir = source_dir_remote_.get();
     } else {
       base::FilePath relative_path = GetRelativePath(dir_path);
       base::File::Error error;
-      source_dir_mojo_->OpenDirectory(
-          relative_path.value(), mojo::MakeRequest(&dir_mojo_ptr),
+      source_dir_remote_->OpenDirectory(
+          relative_path.value(), dir_remote.BindNewPipeAndPassReceiver(),
           filesystem::mojom::kFlagRead | filesystem::mojom::kFlagOpen, &error);
       if (error != base::File::Error::FILE_OK) {
         LOG(ERROR) << "Failed to open " << dir_path.value() << " error "
                    << error;
         return results;
       }
-      dir_mojo = dir_mojo_ptr.get();
+      dir = dir_remote.get();
     }
 
     base::Optional<std::vector<filesystem::mojom::DirectoryEntryPtr>>
         directory_contents;
     base::File::Error error;
-    dir_mojo->Read(&error, &directory_contents);
+    dir->Read(&error, &directory_contents);
     if (error != base::File::Error::FILE_OK) {
       LOG(ERROR) << "Failed to list content of " << dir_path.value()
                  << " error " << error;
@@ -122,7 +124,8 @@
     base::FilePath relative_path = GetRelativePath(absolute_path);
     base::File::Error error;
     filesystem::mojom::FileInformationPtr file_info_mojo;
-    source_dir_mojo_->StatFile(relative_path.value(), &error, &file_info_mojo);
+    source_dir_remote_->StatFile(relative_path.value(), &error,
+                                 &file_info_mojo);
     if (error != base::File::Error::FILE_OK) {
       LOG(ERROR) << "Failed to get last modified time of "
                  << absolute_path.value() << " error " << error;
@@ -145,21 +148,19 @@
   base::FilePath source_dir_;
 
   // Interface ptr to the actual interface implementation used to access files.
-  filesystem::mojom::DirectoryPtr source_dir_mojo_;
+  mojo::Remote<filesystem::mojom::Directory> source_dir_remote_;
 
   DISALLOW_COPY_AND_ASSIGN(MojoFileAccessor);
 };
 
 }  // namespace
 
-ZipFileCreator::ZipFileCreator(
-    std::unique_ptr<service_manager::ServiceContextRef> service_ref)
-    : service_ref_(std::move(service_ref)) {}
+ZipFileCreator::ZipFileCreator() = default;
 
 ZipFileCreator::~ZipFileCreator() = default;
 
 void ZipFileCreator::CreateZipFile(
-    filesystem::mojom::DirectoryPtr source_dir_mojo,
+    mojo::PendingRemote<filesystem::mojom::Directory> source_dir_remote,
     const base::FilePath& source_dir,
     const std::vector<base::FilePath>& source_relative_paths,
     base::File zip_file,
@@ -178,7 +179,7 @@
   zip::ZipParams zip_params(source_dir, zip_file.GetPlatformFile());
   zip_params.set_files_to_zip(source_relative_paths);
   zip_params.set_file_accessor(std::make_unique<MojoFileAccessor>(
-      source_dir, std::move(source_dir_mojo)));
+      source_dir, std::move(source_dir_remote)));
   bool success = zip::Zip(zip_params);
   std::move(callback).Run(success);
 }
diff --git a/chrome/services/file_util/zip_file_creator.h b/chrome/services/file_util/zip_file_creator.h
index e947cc2..7d54dfc 100644
--- a/chrome/services/file_util/zip_file_creator.h
+++ b/chrome/services/file_util/zip_file_creator.h
@@ -9,7 +9,6 @@
 
 #include "chrome/services/file_util/public/mojom/zip_file_creator.mojom.h"
 #include "components/services/filesystem/public/mojom/directory.mojom.h"
-#include "services/service_manager/public/cpp/service_context_ref.h"
 
 namespace base {
 class FilePath;
@@ -19,19 +18,17 @@
 
 class ZipFileCreator : public chrome::mojom::ZipFileCreator {
  public:
-  explicit ZipFileCreator(
-      std::unique_ptr<service_manager::ServiceContextRef> service_ref);
+  ZipFileCreator();
   ~ZipFileCreator() override;
 
  private:
   // chrome::mojom::ZipFileCreator:
-  void CreateZipFile(filesystem::mojom::DirectoryPtr source_dir_mojo,
-                     const base::FilePath& source_dir,
-                     const std::vector<base::FilePath>& source_relative_paths,
-                     base::File zip_file,
-                     CreateZipFileCallback callback) override;
-
-  const std::unique_ptr<service_manager::ServiceContextRef> service_ref_;
+  void CreateZipFile(
+      mojo::PendingRemote<filesystem::mojom::Directory> source_dir_remote,
+      const base::FilePath& source_dir,
+      const std::vector<base::FilePath>& source_relative_paths,
+      base::File zip_file,
+      CreateZipFileCallback callback) override;
 
   DISALLOW_COPY_AND_ASSIGN(ZipFileCreator);
 };
diff --git a/chrome/test/chromedriver/net/websocket_unittest.cc b/chrome/test/chromedriver/net/websocket_unittest.cc
index 46cb2ae..50d11ed 100644
--- a/chrome/test/chromedriver/net/websocket_unittest.cc
+++ b/chrome/test/chromedriver/net/websocket_unittest.cc
@@ -14,9 +14,9 @@
 #include "base/compiler_specific.h"
 #include "base/location.h"
 #include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
+#include "base/test/scoped_task_environment.h"
 #include "base/threading/thread.h"
 #include "base/time/time.h"
 #include "chrome/test/chromedriver/net/test_http_server.h"
@@ -31,12 +31,6 @@
   run_loop->Quit();
 }
 
-void RunPending(base::MessageLoop* loop) {
-  base::RunLoop run_loop;
-  loop->task_runner()->PostTask(FROM_HERE, run_loop.QuitClosure());
-  run_loop.Run();
-}
-
 class Listener : public WebSocketListener {
  public:
   explicit Listener(const std::vector<std::string>& messages)
@@ -60,8 +54,7 @@
 
 class CloseListener : public WebSocketListener {
  public:
-  explicit CloseListener(base::RunLoop* run_loop)
-      : run_loop_(run_loop) {}
+  explicit CloseListener(base::RunLoop* run_loop) : run_loop_(run_loop) {}
 
   ~CloseListener() override { EXPECT_FALSE(run_loop_); }
 
@@ -97,8 +90,8 @@
             : new WebSocket(url, listener, read_buffer_size_));
     base::RunLoop run_loop;
     sock->Connect(base::BindOnce(&OnConnectFinished, &run_loop, &error));
-    loop_.task_runner()->PostDelayedTask(FROM_HERE, run_loop.QuitClosure(),
-                                         base::TimeDelta::FromSeconds(10));
+    scoped_task_environment_.GetMainThreadTaskRunner()->PostDelayedTask(
+        FROM_HERE, run_loop.QuitClosure(), base::TimeDelta::FromSeconds(10));
     run_loop.Run();
     if (error == net::OK)
       return sock;
@@ -118,14 +111,15 @@
       ASSERT_TRUE(sock->Send(messages[i]));
     }
     base::RunLoop run_loop;
-    loop_.task_runner()->PostDelayedTask(FROM_HERE, run_loop.QuitClosure(),
-                                         base::TimeDelta::FromSeconds(10));
+    scoped_task_environment_.GetMainThreadTaskRunner()->PostDelayedTask(
+        FROM_HERE, run_loop.QuitClosure(), base::TimeDelta::FromSeconds(10));
     run_loop.Run();
   }
 
   void SetReadBufferSize(size_t size) { read_buffer_size_ = size; }
 
-  base::MessageLoopForIO loop_;
+  base::test::ScopedTaskEnvironment scoped_task_environment_{
+      base::test::ScopedTaskEnvironment::MainThreadType::IO};
   TestHttpServer server_;
   size_t read_buffer_size_ = 0;
 };
@@ -140,7 +134,7 @@
 TEST_F(WebSocketTest, Connect) {
   CloseListener listener(NULL);
   ASSERT_TRUE(CreateWebSocket(server_.web_socket_url(), &listener));
-  RunPending(&loop_);
+  scoped_task_environment_.RunUntilIdle();
   ASSERT_TRUE(server_.WaitForConnectionsToClose());
 }
 
@@ -153,7 +147,7 @@
   server_.SetRequestAction(TestHttpServer::kNotFound);
   CloseListener listener(NULL);
   ASSERT_FALSE(CreateWebSocket(server_.web_socket_url(), NULL));
-  RunPending(&loop_);
+  scoped_task_environment_.RunUntilIdle();
   ASSERT_TRUE(server_.WaitForConnectionsToClose());
 }
 
@@ -170,8 +164,8 @@
   std::unique_ptr<WebSocket> sock(CreateConnectedWebSocket(&listener));
   ASSERT_TRUE(sock);
   ASSERT_TRUE(sock->Send("hi"));
-  loop_.task_runner()->PostDelayedTask(FROM_HERE, run_loop.QuitClosure(),
-                                       base::TimeDelta::FromSeconds(10));
+  scoped_task_environment_.GetMainThreadTaskRunner()->PostDelayedTask(
+      FROM_HERE, run_loop.QuitClosure(), base::TimeDelta::FromSeconds(10));
   run_loop.Run();
 }
 
@@ -183,8 +177,8 @@
   server_.Stop();
 
   sock->Send("hi");
-  loop_.task_runner()->PostDelayedTask(FROM_HERE, run_loop.QuitClosure(),
-                                       base::TimeDelta::FromSeconds(10));
+  scoped_task_environment_.GetMainThreadTaskRunner()->PostDelayedTask(
+      FROM_HERE, run_loop.QuitClosure(), base::TimeDelta::FromSeconds(10));
   run_loop.Run();
   ASSERT_FALSE(sock->Send("hi"));
 }
diff --git a/chrome/test/data/custom_handler_foo.html b/chrome/test/data/custom_handler.html
similarity index 100%
rename from chrome/test/data/custom_handler_foo.html
rename to chrome/test/data/custom_handler.html
diff --git a/chrome/test/data/extensions/api_test/autotest_private/test.js b/chrome/test/data/extensions/api_test/autotest_private/test.js
index e69beb7..339c664 100644
--- a/chrome/test/data/extensions/api_test/autotest_private/test.js
+++ b/chrome/test/data/extensions/api_test/autotest_private/test.js
@@ -322,6 +322,23 @@
       chrome.test.succeed();
     });
   },
+  // This test verifies that only Chromium is available by default.
+  function getShelfItems() {
+    chrome.autotestPrivate.getShelfItems(chrome.test.callbackPass(items => {
+      chrome.test.assertEq(1, items.length);
+      item = items[0];
+      // Only check that appId and title are set because their values change if
+      // chrome_branded is true.
+      chrome.test.assertTrue(!!item.appId);
+      chrome.test.assertTrue(!!item.title);
+      chrome.test.assertEq('', item.launchId);
+      chrome.test.assertEq('BrowserShortcut', item.type);
+      chrome.test.assertEq('Running', item.status);
+      chrome.test.assertTrue(item.showsTooltip);
+      chrome.test.assertFalse(item.pinnedByPolicy);
+      chrome.test.assertFalse(item.hasNotification);
+    }));
+  },
   // This test verifies that changing the shelf behavior works as expected.
   function setShelfAutoHideBehavior() {
     // Using shelf from primary display.
diff --git a/chrome/test/data/webui/BUILD.gn b/chrome/test/data/webui/BUILD.gn
index 1ad27cd..d5702a2 100644
--- a/chrome/test/data/webui/BUILD.gn
+++ b/chrome/test/data/webui/BUILD.gn
@@ -123,7 +123,7 @@
       "signin/signin_browsertest.js",
       "user_manager/user_manager_browsertest.js",
       "welcome/a11y_tests.js",
-      "welcome/welcome_browsertest.js",
+      "welcome/onboarding_welcome_browsertest.js",
     ]
   }
 
diff --git a/chrome/test/data/webui/welcome/a11y_tests.js b/chrome/test/data/webui/welcome/a11y_tests.js
index 6a611f44..d069baa 100644
--- a/chrome/test/data/webui/welcome/a11y_tests.js
+++ b/chrome/test/data/webui/welcome/a11y_tests.js
@@ -9,7 +9,7 @@
 ]);
 GEN('#include "chrome/browser/ui/webui/welcome/helpers.h"');
 
-WelcomeA11y = class extends PolymerTest {
+OnboardingA11y = class extends PolymerTest {
   /** @override */
   get browsePreload() {
     return 'chrome://welcome/';
@@ -17,13 +17,13 @@
 
   /** @override */
   get featureList() {
-    return {enabled: ['welcome::kForceEnabled']};
+    return {enabled: ['welcome::kOnboardingForceEnabled']};
   }
 };
 
-AccessibilityTest.define('WelcomeA11y', {
+AccessibilityTest.define('OnboardingA11y', {
   // Must be unique within the test fixture and cannot have spaces.
-  name: 'WelcomeFlow',
+  name: 'OnboardingFlow',
 
   // Optional. Configuration for axe-core. Can be used to disable a test.
   axeOptions: {},
diff --git a/chrome/test/data/webui/welcome/app_chooser_test.js b/chrome/test/data/webui/welcome/app_chooser_test.js
index 0bdfb63..4bd0318 100644
--- a/chrome/test/data/webui/welcome/app_chooser_test.js
+++ b/chrome/test/data/webui/welcome/app_chooser_test.js
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-cr.define('welcome_app_chooser', function() {
+cr.define('onboarding_welcome_app_chooser', function() {
   suite('AppChooserTest', function() {
     const apps = [
       {
diff --git a/chrome/test/data/webui/welcome/module_metrics_test.js b/chrome/test/data/webui/welcome/module_metrics_test.js
index 41b4c51..4c729898 100644
--- a/chrome/test/data/webui/welcome/module_metrics_test.js
+++ b/chrome/test/data/webui/welcome/module_metrics_test.js
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-cr.define('welcome_module_metrics', function() {
+cr.define('onboarding_welcome_module_metrics', function() {
   suite('ModuleMetricsTest', function() {
     /** @type {welcome.ModuleMetricsProxy} */
     let testMetricsProxy;
diff --git a/chrome/test/data/webui/welcome/navigation_behavior_test.js b/chrome/test/data/webui/welcome/navigation_behavior_test.js
index bf68e33..2542bf5 100644
--- a/chrome/test/data/webui/welcome/navigation_behavior_test.js
+++ b/chrome/test/data/webui/welcome/navigation_behavior_test.js
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-cr.define('welcome_navigation_behavior_test', function() {
+cr.define('onboarding_welcome_navigation_behavior_test', function() {
   suite('NavigationBehaviorTest', function() {
     let elements = [];
     let callOrders = [];
diff --git a/chrome/test/data/webui/welcome/nux_ntp_background_test.js b/chrome/test/data/webui/welcome/nux_ntp_background_test.js
index ec33882..4798026 100644
--- a/chrome/test/data/webui/welcome/nux_ntp_background_test.js
+++ b/chrome/test/data/webui/welcome/nux_ntp_background_test.js
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-cr.define('ntp_background_test', function() {
+cr.define('onboarding_ntp_background_test', function() {
   suite('NuxNtpBackgroundTest', function() {
     /** @type {!Array<!welcome.NtpBackgroundData} */
     let backgrounds = [
diff --git a/chrome/test/data/webui/welcome/nux_set_as_default_test.js b/chrome/test/data/webui/welcome/nux_set_as_default_test.js
index 58b720db..aedb067 100644
--- a/chrome/test/data/webui/welcome/nux_set_as_default_test.js
+++ b/chrome/test/data/webui/welcome/nux_set_as_default_test.js
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-cr.define('set_as_default_test', function() {
+cr.define('onboarding_set_as_default_test', function() {
   suite('SetAsDefaultTest', function() {
     /** @type {NuxSetAsDefaultElement} */
     let testElement;
diff --git a/chrome/test/data/webui/welcome/welcome_browsertest.js b/chrome/test/data/webui/welcome/onboarding_welcome_browsertest.js
similarity index 70%
rename from chrome/test/data/webui/welcome/welcome_browsertest.js
rename to chrome/test/data/webui/welcome/onboarding_welcome_browsertest.js
index 5cfe6cf..3d703cef 100644
--- a/chrome/test/data/webui/welcome/welcome_browsertest.js
+++ b/chrome/test/data/webui/welcome/onboarding_welcome_browsertest.js
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-/** @fileoverview Runs the Polymer welcome tests on welcome UI. */
+/** @fileoverview Runs the Polymer welcome tests on onboarding-welcome UI. */
 
 // Polymer BrowserTest fixture.
 GEN_INCLUDE(['//chrome/test/data/webui/polymer_browser_test_base.js']);
 GEN('#include "chrome/browser/ui/webui/welcome/helpers.h"');
 
-/** Test fixture for Polymer welcome elements. */
-const WelcomeBrowserTest = class extends PolymerTest {
+/** Test fixture for Polymer onboarding welcome elements. */
+const OnboardingWelcomeBrowserTest = class extends PolymerTest {
   /** @override */
   get browsePreload() {
     throw 'this is abstract and should be overridden by subclasses';
@@ -24,12 +24,13 @@
 
   /** @override */
   get featureList() {
-    return {enabled: ['welcome::kForceEnabled']};
+    return {enabled: ['welcome::kOnboardingForceEnabled']};
   }
 };
 
 // eslint-disable-next-line no-var
-var WelcomeAppChooserTest = class extends WelcomeBrowserTest {
+var OnboardingWelcomeAppChooserTest =
+    class extends OnboardingWelcomeBrowserTest {
   /** @override */
   get browsePreload() {
     return 'chrome://welcome/google_apps/nux_google_apps.html';
@@ -46,12 +47,13 @@
   }
 };
 
-TEST_F('WelcomeAppChooserTest', 'All', function() {
+TEST_F('OnboardingWelcomeAppChooserTest', 'All', function() {
   mocha.run();
 });
 
 // eslint-disable-next-line no-var
-var WelcomeWelcomeAppTest = class extends WelcomeBrowserTest {
+var OnboardingWelcomeWelcomeAppTest =
+    class extends OnboardingWelcomeBrowserTest {
   /** @override */
   get browsePreload() {
     return 'chrome://welcome/welcome_app.html';
@@ -69,12 +71,13 @@
   }
 };
 
-TEST_F('WelcomeWelcomeAppTest', 'All', function() {
+TEST_F('OnboardingWelcomeWelcomeAppTest', 'All', function() {
   mocha.run();
 });
 
 // eslint-disable-next-line no-var
-var WelcomeSigninViewTest = class extends WelcomeBrowserTest {
+var OnboardingWelcomeSigninViewTest =
+    class extends OnboardingWelcomeBrowserTest {
   /** @override */
   get browsePreload() {
     return 'chrome://welcome/signin_view.html';
@@ -89,12 +92,13 @@
   }
 };
 
-TEST_F('WelcomeSigninViewTest', 'All', function() {
+TEST_F('OnboardingWelcomeSigninViewTest', 'All', function() {
   mocha.run();
 });
 
 // eslint-disable-next-line no-var
-var WelcomeNavigationBehaviorTest = class extends WelcomeBrowserTest {
+var OnboardingWelcomeNavigationBehaviorTest =
+    class extends OnboardingWelcomeBrowserTest {
   /** @override */
   get browsePreload() {
     return 'chrome://welcome/navigation_behavior.html';
@@ -109,12 +113,13 @@
   }
 };
 
-TEST_F('WelcomeNavigationBehaviorTest', 'All', function() {
+TEST_F('OnboardingWelcomeNavigationBehaviorTest', 'All', function() {
   mocha.run();
 });
 
 // eslint-disable-next-line no-var
-var WelcomeModuleMetricsTest = class extends WelcomeBrowserTest {
+var OnboardingWelcomeModuleMetricsTest =
+    class extends OnboardingWelcomeBrowserTest {
   /** @override */
   get browsePreload() {
     return 'chrome://welcome/shared/module_metrics_proxy.html';
@@ -129,12 +134,13 @@
   }
 };
 
-TEST_F('WelcomeModuleMetricsTest', 'All', function() {
+TEST_F('OnboardingWelcomeModuleMetricsTest', 'All', function() {
   mocha.run();
 });
 
 // eslint-disable-next-line no-var
-var WelcomeSetAsDefaultTest = class extends WelcomeBrowserTest {
+var OnboardingWelcomeSetAsDefaultTest =
+    class extends OnboardingWelcomeBrowserTest {
   /** @override */
   get browsePreload() {
     return 'chrome://welcome/set_as_default/nux_set_as_default.html';
@@ -150,12 +156,13 @@
   }
 };
 
-TEST_F('WelcomeSetAsDefaultTest', 'All', function() {
+TEST_F('OnboardingWelcomeSetAsDefaultTest', 'All', function() {
   mocha.run();
 });
 
 // eslint-disable-next-line no-var
-var WelcomeNtpBackgroundTest = class extends WelcomeBrowserTest {
+var OnboardingWelcomeNtpBackgroundTest =
+    class extends OnboardingWelcomeBrowserTest {
   /** @override */
   get browsePreload() {
     return 'chrome://welcome/ntp_background/nux_ntp_background.html';
@@ -171,6 +178,6 @@
   }
 };
 
-TEST_F('WelcomeNtpBackgroundTest', 'All', function() {
+TEST_F('OnboardingWelcomeNtpBackgroundTest', 'All', function() {
   mocha.run();
 });
diff --git a/chrome/test/data/webui/welcome/signin_view_test.js b/chrome/test/data/webui/welcome/signin_view_test.js
index c5ce927a..dc1af86 100644
--- a/chrome/test/data/webui/welcome/signin_view_test.js
+++ b/chrome/test/data/webui/welcome/signin_view_test.js
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-cr.define('signin_view_test', function() {
+cr.define('onboarding_signin_view_test', function() {
   suite('SigninViewTest', function() {
 
     /** @type {SigninViewElement} */
diff --git a/chrome/test/data/webui/welcome/welcome_app_test.js b/chrome/test/data/webui/welcome/welcome_app_test.js
index 193ddb6..2a5112f 100644
--- a/chrome/test/data/webui/welcome/welcome_app_test.js
+++ b/chrome/test/data/webui/welcome/welcome_app_test.js
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-cr.define('welcome_app_test', function() {
+cr.define('onboarding_welcome_app_test', function() {
   suite('WelcomeAppTest', function() {
 
     /** @type {WelcomeAppElement} */
diff --git a/chrome/updater/win/BUILD.gn b/chrome/updater/win/BUILD.gn
index d99451251..8aaf244 100644
--- a/chrome/updater/win/BUILD.gn
+++ b/chrome/updater/win/BUILD.gn
@@ -5,9 +5,11 @@
 import("//chrome/process_version_rc_template.gni")
 import("//testing/test.gni")
 
+# This target build the updater executable and its installer.
 group("win") {
   deps = [
     ":updater",
+    "//chrome/updater/win/installer:installer",
   ]
 }
 
@@ -26,6 +28,10 @@
     "//build/win:default_exe_manifest",
     "//chrome/updater:common",
   ]
+
+  data_deps = [
+    ":uninstall.cmd",
+  ]
 }
 
 copy("uninstall.cmd") {
@@ -67,14 +73,6 @@
     "//chrome/installer/util:with_no_strings",
     "//components/update_client",
   ]
-
-  data = [
-    "setup/uninstall.cmd",
-  ]
-
-  data_deps = [
-    ":uninstall.cmd",
-  ]
 }
 
 source_set("unittest") {
@@ -90,4 +88,8 @@
     "//base/test:test_support",
     "//testing/gtest",
   ]
+
+  data_deps = [
+    "//chrome/updater/win/installer:installer_unittest",
+  ]
 }
diff --git a/chrome/updater/win/installer/BUILD.gn b/chrome/updater/win/installer/BUILD.gn
new file mode 100644
index 0000000..4d09ba9
--- /dev/null
+++ b/chrome/updater/win/installer/BUILD.gn
@@ -0,0 +1,138 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//chrome/process_version_rc_template.gni")
+import("//testing/test.gni")
+
+source_set("lib") {
+  sources = [
+    "configuration.cc",
+    "configuration.h",
+    "exit_code.h",
+    "installer.cc",
+    "installer.h",
+    "installer.rc",
+    "installer_constants.cc",
+    "installer_constants.h",
+    "installer_resource.h",
+    "pe_resource.cc",
+    "pe_resource.h",
+    "regkey.cc",
+    "regkey.h",
+    "string.cc",
+    "string.h",
+  ]
+}
+
+process_version_rc_template("version") {
+  template_file = "installer_version.rc.version"
+  output = "$root_out_dir/installer_version.rc"
+}
+
+# This target creats a list of runtime dependencies for the component
+# builds. This list is parsed by the |create_installer_archive| script, the
+# DLL paths extracted out from the list, and included in the archive.
+updater_runtime_deps = "$root_gen_dir/updater.runtime_deps"
+group("updater_runtime_deps") {
+  write_runtime_deps = updater_runtime_deps
+  data_deps = [
+    "//chrome/updater/win:updater",
+  ]
+}
+
+template("generate_installer") {
+  output_dir = invoker.out_dir
+  packed_files_rc_file = "$target_gen_dir/$target_name/packed_files.rc"
+  archive_name = target_name + "_archive"
+  staging_dir = "$target_gen_dir/$target_name"
+
+  action(archive_name) {
+    script = "create_installer_archive.py"
+
+    release_file = "updater.release"
+
+    inputs = [
+      release_file,
+    ]
+
+    outputs = [
+      "$output_dir/updater.packed.7z",
+      packed_files_rc_file,
+    ]
+
+    args = [
+      "--build_dir",
+      rebase_path(root_out_dir, root_build_dir),
+      "--staging_dir",
+      rebase_path(staging_dir, root_build_dir),
+      "--input_file",
+      rebase_path(release_file, root_build_dir),
+      "--resource_file_path",
+      rebase_path(packed_files_rc_file, root_build_dir),
+      "--output_dir",
+      rebase_path(output_dir, root_build_dir),
+      "--setup_runtime_deps",
+      rebase_path(updater_runtime_deps, root_build_dir),
+      "--output_name=updater",
+      "--verbose",
+    ]
+
+    deps = [
+      ":updater_runtime_deps",
+      "//chrome/updater/win:updater",
+    ]
+
+    if (is_component_build) {
+      args += [ "--component_build=1" ]
+    }
+  }
+
+  executable(target_name) {
+    output_name = invoker.output_name
+
+    sources = [
+      "installer_main.cc",
+      packed_files_rc_file,
+    ]
+
+    configs += [ "//build/config/win:windowed" ]
+
+    libs = [ "setupapi.lib" ]
+
+    deps = [
+      ":$archive_name",
+      ":lib",
+      ":version",
+      "//build/win:default_exe_manifest",
+      "//chrome/installer/util:with_no_strings",
+    ]
+  }
+}
+
+generate_installer("installer") {
+  out_dir = root_out_dir
+  output_name = "UpdaterSetup"
+}
+
+test("installer_unittest") {
+  testonly = true
+
+  output_name = "updater_installer_unittest"
+
+  sources = [
+    "configuration_unittest.cc",
+    "run_all_unittests.cc",
+    "string_unittest.cc",
+  ]
+
+  public_deps = [
+    ":lib",
+  ]
+  deps = [
+    "//base",
+    "//base/test:test_support",
+    "//chrome/installer/util:with_no_strings",
+    "//testing/gtest",
+  ]
+}
diff --git a/chrome/updater/win/installer/configuration.cc b/chrome/updater/win/installer/configuration.cc
new file mode 100644
index 0000000..9059273
--- /dev/null
+++ b/chrome/updater/win/installer/configuration.cc
@@ -0,0 +1,71 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/updater/win/installer/configuration.h"
+#include <shellapi.h>
+#include "chrome/updater/win/installer/string.h"
+
+namespace updater {
+
+namespace {
+
+// Returns true if GoogleUpdateIsMachine=1 is present in the environment.
+bool GetGoogleUpdateIsMachineEnvVar() {
+  constexpr DWORD kBufferSize = 2;
+  StackString<kBufferSize> value;
+  const auto length = ::GetEnvironmentVariableW(L"GoogleUpdateIsMachine",
+                                                value.get(), kBufferSize);
+  return length == 1 && *value.get() == L'1';
+}
+
+}  // namespace
+
+Configuration::Configuration() {
+  Clear();
+}
+
+Configuration::~Configuration() {
+  Clear();
+}
+
+bool Configuration::Initialize(HMODULE module) {
+  Clear();
+  return ParseCommandLine(::GetCommandLine());
+}
+
+void Configuration::Clear() {
+  if (args_ != nullptr) {
+    ::LocalFree(args_);
+    args_ = nullptr;
+  }
+  command_line_ = nullptr;
+  operation_ = INSTALL_PRODUCT;
+  argument_count_ = 0;
+  is_system_level_ = false;
+  has_invalid_switch_ = false;
+}
+
+// |command_line| is shared with this instance in the sense that this
+// instance may refer to it at will throughout its lifetime, yet it will
+// not release it.
+bool Configuration::ParseCommandLine(const wchar_t* command_line) {
+  command_line_ = command_line;
+  args_ = ::CommandLineToArgvW(command_line_, &argument_count_);
+  if (!args_)
+    return false;
+
+  for (int i = 1; i < argument_count_; ++i) {
+    if (0 == ::lstrcmpi(args_[i], L"--system-level"))
+      is_system_level_ = true;
+    else if (0 == ::lstrcmpi(args_[i], L"--cleanup"))
+      operation_ = CLEANUP;
+  }
+
+  if (!is_system_level_)
+    is_system_level_ = GetGoogleUpdateIsMachineEnvVar();
+
+  return true;
+}
+
+}  // namespace updater
diff --git a/chrome/updater/win/installer/configuration.h b/chrome/updater/win/installer/configuration.h
new file mode 100644
index 0000000..c47a00d
--- /dev/null
+++ b/chrome/updater/win/installer/configuration.h
@@ -0,0 +1,55 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_UPDATER_WIN_INSTALLER_CONFIGURATION_H_
+#define CHROME_UPDATER_WIN_INSTALLER_CONFIGURATION_H_
+
+#include <windows.h>
+
+namespace updater {
+
+// A simple container of the updater's configuration, as defined by the
+// command line used to invoke it.
+class Configuration {
+ public:
+  enum Operation {
+    INSTALL_PRODUCT,
+    CLEANUP,
+  };
+
+  Configuration();
+  ~Configuration();
+
+  // Initializes this instance on the basis of the process's command line.
+  bool Initialize(HMODULE module);
+
+  // Returns the desired operation dictated by the command line options.
+  Operation operation() const { return operation_; }
+
+  // Returns true if --system-level is on the command line or if
+  // GoogleUpdateIsMachine=1 is set in the process's environment.
+  bool is_system_level() const { return is_system_level_; }
+
+  // Returns true if any invalid switch is found on the command line.
+  bool has_invalid_switch() const { return has_invalid_switch_; }
+
+ protected:
+  void Clear();
+  bool ParseCommandLine(const wchar_t* command_line);
+
+  wchar_t** args_ = nullptr;
+  const wchar_t* command_line_ = nullptr;
+  int argument_count_ = 0;
+  Operation operation_ = INSTALL_PRODUCT;
+  bool is_system_level_ = false;
+  bool has_invalid_switch_ = false;
+
+ private:
+  Configuration(const Configuration&) = delete;
+  Configuration& operator=(const Configuration&) = delete;
+};
+
+}  // namespace updater
+
+#endif  // CHROME_UPDATER_WIN_INSTALLER_CONFIGURATION_H_
diff --git a/chrome/updater/win/installer/configuration_unittest.cc b/chrome/updater/win/installer/configuration_unittest.cc
new file mode 100644
index 0000000..54ec28b1
--- /dev/null
+++ b/chrome/updater/win/installer/configuration_unittest.cc
@@ -0,0 +1,92 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/updater/win/installer/configuration.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+
+#include <memory>
+
+#include "base/environment.h"
+#include "base/macros.h"
+#include "base/test/test_reg_util_win.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace updater {
+
+namespace {
+
+// A helper class to set the "GoogleUpdateIsMachine" environment variable.
+class ScopedGoogleUpdateIsMachine {
+ public:
+  explicit ScopedGoogleUpdateIsMachine(bool value)
+      : env_(base::Environment::Create()) {
+    env_->SetVar("GoogleUpdateIsMachine", value ? "1" : "0");
+  }
+
+  ~ScopedGoogleUpdateIsMachine() { env_->UnSetVar("GoogleUpdateIsMachine"); }
+
+ private:
+  std::unique_ptr<base::Environment> env_;
+};
+
+class TestConfiguration : public Configuration {
+ public:
+  explicit TestConfiguration(const wchar_t* command_line) {
+    EXPECT_TRUE(ParseCommandLine(command_line));
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TestConfiguration);
+};
+
+}  // namespace
+
+class UpdaterInstallerConfigurationTest : public ::testing::Test {
+ protected:
+  UpdaterInstallerConfigurationTest() = default;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(UpdaterInstallerConfigurationTest);
+};
+
+// Test that the operation type is CLEANUP iff --cleanup is on the cmdline.
+TEST_F(UpdaterInstallerConfigurationTest, Operation) {
+  EXPECT_EQ(Configuration::INSTALL_PRODUCT,
+            TestConfiguration(L"spam.exe").operation());
+  EXPECT_EQ(Configuration::INSTALL_PRODUCT,
+            TestConfiguration(L"spam.exe --clean").operation());
+  EXPECT_EQ(Configuration::INSTALL_PRODUCT,
+            TestConfiguration(L"spam.exe --cleanupthis").operation());
+
+  EXPECT_EQ(Configuration::CLEANUP,
+            TestConfiguration(L"spam.exe --cleanup").operation());
+  EXPECT_EQ(Configuration::CLEANUP,
+            TestConfiguration(L"spam.exe --cleanup now").operation());
+}
+
+TEST_F(UpdaterInstallerConfigurationTest, IsSystemLevel) {
+  EXPECT_FALSE(TestConfiguration(L"spam.exe").is_system_level());
+  EXPECT_FALSE(TestConfiguration(L"spam.exe --chrome").is_system_level());
+  EXPECT_TRUE(TestConfiguration(L"spam.exe --system-level").is_system_level());
+
+  {
+    ScopedGoogleUpdateIsMachine env_setter(false);
+    EXPECT_FALSE(TestConfiguration(L"spam.exe").is_system_level());
+  }
+
+  {
+    ScopedGoogleUpdateIsMachine env_setter(true);
+    EXPECT_TRUE(TestConfiguration(L"spam.exe").is_system_level());
+  }
+}
+
+TEST_F(UpdaterInstallerConfigurationTest, HasInvalidSwitch) {
+  EXPECT_FALSE(TestConfiguration(L"spam.exe").has_invalid_switch());
+  EXPECT_TRUE(
+      TestConfiguration(L"spam.exe --chrome-frame").has_invalid_switch());
+}
+
+}  // namespace updater
diff --git a/chrome/updater/win/installer/create_installer_archive.py b/chrome/updater/win/installer/create_installer_archive.py
new file mode 100644
index 0000000..c8dbb9c
--- /dev/null
+++ b/chrome/updater/win/installer/create_installer_archive.py
@@ -0,0 +1,341 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Script to create the Chrome Updater Installer archive.
+
+  This script is used to create an archive of all the files required for a
+  Chrome Updater install in appropriate directory structure. It reads
+  updater.release file as input, creates updater.7z ucompressed archive, and
+  generates the updater.packed.7z compressed archive.
+
+"""
+
+import ConfigParser
+import glob
+import optparse
+import os
+import shutil
+import subprocess
+import sys
+
+# Directory name inside the uncompressed archive where all the files are.
+UPDATER_DIR = "bin"
+
+# Suffix to uncompressed full archive file, appended to options.output_name.
+ARCHIVE_SUFFIX = ".7z"
+
+# compressed full archive suffix, will be prefixed by options.output_name.
+COMPRESSED_ARCHIVE_SUFFIX = ".packed.7z"
+TEMP_ARCHIVE_DIR = "temp_installer_archive"
+
+g_archive_inputs = []
+
+def CompressUsingLZMA(build_dir, compressed_file, input_file, verbose):
+  lzma_exec = GetLZMAExec(build_dir)
+  cmd = [lzma_exec,
+         'a', '-t7z',
+          # Flags equivalent to -mx9 (ultra) but with the bcj2 turned on (exe
+          # pre-filter). These arguments are the similar to what the Chrome mini
+          # installer is using.
+          '-m0=BCJ2',
+          '-m1=LZMA:d27:fb128',
+          '-m2=LZMA:d22:fb128:mf=bt2',
+          '-m3=LZMA:d22:fb128:mf=bt2',
+          '-mb0:1',
+          '-mb0s1:2',
+          '-mb0s2:3',
+          os.path.abspath(compressed_file),
+          os.path.abspath(input_file),]
+  if os.path.exists(compressed_file):
+    os.remove(compressed_file)
+  RunSystemCommand(cmd, verbose)
+
+
+def CopyAllFilesToStagingDir(config, staging_dir, build_dir):
+  """Copies the files required for installer archive.
+  """
+  CopySectionFilesToStagingDir(config, 'GENERAL', staging_dir, build_dir)
+
+
+def CopySectionFilesToStagingDir(config, section, staging_dir, src_dir):
+  """Copies installer archive files specified in section from src_dir to
+  staging_dir. This method reads section from config and copies all the
+  files specified from src_dir to staging dir.
+  """
+  for option in config.options(section):
+    src_subdir = option.replace('\\', os.sep)
+    dst_dir = os.path.join(staging_dir, config.get(section, option))
+    dst_dir = dst_dir.replace('\\', os.sep)
+    src_paths = glob.glob(os.path.join(src_dir, src_subdir))
+    if src_paths and not os.path.exists(dst_dir):
+      os.makedirs(dst_dir)
+    for src_path in src_paths:
+      print(src_path)
+      dst_path = os.path.join(dst_dir, os.path.basename(src_path))
+      if not os.path.exists(dst_path):
+        g_archive_inputs.append(src_path)
+        print('paths src_path={0}, dest_dir={1}'.format(src_path, dst_dir))
+        shutil.copy(src_path, dst_dir)
+
+def GetLZMAExec(build_dir):
+  if sys.platform == 'win32':
+    lzma_exec = os.path.join(build_dir, "..", "..", "third_party",
+                             "lzma_sdk", "Executable", "7za.exe")
+  else:
+    lzma_exec = '7zr'  # Use system 7zr.
+  return lzma_exec
+
+def MakeStagingDirectory(staging_dir):
+  """Creates a staging path for installer archive. If directory exists already,
+  deletes the existing directory.
+  """
+  file_path = os.path.join(staging_dir, TEMP_ARCHIVE_DIR)
+  if os.path.exists(file_path):
+    shutil.rmtree(file_path)
+  os.makedirs(file_path)
+  return file_path
+
+def Readconfig(input_file):
+  """Reads config information from input file after setting default value of
+  global variables.
+  """
+  variables = {}
+  variables['UpdaterDir'] = UPDATER_DIR
+  config = ConfigParser.SafeConfigParser(variables)
+  config.read(input_file)
+  return config
+
+def RunSystemCommand(cmd, verbose):
+  """Runs |cmd|, prints the |cmd| and its output if |verbose|; otherwise
+  captures its output and only emits it on failure.
+  """
+  if verbose:
+    print 'Running', cmd
+
+  try:
+    # Run |cmd|, redirecting stderr to stdout in order for captured errors to be
+    # inline with corresponding stdout.
+    output = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
+    if verbose:
+      print output
+  except subprocess.CalledProcessError as e:
+    raise Exception("Error while running cmd: %s\n"
+                    "Exit code: %s\n"
+                    "Command output:\n%s" %
+                    (e.cmd, e.returncode, e.output))
+
+def CreateArchiveFile(options, staging_dir):
+  """Creates a new installer archive file after deleting any existing old file.
+  """
+  # First create an uncompressed archive file for the current build (updater.7z)
+  lzma_exec = GetLZMAExec(options.build_dir)
+  archive_file = os.path.join(options.output_dir,
+                              options.output_name + ARCHIVE_SUFFIX)
+
+  if options.depfile:
+    # If a depfile was requested, do the glob of the staging dir and generate
+    # a list of dependencies in .d format. We list the files that were copied
+    # into the staging dir, not the files that are actually in the staging dir
+    # because the ones in the staging dir will never be edited, and we want
+    # to have the build be triggered when the thing-that-was-copied-there
+    # changes.
+
+    def PathFixup(path):
+      """Fixes path for depfile format: backslash to forward slash, and
+      backslash escaping for spaces."""
+      return path.replace('\\', '/').replace(' ', '\\ ')
+
+    # Gather the list of files in the staging dir that will be zipped up. We
+    # only gather this list to make sure that g_archive_inputs is complete (i.e.
+    # that there's not file copies that got missed).
+    staging_contents = []
+    for root, files in os.walk(os.path.join(staging_dir, UPDATER_DIR)):
+      for filename in files:
+        staging_contents.append(PathFixup(os.path.join(root, filename)))
+
+    # Make sure there's an archive_input for each staging dir file.
+    for staging_file in staging_contents:
+      for archive_input in g_archive_inputs:
+        archive_rel = PathFixup(archive_input)
+        if (os.path.basename(staging_file).lower() ==
+            os.path.basename(archive_rel).lower()):
+          break
+      else:
+        raise Exception('Did not find an archive input file for "%s"' %
+                        staging_file)
+
+    # Finally, write the depfile referencing the inputs.
+    with open(options.depfile, 'wb') as f:
+      f.write(PathFixup(os.path.relpath(archive_file, options.build_dir)) +
+              ': \\\n')
+      f.write('  ' + ' \\\n  '.join(PathFixup(x) for x in g_archive_inputs))
+
+  # It is important to use abspath to create the path to the directory because
+  # if you use a relative path without any .. sequences then 7za.exe uses the
+  # entire relative path as part of the file paths in the archive. If you have
+  # a .. sequence or an absolute path then only the last directory is stored as
+  # part of the file paths in the archive, which is what we want.
+  cmd = [lzma_exec,
+         'a',
+         '-t7z',
+         archive_file,
+         os.path.abspath(os.path.join(staging_dir, UPDATER_DIR)),
+         '-mx0',]
+  # There does not seem to be any way in 7za.exe to override existing file so
+  # we always delete before creating a new one.
+  if not os.path.exists(archive_file):
+    RunSystemCommand(cmd, options.verbose)
+  elif options.skip_rebuild_archive != "true":
+    os.remove(archive_file)
+    RunSystemCommand(cmd, options.verbose)
+
+  # Do not compress the archive when skip_archive_compression is specified.
+  if options.skip_archive_compression:
+    compressed_file = os.path.join(
+        options.output_dir, options.output_name + COMPRESSED_ARCHIVE_SUFFIX)
+    if os.path.exists(compressed_file):
+      os.remove(compressed_file)
+    return os.path.basename(archive_file)
+
+  compressed_archive_file = options.output_name + COMPRESSED_ARCHIVE_SUFFIX
+  compressed_archive_file_path = os.path.join(options.output_dir,
+                                              compressed_archive_file)
+  CompressUsingLZMA(options.build_dir, compressed_archive_file_path,
+                    archive_file, options.verbose)
+
+  return compressed_archive_file
+
+
+_RESOURCE_FILE_HEADER = """\
+// This file is automatically generated by create_installer_archive.py.
+// It contains the resource entries that are going to be linked inside the exe.
+// For each file to be linked there should be two lines:
+// - The first line contains the output filename (without path) and the
+// type of the resource ('BN' - not compressed , 'BL' - LZ compressed,
+// 'B7' - LZMA compressed)
+// - The second line contains the path to the input file. Uses '/' to
+// separate path components.
+"""
+
+def CreateResourceInputFile(
+    output_dir, archive_file, resource_file_path,
+    component_build, staging_dir):
+  """Creates resource input file for installer target."""
+
+  # An array of (file, type, path) tuples of the files to be included.
+  resources = [(archive_file, 'B7',
+                    os.path.join(output_dir, archive_file))]
+
+  with open(resource_file_path, 'w') as f:
+    f.write(_RESOURCE_FILE_HEADER)
+    for (file, type, path) in resources:
+      f.write('\n%s  %s\n    "%s"\n' % (file, type, path.replace("\\","/")))
+
+
+def ParseDLLsFromDeps(build_dir, runtime_deps_file):
+  """Parses the runtime_deps file and returns the set of DLLs in it, relative
+  to build_dir."""
+  build_dlls = set()
+  args = open(runtime_deps_file).read()
+  for l in args.splitlines():
+    if os.path.splitext(l)[1] == ".dll":
+      build_dlls.add(os.path.join(build_dir, l))
+  return build_dlls
+
+# Copies component build DLLs for the setup to be able to find those DLLs at
+# run-time.
+# This is meant for developer builds only and should never be used to package
+# an official build.
+def DoComponentBuildTasks(staging_dir, build_dir, setup_runtime_deps):
+  installer_dir = os.path.join(staging_dir, UPDATER_DIR)
+  if not os.path.exists(installer_dir):
+    os.mkdir(installer_dir)
+
+  setup_component_dlls = ParseDLLsFromDeps(build_dir, setup_runtime_deps)
+
+  for setup_component_dll in setup_component_dlls:
+    g_archive_inputs.append(setup_component_dll)
+    shutil.copy(setup_component_dll, installer_dir)
+
+def main(options):
+  """Main method that reads input file, creates archive file and writes
+  resource input file.
+  """
+  config = Readconfig(options.input_file)
+
+  staging_dir = MakeStagingDirectory(options.staging_dir)
+
+  # Copy the files from the build dir.
+  CopyAllFilesToStagingDir(config, staging_dir, options.build_dir)
+
+  if options.component_build == '1':
+    DoComponentBuildTasks(staging_dir, options.build_dir,
+                          options.setup_runtime_deps)
+
+  # Name of the archive file built (for example - updater.7z)
+  archive_file = CreateArchiveFile(options, staging_dir)
+  CreateResourceInputFile(options.output_dir,
+                          archive_file, options.resource_file_path,
+                          options.component_build == '1', staging_dir)
+
+def _ParseOptions():
+  parser = optparse.OptionParser()
+  parser.add_option('-i', '--input_file',
+      help='Input file describing which files to archive.')
+  parser.add_option('-b', '--build_dir',
+      help='Build directory. The paths in input_file are relative to this.')
+  parser.add_option('--staging_dir',
+      help='Staging directory where intermediate files and directories '
+           'will be created')
+  parser.add_option('-o', '--output_dir',
+      help='The output directory where the archives will be written. '
+            'Defaults to the build_dir.')
+  parser.add_option('--resource_file_path',
+      help='The path where the resource file will be output. ')
+  parser.add_option('-s', '--skip_rebuild_archive',
+      default="False", help='Skip re-building updater.7z archive if it exists.')
+  parser.add_option('-n', '--output_name', default='updater',
+      help='Name used to prefix names of generated archives.')
+  parser.add_option('--component_build', default='0',
+      help='Whether this archive is packaging a component build.')
+  parser.add_option('--skip_archive_compression',
+      action='store_true', default=False,
+      help='Turn off compression of updater.7z into updater.packed.7z and '
+           'helpfully delete any old updater.packed.7z in |output_dir|.')
+  parser.add_option('--depfile',
+      help='Generate a depfile with the given name listing the implicit inputs '
+           'to the archive process that can be used with a build system.')
+  parser.add_option('--setup_runtime_deps',
+      help='A file listing runtime dependencies for setup.exe. This will be '
+           'used to get a list of DLLs to archive in a component build.')
+  parser.add_option('-v', '--verbose', action='store_true', dest='verbose',
+                    default=False)
+
+  options, _ = parser.parse_args()
+  if not options.build_dir:
+    parser.error('You must provide a build dir.')
+
+  options.build_dir = os.path.normpath(options.build_dir)
+
+  if not options.staging_dir:
+    parser.error('You must provide a staging dir.')
+
+  if not options.input_file:
+    parser.error('You must provide an input file')
+
+  is_component_build = options.component_build == '1'
+  if is_component_build and not options.setup_runtime_deps:
+    parser.error("updater_runtime_deps must be specified for a component build")
+
+  if not options.output_dir:
+    options.output_dir = options.build_dir
+
+  return options
+
+
+if '__main__' == __name__:
+  options = _ParseOptions()
+  if options.verbose:
+    print sys.argv
+  sys.exit(main(options))
diff --git a/chrome/updater/win/installer/exit_code.h b/chrome/updater/win/installer/exit_code.h
new file mode 100644
index 0000000..a9704000d
--- /dev/null
+++ b/chrome/updater/win/installer/exit_code.h
@@ -0,0 +1,28 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_UPDATER_WIN_INSTALLER_EXIT_CODE_H_
+#define CHROME_UPDATER_WIN_INSTALLER_EXIT_CODE_H_
+
+namespace updater {
+
+// Installer process exit codes (the underlying type is uint32_t).
+enum ExitCode {
+  SUCCESS_EXIT_CODE = 0,
+  GENERIC_INITIALIZATION_FAILURE = 101,
+  COMMAND_STRING_OVERFLOW = 105,
+  WAIT_FOR_PROCESS_FAILED = 107,
+  PATH_STRING_OVERFLOW = 108,
+  UNABLE_TO_GET_WORK_DIRECTORY = 109,
+  UNABLE_TO_EXTRACT_ARCHIVE = 112,
+  UNABLE_TO_SET_DIRECTORY_ACL = 117,
+  INVALID_OPTION = 118,
+  RUN_SETUP_FAILED_FILE_NOT_FOUND = 122,            // ERROR_FILE_NOT_FOUND.
+  RUN_SETUP_FAILED_PATH_NOT_FOUND = 123,            // ERROR_PATH_NOT_FOUND.
+  RUN_SETUP_FAILED_COULD_NOT_CREATE_PROCESS = 124,  // All other errors.
+};
+
+}  // namespace updater
+
+#endif  // CHROME_UPDATER_WIN_INSTALLER_EXIT_CODE_H_
diff --git a/chrome/updater/win/installer/installer.cc b/chrome/updater/win/installer/installer.cc
new file mode 100644
index 0000000..787a3da
--- /dev/null
+++ b/chrome/updater/win/installer/installer.cc
@@ -0,0 +1,460 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// GoogleUpdateSetup.exe is the first exe that is run when chrome is being
+// installed. It has two main jobs:
+//   1) unpack the resources (possibly decompressing some)
+//   2) run the real installer (updater.exe) with appropriate flags (--install).
+//
+// All files needed by the updater are archived together as an uncompressed
+// LZMA file, which is further compressed as one file, and inserted as a
+// binary resource in the resource section of the setup program.
+
+#include "chrome/updater/win/installer/installer.h"
+
+// #define needed to link in RtlGenRandom(), a.k.a. SystemFunction036.  See the
+// "Community Additions" comment on MSDN here:
+// http://msdn.microsoft.com/en-us/library/windows/desktop/aa387694.aspx
+#define SystemFunction036 NTAPI SystemFunction036
+#include <NTSecAPI.h>
+#undef SystemFunction036
+
+#include <sddl.h>
+#include <shellapi.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+#include <initializer_list>
+
+// TODO(sorin): remove the dependecies on //base/ to reduce the code size.
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/path_service.h"
+#include "chrome/installer/util/lzma_util.h"
+#include "chrome/installer/util/self_cleaning_temp_dir.h"
+#include "chrome/installer/util/util_constants.h"
+#include "chrome/updater/win/installer/configuration.h"
+#include "chrome/updater/win/installer/installer_constants.h"
+#include "chrome/updater/win/installer/pe_resource.h"
+#include "chrome/updater/win/installer/regkey.h"
+
+namespace updater {
+
+namespace {
+
+// Initializes |temp_path| to "Temp" within the target directory, and
+// |unpack_path| to a random directory beginning with "source" within
+// |temp_path|. Returns false on error.
+bool CreateTemporaryAndUnpackDirectories(
+    installer::SelfCleaningTempDir* temp_path,
+    base::FilePath* unpack_path) {
+  DCHECK(temp_path && unpack_path);
+
+  base::FilePath temp_dir;
+  if (!base::PathService::Get(base::DIR_TEMP, &temp_dir))
+    return false;
+
+  if (!temp_path->Initialize(temp_dir, kTempPrefix)) {
+    PLOG(ERROR) << "Could not create temporary path.";
+    return false;
+  }
+  VLOG(1) << "Created path " << temp_path->path().value();
+
+  if (!base::CreateTemporaryDirInDir(temp_path->path(), L"source",
+                                     unpack_path)) {
+    PLOG(ERROR) << "Could not create temporary path for unpacked archive.";
+    return false;
+  }
+
+  return true;
+}
+
+}  // namespace
+
+using PathString = StackString<MAX_PATH>;
+
+// This structure passes data back and forth for the processing
+// of resource callbacks.
+struct Context {
+  // Input to the call back method. Specifies the dir to save resources into.
+  const wchar_t* base_path = nullptr;
+
+  // First output from call back method. Specifies the path of resource archive.
+  PathString* updater_resource_path = nullptr;
+};
+
+// Calls CreateProcess with good default parameters and waits for the process to
+// terminate returning the process exit code. In case of CreateProcess failure,
+// returns a results object with the provided codes as follows:
+// - ERROR_FILE_NOT_FOUND: (file_not_found_code, attributes of setup.exe).
+// - ERROR_PATH_NOT_FOUND: (path_not_found_code, attributes of setup.exe).
+// - Otherwise: (generic_failure_code, CreateProcess error code).
+// In case of error waiting for the process to exit, returns a results object
+// with (WAIT_FOR_PROCESS_FAILED, last error code). Otherwise, returns a results
+// object with the subprocess's exit code.
+ProcessExitResult RunProcessAndWait(const wchar_t* exe_path, wchar_t* cmdline) {
+  STARTUPINFOW si = {sizeof(si)};
+  PROCESS_INFORMATION pi = {0};
+  if (!::CreateProcess(exe_path, cmdline, nullptr, nullptr, FALSE,
+                       CREATE_NO_WINDOW, nullptr, nullptr, &si, &pi)) {
+    // Split specific failure modes. If the process couldn't be launched because
+    // its file/path couldn't be found, report its attributes in ExtraCode1.
+    // This will help diagnose the prevalence of launch failures due to Image
+    // File Execution Options tampering. See https://crbug.com/672813 for more
+    // details.
+    const DWORD last_error = ::GetLastError();
+    const DWORD attributes = ::GetFileAttributes(exe_path);
+    switch (last_error) {
+      case ERROR_FILE_NOT_FOUND:
+        return ProcessExitResult(RUN_SETUP_FAILED_FILE_NOT_FOUND, attributes);
+      case ERROR_PATH_NOT_FOUND:
+        return ProcessExitResult(RUN_SETUP_FAILED_PATH_NOT_FOUND, attributes);
+      default:
+        break;
+    }
+    // Lump all other errors into a distinct failure bucket.
+    return ProcessExitResult(RUN_SETUP_FAILED_COULD_NOT_CREATE_PROCESS,
+                             last_error);
+  }
+
+  ::CloseHandle(pi.hThread);
+
+  DWORD exit_code = SUCCESS_EXIT_CODE;
+  DWORD wr = ::WaitForSingleObject(pi.hProcess, INFINITE);
+  if (WAIT_OBJECT_0 != wr || !::GetExitCodeProcess(pi.hProcess, &exit_code)) {
+    // Note:  We've assumed that WAIT_OBJCT_0 != wr means a failure.  The call
+    // could return a different object but since we never spawn more than one
+    // sub-process at a time that case should never happen.
+    return ProcessExitResult(WAIT_FOR_PROCESS_FAILED, ::GetLastError());
+  }
+
+  ::CloseHandle(pi.hProcess);
+
+  return ProcessExitResult(exit_code);
+}
+
+// Windows defined callback used in the EnumResourceNames call. For each
+// matching resource found, the callback is invoked and at this point we write
+// it to disk. We expect resource names to start with the 'updater' prefix.
+// Any other name is treated as an error.
+BOOL CALLBACK OnResourceFound(HMODULE module,
+                              const wchar_t* type,
+                              wchar_t* name,
+                              LONG_PTR context) {
+  Context* ctx = reinterpret_cast<Context*>(context);
+  if (!ctx)
+    return FALSE;
+
+  if (!StrStartsWith(name, kUpdaterArchivePrefix))
+    return FALSE;
+
+  PEResource resource(name, type, module);
+  if (!resource.IsValid() || resource.Size() < 1)
+    return FALSE;
+
+  PathString full_path;
+  if (!full_path.assign(ctx->base_path) || !full_path.append(name) ||
+      !resource.WriteToDisk(full_path.get())) {
+    return FALSE;
+  }
+
+  if (!ctx->updater_resource_path->assign(full_path.get()))
+    return FALSE;
+
+  return TRUE;
+}
+
+// Finds and writes to disk resources of type 'B7' (7zip archive). Returns false
+// if there is a problem in writing any resource to disk.
+ProcessExitResult UnpackBinaryResources(const Configuration& configuration,
+                                        HMODULE module,
+                                        const wchar_t* base_path,
+                                        PathString* archive_path) {
+  // Prepare the input to OnResourceFound method that needs a location where
+  // it will write all the resources.
+  Context context = {base_path, archive_path};
+
+  // Get the resources of type 'B7' (7zip archive).
+  if (!::EnumResourceNames(module, kLZMAResourceType, OnResourceFound,
+                           reinterpret_cast<LONG_PTR>(&context))) {
+    return ProcessExitResult(UNABLE_TO_EXTRACT_ARCHIVE, ::GetLastError());
+  }
+
+  if (archive_path->length() == 0)
+    return ProcessExitResult(UNABLE_TO_EXTRACT_ARCHIVE);
+
+  ProcessExitResult exit_code = ProcessExitResult(SUCCESS_EXIT_CODE);
+
+  return exit_code;
+}
+
+// Executes updater.exe, waits for it to finish and returns the exit code.
+ProcessExitResult RunSetup(const Configuration& configuration,
+                           const wchar_t* setup_path) {
+  PathString setup_exe;
+
+  if (*setup_path != L'\0') {
+    if (!setup_exe.assign(setup_path))
+      return ProcessExitResult(COMMAND_STRING_OVERFLOW);
+  }
+
+  CommandString cmd_line;
+
+  // Put the quoted path to setup.exe in cmd_line first.
+  if (!cmd_line.assign(L"\"") || !cmd_line.append(setup_exe.get()) ||
+      !cmd_line.append(L"\"")) {
+    return ProcessExitResult(COMMAND_STRING_OVERFLOW);
+  }
+
+  if (!cmd_line.append(L" --install --enable-logging --v=1"))
+    return ProcessExitResult(COMMAND_STRING_OVERFLOW);
+
+  return RunProcessAndWait(setup_exe.get(), cmd_line.get());
+}
+
+// Returns true if the supplied path supports ACLs.
+bool IsAclSupportedForPath(const wchar_t* path) {
+  PathString volume;
+  DWORD flags = 0;
+  return ::GetVolumePathName(path, volume.get(),
+                             static_cast<DWORD>(volume.capacity())) &&
+         ::GetVolumeInformation(volume.get(), nullptr, 0, nullptr, nullptr,
+                                &flags, nullptr, 0) &&
+         (flags & FILE_PERSISTENT_ACLS);
+}
+
+// Retrieves the SID of the default owner for objects created by this user
+// token (accounting for different behavior under UAC elevation, etc.).
+// NOTE: On success the |sid| parameter must be freed with LocalFree().
+bool GetCurrentOwnerSid(wchar_t** sid) {
+  HANDLE token;
+  if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, &token))
+    return false;
+
+  DWORD size = 0;
+  bool result = false;
+  // We get the TokenOwner rather than the TokenUser because e.g. under UAC
+  // elevation we want the admin to own the directory rather than the user.
+  ::GetTokenInformation(token, TokenOwner, nullptr, 0, &size);
+  if (size && GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
+    if (TOKEN_OWNER* owner =
+            reinterpret_cast<TOKEN_OWNER*>(::LocalAlloc(LPTR, size))) {
+      if (::GetTokenInformation(token, TokenOwner, owner, size, &size))
+        result = !!::ConvertSidToStringSid(owner->Owner, sid);
+      ::LocalFree(owner);
+    }
+  }
+  ::CloseHandle(token);
+  return result;
+}
+
+// Populates |sd| suitable for use when creating directories within |path| with
+// ACLs allowing access to only the current owner, admin, and system.
+// NOTE: On success the |sd| parameter must be freed with LocalFree().
+bool SetSecurityDescriptor(const wchar_t* path, PSECURITY_DESCRIPTOR* sd) {
+  *sd = nullptr;
+  // We succeed without doing anything if ACLs aren't supported.
+  if (!IsAclSupportedForPath(path))
+    return true;
+
+  wchar_t* sid = nullptr;
+  if (!GetCurrentOwnerSid(&sid))
+    return false;
+
+  // The largest SID is under 200 characters, so 300 should give enough slack.
+  StackString<300> sddl;
+  bool result = sddl.append(
+                    L"D:PAI"         // Protected, auto-inherited DACL.
+                    L"(A;;FA;;;BA)"  // Admin: Full control.
+                    L"(A;OIIOCI;GA;;;BA)"
+                    L"(A;;FA;;;SY)"  // System: Full control.
+                    L"(A;OIIOCI;GA;;;SY)"
+                    L"(A;OIIOCI;GA;;;CO)"  // Owner: Full control.
+                    L"(A;;FA;;;") &&
+                sddl.append(sid) && sddl.append(L")");
+  if (result) {
+    result = !!::ConvertStringSecurityDescriptorToSecurityDescriptor(
+        sddl.get(), SDDL_REVISION_1, sd, nullptr);
+  }
+
+  ::LocalFree(sid);
+  return result;
+}
+
+// Creates a temporary directory under |base_path| and returns the full path
+// of created directory in |work_dir|. If successful return true, otherwise
+// false.  When successful, the returned |work_dir| will always have a trailing
+// backslash and this function requires that |base_path| always includes a
+// trailing backslash as well.
+// We do not use GetTempFileName here to avoid running into AV software that
+// might hold on to the temp file as soon as we create it and then we can't
+// delete it and create a directory in its place.  So, we use our own mechanism
+// for creating a directory with a hopefully-unique name.  In the case of a
+// collision, we retry a few times with a new name before failing.
+bool CreateWorkDir(const wchar_t* base_path,
+                   PathString* work_dir,
+                   ProcessExitResult* exit_code) {
+  *exit_code = ProcessExitResult(PATH_STRING_OVERFLOW);
+  if (!work_dir->assign(base_path) || !work_dir->append(kTempPrefix))
+    return false;
+
+  // Store the location where we'll append the id.
+  size_t end = work_dir->length();
+
+  // Check if we'll have enough buffer space to continue.
+  // The name of the directory will use up 11 chars and then we need to append
+  // the trailing backslash and a terminator.  We've already added the prefix
+  // to the buffer, so let's just make sure we've got enough space for the rest.
+  if ((work_dir->capacity() - end) < (_countof("fffff.tmp") + 1))
+    return false;
+
+  // Add an ACL if supported by the filesystem. Otherwise system-level installs
+  // are potentially vulnerable to file squatting attacks.
+  SECURITY_ATTRIBUTES sa = {};
+  sa.nLength = sizeof(SECURITY_ATTRIBUTES);
+  if (!SetSecurityDescriptor(base_path, &sa.lpSecurityDescriptor)) {
+    *exit_code =
+        ProcessExitResult(UNABLE_TO_SET_DIRECTORY_ACL, ::GetLastError());
+    return false;
+  }
+
+  unsigned int id;
+  *exit_code = ProcessExitResult(UNABLE_TO_GET_WORK_DIRECTORY);
+  for (int max_attempts = 10; max_attempts; --max_attempts) {
+    ::RtlGenRandom(&id, sizeof(id));  // Try a different name.
+
+    // This converts 'id' to a string in the format "78563412" on windows
+    // because of little endianness, but we don't care since it's just
+    // a name. Since we checked capaity at the front end, we don't need to
+    // duplicate it here.
+    HexEncode(&id, sizeof(id), work_dir->get() + end,
+              work_dir->capacity() - end);
+
+    // We only want the first 5 digits to remain within the 8.3 file name
+    // format (compliant with previous implementation).
+    work_dir->truncate_at(end + 5);
+
+    // for consistency with the previous implementation which relied on
+    // GetTempFileName, we append the .tmp extension.
+    work_dir->append(L".tmp");
+
+    if (::CreateDirectory(work_dir->get(),
+                          sa.lpSecurityDescriptor ? &sa : nullptr)) {
+      // Yay!  Now let's just append the backslash and we're done.
+      work_dir->append(L"\\");
+      *exit_code = ProcessExitResult(SUCCESS_EXIT_CODE);
+      break;
+    }
+  }
+
+  if (sa.lpSecurityDescriptor)
+    LocalFree(sa.lpSecurityDescriptor);
+  return exit_code->IsSuccess();
+}
+
+// Creates and returns a temporary directory in |work_dir| that can be used to
+// extract updater payload. |work_dir| ends with a path separator.
+bool GetWorkDir(HMODULE module,
+                PathString* work_dir,
+                ProcessExitResult* exit_code) {
+  PathString base_path;
+  DWORD len =
+      ::GetTempPath(static_cast<DWORD>(base_path.capacity()), base_path.get());
+  if (!len || len >= base_path.capacity() ||
+      !CreateWorkDir(base_path.get(), work_dir, exit_code)) {
+    // Problem creating the work dir under TEMP path, so try using the
+    // current directory as the base path.
+    len = ::GetModuleFileName(module, base_path.get(),
+                              static_cast<DWORD>(base_path.capacity()));
+    if (len >= base_path.capacity() || !len)
+      return false;  // Can't even get current directory? Return an error.
+
+    wchar_t* name = GetNameFromPathExt(base_path.get(), len);
+    if (name == base_path.get())
+      return false;  // There was no directory in the string!  Bail out.
+
+    *name = L'\0';
+
+    *exit_code = ProcessExitResult(SUCCESS_EXIT_CODE);
+    return CreateWorkDir(base_path.get(), work_dir, exit_code);
+  }
+  return true;
+}
+
+// Returns true for ".." and "." directories.
+bool IsCurrentOrParentDirectory(const wchar_t* dir) {
+  return dir && dir[0] == L'.' &&
+         (dir[1] == L'\0' || (dir[1] == L'.' && dir[2] == L'\0'));
+}
+
+ProcessExitResult WMain(HMODULE module) {
+  ProcessExitResult exit_code = ProcessExitResult(SUCCESS_EXIT_CODE);
+
+  // Parse configuration from the command line and resources.
+  Configuration configuration;
+  if (!configuration.Initialize(module))
+    return ProcessExitResult(GENERIC_INITIALIZATION_FAILURE, ::GetLastError());
+
+  // Exit early if an invalid switch was found on the command line.
+  if (configuration.has_invalid_switch())
+    return ProcessExitResult(INVALID_OPTION);
+
+  // First get a path where we can extract the resource payload, which is
+  // a compressed LZMA archive of a single file.
+  base::ScopedTempDir base_path_owner;
+  PathString base_path;
+  if (!GetWorkDir(module, &base_path, &exit_code))
+    return exit_code;
+  if (!base_path_owner.Set(base::FilePath(base_path.get()))) {
+    ::DeleteFile(base_path.get());
+    return ProcessExitResult(static_cast<DWORD>(installer::TEMP_DIR_FAILED));
+  }
+
+  PathString compressed_archive;
+  exit_code = UnpackBinaryResources(configuration, module, base_path.get(),
+                                    &compressed_archive);
+
+  // Create a temp folder where the archives are unpacked.
+  base::FilePath unpack_path;
+  installer::SelfCleaningTempDir temp_path;
+  if (!CreateTemporaryAndUnpackDirectories(&temp_path, &unpack_path))
+    return ProcessExitResult(static_cast<DWORD>(installer::TEMP_DIR_FAILED));
+
+  // Unpack the compressed archive to extract the uncompressed archive file.
+  UnPackStatus unpack_status = UNPACK_NO_ERROR;
+  int32_t ntstatus = 0;
+  auto lzma_result =
+      UnPackArchive(base::FilePath(compressed_archive.get()), unpack_path,
+                    nullptr, &unpack_status, &ntstatus);
+  if (lzma_result)
+    return ProcessExitResult(static_cast<DWORD>(installer::UNPACKING_FAILED));
+
+  // Unpack the uncompressed archive to extract the updater files.
+  base::FilePath uncompressed_archive =
+      unpack_path.Append(FILE_PATH_LITERAL("updater.7z"));
+  lzma_result = UnPackArchive(uncompressed_archive, unpack_path, nullptr,
+                              &unpack_status, &ntstatus);
+  if (lzma_result)
+    return ProcessExitResult(static_cast<DWORD>(installer::UNPACKING_FAILED));
+
+  // While unpacking the binaries, we paged in a whole bunch of memory that
+  // we don't need anymore.  Let's give it back to the pool before running
+  // setup.
+  ::SetProcessWorkingSetSize(::GetCurrentProcess(), static_cast<SIZE_T>(-1),
+                             static_cast<SIZE_T>(-1));
+
+  PathString setup_path;
+  if (!setup_path.assign(unpack_path.value().c_str()) ||
+      !setup_path.append(L"\\bin\\updater.exe")) {
+    exit_code = ProcessExitResult(PATH_STRING_OVERFLOW);
+  }
+
+  if (exit_code.IsSuccess())
+    exit_code = RunSetup(configuration, setup_path.get());
+
+  return exit_code;
+}
+
+}  // namespace updater
diff --git a/chrome/updater/win/installer/installer.exe.manifest b/chrome/updater/win/installer/installer.exe.manifest
new file mode 100644
index 0000000..c7ac2fa0
--- /dev/null
+++ b/chrome/updater/win/installer/installer.exe.manifest
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+  <!--
+    Have compatibility section here instead of using
+      build/win/compatibility.manifest
+    to work around crbug.com/272660.
+    TODO(yukawa): Use build/win/compatibility.manifest again.
+  -->
+  <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
+    <application>
+      <!--The ID below indicates application support for Windows Vista -->
+      <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
+      <!--The ID below indicates application support for Windows 7 -->
+      <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
+      <!--The ID below indicates application support for Windows 8 -->
+      <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
+      <!--The ID below indicates application support for Windows 8.1 -->
+      <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
+      <!--The ID below indicates application support for Windows 10 -->
+      <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
+    </application>
+  </compatibility>
+  <ms_asmv2:trustInfo xmlns:ms_asmv2="urn:schemas-microsoft-com:asm.v2">
+    <ms_asmv2:security>
+      <ms_asmv2:requestedPrivileges>
+        <ms_asmv2:requestedExecutionLevel level="asInvoker" />
+      </ms_asmv2:requestedPrivileges>
+    </ms_asmv2:security>
+  </ms_asmv2:trustInfo>
+</assembly>
diff --git a/chrome/updater/win/installer/installer.h b/chrome/updater/win/installer/installer.h
new file mode 100644
index 0000000..0a7b75e
--- /dev/null
+++ b/chrome/updater/win/installer/installer.h
@@ -0,0 +1,37 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_UPDATER_WIN_INSTALLER_INSTALLER_H_
+#define CHROME_UPDATER_WIN_INSTALLER_INSTALLER_H_
+
+#include <windows.h>
+
+#include "chrome/updater/win/installer/exit_code.h"
+#include "chrome/updater/win/installer/string.h"
+
+namespace updater {
+
+// A container of a process exit code (eventually passed to ExitProcess) and
+// a Windows error code for cases where the exit code is non-zero.
+struct ProcessExitResult {
+  DWORD exit_code;
+  DWORD windows_error;
+
+  explicit ProcessExitResult(DWORD exit) : exit_code(exit), windows_error(0) {}
+  ProcessExitResult(DWORD exit, DWORD win)
+      : exit_code(exit), windows_error(win) {}
+
+  bool IsSuccess() const { return exit_code == SUCCESS_EXIT_CODE; }
+};
+
+// A stack-based string large enough to hold an executable to run
+// (which is a path), plus a few extra arguments.
+using CommandString = StackString<MAX_PATH * 4>;
+
+// Main function for the installer.
+ProcessExitResult WMain(HMODULE module);
+
+}  // namespace updater
+
+#endif  // CHROME_UPDATER_WIN_INSTALLER_INSTALLER_H_
diff --git a/chrome/updater/win/installer/installer.ico b/chrome/updater/win/installer/installer.ico
new file mode 100644
index 0000000..5ecfcbd
--- /dev/null
+++ b/chrome/updater/win/installer/installer.ico
Binary files differ
diff --git a/chrome/updater/win/installer/installer.rc b/chrome/updater/win/installer/installer.rc
new file mode 100644
index 0000000..76cb035
--- /dev/null
+++ b/chrome/updater/win/installer/installer.rc
@@ -0,0 +1,55 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "installer_resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#define APSTUDIO_HIDDEN_SYMBOLS
+#include "windows.h"
+#undef APSTUDIO_HIDDEN_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_MINI_INSTALLER      ICON                    "installer.ico"
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+    "installer_resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+    "#define APSTUDIO_HIDDEN_SYMBOLS\r\n"
+    "#include ""windows.h""\r\n"
+    "#undef APSTUDIO_HIDDEN_SYMBOL\0"
+END
+
+#endif    // APSTUDIO_INVOKED
+
+#endif    // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
diff --git a/chrome/updater/win/installer/installer_constants.cc b/chrome/updater/win/installer/installer_constants.cc
new file mode 100644
index 0000000..f102f7a8
--- /dev/null
+++ b/chrome/updater/win/installer/installer_constants.cc
@@ -0,0 +1,18 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/updater/win/installer/installer_constants.h"
+
+namespace updater {
+
+// The prefix of the updater archive resource.
+const wchar_t kUpdaterArchivePrefix[] = L"updater";
+
+// Temp directory prefix that this process creates.
+const wchar_t kTempPrefix[] = L"UPDATER";
+
+// 7zip archive.
+const wchar_t kLZMAResourceType[] = L"B7";
+
+}  // namespace updater
diff --git a/chrome/updater/win/installer/installer_constants.h b/chrome/updater/win/installer/installer_constants.h
new file mode 100644
index 0000000..fc0bf779
--- /dev/null
+++ b/chrome/updater/win/installer/installer_constants.h
@@ -0,0 +1,19 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_UPDATER_WIN_INSTALLER_INSTALLER_CONSTANTS_H_
+#define CHROME_UPDATER_WIN_INSTALLER_INSTALLER_CONSTANTS_H_
+
+namespace updater {
+
+// Various filenames and prefixes.
+extern const wchar_t kUpdaterArchivePrefix[];
+extern const wchar_t kTempPrefix[];
+
+// The resource types that would be unpacked from the mini installer.
+extern const wchar_t kLZMAResourceType[];
+
+}  // namespace updater
+
+#endif  // CHROME_UPDATER_WIN_INSTALLER_INSTALLER_CONSTANTS_H_
diff --git a/chrome/updater/win/installer/installer_main.cc b/chrome/updater/win/installer/installer_main.cc
new file mode 100644
index 0000000..8c181caa
--- /dev/null
+++ b/chrome/updater/win/installer/installer_main.cc
@@ -0,0 +1,20 @@
+// 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 <windows.h>
+
+#include "chrome/updater/win/installer/installer.h"
+
+// http://blogs.msdn.com/oldnewthing/archive/2004/10/25/247180.aspx
+extern "C" IMAGE_DOS_HEADER __ImageBase;
+
+int WINAPI wWinMain(HINSTANCE /* instance */,
+                    HINSTANCE /* previous_instance */,
+                    LPWSTR /* command_line */,
+                    int /* command_show */) {
+  updater::ProcessExitResult result =
+      updater::WMain(reinterpret_cast<HMODULE>(&__ImageBase));
+
+  return result.exit_code;
+}
diff --git a/chrome/updater/win/installer/installer_resource.h b/chrome/updater/win/installer/installer_resource.h
new file mode 100644
index 0000000..2bf5e973
--- /dev/null
+++ b/chrome/updater/win/installer/installer_resource.h
@@ -0,0 +1,22 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_UPDATER_WIN_INSTALLER_INSTALLER_RESOURCE_H_
+#define CHROME_UPDATER_WIN_INSTALLER_INSTALLER_RESOURCE_H_
+
+#define IDC_STATIC -1
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NO_MFC 1
+#define _APS_NEXT_RESOURCE_VALUE 129
+#define _APS_NEXT_COMMAND_VALUE 32771
+#define _APS_NEXT_CONTROL_VALUE 1000
+#define _APS_NEXT_SYMED_VALUE 110
+#endif
+#endif
+
+#endif  // CHROME_UPDATER_WIN_INSTALLER_INSTALLER_RESOURCE_H_
diff --git a/chrome/updater/win/installer/installer_version.rc.version b/chrome/updater/win/installer/installer_version.rc.version
new file mode 100644
index 0000000..bbe41b4b
--- /dev/null
+++ b/chrome/updater/win/installer/installer_version.rc.version
@@ -0,0 +1,44 @@
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+// Use the ordinal 1 here, to avoid needing to #include a header file
+// to use the VS_VERSION_INFO macro. This header file changes with different
+// SDK versions which causes headaches building in some environments. The
+// VERSIONINFO resource will always be at index 1.
+1 VERSIONINFO
+ FILEVERSION @MAJOR@,@MINOR@,@BUILD@,@PATCH@
+ PRODUCTVERSION @MAJOR@,@MINOR@,@BUILD@,@PATCH@
+ FILEFLAGSMASK 0x17L
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "040904b0"
+        BEGIN
+            VALUE "CompanyName", "@COMPANY_FULLNAME@"
+            VALUE "FileDescription", "@PRODUCT_INSTALLER_FULLNAME@"
+            VALUE "FileVersion", "@MAJOR@.@MINOR@.@BUILD@.@PATCH@"
+            VALUE "InternalName", "Chrome Updater"
+            VALUE "LegalCopyright", "@COPYRIGHT@"
+            VALUE "ProductName", "@PRODUCT_INSTALLER_FULLNAME@"
+            VALUE "ProductVersion", "@MAJOR@.@MINOR@.@BUILD@.@PATCH@"
+            VALUE "CompanyShortName", "@COMPANY_SHORTNAME@"
+            VALUE "ProductShortName", "@PRODUCT_INSTALLER_SHORTNAME@"
+            VALUE "LastChange", "@LASTCHANGE@"
+            VALUE "Official Build", "@OFFICIAL_BUILD@"
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x409, 1200
+    END
+END
diff --git a/chrome/updater/win/installer/pe_resource.cc b/chrome/updater/win/installer/pe_resource.cc
new file mode 100644
index 0000000..248a133
--- /dev/null
+++ b/chrome/updater/win/installer/pe_resource.cc
@@ -0,0 +1,48 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/updater/win/installer/pe_resource.h"
+
+namespace updater {
+
+PEResource::PEResource(const wchar_t* name, const wchar_t* type, HMODULE module)
+    : resource_(nullptr), module_(module) {
+  resource_ = ::FindResource(module, name, type);
+}
+
+bool PEResource::IsValid() {
+  return nullptr != resource_;
+}
+
+size_t PEResource::Size() {
+  return ::SizeofResource(module_, resource_);
+}
+
+bool PEResource::WriteToDisk(const wchar_t* full_path) {
+  // Resource handles are not real HGLOBALs so do not attempt to close them.
+  // Windows frees them whenever there is memory pressure.
+  HGLOBAL data_handle = ::LoadResource(module_, resource_);
+  if (nullptr == data_handle)
+    return false;
+
+  void* data = ::LockResource(data_handle);
+  if (nullptr == data)
+    return false;
+
+  size_t resource_size = Size();
+  HANDLE out_file = ::CreateFile(full_path, GENERIC_WRITE, 0, nullptr,
+                                 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
+  if (INVALID_HANDLE_VALUE == out_file)
+    return false;
+
+  DWORD written = 0;
+  if (!::WriteFile(out_file, data, static_cast<DWORD>(resource_size), &written,
+                   nullptr)) {
+    ::CloseHandle(out_file);
+    return false;
+  }
+  return ::CloseHandle(out_file) ? true : false;
+}
+
+}  // namespace updater
diff --git a/chrome/updater/win/installer/pe_resource.h b/chrome/updater/win/installer/pe_resource.h
new file mode 100644
index 0000000..e19531a
--- /dev/null
+++ b/chrome/updater/win/installer/pe_resource.h
@@ -0,0 +1,42 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_UPDATER_WIN_INSTALLER_PE_RESOURCE_H_
+#define CHROME_UPDATER_WIN_INSTALLER_PE_RESOURCE_H_
+
+#include <stddef.h>
+#include <windows.h>
+
+namespace updater {
+
+// This class models a windows PE resource. It does not pretend to be a full
+// API wrapper and it is just concerned with loading it to memory and writing
+// it to disk. Each resource is unique only in the context of a loaded module,
+// that is why you need to specify one on each constructor.
+class PEResource {
+ public:
+  // Takes the resource name, the resource type, and the module where
+  // to look for the resource. If the resource is found IsValid() returns true.
+  PEResource(const wchar_t* name, const wchar_t* type, HMODULE module);
+
+  // Returns true if the resource is valid.
+  bool IsValid();
+
+  // Returns the size in bytes of the resource. Returns zero if the resource is
+  // not valid.
+  size_t Size();
+
+  // Creates a file in |path| with a copy of the resource. If the resource can
+  // not be loaded into memory or if it cannot be written to disk it returns
+  // false.
+  bool WriteToDisk(const wchar_t* path);
+
+ private:
+  HRSRC resource_ = nullptr;
+  HMODULE module_ = nullptr;
+};
+
+}  // namespace updater
+
+#endif  // CHROME_UPDATER_WIN_INSTALLER_PE_RESOURCE_H_
diff --git a/chrome/updater/win/installer/regkey.cc b/chrome/updater/win/installer/regkey.cc
new file mode 100644
index 0000000..62b622de
--- /dev/null
+++ b/chrome/updater/win/installer/regkey.cc
@@ -0,0 +1,83 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/updater/win/installer/regkey.h"
+
+#include "chrome/updater/win/installer/installer_constants.h"
+#include "chrome/updater/win/installer/string.h"
+
+namespace updater {
+
+LONG RegKey::Open(HKEY key, const wchar_t* sub_key, REGSAM access) {
+  Close();
+  return ::RegOpenKeyEx(key, sub_key, 0, access, &key_);
+}
+
+LONG RegKey::ReadSZValue(const wchar_t* value_name,
+                         wchar_t* value,
+                         size_t value_size) const {
+  DWORD type = 0;
+  DWORD byte_length = static_cast<DWORD>(value_size * sizeof(wchar_t));
+  LONG result = ::RegQueryValueEx(key_, value_name, nullptr, &type,
+                                  reinterpret_cast<BYTE*>(value), &byte_length);
+  if (result == ERROR_SUCCESS) {
+    if (type != REG_SZ) {
+      result = ERROR_NOT_SUPPORTED;
+    } else if (byte_length < 2) {
+      *value = L'\0';
+    } else if (value[byte_length / sizeof(wchar_t) - 1] != L'\0') {
+      if ((byte_length / sizeof(wchar_t)) < value_size)
+        value[byte_length / sizeof(wchar_t)] = L'\0';
+      else
+        result = ERROR_MORE_DATA;
+    }
+  }
+  return result;
+}
+
+LONG RegKey::ReadDWValue(const wchar_t* value_name, DWORD* value) const {
+  DWORD type = 0;
+  DWORD byte_length = sizeof(*value);
+  LONG result = ::RegQueryValueEx(key_, value_name, nullptr, &type,
+                                  reinterpret_cast<BYTE*>(value), &byte_length);
+  if (result == ERROR_SUCCESS) {
+    if (type != REG_DWORD) {
+      result = ERROR_NOT_SUPPORTED;
+    } else if (byte_length != sizeof(*value)) {
+      result = ERROR_NO_DATA;
+    }
+  }
+  return result;
+}
+
+LONG RegKey::WriteSZValue(const wchar_t* value_name, const wchar_t* value) {
+  return ::RegSetValueEx(key_, value_name, 0, REG_SZ,
+                         reinterpret_cast<const BYTE*>(value),
+                         (lstrlen(value) + 1) * sizeof(wchar_t));
+}
+
+LONG RegKey::WriteDWValue(const wchar_t* value_name, DWORD value) {
+  return ::RegSetValueEx(key_, value_name, 0, REG_DWORD,
+                         reinterpret_cast<const BYTE*>(&value), sizeof(value));
+}
+
+void RegKey::Close() {
+  if (key_ != nullptr) {
+    ::RegCloseKey(key_);
+    key_ = nullptr;
+  }
+}
+
+// static
+bool RegKey::ReadSZValue(HKEY root_key,
+                         const wchar_t* sub_key,
+                         const wchar_t* value_name,
+                         wchar_t* value,
+                         size_t size) {
+  RegKey key;
+  return (key.Open(root_key, sub_key, KEY_QUERY_VALUE) == ERROR_SUCCESS &&
+          key.ReadSZValue(value_name, value, size) == ERROR_SUCCESS);
+}
+
+}  // namespace updater
diff --git a/chrome/updater/win/installer/regkey.h b/chrome/updater/win/installer/regkey.h
new file mode 100644
index 0000000..5dd7c402
--- /dev/null
+++ b/chrome/updater/win/installer/regkey.h
@@ -0,0 +1,61 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_UPDATER_WIN_INSTALLER_REGKEY_H_
+#define CHROME_UPDATER_WIN_INSTALLER_REGKEY_H_
+
+#include <stddef.h>
+#include <windows.h>
+
+namespace updater {
+
+// A helper class used to manipulate the Windows registry.
+class RegKey {
+ public:
+  RegKey() : key_(nullptr) {}
+  ~RegKey() { Close(); }
+
+  // Opens the key named |sub_key| with given |access| rights.  Returns
+  // ERROR_SUCCESS or some other error.
+  LONG Open(HKEY key, const wchar_t* sub_key, REGSAM access);
+
+  // Returns true if a key is open.
+  bool is_valid() const { return key_ != nullptr; }
+
+  // Read a value from the registry into the memory indicated by |value|
+  // (of |value_size| wchar_t units).  Returns ERROR_SUCCESS,
+  // ERROR_FILE_NOT_FOUND, ERROR_MORE_DATA, or some other error.  |value| is
+  // guaranteed to be null-terminated on success.
+  LONG ReadSZValue(const wchar_t* value_name,
+                   wchar_t* value,
+                   size_t value_size) const;
+  LONG ReadDWValue(const wchar_t* value_name, DWORD* value) const;
+
+  // Write a value to the registry.  SZ |value| must be null-terminated.
+  // Returns ERROR_SUCCESS or an error code.
+  LONG WriteSZValue(const wchar_t* value_name, const wchar_t* value);
+  LONG WriteDWValue(const wchar_t* value_name, DWORD value);
+
+  // Closes the key if it was open.
+  void Close();
+
+  // Helper function to read a value from registry.  Returns true if value
+  // is read successfully and stored in parameter value. Returns false
+  // otherwise. |size| is measured in wchar_t units.
+  static bool ReadSZValue(HKEY root_key,
+                          const wchar_t* sub_key,
+                          const wchar_t* value_name,
+                          wchar_t* value,
+                          size_t value_size);
+
+ private:
+  RegKey(const RegKey&);
+  RegKey& operator=(const RegKey&);
+
+  HKEY key_;
+};
+
+}  // namespace updater
+
+#endif  // CHROME_UPDATER_WIN_INSTALLER_REGKEY_H_
diff --git a/chrome/updater/win/installer/run_all_unittests.cc b/chrome/updater/win/installer/run_all_unittests.cc
new file mode 100644
index 0000000..875ccb9
--- /dev/null
+++ b/chrome/updater/win/installer/run_all_unittests.cc
@@ -0,0 +1,15 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/bind.h"
+#include "base/test/launcher/unit_test_launcher.h"
+#include "base/test/test_suite.h"
+
+int main(int argc, char** argv) {
+  base::TestSuite test_suite(argc, argv);
+
+  return base::LaunchUnitTestsSerially(
+      argc, argv,
+      base::Bind(&base::TestSuite::Run, base::Unretained(&test_suite)));
+}
diff --git a/chrome/updater/win/installer/string.cc b/chrome/updater/win/installer/string.cc
new file mode 100644
index 0000000..61120a1
--- /dev/null
+++ b/chrome/updater/win/installer/string.cc
@@ -0,0 +1,118 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/updater/win/installer/string.h"
+
+#include <windows.h>
+
+namespace {
+
+// Returns true if the given two ASCII characters are same (ignoring case).
+bool EqualASCIICharI(wchar_t a, wchar_t b) {
+  if (a >= L'A' && a <= L'Z')
+    a += (L'a' - L'A');
+  if (b >= L'A' && b <= L'Z')
+    b += (L'a' - L'A');
+  return (a == b);
+}
+
+}  // namespace
+
+namespace updater {
+
+// Formats a sequence of |bytes| as hex.  The |str| buffer must have room for
+// at least 2*|size| + 1.
+bool HexEncode(const void* bytes, size_t size, wchar_t* str, size_t str_size) {
+  if (str_size <= (size * 2))
+    return false;
+
+  static const wchar_t kHexChars[] = L"0123456789ABCDEF";
+
+  str[size * 2] = L'\0';
+
+  for (size_t i = 0; i < size; ++i) {
+    char b = reinterpret_cast<const char*>(bytes)[i];
+    str[(i * 2)] = kHexChars[(b >> 4) & 0xf];
+    str[(i * 2) + 1] = kHexChars[b & 0xf];
+  }
+
+  return true;
+}
+
+size_t SafeStrLen(const wchar_t* str, size_t alloc_size) {
+  if (!str || !alloc_size)
+    return 0;
+  size_t len = 0;
+  while (--alloc_size && str[len] != L'\0')
+    ++len;
+  return len;
+}
+
+bool SafeStrCopy(wchar_t* dest, size_t dest_size, const wchar_t* src) {
+  if (!dest || !dest_size)
+    return false;
+
+  wchar_t* write = dest;
+  for (size_t remaining = dest_size; remaining != 0; --remaining) {
+    if ((*write++ = *src++) == L'\0')
+      return true;
+  }
+
+  // If we fail, we do not want to leave the string with partially copied
+  // contents.  The reason for this is that we use these strings mostly for
+  // named objects such as files.  If we copy a partial name, then that could
+  // match with something we do not want it to match with.
+  // Furthermore, since SafeStrCopy is called from SafeStrCat, we do not
+  // want to mutate the string in case the caller handles the error of a
+  // failed concatenation.  For example:
+  //
+  // wchar_t buf[5] = {0};
+  // if (!SafeStrCat(buf, _countof(buf), kLongName))
+  //   SafeStrCat(buf, _countof(buf), kShortName);
+  //
+  // If we were to return false in the first call to SafeStrCat but still
+  // mutate the buffer, the buffer will be in an unexpected state.
+  *dest = L'\0';
+  return false;
+}
+
+// Safer replacement for lstrcat function.
+bool SafeStrCat(wchar_t* dest, size_t dest_size, const wchar_t* src) {
+  // Use SafeStrLen instead of lstrlen just in case the |dest| buffer isn't
+  // terminated.
+  size_t str_len = SafeStrLen(dest, dest_size);
+  return SafeStrCopy(dest + str_len, dest_size - str_len, src);
+}
+
+bool StrStartsWith(const wchar_t* str, const wchar_t* start_str) {
+  if (str == nullptr || start_str == nullptr)
+    return false;
+
+  for (int i = 0; start_str[i] != L'\0'; ++i) {
+    if (!EqualASCIICharI(str[i], start_str[i]))
+      return false;
+  }
+
+  return true;
+}
+
+const wchar_t* GetNameFromPathExt(const wchar_t* path, size_t size) {
+  if (!size)
+    return path;
+
+  const wchar_t* current = &path[size - 1];
+  while (current != path && L'\\' != *current)
+    --current;
+
+  // If no path separator found, just return |path|.
+  // Otherwise, return a pointer right after the separator.
+  return ((current == path) && (L'\\' != *current)) ? current : (current + 1);
+}
+
+wchar_t* GetNameFromPathExt(wchar_t* path, size_t size) {
+  return const_cast<wchar_t*>(
+      GetNameFromPathExt(const_cast<const wchar_t*>(path), size));
+}
+
+}  // namespace updater
diff --git a/chrome/updater/win/installer/string.h b/chrome/updater/win/installer/string.h
new file mode 100644
index 0000000..a04e7f79
--- /dev/null
+++ b/chrome/updater/win/installer/string.h
@@ -0,0 +1,117 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_UPDATER_WIN_INSTALLER_STRING_H_
+#define CHROME_UPDATER_WIN_INSTALLER_STRING_H_
+
+#include <stddef.h>
+
+namespace updater {
+
+// NOTE: Do not assume that these string functions support UTF encoding.
+// This is fine for the purposes of the mini_installer, but you have
+// been warned!
+
+// Formats a sequence of |bytes| as hex.  The |str| buffer must have room for
+// at least 2*|size| + 1.
+bool HexEncode(const void* bytes, size_t size, wchar_t* str, size_t str_size);
+
+// Counts the number of characters in the string up to a maximum of
+// alloc_size.  The highest return value from this function can therefore be
+// alloc_size - 1 since |alloc_size| includes the \0 terminator.
+size_t SafeStrLen(const wchar_t* str, size_t alloc_size);
+
+// Simple replacement for CRT string copy method that does not overflow.
+// Returns true if the source was copied successfully otherwise returns false.
+// Parameter src is assumed to be nullptr terminated and the nullptr character
+// is copied over to string dest.
+bool SafeStrCopy(wchar_t* dest, size_t dest_size, const wchar_t* src);
+
+// Simple replacement for CRT string copy method that does not overflow.
+// Returns true if the source was copied successfully otherwise returns false.
+// Parameter src is assumed to be nullptr terminated and the nullptr character
+// is copied over to string dest.  If the return value is false, the |dest|
+// string should be the same as it was before.
+bool SafeStrCat(wchar_t* dest, size_t dest_size, const wchar_t* src);
+
+// Function to check if a string (specified by str) starts with another string
+// (specified by start_str). The comparison is string insensitive.
+bool StrStartsWith(const wchar_t* str, const wchar_t* start_str);
+
+// Takes the path to file and returns a pointer to the basename component.
+// Example input -> output:
+//     c:\full\path\to\file.ext -> file.ext
+//     file.ext -> file.ext
+// Note: |size| is the number of characters in |path| not including the string
+// terminator.
+const wchar_t* GetNameFromPathExt(const wchar_t* path, size_t size);
+wchar_t* GetNameFromPathExt(wchar_t* path, size_t size);
+
+// A string class that manages a fixed size buffer on the stack.
+// The methods in the class are based on the above string methods and the
+// class additionally is careful about proper buffer termination.
+template <size_t kCapacity>
+class StackString {
+ public:
+  StackString() {
+    static_assert(kCapacity != 0, "invalid buffer size");
+    buffer_[kCapacity] = L'\0';  // We always reserve 1 more than asked for.
+    clear();
+  }
+
+  // We do not expose a constructor that accepts a string pointer on purpose.
+  // We expect the caller to call assign() and handle failures.
+
+  // Returns the number of reserved characters in this buffer, _including_
+  // the reserved char for the terminator.
+  size_t capacity() const { return kCapacity; }
+
+  wchar_t* get() { return buffer_; }
+
+  bool assign(const wchar_t* str) {
+    return SafeStrCopy(buffer_, kCapacity, str);
+  }
+
+  bool append(const wchar_t* str) {
+    return SafeStrCat(buffer_, kCapacity, str);
+  }
+
+  void clear() { buffer_[0] = L'\0'; }
+
+  size_t length() const { return SafeStrLen(buffer_, kCapacity); }
+
+  // Does a case insensitive search for a substring.
+  const wchar_t* findi(const wchar_t* find) const {
+    return SearchStringI(buffer_, find);
+  }
+
+  // Case insensitive string compare.
+  int comparei(const wchar_t* str) const { return lstrcmpiW(buffer_, str); }
+
+  // Case sensitive string compare.
+  int compare(const wchar_t* str) const { return lstrcmpW(buffer_, str); }
+
+  // Terminates the string at the specified location.
+  // Note: this method has no effect if this object's length is less than
+  // |location|.
+  bool truncate_at(size_t location) {
+    if (location >= kCapacity)
+      return false;
+    buffer_[location] = L'\0';
+    return true;
+  }
+
+ protected:
+  // We reserve 1 more than what is asked for as a safeguard against
+  // off-by-one errors.
+  wchar_t buffer_[kCapacity + 1];
+
+ private:
+  StackString(const StackString&);
+  StackString& operator=(const StackString&);
+};
+
+}  // namespace updater
+
+#endif  // CHROME_UPDATER_WIN_INSTALLER_STRING_H_
diff --git a/chrome/updater/win/installer/string_unittest.cc b/chrome/updater/win/installer/string_unittest.cc
new file mode 100644
index 0000000..d36b3a040
--- /dev/null
+++ b/chrome/updater/win/installer/string_unittest.cc
@@ -0,0 +1,60 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <windows.h>
+
+#include <string>
+
+#include "chrome/updater/win/installer/string.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using updater::StackString;
+
+namespace {
+class InstallerStringTest : public testing::Test {
+ protected:
+  void SetUp() override {}
+  void TearDown() override {}
+};
+}  // namespace
+
+// Tests the strcat/strcpy/length support of the StackString class.
+TEST_F(InstallerStringTest, StackStringOverflow) {
+  static const wchar_t kTestString[] = L"1234567890";
+
+  StackString<MAX_PATH> str;
+  EXPECT_EQ(static_cast<size_t>(MAX_PATH), str.capacity());
+
+  std::wstring compare_str;
+
+  EXPECT_EQ(str.length(), compare_str.length());
+  EXPECT_EQ(0, compare_str.compare(str.get()));
+
+  size_t max_chars = str.capacity() - 1;
+
+  while ((str.length() + (_countof(kTestString) - 1)) <= max_chars) {
+    EXPECT_TRUE(str.append(kTestString));
+    compare_str.append(kTestString);
+    EXPECT_EQ(str.length(), compare_str.length());
+    EXPECT_EQ(0, compare_str.compare(str.get()));
+  }
+
+  EXPECT_GT(static_cast<size_t>(MAX_PATH), str.length());
+
+  // Now we've exhausted the space we allocated for the string,
+  // so append should fail.
+  EXPECT_FALSE(str.append(kTestString));
+
+  // ...and remain unchanged.
+  EXPECT_EQ(0, compare_str.compare(str.get()));
+  EXPECT_EQ(str.length(), compare_str.length());
+
+  // Last test for fun.
+  str.clear();
+  compare_str.clear();
+  EXPECT_EQ(0, compare_str.compare(str.get()));
+  EXPECT_EQ(str.length(), compare_str.length());
+}
diff --git a/chrome/updater/win/installer/updater.release b/chrome/updater/win/installer/updater.release
new file mode 100644
index 0000000..9d20d88
--- /dev/null
+++ b/chrome/updater/win/installer/updater.release
@@ -0,0 +1,3 @@
+[GENERAL]
+updater.exe: %(UpdaterDir)s\
+gen\chrome\updater\win\uninstall.cmd: %(UpdaterDir)s\
diff --git a/chrome/updater/win/setup/setup.cc b/chrome/updater/win/setup/setup.cc
index 2d7ab4e..c59b5be8 100644
--- a/chrome/updater/win/setup/setup.cc
+++ b/chrome/updater/win/setup/setup.cc
@@ -21,14 +21,21 @@
 
 namespace {
 
-constexpr char kBuildGenWinDir[] = "gen\\chrome\\updater\\win";
-
 const base::char16* kUpdaterFiles[] = {
     L"updater.exe",
+    L"uninstall.cmd",
 #if defined(COMPONENT_BUILD)
-    L"base.dll",    L"boringssl.dll", L"crcrypto.dll",      L"icuuc.dll",
-    L"libc++.dll",  L"prefs.dll",     L"protobuf_lite.dll", L"updater.exe",
-    L"url_lib.dll", L"zlib.dll",
+    // TODO(sorin): get the list of component dependencies from a build-time
+    // file instead of hardcoding the names of the components here.
+    L"base.dll",
+    L"boringssl.dll",
+    L"crcrypto.dll",
+    L"icuuc.dll",
+    L"libc++.dll",
+    L"prefs.dll",
+    L"protobuf_lite.dll",
+    L"url_lib.dll",
+    L"zlib.dll",
 #endif
 };
 
@@ -69,10 +76,6 @@
         WorkItem::CreateCopyTreeWorkItem(source_path, target_path, temp_dir,
                                          WorkItem::ALWAYS, base::FilePath()));
   }
-  install_list->AddWorkItem(WorkItem::CreateCopyTreeWorkItem(
-      source_dir.AppendASCII(kBuildGenWinDir).AppendASCII(kUninstallScript),
-      product_dir.AppendASCII(kUninstallScript), temp_dir, WorkItem::ALWAYS,
-      base::FilePath()));
 
   if (!install_list->Do()) {
     LOG(ERROR) << "Install failed, rolling back...";
diff --git a/chrome/utility/BUILD.gn b/chrome/utility/BUILD.gn
index 89d2abfb..5e94d02 100644
--- a/chrome/utility/BUILD.gn
+++ b/chrome/utility/BUILD.gn
@@ -152,7 +152,7 @@
 
   if (is_chromeos) {
     deps += [
-      "//chrome/services/file_util:lib",
+      "//chrome/services/file_util",
       "//chromeos/assistant:buildflags",
       "//chromeos/services/ime:lib",
       "//chromeos/services/ime/public/mojom",
@@ -203,7 +203,7 @@
   }
 
   if (safe_browsing_mode == 1) {
-    deps += [ "//chrome/services/file_util:lib" ]
+    deps += [ "//chrome/services/file_util" ]
     if (is_mac) {
       deps += [ "//chrome/utility/safe_browsing/mac" ]
     }
diff --git a/chrome/utility/chrome_content_utility_client.cc b/chrome/utility/chrome_content_utility_client.cc
index 1f8f536..9c4e531 100644
--- a/chrome/utility/chrome_content_utility_client.cc
+++ b/chrome/utility/chrome_content_utility_client.cc
@@ -93,11 +93,6 @@
 #include "chrome/utility/printing_handler.h"
 #endif
 
-#if BUILDFLAG(FULL_SAFE_BROWSING) || defined(OS_CHROMEOS)
-#include "chrome/services/file_util/file_util_service.h"  // nogncheck
-#include "chrome/services/file_util/public/mojom/constants.mojom.h"  // nogncheck
-#endif
-
 #if BUILDFLAG(ENABLE_SIMPLE_BROWSER_SERVICE_OUT_OF_PROCESS)
 #include "services/content/simple_browser/public/mojom/constants.mojom.h"  // nogncheck
 #include "services/content/simple_browser/simple_browser_service.h"  // nogncheck
@@ -233,11 +228,6 @@
   }
 #endif
 
-#if BUILDFLAG(FULL_SAFE_BROWSING) || defined(OS_CHROMEOS)
-  if (service_name == chrome::mojom::kFileUtilServiceName)
-    return std::make_unique<FileUtilService>(std::move(request));
-#endif
-
 #if BUILDFLAG(ENABLE_EXTENSIONS) && !defined(OS_WIN)
   // On Windows the service is running elevated.
   if (service_name == chrome::mojom::kRemovableStorageWriterServiceName)
diff --git a/chrome/utility/services.cc b/chrome/utility/services.cc
index 7a25dbc..33063ad 100644
--- a/chrome/utility/services.cc
+++ b/chrome/utility/services.cc
@@ -10,6 +10,7 @@
 #include "base/macros.h"
 #include "base/no_destructor.h"
 #include "build/build_config.h"
+#include "components/safe_browsing/buildflags.h"
 #include "components/services/patch/file_patcher_impl.h"
 #include "components/services/patch/public/mojom/file_patcher.mojom.h"
 #include "components/services/unzip/public/mojom/unzipper.mojom.h"
@@ -32,6 +33,10 @@
 #include "chrome/services/ipp_parser/public/mojom/ipp_parser.mojom.h"  // nogncheck
 #endif
 
+#if BUILDFLAG(FULL_SAFE_BROWSING) || defined(OS_CHROMEOS)
+#include "chrome/services/file_util/file_util_service.h"  // nogncheck
+#endif
+
 namespace {
 
 auto RunFilePatcher(mojo::PendingReceiver<patch::mojom::FilePatcher> receiver) {
@@ -64,6 +69,13 @@
 }
 #endif
 
+#if BUILDFLAG(FULL_SAFE_BROWSING) || defined(OS_CHROMEOS)
+auto RunFileUtil(
+    mojo::PendingReceiver<chrome::mojom::FileUtilService> receiver) {
+  return std::make_unique<FileUtilService>(std::move(receiver));
+}
+#endif
+
 }  // namespace
 
 mojo::ServiceFactory* GetMainThreadServiceFactory() {
@@ -79,6 +91,10 @@
 #if BUILDFLAG(ENABLE_PRINTING) && defined(OS_CHROMEOS)
     RunCupsIppParser,
 #endif
+
+#if BUILDFLAG(FULL_SAFE_BROWSING) || defined(OS_CHROMEOS)
+    RunFileUtil,
+#endif
   };
   // clang-format on
   return factory.get();
diff --git a/chromecast/external_mojo/broker_service/BUILD.gn b/chromecast/external_mojo/broker_service/BUILD.gn
index c6e84e4..5d0d1a4 100644
--- a/chromecast/external_mojo/broker_service/BUILD.gn
+++ b/chromecast/external_mojo/broker_service/BUILD.gn
@@ -9,6 +9,7 @@
   ]
   deps = [
     "//base",
+    "//chromecast/external_mojo/public/cpp:common",
     "//chromecast/external_mojo/public/cpp:external_mojo_broker",
     "//services/service_manager/public/cpp",
     "//services/service_manager/public/mojom",
diff --git a/chromecast/external_mojo/broker_service/broker_service.cc b/chromecast/external_mojo/broker_service/broker_service.cc
index 4bb6493..e804c6c 100644
--- a/chromecast/external_mojo/broker_service/broker_service.cc
+++ b/chromecast/external_mojo/broker_service/broker_service.cc
@@ -14,6 +14,7 @@
 #include "base/no_destructor.h"
 #include "base/sequenced_task_runner.h"
 #include "base/threading/thread.h"
+#include "chromecast/external_mojo/public/cpp/common.h"
 #include "chromecast/external_mojo/public/cpp/external_mojo_broker.h"
 #include "services/service_manager/public/cpp/manifest_builder.h"
 
@@ -68,7 +69,8 @@
   for (const auto& sub_manifest : manifest.packaged_services) {
     external_services_to_proxy.push_back(sub_manifest.service_name);
   }
-  broker_ = base::SequenceBound<ExternalMojoBroker>(io_thread_->task_runner());
+  broker_ = base::SequenceBound<ExternalMojoBroker>(io_thread_->task_runner(),
+                                                    GetBrokerPath());
   broker_.Post(FROM_HERE, &ExternalMojoBroker::InitializeChromium,
                service_binding_.GetConnector()->Clone(),
                external_services_to_proxy);
diff --git a/chromecast/external_mojo/external_service_support/BUILD.gn b/chromecast/external_mojo/external_service_support/BUILD.gn
index f300389e..8006a1d 100644
--- a/chromecast/external_mojo/external_service_support/BUILD.gn
+++ b/chromecast/external_mojo/external_service_support/BUILD.gn
@@ -70,6 +70,7 @@
   deps = [
     ":process_setup",
     "//base",
+    "//chromecast/external_mojo/public/cpp:common",
     "//chromecast/external_mojo/public/cpp:external_mojo_broker",
     "//mojo/core/embedder",
   ]
diff --git a/chromecast/external_mojo/external_service_support/standalone_mojo_broker.cc b/chromecast/external_mojo/external_service_support/standalone_mojo_broker.cc
index 77d194c..b4cbc2f 100644
--- a/chromecast/external_mojo/external_service_support/standalone_mojo_broker.cc
+++ b/chromecast/external_mojo/external_service_support/standalone_mojo_broker.cc
@@ -11,6 +11,7 @@
 #include "base/run_loop.h"
 #include "base/task/single_thread_task_executor.h"
 #include "chromecast/external_mojo/external_service_support/process_setup.h"
+#include "chromecast/external_mojo/public/cpp/common.h"
 #include "chromecast/external_mojo/public/cpp/external_mojo_broker.h"
 #include "mojo/core/embedder/embedder.h"
 #include "mojo/core/embedder/scoped_ipc_support.h"
@@ -32,7 +33,8 @@
       io_task_executor.task_runner(),
       mojo::core::ScopedIPCSupport::ShutdownPolicy::CLEAN);
 
-  chromecast::external_mojo::ExternalMojoBroker broker;
+  chromecast::external_mojo::ExternalMojoBroker broker(
+      chromecast::external_mojo::GetBrokerPath());
 
   run_loop.Run();
 
diff --git a/chromecast/external_mojo/public/cpp/external_mojo_broker.cc b/chromecast/external_mojo/public/cpp/external_mojo_broker.cc
index 9fd07fb..d690ccc 100644
--- a/chromecast/external_mojo/public/cpp/external_mojo_broker.cc
+++ b/chromecast/external_mojo/public/cpp/external_mojo_broker.cc
@@ -375,11 +375,13 @@
   DISALLOW_COPY_AND_ASSIGN(ReadWatcher);
 };
 
-ExternalMojoBroker::ExternalMojoBroker() {
+ExternalMojoBroker::ExternalMojoBroker(const std::string& broker_path) {
   connector_ = std::make_unique<ConnectorImpl>();
 
+  LOG(INFO) << "Initializing external mojo broker at: " << broker_path;
+
   mojo::NamedPlatformChannel::Options channel_options;
-  channel_options.server_name = GetBrokerPath();
+  channel_options.server_name = broker_path;
   mojo::NamedPlatformChannel named_channel(channel_options);
 
   mojo::PlatformChannelServerEndpoint server_endpoint =
@@ -396,6 +398,12 @@
                                  external_services_to_proxy);
 }
 
+mojom::ExternalConnectorPtr ExternalMojoBroker::CreateConnector() {
+  mojom::ExternalConnectorPtrInfo info;
+  connector_->AddBinding(mojo::MakeRequest(&info));
+  return mojom::ExternalConnectorPtr(std::move(info));
+}
+
 ExternalMojoBroker::~ExternalMojoBroker() = default;
 
 }  // namespace external_mojo
diff --git a/chromecast/external_mojo/public/cpp/external_mojo_broker.h b/chromecast/external_mojo/public/cpp/external_mojo_broker.h
index eb302ef7..b8a2ee6 100644
--- a/chromecast/external_mojo/public/cpp/external_mojo_broker.h
+++ b/chromecast/external_mojo/public/cpp/external_mojo_broker.h
@@ -10,6 +10,7 @@
 #include <vector>
 
 #include "base/macros.h"
+#include "chromecast/external_mojo/public/mojom/connector.mojom.h"
 
 namespace service_manager {
 class Connector;
@@ -22,7 +23,8 @@
 // either in a standalone broker process, or embedded into a Chromium process.
 class ExternalMojoBroker {
  public:
-  ExternalMojoBroker();
+  explicit ExternalMojoBroker(const std::string& broker_path);
+
   ~ExternalMojoBroker();
 
   // Initializes the embedded into a Chromium process (eg in cast_shell).
@@ -33,6 +35,8 @@
       std::unique_ptr<service_manager::Connector> connector,
       const std::vector<std::string>& external_services_to_proxy);
 
+  mojom::ExternalConnectorPtr CreateConnector();
+
  private:
   class ConnectorImpl;
   class ReadWatcher;
diff --git a/chromecast/media/cma/backend/android/java/src/org/chromium/chromecast/cma/backend/android/AudioSinkAudioTrackImpl.java b/chromecast/media/cma/backend/android/java/src/org/chromium/chromecast/cma/backend/android/AudioSinkAudioTrackImpl.java
index bce8d382..a704a199 100644
--- a/chromecast/media/cma/backend/android/java/src/org/chromium/chromecast/cma/backend/android/AudioSinkAudioTrackImpl.java
+++ b/chromecast/media/cma/backend/android/java/src/org/chromium/chromecast/cma/backend/android/AudioSinkAudioTrackImpl.java
@@ -12,7 +12,6 @@
 import android.media.AudioTimestamp;
 import android.media.AudioTrack;
 import android.os.Build;
-import android.os.SystemClock;
 import android.support.annotation.IntDef;
 import android.util.SparseIntArray;
 
@@ -110,10 +109,14 @@
     private static final long UNDERRUN_LOG_THROTTLE_PERIOD = SEC_IN_NSEC;
 
     // Internally Android fetches data from AudioTrack buffer in periods of 20ms.
-    private static final long ANDROID_AUDIO_PERIOD_SIZE_US = 20000;
+    private static final long ANDROID_AUDIO_PERIOD_SIZE_USEC = 20000;
+
+    // Minimum amount of data written to the AudioTrack before we can call play().
+    // This is needed to avoid hitting a (false) underrun.
+    private static final long PLAY_START_THRESHOLD_USEC = 40000;
 
     // Threshold at which we start logging low buffer warnings.
-    private static final long VERY_LOW_BUFFER_LEVEL = ANDROID_AUDIO_PERIOD_SIZE_US;
+    private static final long VERY_LOW_BUFFER_LEVEL_USEC = ANDROID_AUDIO_PERIOD_SIZE_USEC;
 
     private static long sInstanceCounter;
 
@@ -132,7 +135,7 @@
     private static final long MAX_TIME_IGNORING_TSTAMPS_NSECS = SEC_IN_NSEC;
 
     // Additional padding for minimum buffer time, determined experimentally.
-    private static final long MIN_BUFFERED_TIME_PADDING_US = ANDROID_AUDIO_PERIOD_SIZE_US;
+    private static final long MIN_BUFFERED_TIME_PADDING_USEC = ANDROID_AUDIO_PERIOD_SIZE_USEC;
 
     private static AudioManager sAudioManager;
 
@@ -146,6 +149,7 @@
     private ThrottledLog mBufferLevelWarningLog;
     private ThrottledLog mUnderrunWarningLog;
     private ThrottledLog mTStampJitterWarningLog;
+    private ThrottledLog mStatisticsLog;
 
     @IntDef({ReferenceTimestampState.STARTING_UP, ReferenceTimestampState.STABLE,
             ReferenceTimestampState.RESYNCING_AFTER_PAUSE,
@@ -174,6 +178,9 @@
 
     private AudioTrack mAudioTrack;
 
+    private long mBufferSizeInSec; // Size of AudioTrack Buffer allocated.
+    private long mBufferLevelUsec;
+
     // Timestamping logic for RenderingDelay calculations. See also the description for
     // getNewFramePos0Timestamp() for additional information.
     private long mRefNanoTimeAtFramePos0; // Reference time used to interpolate new timestamps at
@@ -213,7 +220,7 @@
      * Converts the given nanoseconds value into microseconds with proper rounding. It is assumed
      * that the value given is positive.
      */
-    private static long convertNsecsToUsecs(long nsecs) {
+    private static long nSecToUsec(long nsecs) {
         return (nsecs + 500) / 1000;
     }
 
@@ -229,7 +236,7 @@
     public static long getMinimumBufferedTime(int sampleRateInHz) {
         int sizeBytes = AudioTrack.getMinBufferSize(sampleRateInHz, CHANNEL_CONFIG, AUDIO_FORMAT);
         long sizeUs = SEC_IN_USEC * (long) sizeBytes / (BYTES_PER_FRAME * (long) sampleRateInHz);
-        return sizeUs + MIN_BUFFERED_TIME_PADDING_US;
+        return sizeUs + MIN_BUFFERED_TIME_PADDING_USEC;
     }
 
     @CalledByNative
@@ -286,12 +293,6 @@
         return mLastTimestampUpdateNsec != NO_TIMESTAMP;
     }
 
-    /** Converts the given number of frames into an equivalent nanoTime period. */
-    private long convertFramesToNanoTime(long numOfFrames) {
-        // Use proper rounding (assumes all numbers are positive).
-        return (SEC_IN_NSEC * numOfFrames + mSampleRateInHz / 2) / mSampleRateInHz;
-    }
-
     /**
      * Initializes the instance by creating the AudioTrack object and allocating
      * the shared memory buffers.
@@ -305,6 +306,7 @@
         mBufferLevelWarningLog = new ThrottledLog(Log::w, 5, 1000, 5000);
         mUnderrunWarningLog = new ThrottledLog(Log::w, 5, 1000, 5000);
         mTStampJitterWarningLog = new ThrottledLog(Log::w, 5, 1000, 5000);
+        mStatisticsLog = new ThrottledLog(Log::i, 1, 1000, 5000);
 
         Log.i(mTag,
                 "Init:"
@@ -335,10 +337,10 @@
 
         int bufferSizeInBytes = MIN_BUFFER_SIZE_MULTIPLIER
                 * AudioTrack.getMinBufferSize(mSampleRateInHz, CHANNEL_CONFIG, AUDIO_FORMAT);
-        int bufferSizeInMs = 1000 * bufferSizeInBytes / (BYTES_PER_FRAME * mSampleRateInHz);
+        mBufferSizeInSec = bytesToSec(bufferSizeInBytes);
         Log.i(mTag,
-                "Init: create an AudioTrack of size=" + bufferSizeInBytes + " (" + bufferSizeInMs
-                        + "ms) usageType=" + usageType + " contentType=" + contentType
+                "Init: create an AudioTrack of size=" + bufferSizeInBytes + " (" + mBufferSizeInSec
+                        + "sec) usageType=" + usageType + " contentType=" + contentType
                         + " with session-id=" + sessionId);
 
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
@@ -410,16 +412,10 @@
         return mAudioTrack.getPlayState() == AudioTrack.PLAYSTATE_STOPPED;
     }
 
-    private boolean isPlaying() {
-        return mAudioTrack.getPlayState() == AudioTrack.PLAYSTATE_PLAYING;
-    }
-
-    private boolean isPaused() {
-        return mAudioTrack.getPlayState() == AudioTrack.PLAYSTATE_PAUSED;
-    }
-
-    /** Stops the AudioTrack and returns an estimate of the time it takes for the remaining data
-     * left in the internal queue to be played out (in usecs). */
+    /**
+     * Stops the AudioTrack and returns an estimate of the time it takes for the remaining data
+     * left in the internal queue to be played out (in usecs).
+     */
     @CalledByNative
     private long prepareForShutdown() {
         long playtimeLeftNsecs;
@@ -439,7 +435,7 @@
             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                 long most_frames_left =
                         Math.min(mTotalFramesWritten, mAudioTrack.getBufferSizeInFrames());
-                playtimeLeftNsecs = convertFramesToNanoTime(most_frames_left);
+                playtimeLeftNsecs = SEC_IN_NSEC * framesToSec(most_frames_left);
             } else {
                 // Using pre-M API. Don't know how many frames there are, so assume the worst case.
                 playtimeLeftNsecs = 0;
@@ -449,8 +445,10 @@
     }
 
     @CalledByNative
-    /** Closes the instance by stopping playback and releasing the AudioTrack
-     * object. */
+    /**
+     * Closes the instance by stopping playback and releasing the AudioTrack
+     * object.
+     */
     private void close() {
         Log.i(mTag, "Close AudioSinkAudioTrackImpl!");
         if (!mIsInitialized) {
@@ -475,7 +473,7 @@
         }
     }
 
-    int getUnderrunCount() {
+    private int getUnderrunCount() {
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
             return mAudioTrack.getUnderrunCount();
         }
@@ -483,18 +481,62 @@
         return 0;
     }
 
-    /** Writes the PCM data of the given size into the AudioTrack object. The
+    /** Convert the given number of bytes into an equivalent frames with proper rounding */
+    private long bytesToFrames(long bytes) {
+        return (bytes + BYTES_PER_FRAME / 2) / BYTES_PER_FRAME;
+    }
+
+    /** Convert the given number of frames into an equivalent seconds */
+    private long framesToSec(long frames) {
+        return frames / mSampleRateInHz;
+    }
+
+    /** Convert the given number of bytes into an equivalent seconds with proper rounding */
+    private long bytesToSec(long bytes) {
+        return framesToSec(bytesToFrames(bytes));
+    }
+
+    private void startPlayingIfItIsTime() {
+        if (mTotalFramesWritten > PLAY_START_THRESHOLD_USEC) {
+            play();
+        }
+    }
+
+    private void waitUntilBufferAvail(int bytes) {
+        long sleepTimeUsec = SEC_IN_USEC * bytesToSec(bytes);
+        long bufferSizeInUsec = SEC_IN_USEC * mBufferSizeInSec;
+        if (sleepTimeUsec >= bufferSizeInUsec / 2) {
+            sleepTimeUsec = bufferSizeInUsec / 2;
+        } else {
+            long d = sleepTimeUsec / ANDROID_AUDIO_PERIOD_SIZE_USEC;
+            if (d * ANDROID_AUDIO_PERIOD_SIZE_USEC < sleepTimeUsec) {
+                sleepTimeUsec = (d + 1) * ANDROID_AUDIO_PERIOD_SIZE_USEC;
+            }
+        }
+
+        if (DEBUG_LEVEL >= 1) {
+            Log.i(mTag, "Buffer full, sleep for " + sleepTimeUsec + "usec");
+        }
+
+        try {
+            Thread.sleep(sleepTimeUsec / 1000);
+        } catch (InterruptedException ex) {
+            Log.i(mTag, "Sleep was interrupted: " + ex);
+        }
+    }
+
+    /**
+     * Writes the PCM data of the given size into the AudioTrack object. The
      * PCM data is provided through the memory-mapped ByteBuffer.
      *
      * Returns the number of bytes written into the AudioTrack object, -1 for
      * error.
      */
     @CalledByNative
-    private int writePcm(int sizeInBytes) {
+    private int writePcm(int totalBytesToWrite) {
         if (DEBUG_LEVEL >= 3) {
             Log.i(mTag,
-                    "Writing new PCM data:"
-                            + " sizeInBytes=" + sizeInBytes + " state=" + getPlayStateString()
+                    "Writing new PCM data [" + totalBytesToWrite + "] state=" + getPlayStateString()
                             + " underruns=" + mLastUnderrunCount);
         }
 
@@ -504,65 +546,70 @@
         }
 
         // Check buffer level before feeding in new data.
-        if (haveValidRefPoint()) checkBufferLevel();
+        checkBufferLevel();
 
         // Setup the PCM ByteBuffer correctly.
-        mPcmBuffer.limit(sizeInBytes);
-        mPcmBuffer.position(0);
+        mPcmBuffer.limit(totalBytesToWrite);
 
-        // Feed into AudioTrack - blocking call.
-        long beforeMsecs = SystemClock.elapsedRealtime();
-        int bytesWritten = mAudioTrack.write(mPcmBuffer, sizeInBytes, AudioTrack.WRITE_BLOCKING);
+        long maxTimeToWriteNsec = 2 * bytesToSec(totalBytesToWrite) * SEC_IN_NSEC;
+        long startTimeNsec = System.nanoTime();
 
-        if (bytesWritten < 0) {
-            int error = bytesWritten;
-            Log.e(mTag, "Couldn't write into AudioTrack (" + error + ")");
-            return error;
-        }
+        int bytesLeftToWrite = totalBytesToWrite;
+        int bytesWritten = 0;
 
-        if (isStopped()) {
-            // Data was written, start playing now.
-            play();
+        while (bytesLeftToWrite > 0) {
+            mPcmBuffer.position(totalBytesToWrite - bytesLeftToWrite);
+            long beforeNsecs = System.nanoTime();
+            bytesWritten =
+                    mAudioTrack.write(mPcmBuffer, bytesLeftToWrite, AudioTrack.WRITE_NON_BLOCKING);
 
-            // If not all data fit on the previous write() call (since we were not in PLAYING state
-            // it didn't block), do a second (now blocking) call to write().
-            int bytesLeft = sizeInBytes - bytesWritten;
-            if (bytesLeft > 0) {
-                mPcmBuffer.position(bytesWritten);
-                int moreBytesWritten =
-                        mAudioTrack.write(mPcmBuffer, bytesLeft, AudioTrack.WRITE_BLOCKING);
-                if (moreBytesWritten < 0) {
-                    int error = moreBytesWritten;
-                    Log.e(mTag, "Couldn't write into AudioTrack (" + error + ")");
-                    return error;
-                }
-                bytesWritten += moreBytesWritten;
+            if (bytesWritten < 0) {
+                int error = bytesWritten;
+                Log.e(mTag, "Couldn't write into AudioTrack (" + error + ")");
+                return error;
+            }
+
+            mTotalFramesWritten = bytesToFrames(bytesWritten);
+            bytesLeftToWrite -= bytesWritten;
+            if (isStopped()) {
+                startPlayingIfItIsTime();
+            }
+
+            if (DEBUG_LEVEL >= 3) {
+                long lastRenderingDelayUsec =
+                        (mLastRenderingDelayUsecs == NO_TIMESTAMP) ? -1 : mLastRenderingDelayUsecs;
+                Log.i(mTag,
+                        "  wrote " + bytesWritten + "/" + bytesWritten
+                                + " total_bytes_written=" + (mTotalFramesWritten * BYTES_PER_FRAME)
+                                + " took:" + (elapsedNsec(beforeNsecs) / MSEC_IN_NSEC) + "ms"
+                                + " RenderingDelayUsec=" + lastRenderingDelayUsec
+                                + " BufferLevelUsec=" + mBufferLevelUsec);
+            }
+
+            if (bytesLeftToWrite > 0) {
+                waitUntilBufferAvail(bytesLeftToWrite);
+                checkBufferLevel();
+                maxTimeToWriteNsec = 2 * bytesToSec(bytesLeftToWrite) * SEC_IN_NSEC;
+                startTimeNsec = System.nanoTime();
+            }
+
+            if (bytesLeftToWrite > 0 && elapsedNsec(startTimeNsec) > maxTimeToWriteNsec) {
+                Log.e(mTag, "Took too long to write all data, abort!");
+                break;
             }
         }
+        int totalBytesWritten = totalBytesToWrite - bytesLeftToWrite;
+        updateSampleRateMeasure(bytesToFrames(totalBytesWritten));
 
-        int framesWritten = bytesWritten / BYTES_PER_FRAME;
-        mTotalFramesWritten += framesWritten;
+        updateRefPointTimestamp();
 
-        if (DEBUG_LEVEL >= 3) {
-            Log.i(mTag,
-                    "  wrote " + bytesWritten + "/" + sizeInBytes
-                            + " total_bytes_written=" + (mTotalFramesWritten * BYTES_PER_FRAME)
-                            + " took:" + (SystemClock.elapsedRealtime() - beforeMsecs) + "ms");
-        }
+        long lastRenderingDelayUsec =
+                (mLastRenderingDelayUsecs == NO_TIMESTAMP) ? -1 : mLastRenderingDelayUsecs;
+        mStatisticsLog.log(mTag,
+                "SampleRateHz=" + mSampleRateInHz + " RenderingDelayUsec=" + lastRenderingDelayUsec
+                        + " BufferLevelUsec=" + mBufferLevelUsec);
 
-        if (bytesWritten < sizeInBytes && isPaused()) {
-            // We are in PAUSED state, in which case the write() is non-blocking. If not all data
-            // was written, we will come back here once we transition back into PLAYING state.
-            return bytesWritten;
-        }
-
-        updateSampleRateMeasure(framesWritten);
-
-        updateRenderingDelay();
-
-        // TODO(ckuiper): Log key statistics (SR and underruns, e.g.) in regular intervals
-
-        return bytesWritten;
+        return totalBytesWritten;
     }
 
     /** Returns the elapsed time from the given start_time until now, in nsec. */
@@ -572,13 +619,13 @@
 
     private void checkBufferLevel() {
         long bufferLevel = mTotalFramesWritten - mAudioTrack.getPlaybackHeadPosition();
-        long bufferLevelUsec = convertNsecsToUsecs(convertFramesToNanoTime(bufferLevel));
-        if (bufferLevelUsec <= VERY_LOW_BUFFER_LEVEL) {
+        mBufferLevelUsec = SEC_IN_USEC * framesToSec(bufferLevel);
+        if (mBufferLevelUsec <= VERY_LOW_BUFFER_LEVEL_USEC) {
             long lastRenderingDelayUsec =
                     (mLastRenderingDelayUsecs == NO_TIMESTAMP) ? -1 : mLastRenderingDelayUsecs;
             boolean hitUnderrun = (getUnderrunCount() != mLastUnderrunCount);
             mBufferLevelWarningLog.log(mTag,
-                    "Low buffer level=" + bufferLevelUsec + "us "
+                    "Low buffer level=" + mBufferLevelUsec + "us "
                             + " RD=" + lastRenderingDelayUsec + (hitUnderrun ? "us *" : "us"));
         }
     }
@@ -613,8 +660,8 @@
 
         // Interpolate to get proper Rendering delay.
         long playoutTimeNsecs = getInterpolatedTStampNsecs(mTotalFramesWritten);
-        long playoutTimeUsecs = convertNsecsToUsecs(playoutTimeNsecs);
-        long nowUsecs = convertNsecsToUsecs(System.nanoTime());
+        long playoutTimeUsecs = nSecToUsec(playoutTimeNsecs);
+        long nowUsecs = nSecToUsec(System.nanoTime());
         long delayUsecs = playoutTimeUsecs - nowUsecs;
 
         // Populate RenderingDelay return value for native land.
@@ -647,14 +694,14 @@
             return NO_TIMESTAMP;
         }
         mOriginalFramePosOfLastTimestamp = ts.framePosition;
-        return ts.nanoTime - convertFramesToNanoTime(ts.framePosition);
+        return ts.nanoTime - (SEC_IN_NSEC * framesToSec(ts.framePosition));
     }
 
     /**
      * Returns a timestamp for the given frame position, interpolated from the reference timestamp.
      */
     private long getInterpolatedTStampNsecs(long framePosition) {
-        return mRefNanoTimeAtFramePos0 + convertFramesToNanoTime(framePosition);
+        return mRefNanoTimeAtFramePos0 + (SEC_IN_NSEC * framesToSec(framePosition));
     }
 
     /** Checks for underruns and if detected invalidates the reference point timestamp. */
@@ -780,7 +827,7 @@
                 long devNsec = mRefNanoTimeAtFramePos0 - newNanoTimeAtFramePos0;
                 if (Math.abs(devNsec) > TSTAMP_DEV_THRESHOLD_TO_IGNORE_NSEC) {
                     mTStampJitterWarningLog.log(
-                            mTag, "Too jittery timestamp (" + convertNsecsToUsecs(devNsec) + ")");
+                            mTag, "Too jittery timestamp (" + nSecToUsec(devNsec) + ")");
                     long timeSinceLastGoodTstamp = elapsedNsec(mLastTimestampUpdateNsec);
                     if (timeSinceLastGoodTstamp <= MAX_TIME_IGNORING_TSTAMPS_NSECS) {
                         return; // Ignore this one.
@@ -800,8 +847,8 @@
 
         // Got a new value.
         if (DEBUG_LEVEL >= 1) {
-            long dev1 = convertNsecsToUsecs(prevRefNanoTimeAtFramePos0 - newNanoTimeAtFramePos0);
-            long dev2 = convertNsecsToUsecs(prevRefNanoTimeAtFramePos0 - mRefNanoTimeAtFramePos0);
+            long dev1 = nSecToUsec(prevRefNanoTimeAtFramePos0 - newNanoTimeAtFramePos0);
+            long dev2 = nSecToUsec(prevRefNanoTimeAtFramePos0 - mRefNanoTimeAtFramePos0);
             Log.i(mTag,
                     "Updated mRefNanoTimeAtFramePos0=" + mRefNanoTimeAtFramePos0 / 1000 + " us ("
                             + dev1 + "/" + dev2 + ")");
diff --git a/chromecast/media/cma/backend/cast_audio_json.cc b/chromecast/media/cma/backend/cast_audio_json.cc
index fcdc424..ba49f93c 100644
--- a/chromecast/media/cma/backend/cast_audio_json.cc
+++ b/chromecast/media/cma/backend/cast_audio_json.cc
@@ -8,18 +8,37 @@
 #include <utility>
 
 #include "base/bind.h"
-#include "base/files/file_path_watcher.h"
 #include "base/files/file_util.h"
 #include "base/json/json_reader.h"
 #include "base/location.h"
 #include "base/logging.h"
-#include "base/message_loop/message_pump_type.h"
-#include "base/sequenced_task_runner.h"
+#include "base/task/post_task.h"
+#include "base/task/task_traits.h"
 #include "build/build_config.h"
 
 namespace chromecast {
 namespace media {
 
+namespace {
+
+void ReadFileRunCallback(CastAudioJsonProvider::TuningChangedCallback callback,
+                         const base::FilePath& path,
+                         bool error) {
+  DCHECK(callback);
+
+  std::string contents;
+  base::ReadFileToString(path, &contents);
+  std::unique_ptr<base::Value> value =
+      base::JSONReader::ReadDeprecated(contents);
+  if (value) {
+    callback.Run(std::move(value));
+    return;
+  }
+  LOG(ERROR) << "Unable to parse JSON in " << path;
+}
+
+}  // namespace
+
 #if defined(OS_FUCHSIA)
 const char kCastAudioJsonFilePath[] = "/system/data/cast_audio.json";
 #else
@@ -27,14 +46,6 @@
 #endif
 const char kCastAudioJsonFileName[] = "cast_audio.json";
 
-#define ENSURE_OWN_THREAD(method, ...)                                     \
-  if (!task_runner_->RunsTasksInCurrentSequence()) {                       \
-    task_runner_->PostTask(                                                \
-        FROM_HERE, base::BindOnce(&CastAudioJsonProviderImpl::method,      \
-                                  base::Unretained(this), ##__VA_ARGS__)); \
-    return;                                                                \
-  }
-
 // static
 base::FilePath CastAudioJson::GetFilePath() {
   base::FilePath tuning_path = CastAudioJson::GetFilePathForTuning();
@@ -56,17 +67,11 @@
 }
 
 CastAudioJsonProviderImpl::CastAudioJsonProviderImpl()
-    : thread_("cast_audio_json_provider"),
-      cast_audio_watcher_(std::make_unique<base::FilePathWatcher>()) {
-  base::Thread::Options options;
-  options.message_pump_type = base::MessagePumpType::IO;
-  thread_.StartWithOptions(options);
-  task_runner_ = thread_.task_runner();
-}
+    : cast_audio_watcher_(
+          base::SequenceBound<FileWatcher>(base::CreateSequencedTaskRunner(
+              {base::MayBlock(), base::TaskPriority::LOWEST}))) {}
 
-CastAudioJsonProviderImpl::~CastAudioJsonProviderImpl() {
-  StopWatchingFileOnThread();
-}
+CastAudioJsonProviderImpl::~CastAudioJsonProviderImpl() = default;
 
 std::unique_ptr<base::Value> CastAudioJsonProviderImpl::GetCastAudioConfig() {
   std::string contents;
@@ -76,35 +81,18 @@
 
 void CastAudioJsonProviderImpl::SetTuningChangedCallback(
     TuningChangedCallback callback) {
-  ENSURE_OWN_THREAD(SetTuningChangedCallback, std::move(callback));
+  cast_audio_watcher_.Post(FROM_HERE, &FileWatcher::SetTuningChangedCallback,
+                           std::move(callback));
+}
 
-  CHECK(!callback_);
-  callback_ = callback;
-  cast_audio_watcher_->Watch(
+CastAudioJsonProviderImpl::FileWatcher::FileWatcher() = default;
+CastAudioJsonProviderImpl::FileWatcher::~FileWatcher() = default;
+
+void CastAudioJsonProviderImpl::FileWatcher::SetTuningChangedCallback(
+    TuningChangedCallback callback) {
+  watcher_.Watch(
       CastAudioJson::GetFilePathForTuning(), false /* recursive */,
-      base::BindRepeating(&CastAudioJsonProviderImpl::OnTuningFileChanged,
-                          base::Unretained(this)));
-}
-
-void CastAudioJsonProviderImpl::StopWatchingFileOnThread() {
-  ENSURE_OWN_THREAD(StopWatchingFileOnThread);
-  cast_audio_watcher_.reset();
-}
-
-void CastAudioJsonProviderImpl::OnTuningFileChanged(const base::FilePath& path,
-                                                    bool error) {
-  DCHECK(task_runner_->RunsTasksInCurrentSequence());
-  DCHECK(callback_);
-
-  std::string contents;
-  base::ReadFileToString(path, &contents);
-  std::unique_ptr<base::Value> value =
-      base::JSONReader::ReadDeprecated(contents);
-  if (value) {
-    callback_.Run(std::move(value));
-    return;
-  }
-  LOG(ERROR) << "Unable to parse JSON in " << path;
+      base::BindRepeating(&ReadFileRunCallback, std::move(callback)));
 }
 
 }  // namespace media
diff --git a/chromecast/media/cma/backend/cast_audio_json.h b/chromecast/media/cma/backend/cast_audio_json.h
index 38fc7668..99dadec 100644
--- a/chromecast/media/cma/backend/cast_audio_json.h
+++ b/chromecast/media/cma/backend/cast_audio_json.h
@@ -9,15 +9,11 @@
 
 #include "base/callback.h"
 #include "base/files/file_path.h"
+#include "base/files/file_path_watcher.h"
 #include "base/memory/scoped_refptr.h"
-#include "base/threading/thread.h"
+#include "base/threading/sequence_bound.h"
 #include "base/values.h"
 
-namespace base {
-class FilePathWatcher;
-class SequencedTaskRunner;
-}  // namespace base
-
 namespace chromecast {
 namespace media {
 
@@ -48,9 +44,8 @@
   virtual std::unique_ptr<base::Value> GetCastAudioConfig() = 0;
 
   // |callback| will be called when a new cast_audio config is available.
-  // |callback| will always be called from the same thread, but not the same
-  // thread on which |SetTuningChangedCallback| is called.
-  // |callback| will never be called after ~CastAudioJsonProvider() is called.
+  // |callback| will always be called from the same thread, but not necessarily
+  // the same thread on which |SetTuningChangedCallback| is called.
   virtual void SetTuningChangedCallback(TuningChangedCallback callback) = 0;
 };
 
@@ -60,17 +55,22 @@
   ~CastAudioJsonProviderImpl() override;
 
  private:
+  class FileWatcher {
+   public:
+    FileWatcher();
+    ~FileWatcher();
+
+    void SetTuningChangedCallback(TuningChangedCallback callback);
+
+   private:
+    base::FilePathWatcher watcher_;
+  };
+
   // CastAudioJsonProvider implementation:
   std::unique_ptr<base::Value> GetCastAudioConfig() override;
   void SetTuningChangedCallback(TuningChangedCallback callback) override;
 
-  void StopWatchingFileOnThread();
-  void OnTuningFileChanged(const base::FilePath& path, bool error);
-
-  TuningChangedCallback callback_;
-  base::Thread thread_;
-  scoped_refptr<base::SequencedTaskRunner> task_runner_;
-  std::unique_ptr<base::FilePathWatcher> cast_audio_watcher_;
+  base::SequenceBound<FileWatcher> cast_audio_watcher_;
 
   DISALLOW_COPY_AND_ASSIGN(CastAudioJsonProviderImpl);
 };
diff --git a/chromeos/cryptohome/cryptohome_util.cc b/chromeos/cryptohome/cryptohome_util.cc
index 3ffe345..62c1757e 100644
--- a/chromeos/cryptohome/cryptohome_util.cc
+++ b/chromeos/cryptohome/cryptohome_util.cc
@@ -366,6 +366,7 @@
     case CRYPTOHOME_ERROR_FIRMWARE_MANAGEMENT_PARAMETERS_INVALID:
     case CRYPTOHOME_ERROR_FIRMWARE_MANAGEMENT_PARAMETERS_CANNOT_STORE:
     case CRYPTOHOME_ERROR_FIRMWARE_MANAGEMENT_PARAMETERS_CANNOT_REMOVE:
+    case CRYPTOHOME_ERROR_UPDATE_USER_ACTIVITY_TIMESTAMP_FAILED:
       NOTREACHED();
       return MOUNT_ERROR_FATAL;
   }
diff --git a/chromeos/dbus/power/OWNERS b/chromeos/dbus/power/OWNERS
new file mode 100644
index 0000000..20fd45cc
--- /dev/null
+++ b/chromeos/dbus/power/OWNERS
@@ -0,0 +1,3 @@
+abhishekbh@chromium.org
+ejcaruso@chromium.org
+ravisadineni@chromium.org
diff --git a/chromeos/dbus/upstart/upstart_client.cc b/chromeos/dbus/upstart/upstart_client.cc
index 930471b2..12f9f76 100644
--- a/chromeos/dbus/upstart/upstart_client.cc
+++ b/chromeos/dbus/upstart/upstart_client.cc
@@ -4,6 +4,8 @@
 
 #include "chromeos/dbus/upstart/upstart_client.h"
 
+#include <utility>
+
 #include "base/bind.h"
 #include "base/memory/weak_ptr.h"
 #include "chromeos/dbus/upstart/fake_upstart_client.h"
@@ -91,11 +93,11 @@
   using UpstartClient::StopJob;
 
   void StopMediaAnalytics() override {
-    StopJob(kMediaAnalyticsJob, EmptyVoidDBusMethodCallback());
+    StopJob(kMediaAnalyticsJob, {}, EmptyVoidDBusMethodCallback());
   }
 
   void StopMediaAnalytics(VoidDBusMethodCallback callback) override {
-    StopJob(kMediaAnalyticsJob, std::move(callback));
+    StopJob(kMediaAnalyticsJob, {}, std::move(callback));
   }
 
   void StartWilcoDtcService(VoidDBusMethodCallback callback) override {
@@ -103,7 +105,7 @@
   }
 
   void StopWilcoDtcService(VoidDBusMethodCallback callback) override {
-    StopJob(kWilcoDtcDispatcherJob, std::move(callback));
+    StopJob(kWilcoDtcDispatcherJob, {}, std::move(callback));
   }
 
  private:
diff --git a/chromeos/dbus/upstart/upstart_client.h b/chromeos/dbus/upstart/upstart_client.h
index 182bbbf7..3ddcbf3 100644
--- a/chromeos/dbus/upstart/upstart_client.h
+++ b/chromeos/dbus/upstart/upstart_client.h
@@ -68,10 +68,6 @@
                        const std::vector<std::string>& upstart_env,
                        VoidDBusMethodCallback callback) = 0;
 
-  void StopJob(const std::string& job, VoidDBusMethodCallback callback) {
-    StopJob(job, {}, std::move(callback));
-  }
-
   // Starts authpolicyd.
   virtual void StartAuthPolicyService() = 0;
 
diff --git a/components/autofill/core/browser/form_structure.cc b/components/autofill/core/browser/form_structure.cc
index 7828bd2..f6f017a8 100644
--- a/components/autofill/core/browser/form_structure.cc
+++ b/components/autofill/core/browser/form_structure.cc
@@ -585,7 +585,8 @@
       form_parsed_timestamp_(base::TimeTicks::Now()),
       passwords_were_revealed_(false),
       password_symbol_vote_(0),
-      developer_engagement_metrics_(0) {
+      developer_engagement_metrics_(0),
+      unique_renderer_id_(form.unique_renderer_id) {
   // Copy the form fields.
   std::map<base::string16, size_t> unique_names;
   for (const FormFieldData& field : form.fields) {
@@ -1360,6 +1361,7 @@
   data.url = source_url_;
   data.action = target_url_;
   data.main_frame_origin = main_frame_origin_;
+  data.unique_renderer_id = unique_renderer_id_;
 
   for (size_t i = 0; i < fields_.size(); ++i) {
     data.fields.push_back(FormFieldData(*fields_[i]));
diff --git a/components/autofill/core/browser/form_structure.h b/components/autofill/core/browser/form_structure.h
index 805dc59..7813505 100644
--- a/components/autofill/core/browser/form_structure.h
+++ b/components/autofill/core/browser/form_structure.h
@@ -357,6 +357,8 @@
     value_from_dynamic_change_form_ = v;
   }
 
+  uint32_t unique_renderer_id() const { return unique_renderer_id_; }
+
  private:
   friend class AutofillMergeTest;
   friend class FormStructureTest;
@@ -625,6 +627,8 @@
 
   bool value_from_dynamic_change_form_ = false;
 
+  uint32_t unique_renderer_id_;
+
   DISALLOW_COPY_AND_ASSIGN(FormStructure);
 };
 
diff --git a/components/download/public/common/input_stream.cc b/components/download/public/common/input_stream.cc
index 83558fa..33390e7a 100644
--- a/components/download/public/common/input_stream.cc
+++ b/components/download/public/common/input_stream.cc
@@ -10,6 +10,10 @@
 
 void InputStream::Initialize() {}
 
+bool InputStream::IsEmpty() {
+  return true;
+}
+
 void InputStream::RegisterDataReadyCallback(
     const mojo::SimpleWatcher::ReadyCallback& callback) {}
 
@@ -17,4 +21,13 @@
 
 void InputStream::RegisterCompletionCallback(base::OnceClosure callback) {}
 
+InputStream::StreamState InputStream::Read(scoped_refptr<net::IOBuffer>* data,
+                                           size_t* length) {
+  return StreamState::EMPTY;
+}
+
+DownloadInterruptReason InputStream::GetCompletionStatus() {
+  return DOWNLOAD_INTERRUPT_REASON_NONE;
+}
+
 }  // namespace download
diff --git a/components/download/public/common/input_stream.h b/components/download/public/common/input_stream.h
index 938daba2..87871ea 100644
--- a/components/download/public/common/input_stream.h
+++ b/components/download/public/common/input_stream.h
@@ -30,7 +30,7 @@
   virtual void Initialize();
 
   // Returns true if the input stream contains no data, or false otherwise.
-  virtual bool IsEmpty() = 0;
+  virtual bool IsEmpty();
 
   // Register/clear callbacks when data become available.
   virtual void RegisterDataReadyCallback(
@@ -42,11 +42,10 @@
 
   // Reads data from the stream into |data|, |length| is the number of bytes
   // returned.
-  virtual StreamState Read(scoped_refptr<net::IOBuffer>* data,
-                           size_t* length) = 0;
+  virtual StreamState Read(scoped_refptr<net::IOBuffer>* data, size_t* length);
 
   // Returns the completion status.
-  virtual DownloadInterruptReason GetCompletionStatus() = 0;
+  virtual DownloadInterruptReason GetCompletionStatus();
 };
 
 }  // namespace download
diff --git a/components/password_manager/core/browser/BUILD.gn b/components/password_manager/core/browser/BUILD.gn
index dd15f5a..928bce40 100644
--- a/components/password_manager/core/browser/BUILD.gn
+++ b/components/password_manager/core/browser/BUILD.gn
@@ -291,6 +291,8 @@
     "import/csv_field_parser.h",
     "import/csv_password.cc",
     "import/csv_password.h",
+    "import/csv_password_iterator.cc",
+    "import/csv_password_iterator.h",
   ]
   deps = [
     ":affiliation",
@@ -304,6 +306,7 @@
   testonly = true
   sources = [
     "import/csv_field_parser_unittest.cc",
+    "import/csv_password_iterator_unittest.cc",
     "import/csv_password_unittest.cc",
   ]
   deps = [
diff --git a/components/password_manager/core/browser/import/csv_password.h b/components/password_manager/core/browser/import/csv_password.h
index e0f260ab..e85ff971 100644
--- a/components/password_manager/core/browser/import/csv_password.h
+++ b/components/password_manager/core/browser/import/csv_password.h
@@ -24,7 +24,7 @@
   // Number of values in the Label enum.
   static constexpr size_t kLabelCount = 3;
 
-  CSVPassword(const ColumnMap& map, base::StringPiece csv_row);
+  explicit CSVPassword(const ColumnMap& map, base::StringPiece csv_row);
   CSVPassword(const CSVPassword&) = delete;
   CSVPassword(CSVPassword&&) = delete;
   CSVPassword& operator=(const CSVPassword&) = delete;
diff --git a/components/password_manager/core/browser/import/csv_password_iterator.cc b/components/password_manager/core/browser/import/csv_password_iterator.cc
new file mode 100644
index 0000000..6892ab8e
--- /dev/null
+++ b/components/password_manager/core/browser/import/csv_password_iterator.cc
@@ -0,0 +1,124 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/password_manager/core/browser/import/csv_password_iterator.h"
+
+#include <utility>
+
+#include "base/logging.h"
+#include "base/strings/string_util.h"
+#include "base/template_util.h"
+
+namespace password_manager {
+
+namespace {
+
+// Returns all the characters from the start of |input| until the first '\n',
+// "\r\n" (exclusive) or the end of |input|. Cuts the returned part (inclusive
+// the line breaks) from |input|. Skips blocks of matching quotes. Examples:
+// old input -> returned value, new input
+// "ab\ncd" -> "ab", "cd"
+// "\r\n" -> "", ""
+// "abcd" -> "abcd", ""
+// "\r" -> "\r", ""
+// "a\"\n\"b" -> "a\"\n\"b", ""
+base::StringPiece ConsumeLine(base::StringPiece* input) {
+  DCHECK(input);
+  DCHECK(!input->empty());
+
+  bool inside_quotes = false;
+  bool last_char_was_CR = false;
+  for (size_t current = 0; current < input->size(); ++current) {
+    char c = (*input)[current];
+    switch (c) {
+      case '\n':
+        if (!inside_quotes) {
+          const size_t eol_start = last_char_was_CR ? current - 1 : current;
+          base::StringPiece ret = input->substr(0, eol_start);
+          *input = input->substr(current + 1);
+          return ret;
+        }
+        break;
+      case '"':
+        inside_quotes = !inside_quotes;
+        break;
+      default:
+        break;
+    }
+    last_char_was_CR = (c == '\r');
+  }
+
+  // The whole |*input| is one line.
+  return std::exchange(*input, base::StringPiece());
+}
+
+// Takes the |rest| of the CSV lines, returns the first one and stores the
+// remaining ones back in |rest|.
+base::StringPiece ExtractFirstRow(base::StringPiece* rest) {
+  DCHECK(rest);
+  if (!rest->empty())
+    return ConsumeLine(rest);
+  return base::StringPiece();
+}
+
+}  // namespace
+
+CSVPasswordIterator::CSVPasswordIterator() = default;
+
+CSVPasswordIterator::CSVPasswordIterator(const CSVPassword::ColumnMap& map,
+                                         base::StringPiece csv)
+    : map_(&map),
+      csv_rest_(csv),
+      csv_row_(ExtractFirstRow(&csv_rest_)),
+      password_(base::in_place, map, csv_row_) {}
+
+CSVPasswordIterator::CSVPasswordIterator(const CSVPasswordIterator& other) {
+  *this = other;
+}
+
+CSVPasswordIterator& CSVPasswordIterator::operator=(
+    const CSVPasswordIterator& other) {
+  map_ = other.map_;
+  csv_rest_ = other.csv_rest_;
+  csv_row_ = other.csv_row_;
+  if (map_)
+    password_.emplace(*map_, csv_row_);
+  else
+    password_.reset();
+  return *this;
+}
+
+CSVPasswordIterator::~CSVPasswordIterator() = default;
+
+CSVPasswordIterator& CSVPasswordIterator::operator++() {
+  DCHECK(map_);
+  csv_row_ = ExtractFirstRow(&csv_rest_);
+  password_.emplace(*map_, csv_row_);
+  return *this;
+}
+
+CSVPasswordIterator CSVPasswordIterator::operator++(int) {
+  CSVPasswordIterator old = *this;
+  ++*this;
+  return old;
+}
+
+bool CSVPasswordIterator::operator==(const CSVPasswordIterator& other) const {
+  // There is no need to compare |password_|, because it is determined by |map_|
+  // and |csv_row_|.
+  return
+      // Checking StringPiece::data() equality instead of just StringPiece has
+      // two reasons: (1) flagging the case when, e.g., two identical lines in
+      // one CSV blob would otherwise cause the corresponding iterators look the
+      // same, and (2) efficiency. StringPiece::size() is not checked on the
+      // assumption that always the whole row is contained in |csv_row_|.
+      csv_row_.data() == other.csv_row_.data() &&
+      // The column map should reference the same map if the iterators come from
+      // the same sequence, and iterators from different sequences are not
+      // considered equal. Therefore the maps' addresses are checked instead of
+      // their contents.
+      map_ == other.map_;
+}
+
+}  // namespace password_manager
diff --git a/components/password_manager/core/browser/import/csv_password_iterator.h b/components/password_manager/core/browser/import/csv_password_iterator.h
new file mode 100644
index 0000000..65bc400b
--- /dev/null
+++ b/components/password_manager/core/browser/import/csv_password_iterator.h
@@ -0,0 +1,67 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_IMPORT_CSV_PASSWORD_ITERATOR_H_
+#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_IMPORT_CSV_PASSWORD_ITERATOR_H_
+
+#include <stddef.h>
+
+#include <iterator>
+
+#include "base/optional.h"
+#include "base/strings/string_piece.h"
+#include "components/password_manager/core/browser/import/csv_password.h"
+
+namespace password_manager {
+
+// CSVPasswordIterator abstracts reading a CSV text line by line by creating
+// and providing a CSVPassword for each line. For more details, see
+// https://docs.google.com/document/d/1wsZBl93S_WGaXZqrqq5SP08LVZ0zDKf6e9nlptyl9AY/edit?usp=sharing.
+class CSVPasswordIterator {
+ public:
+  using iterator_category = std::forward_iterator_tag;
+  using value_type = CSVPassword;
+  using difference_type = std::ptrdiff_t;
+  using pointer = const value_type*;
+  using reference = const value_type&;
+
+  CSVPasswordIterator();
+  explicit CSVPasswordIterator(const CSVPassword::ColumnMap& map,
+                               base::StringPiece csv);
+  CSVPasswordIterator(const CSVPasswordIterator&);
+  CSVPasswordIterator& operator=(const CSVPasswordIterator&);
+  ~CSVPasswordIterator();
+
+  reference operator*() const {
+    DCHECK(password_);
+    return *password_;
+  }
+  pointer operator->() const { return &**this; }
+
+  CSVPasswordIterator& operator++();
+  CSVPasswordIterator operator++(int);
+
+  // Defining comparison as methods rather than non-member functions, because
+  // while the latter allows implicit conversions on the lhs argument as well,
+  // there are no implicit conversions available for CSVPasswordIterator, and
+  // the methods avoid having to declare the operators as friends.
+  bool operator==(const CSVPasswordIterator& other) const;
+  bool operator!=(const CSVPasswordIterator& other) const {
+    return !(*this == other);
+  }
+
+ private:
+  // |map_| stores the meaning of particular columns in the row.
+  const CSVPassword::ColumnMap* map_ = nullptr;
+  // |csv_rest_| contains the CSV lines left to be iterated over.
+  base::StringPiece csv_rest_;
+  // |csv_row_| contains the CSV row which the iterator points at.
+  base::StringPiece csv_row_;
+  // Contains a CSVPassword created from |map_| and |csv_row_| if possible.
+  base::Optional<CSVPassword> password_;
+};
+
+}  // namespace password_manager
+
+#endif  // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_IMPORT_CSV_PASSWORD_ITERATOR_H_
diff --git a/components/password_manager/core/browser/import/csv_password_iterator_unittest.cc b/components/password_manager/core/browser/import/csv_password_iterator_unittest.cc
new file mode 100644
index 0000000..b9e727a
--- /dev/null
+++ b/components/password_manager/core/browser/import/csv_password_iterator_unittest.cc
@@ -0,0 +1,118 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/password_manager/core/browser/import/csv_password_iterator.h"
+
+#include <string>
+#include <utility>
+
+#include "base/stl_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace password_manager {
+
+using ::autofill::PasswordForm;
+
+TEST(CSVPasswordIteratorTest, Operations) {
+  // Default.
+  CSVPasswordIterator def;
+  EXPECT_EQ(def, def);
+
+  // From CSV.
+  const CSVPassword::ColumnMap kColMap = {
+      {0, CSVPassword::Label::kOrigin},
+      {1, CSVPassword::Label::kUsername},
+      {2, CSVPassword::Label::kPassword},
+  };
+  constexpr base::StringPiece kCSV = "http://example.com,user,password";
+  CSVPasswordIterator iter(kColMap, kCSV);
+  // Because kCSV is just one row, it can be used to create a CSVPassword
+  // directly.
+  EXPECT_EQ(iter->ParseValid(), CSVPassword(kColMap, kCSV).ParseValid());
+
+  // Copy.
+  CSVPasswordIterator copy = iter;
+  EXPECT_EQ(copy, iter);
+
+  // Assignment.
+  CSVPasswordIterator target;
+  target = iter;
+  EXPECT_EQ(target, iter);
+  copy = def;
+  EXPECT_EQ(copy, def);
+
+  // More of equality and increment.
+  CSVPasswordIterator dummy;
+  EXPECT_NE(dummy, iter);
+  CSVPasswordIterator same_as_iter(kColMap, kCSV);
+  EXPECT_EQ(same_as_iter, iter);
+  const std::string kCSVCopy(kCSV);
+  CSVPasswordIterator same_looking(kColMap, kCSVCopy);
+  EXPECT_NE(same_looking, iter);
+  CSVPasswordIterator old = iter++;
+  EXPECT_NE(old, iter);
+  EXPECT_EQ(++old, iter);
+}
+
+TEST(CSVPasswordIteratorTest, Success) {
+  const CSVPassword::ColumnMap kColMap = {
+      {0, CSVPassword::Label::kOrigin},
+      {1, CSVPassword::Label::kUsername},
+      {2, CSVPassword::Label::kPassword},
+  };
+  constexpr base::StringPiece kCSVBlob =
+      "http://example.com,u1,p1\n"
+      "http://example.com,u2,p2\r\n"
+      "http://example.com,u3,p\r\r\n"
+      "http://example.com,\"u\n4\",\"p\n4\"\n"
+      "http://example.com,u5,p5";
+  constexpr base::StringPiece kExpectedPasswords[] = {"p1", "p2", "p\r", "p\n4",
+                                                      "p5"};
+
+  CSVPasswordIterator iter(kColMap, kCSVBlob);
+
+  CSVPasswordIterator check = iter;
+  for (size_t i = 0; i < base::size(kExpectedPasswords); ++i) {
+    EXPECT_TRUE((check++)->Parse(nullptr)) << "on line " << i;
+  }
+  EXPECT_FALSE(check->Parse(nullptr));
+
+  for (const base::StringPiece& expected_password : kExpectedPasswords) {
+    PasswordForm result = (iter++)->ParseValid();
+    // Detailed checks of the parsed result are made in the test for
+    // CSVPassword. Here only the last field (password) is checked to (1) ensure
+    // that lines are processed in the expected sequence, and (2) line breaks
+    // are handled as expected (in particular, '\r' alone is not a line break).
+    EXPECT_EQ(base::ASCIIToUTF16(expected_password), result.password_value);
+  }
+}
+
+TEST(CSVPasswordIteratorTest, Failure) {
+  const CSVPassword::ColumnMap kColMap = {
+      {0, CSVPassword::Label::kOrigin},
+      {1, CSVPassword::Label::kUsername},
+      {2, CSVPassword::Label::kPassword},
+  };
+  constexpr base::StringPiece kCSVBlob =
+      "too few fields\n"
+      "http://example.com,\"\"trailing,p\n"
+      "http://notascii.ž.com,u,p\n"
+      "http://example.com,empty-password,\n"
+      "http://no-failure.example.com,to check that,operator++ worked";
+  constexpr size_t kLinesInBlob = 5;
+
+  CSVPasswordIterator iter(kColMap, kCSVBlob);
+
+  CSVPasswordIterator check = iter;
+  for (size_t i = 0; i + 1 < kLinesInBlob; ++i) {
+    EXPECT_FALSE((check++)->Parse(nullptr)) << "on line " << i;
+  }
+  // Last line was not a failure.
+  EXPECT_TRUE((check++)->Parse(nullptr));
+  // After iterating over all lines, there is no more data to parse.
+  EXPECT_FALSE(check->Parse(nullptr));
+}
+
+}  // namespace password_manager
diff --git a/components/password_manager/core/browser/leak_detection/BUILD.gn b/components/password_manager/core/browser/leak_detection/BUILD.gn
index 6541850..3afab07 100644
--- a/components/password_manager/core/browser/leak_detection/BUILD.gn
+++ b/components/password_manager/core/browser/leak_detection/BUILD.gn
@@ -35,6 +35,7 @@
 
   public_deps = [
     ":leak_detection_interface_headers",
+    "//services/network/public/cpp",
   ]
 
   deps = [
diff --git a/components/password_manager/core/browser/leak_detection/authenticated_leak_check.cc b/components/password_manager/core/browser/leak_detection/authenticated_leak_check.cc
index e78a078a..011be03 100644
--- a/components/password_manager/core/browser/leak_detection/authenticated_leak_check.cc
+++ b/components/password_manager/core/browser/leak_detection/authenticated_leak_check.cc
@@ -4,12 +4,19 @@
 
 #include "components/password_manager/core/browser/leak_detection/authenticated_leak_check.h"
 
+#include <utility>
+
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+
 namespace password_manager {
 
 AuthenticatedLeakCheck::AuthenticatedLeakCheck(
     LeakDetectionDelegateInterface* delegate,
-    signin::IdentityManager* identity_manager)
-    : delegate_(delegate), identity_manager_(identity_manager) {}
+    signin::IdentityManager* identity_manager,
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
+    : delegate_(delegate),
+      identity_manager_(identity_manager),
+      url_loader_factory_(std::move(url_loader_factory)) {}
 
 AuthenticatedLeakCheck::~AuthenticatedLeakCheck() = default;
 
@@ -19,6 +26,8 @@
   // TODO(crbug.com/986298): get the access token here.
   std::ignore = delegate_;
   std::ignore = identity_manager_;
+  // TODO(crbug.com/986298): Initiate the network request.
+  std::ignore = url_loader_factory_;
 }
 
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/leak_detection/authenticated_leak_check.h b/components/password_manager/core/browser/leak_detection/authenticated_leak_check.h
index f2e6b019..9eecc0b 100644
--- a/components/password_manager/core/browser/leak_detection/authenticated_leak_check.h
+++ b/components/password_manager/core/browser/leak_detection/authenticated_leak_check.h
@@ -5,8 +5,13 @@
 #ifndef COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_LEAK_DETECTION_AUTHENTICATED_LEAK_CHECK_H_
 #define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_LEAK_DETECTION_AUTHENTICATED_LEAK_CHECK_H_
 
+#include "base/memory/scoped_refptr.h"
 #include "components/password_manager/core/browser/leak_detection/leak_detection_check.h"
 
+namespace network {
+class SharedURLLoaderFactory;
+}  // namespace network
+
 namespace signin {
 class IdentityManager;
 }  // namespace signin
@@ -18,8 +23,10 @@
 // Performs a leak-check for {username, password} for Chrome signed-in users.
 class AuthenticatedLeakCheck : public LeakDetectionCheck {
  public:
-  AuthenticatedLeakCheck(LeakDetectionDelegateInterface* delegate,
-                         signin::IdentityManager* identity_manager);
+  AuthenticatedLeakCheck(
+      LeakDetectionDelegateInterface* delegate,
+      signin::IdentityManager* identity_manager,
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory);
   ~AuthenticatedLeakCheck() override;
 
   void Start(const GURL& url,
@@ -31,6 +38,9 @@
   LeakDetectionDelegateInterface* delegate_;
   // Identity manager for the profile.
   signin::IdentityManager* identity_manager_;
+  // URL loader factory required for the network request to the identity
+  // endpoint.
+  scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
 };
 
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/leak_detection/authenticated_leak_check_unittest.cc b/components/password_manager/core/browser/leak_detection/authenticated_leak_check_unittest.cc
index 0ec113b3..9885633 100644
--- a/components/password_manager/core/browser/leak_detection/authenticated_leak_check_unittest.cc
+++ b/components/password_manager/core/browser/leak_detection/authenticated_leak_check_unittest.cc
@@ -4,12 +4,13 @@
 
 #include "components/password_manager/core/browser/leak_detection/authenticated_leak_check.h"
 
+#include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace password_manager {
 
 TEST(AuthenticatedLeakCheck, Create) {
-  AuthenticatedLeakCheck check(nullptr, nullptr);
+  AuthenticatedLeakCheck check(nullptr, nullptr, nullptr);
 }
 
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/leak_detection/leak_detection_request_factory.h b/components/password_manager/core/browser/leak_detection/leak_detection_request_factory.h
index 127ffaf..1a054dd 100644
--- a/components/password_manager/core/browser/leak_detection/leak_detection_request_factory.h
+++ b/components/password_manager/core/browser/leak_detection/leak_detection_request_factory.h
@@ -7,10 +7,16 @@
 
 #include <memory>
 
+#include "base/memory/scoped_refptr.h"
+
 namespace signin {
 class IdentityManager;
 }  // namespace signin
 
+namespace network {
+class SharedURLLoaderFactory;
+}  // namespace network
+
 namespace password_manager {
 
 class LeakDetectionCheck;
@@ -37,7 +43,9 @@
   // |identity_manager| is used to obtain the token.
   virtual std::unique_ptr<LeakDetectionCheck> TryCreateLeakCheck(
       LeakDetectionDelegateInterface* delegate,
-      signin::IdentityManager* identity_manager) const = 0;
+      signin::IdentityManager* identity_manager,
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
+      const = 0;
 };
 
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/leak_detection/leak_detection_request_factory_impl.cc b/components/password_manager/core/browser/leak_detection/leak_detection_request_factory_impl.cc
index 23bc008..8835790e 100644
--- a/components/password_manager/core/browser/leak_detection/leak_detection_request_factory_impl.cc
+++ b/components/password_manager/core/browser/leak_detection/leak_detection_request_factory_impl.cc
@@ -4,8 +4,11 @@
 
 #include "components/password_manager/core/browser/leak_detection/leak_detection_request_factory_impl.h"
 
+#include <utility>
+
 #include "components/password_manager/core/browser/leak_detection/authenticated_leak_check.h"
 #include "components/password_manager/core/common/password_manager_features.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
 
 namespace password_manager {
 
@@ -15,10 +18,12 @@
 std::unique_ptr<LeakDetectionCheck>
 LeakDetectionRequestFactoryImpl::TryCreateLeakCheck(
     LeakDetectionDelegateInterface* delegate,
-    signin::IdentityManager* identity_manager) const {
+    signin::IdentityManager* identity_manager,
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) const {
   if (!base::FeatureList::IsEnabled(features::kLeakDetection))
     return nullptr;
-  return std::make_unique<AuthenticatedLeakCheck>(delegate, identity_manager);
+  return std::make_unique<AuthenticatedLeakCheck>(
+      delegate, identity_manager, std::move(url_loader_factory));
 }
 
-}  // namespace password_manager
\ No newline at end of file
+}  // namespace password_manager
diff --git a/components/password_manager/core/browser/leak_detection/leak_detection_request_factory_impl.h b/components/password_manager/core/browser/leak_detection/leak_detection_request_factory_impl.h
index e8b7d10..4e583a3 100644
--- a/components/password_manager/core/browser/leak_detection/leak_detection_request_factory_impl.h
+++ b/components/password_manager/core/browser/leak_detection/leak_detection_request_factory_impl.h
@@ -21,7 +21,9 @@
 
   std::unique_ptr<LeakDetectionCheck> TryCreateLeakCheck(
       LeakDetectionDelegateInterface* delegate,
-      signin::IdentityManager* identity_manager) const override;
+      signin::IdentityManager* identity_manager,
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
+      const override;
 };
 
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/leak_detection/leak_detection_request_factory_impl_unittest.cc b/components/password_manager/core/browser/leak_detection/leak_detection_request_factory_impl_unittest.cc
index e9de548..784fa49 100644
--- a/components/password_manager/core/browser/leak_detection/leak_detection_request_factory_impl_unittest.cc
+++ b/components/password_manager/core/browser/leak_detection/leak_detection_request_factory_impl_unittest.cc
@@ -8,6 +8,7 @@
 #include "components/password_manager/core/browser/leak_detection/leak_detection_check.h"
 #include "components/password_manager/core/browser/leak_detection/leak_detection_delegate_interface.h"
 #include "components/password_manager/core/common/password_manager_features.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace password_manager {
@@ -33,7 +34,7 @@
 
   LeakDetectionRequestFactoryImpl factory;
   TestLeakDetectionDelegateInterface delegate;
-  EXPECT_FALSE(factory.TryCreateLeakCheck(&delegate, nullptr));
+  EXPECT_FALSE(factory.TryCreateLeakCheck(&delegate, nullptr, nullptr));
 }
 
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/leak_detection_delegate.cc b/components/password_manager/core/browser/leak_detection_delegate.cc
index 643b0a6..59700ac 100644
--- a/components/password_manager/core/browser/leak_detection_delegate.cc
+++ b/components/password_manager/core/browser/leak_detection_delegate.cc
@@ -10,6 +10,7 @@
 #include "components/password_manager/core/browser/leak_detection/leak_detection_request_factory_impl.h"
 #include "components/password_manager/core/browser/password_manager_client.h"
 #include "components/password_manager/core/browser/password_manager_util.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
 
 namespace password_manager {
 
@@ -24,8 +25,8 @@
 void LeakDetectionDelegate::StartLeakCheck(const autofill::PasswordForm& form) {
   if (client_->IsIncognito())
     return;
-  leak_check_ =
-      leak_factory_->TryCreateLeakCheck(this, client_->GetIdentityManager());
+  leak_check_ = leak_factory_->TryCreateLeakCheck(
+      this, client_->GetIdentityManager(), client_->GetURLLoaderFactory());
   if (leak_check_)
     leak_check_->Start(form.origin, form.username_value, form.password_value);
 }
diff --git a/components/password_manager/core/browser/leak_detection_delegate_unittest.cc b/components/password_manager/core/browser/leak_detection_delegate_unittest.cc
index 1c37f1d..f8dae26 100644
--- a/components/password_manager/core/browser/leak_detection_delegate_unittest.cc
+++ b/components/password_manager/core/browser/leak_detection_delegate_unittest.cc
@@ -9,6 +9,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "components/password_manager/core/browser/leak_detection/leak_detection_check.h"
 #include "components/password_manager/core/browser/stub_password_manager_client.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -45,10 +46,11 @@
 
 class MockLeakDetectionRequestFactory : public LeakDetectionRequestFactory {
  public:
-  MOCK_CONST_METHOD2(
-      TryCreateLeakCheck,
-      std::unique_ptr<LeakDetectionCheck>(LeakDetectionDelegateInterface*,
-                                          signin::IdentityManager*));
+  MOCK_CONST_METHOD3(TryCreateLeakCheck,
+                     std::unique_ptr<LeakDetectionCheck>(
+                         LeakDetectionDelegateInterface*,
+                         signin::IdentityManager*,
+                         scoped_refptr<network::SharedURLLoaderFactory>));
 };
 
 }  // namespace
diff --git a/components/password_manager/core/browser/password_manager.cc b/components/password_manager/core/browser/password_manager.cc
index d59f1d8..1b98812 100644
--- a/components/password_manager/core/browser/password_manager.cc
+++ b/components/password_manager/core/browser/password_manager.cc
@@ -352,6 +352,14 @@
 #endif
 }
 
+bool HasSingleUsernameVote(const FormStructure& form) {
+  for (const auto& field : form) {
+    if (field->server_type() == autofill::SINGLE_USERNAME)
+      return true;
+  }
+  return false;
+}
+
 }  // namespace
 
 // static
@@ -1307,18 +1315,38 @@
 }
 
 void PasswordManager::ProcessAutofillPredictions(
-    password_manager::PasswordManagerDriver* driver,
-    const std::vector<autofill::FormStructure*>& forms) {
+    PasswordManagerDriver* driver,
+    const std::vector<FormStructure*>& forms) {
   std::unique_ptr<BrowserSavePasswordProgressLogger> logger;
-  if (password_manager_util::IsLoggingActive(client_))
+  if (password_manager_util::IsLoggingActive(client_)) {
     logger.reset(
         new BrowserSavePasswordProgressLogger(client_->GetLogManager()));
+  }
 
   if (IsNewFormParsingForFillingEnabled()) {
-    for (const autofill::FormStructure* form : forms)
+    for (const FormStructure* form : forms)
       predictions_[form->form_signature()] = ConvertToFormPredictions(*form);
     for (auto& manager : form_managers_)
       manager->ProcessServerPredictions(predictions_);
+
+    // Create form managers for non-password forms with single usernames.
+    for (const FormStructure* form : forms) {
+      if (form->has_password_field())
+        continue;
+
+      if (!HasSingleUsernameVote(*form))
+        continue;
+
+      if (FindMatchedManagerByRendererId(form->unique_renderer_id(),
+                                         form_managers_, driver)) {
+        // The form manager is already created.
+        continue;
+      }
+
+      FormData form_data = form->ToFormData();
+      auto* manager = CreateFormManager(driver, form_data);
+      manager->ProcessServerPredictions(predictions_);
+    }
   }
 
   // Leave only forms that contain fields that are useful for password manager.
diff --git a/components/password_manager/core/browser/password_manager.h b/components/password_manager/core/browser/password_manager.h
index 22270b4d..da787ad3 100644
--- a/components/password_manager/core/browser/password_manager.h
+++ b/components/password_manager/core/browser/password_manager.h
@@ -277,7 +277,7 @@
   // Create NewPasswordFormManager for |form|, adds the newly created one to
   // |form_managers_| and returns it.
   NewPasswordFormManager* CreateFormManager(PasswordManagerDriver* driver,
-                                            const autofill::FormData& forms);
+                                            const autofill::FormData& form);
 
   // Passes |form| to NewPasswordFormManager that manages it for using it after
   // detecting submission success for saving. |driver| is needed to determine
diff --git a/components/password_manager/core/browser/password_manager_client.h b/components/password_manager/core/browser/password_manager_client.h
index 108c855..dc2dcb6 100644
--- a/components/password_manager/core/browser/password_manager_client.h
+++ b/components/password_manager/core/browser/password_manager_client.h
@@ -12,6 +12,7 @@
 
 #include "base/callback.h"
 #include "base/macros.h"
+#include "base/memory/scoped_refptr.h"
 #include "components/autofill/core/common/mojom/autofill_types.mojom.h"
 #include "components/autofill/core/common/password_form.h"
 #include "components/password_manager/core/browser/credentials_filter.h"
@@ -35,6 +36,10 @@
 class FaviconService;
 }
 
+namespace network {
+class SharedURLLoaderFactory;
+}  // namespace network
+
 namespace signin {
 class IdentityManager;
 }  // namespace signin
@@ -309,6 +314,11 @@
   // Returns the identity manager for profile.
   virtual signin::IdentityManager* GetIdentityManager() = 0;
 
+  // Returns a pointer to the URLLoaderFactory owned by the storage partition of
+  // the current profile.
+  virtual scoped_refptr<network::SharedURLLoaderFactory>
+  GetURLLoaderFactory() = 0;
+
   // Whether the primary account of the current profile is under Advanced
   // Protection - a type of Google Account that helps protect our most at-risk
   // users.
diff --git a/components/password_manager/core/browser/password_manager_unittest.cc b/components/password_manager/core/browser/password_manager_unittest.cc
index 80b3fba..e93b170 100644
--- a/components/password_manager/core/browser/password_manager_unittest.cc
+++ b/components/password_manager/core/browser/password_manager_unittest.cc
@@ -48,6 +48,7 @@
 #include "net/cert/cert_status_flags.h"
 #include "services/metrics/public/cpp/ukm_builders.h"
 #include "services/metrics/public/cpp/ukm_source.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -96,10 +97,11 @@
 
 class MockLeakDetectionRequestFactory : public LeakDetectionRequestFactory {
  public:
-  MOCK_CONST_METHOD2(
-      TryCreateLeakCheck,
-      std::unique_ptr<LeakDetectionCheck>(LeakDetectionDelegateInterface*,
-                                          signin::IdentityManager*));
+  MOCK_CONST_METHOD3(TryCreateLeakCheck,
+                     std::unique_ptr<LeakDetectionCheck>(
+                         LeakDetectionDelegateInterface*,
+                         signin::IdentityManager*,
+                         scoped_refptr<network::SharedURLLoaderFactory>));
 };
 
 class MockStoreResultFilter : public StubCredentialsFilter {
@@ -3882,4 +3884,40 @@
 }
 #endif  // !defined(OS_IOS)
 
+// Check that a non-password form with SINGLE_USERNAME prediction is filled.
+TEST_F(PasswordManagerTest, FillSingleUsername) {
+  NewPasswordFormManager::set_wait_for_server_predictions_for_filling(true);
+  EXPECT_CALL(client_, IsSavingAndFillingEnabled(_))
+      .WillRepeatedly(Return(true));
+  PasswordForm saved_match(MakeSavedForm());
+  EXPECT_CALL(*store_, GetLogins(_, _))
+      .WillRepeatedly(WithArg<1>(InvokeConsumer(saved_match)));
+
+  // Create FormdData for a form with 1 text field.
+  FormData form_data;
+  const uint32_t form_id = 1001;
+  form_data.unique_renderer_id = form_id;
+  form_data.url = GURL("example.com");
+  FormFieldData field;
+  field.form_control_type = "text";
+  const uint32_t field_id = 10;
+  field.unique_renderer_id = field_id;
+  form_data.fields.push_back(field);
+
+  // Set SINGLE_USERNAME predictions for the field.
+  FormStructure form_structure(form_data);
+  form_structure.field(0)->set_server_type(autofill::SINGLE_USERNAME);
+
+  PasswordFormFillData fill_data;
+  EXPECT_CALL(driver_, FillPasswordForm(_)).WillOnce(SaveArg<0>(&fill_data));
+  manager()->ProcessAutofillPredictions(&driver_, {&form_structure});
+  EXPECT_EQ(form_id, fill_data.form_renderer_id);
+  EXPECT_EQ(saved_match.username_value, fill_data.username_field.value);
+  EXPECT_EQ(saved_match.username_value, fill_data.username_field.value);
+  EXPECT_EQ(field_id, fill_data.username_field.unique_renderer_id);
+  EXPECT_EQ(saved_match.password_value, fill_data.password_field.value);
+  EXPECT_EQ(std::numeric_limits<uint32_t>::max(),
+            fill_data.password_field.unique_renderer_id);
+}
+
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/stub_password_manager_client.cc b/components/password_manager/core/browser/stub_password_manager_client.cc
index 24d1742f..df01e1f 100644
--- a/components/password_manager/core/browser/stub_password_manager_client.cc
+++ b/components/password_manager/core/browser/stub_password_manager_client.cc
@@ -8,6 +8,7 @@
 
 #include "components/password_manager/core/browser/credentials_filter.h"
 #include "components/password_manager/core/browser/password_form_manager_for_ui.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
 
 namespace password_manager {
 
@@ -116,6 +117,11 @@
   return nullptr;
 }
 
+scoped_refptr<network::SharedURLLoaderFactory>
+StubPasswordManagerClient::GetURLLoaderFactory() {
+  return nullptr;
+}
+
 bool StubPasswordManagerClient::IsIsolationForPasswordSitesEnabled() const {
   return false;
 }
diff --git a/components/password_manager/core/browser/stub_password_manager_client.h b/components/password_manager/core/browser/stub_password_manager_client.h
index 2683d021..0ccb8641 100644
--- a/components/password_manager/core/browser/stub_password_manager_client.h
+++ b/components/password_manager/core/browser/stub_password_manager_client.h
@@ -71,6 +71,7 @@
   ukm::SourceId GetUkmSourceId() override;
   PasswordManagerMetricsRecorder* GetMetricsRecorder() override;
   signin::IdentityManager* GetIdentityManager() override;
+  scoped_refptr<network::SharedURLLoaderFactory> GetURLLoaderFactory() override;
   bool IsIsolationForPasswordSitesEnabled() const override;
   bool IsNewTabPage() const override;
 
diff --git a/components/resources/OWNERS b/components/resources/OWNERS
index 7038831..704da9fb 100644
--- a/components/resources/OWNERS
+++ b/components/resources/OWNERS
@@ -18,7 +18,7 @@
 per-file neterror*=mmenke@chromium.org
 per-file neterror*=file://net/OWNERS
 per-file ntp_tiles_resources.grdp=file://components/ntp_tiles/OWNERS
-per-file welcome_scaled_resources.grdp=file://ui/webui/PLATFORM_OWNERS
+per-file onboarding_welcome_scaled_resources.grdp=file://ui/webui/PLATFORM_OWNERS
 per-file offline_pages_resources.grdp=file://components/offline_pages/OWNERS
 per-file proximity_auth*=tengs@chromium.org
 per-file printing_resources.grdp=file://printing/OWNERS
diff --git a/components/resources/components_scaled_resources.grd b/components/resources/components_scaled_resources.grd
index a58807f..379fb2f9 100644
--- a/components/resources/components_scaled_resources.grd
+++ b/components/resources/components_scaled_resources.grd
@@ -16,7 +16,7 @@
       <part file="crash_scaled_resources.grdp" />
       <part file="flags_ui_scaled_resources.grdp" />
       <part file="neterror_scaled_resources.grdp" />
-      <part file="welcome_scaled_resources.grdp" />
+      <part file="onboarding_welcome_scaled_resources.grdp" />
       <part file="version_ui_scaled_resources.grdp" />
 
       <!-- Generic resources -->
diff --git a/components/resources/onboarding_welcome_scaled_resources.grdp b/components/resources/onboarding_welcome_scaled_resources.grdp
new file mode 100644
index 0000000..c5a5f73
--- /dev/null
+++ b/components/resources/onboarding_welcome_scaled_resources.grdp
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<grit-part>
+  <if expr="not is_android and not is_ios and _google_chrome">
+    <structure type="chrome_scaled_image" name="IDS_ONBOARDING_WELCOME_GMAIL" file="google_chrome/welcome/gmail.png" />
+    <structure type="chrome_scaled_image" name="IDS_ONBOARDING_WELCOME_MAPS" file="google_chrome/welcome/maps.png" />
+    <structure type="chrome_scaled_image" name="IDS_ONBOARDING_WELCOME_NEWS" file="google_chrome/welcome/news.png" />
+    <structure type="chrome_scaled_image" name="IDS_ONBOARDING_WELCOME_SEARCH" file="google_chrome/welcome/search.png" />
+    <structure type="chrome_scaled_image" name="IDS_ONBOARDING_WELCOME_TRANSLATE" file="google_chrome/welcome/translate.png" />
+    <structure type="chrome_scaled_image" name="IDS_ONBOARDING_WELCOME_YOUTUBE" file="google_chrome/welcome/youtube.png" />
+  </if>
+</grit-part>
diff --git a/components/resources/welcome_scaled_resources.grdp b/components/resources/welcome_scaled_resources.grdp
deleted file mode 100644
index b6c82bd..0000000
--- a/components/resources/welcome_scaled_resources.grdp
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<grit-part>
-  <if expr="not is_android and not is_ios and _google_chrome">
-    <structure type="chrome_scaled_image" name="IDS_WELCOME_GMAIL" file="google_chrome/welcome/gmail.png" />
-    <structure type="chrome_scaled_image" name="IDS_WELCOME_MAPS" file="google_chrome/welcome/maps.png" />
-    <structure type="chrome_scaled_image" name="IDS_WELCOME_NEWS" file="google_chrome/welcome/news.png" />
-    <structure type="chrome_scaled_image" name="IDS_WELCOME_SEARCH" file="google_chrome/welcome/search.png" />
-    <structure type="chrome_scaled_image" name="IDS_WELCOME_TRANSLATE" file="google_chrome/welcome/translate.png" />
-    <structure type="chrome_scaled_image" name="IDS_WELCOME_YOUTUBE" file="google_chrome/welcome/youtube.png" />
-  </if>
-</grit-part>
diff --git a/components/safe_browsing/browser/threat_details.cc b/components/safe_browsing/browser/threat_details.cc
index 55925b2a99..90451cb6 100644
--- a/components/safe_browsing/browser/threat_details.cc
+++ b/components/safe_browsing/browser/threat_details.cc
@@ -381,7 +381,6 @@
       cache_result_(false),
       did_proceed_(false),
       num_visits_(0),
-      ambiguous_dom_(false),
       trim_to_ad_tags_(trim_to_ad_tags),
       cache_collector_(new ThreatDetailsCacheCollector),
       done_callback_(done_callback),
@@ -398,7 +397,6 @@
     : cache_result_(false),
       did_proceed_(false),
       num_visits_(0),
-      ambiguous_dom_(false),
       trim_to_ad_tags_(false),
       all_done_expected_(false),
       is_all_done_(false) {}
@@ -676,10 +674,8 @@
     int child_frame_tree_node_id =
         content::RenderFrameHost::GetFrameTreeNodeIdForRoutingId(
             sender_process_id, node->child_frame_routing_id);
-    if (child_frame_tree_node_id ==
+    if (child_frame_tree_node_id !=
         content::RenderFrameHost::kNoFrameTreeNodeId) {
-      ambiguous_dom_ = true;
-    } else {
       child_frame_tree_map[cur_element_key] = child_frame_tree_node_id;
     }
   }
@@ -822,12 +818,6 @@
   for (auto& element_pair : elements_) {
     report_->add_dom()->Swap(element_pair.second.get());
   }
-  if (!elements_.empty()) {
-    // TODO(lpz): Consider including the ambiguous_dom_ bit in the report
-    // itself.
-    UMA_HISTOGRAM_BOOLEAN("SafeBrowsing.ThreatReport.DomIsAmbiguous",
-                          ambiguous_dom_);
-  }
 
   report_->set_did_proceed(did_proceed_);
   // Only sets repeat_visit if num_visits_ >= 0.
diff --git a/components/safe_browsing/browser/threat_details.h b/components/safe_browsing/browser/threat_details.h
index 76ae1c0..0a77f76 100644
--- a/components/safe_browsing/browser/threat_details.h
+++ b/components/safe_browsing/browser/threat_details.h
@@ -233,11 +233,6 @@
   // How many times this user has visited this page before.
   int num_visits_;
 
-  // Keeps track of whether we have an ambiguous DOM in this report. This can
-  // happen when the HTML Elements returned by a renderer can't be
-  // associated with a parent Element in the parent frame.
-  bool ambiguous_dom_;
-
   // Whether this report should be trimmed down to only ad tags, not the entire
   // page contents. Used for sampling ads.
   bool trim_to_ad_tags_;
diff --git a/components/safe_browsing/renderer/threat_dom_details.cc b/components/safe_browsing/renderer/threat_dom_details.cc
index 4286530..b7d971f2 100644
--- a/components/safe_browsing/renderer/threat_dom_details.cc
+++ b/components/safe_browsing/renderer/threat_dom_details.cc
@@ -327,20 +327,16 @@
   ElementToNodeMap element_to_node_map;
   blink::WebElementCollection elements = document.All();
   blink::WebElement element = elements.FirstItem();
-  bool max_nodes_exceeded = false;
   for (; !element.IsNull(); element = elements.NextItem()) {
     if (ShouldHandleElement(element, tag_and_attributes_list_)) {
       HandleElement(element, tag_and_attributes_list_, details_node.get(),
                     resources, &element_to_node_map);
       if (resources->size() >= kMaxNodes) {
         // We have reached kMaxNodes, exit early.
-        max_nodes_exceeded = true;
         break;
       }
     }
   }
-  UMA_HISTOGRAM_BOOLEAN("SafeBrowsing.ThreatReport.MaxNodesExceededInFrame",
-                        max_nodes_exceeded);
   resources->push_back(std::move(details_node));
 }
 
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 7528377..c27531e 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -810,14 +810,10 @@
     "dom_storage/session_storage_namespace_impl_mojo.h",
     "dom_storage/storage_area_impl.cc",
     "dom_storage/storage_area_impl.h",
-    "download/byte_stream_input_stream.cc",
-    "download/byte_stream_input_stream.h",
     "download/download_item_utils.cc",
     "download/download_manager_impl.cc",
     "download/download_manager_impl.h",
     "download/download_request_utils.cc",
-    "download/download_utils.cc",
-    "download/download_utils.h",
     "download/drag_download_file.cc",
     "download/drag_download_file.h",
     "download/drag_download_util.cc",
diff --git a/content/browser/bad_message.h b/content/browser/bad_message.h
index f4df43c..2674c96 100644
--- a/content/browser/bad_message.h
+++ b/content/browser/bad_message.h
@@ -244,6 +244,7 @@
   RFH_NO_MATCHING_NAVIGATION_REQUEST_ON_COMMIT = 216,
   AUTH_INVALID_ICON_URL = 217,
   MDDH_INVALID_STREAM_SELECTION_INFO = 218,
+  REGISTER_PROTOCOL_HANDLER_INVALID_URL = 219,
 
   // Please add new elements here. The naming convention is abbreviated class
   // name (e.g. RenderFrameHost becomes RFH) plus a unique description of the
diff --git a/content/browser/devtools/protocol/devtools_protocol_browsertest.cc b/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
index e8ef21c..5935492 100644
--- a/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
+++ b/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
@@ -863,8 +863,10 @@
 
 IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest, InspectorTargetCrashedNavigate) {
   set_agent_host_can_close();
-  GURL url = GURL("data:text/html,<body></body>");
-  NavigateToURLBlockUntilNavigationsComplete(shell(), url, 1);
+  ASSERT_TRUE(embedded_test_server()->Start());
+  GURL url_a = embedded_test_server()->GetURL("a.com", "/title1.html");
+
+  NavigateToURLBlockUntilNavigationsComplete(shell(), url_a, 1);
   Attach();
   SendCommand("Inspector.enable", nullptr);
 
@@ -875,7 +877,32 @@
   }
 
   ClearNotifications();
-  shell()->LoadURL(url);
+  shell()->LoadURL(url_a);
+  WaitForNotification("Inspector.targetReloadedAfterCrash", true);
+}
+
+// Same as in DevToolsProtocolTest.InspectorTargetCrashedNavigate, but with a
+// cross-process navigation at the end.
+// Regression test for https://crbug.com/990315
+IN_PROC_BROWSER_TEST_F(DevToolsProtocolTest,
+                       InspectorTargetCrashedNavigateCrossProcess) {
+  set_agent_host_can_close();
+  ASSERT_TRUE(embedded_test_server()->Start());
+  GURL url_a = embedded_test_server()->GetURL("a.com", "/title1.html");
+  GURL url_b = embedded_test_server()->GetURL("b.com", "/title1.html");
+
+  NavigateToURLBlockUntilNavigationsComplete(shell(), url_a, 1);
+  Attach();
+  SendCommand("Inspector.enable", nullptr);
+
+  {
+    ScopedAllowRendererCrashes scoped_allow_renderer_crashes(shell());
+    shell()->LoadURL(GURL(content::kChromeUICrashURL));
+    WaitForNotification("Inspector.targetCrashed");
+  }
+
+  ClearNotifications();
+  shell()->LoadURL(url_b);
   WaitForNotification("Inspector.targetReloadedAfterCrash", true);
 }
 
diff --git a/content/browser/devtools/render_frame_devtools_agent_host.cc b/content/browser/devtools/render_frame_devtools_agent_host.cc
index 27f82a9..083269f9 100644
--- a/content/browser/devtools/render_frame_devtools_agent_host.cc
+++ b/content/browser/devtools/render_frame_devtools_agent_host.cc
@@ -484,10 +484,11 @@
 void RenderFrameDevToolsAgentHost::RenderFrameHostChanged(
     RenderFrameHost* old_host,
     RenderFrameHost* new_host) {
-  if (old_host != frame_host_)
+  auto* new_host_impl = static_cast<RenderFrameHostImpl*>(new_host);
+  FrameTreeNode* frame_tree_node = new_host_impl->frame_tree_node();
+  if (frame_tree_node != frame_tree_node_)
     return;
-
-  UpdateFrameHost(nullptr);
+  UpdateFrameHost(new_host_impl);
   // UpdateFrameHost may destruct |this|.
 }
 
diff --git a/content/browser/download/byte_stream_input_stream.cc b/content/browser/download/byte_stream_input_stream.cc
deleted file mode 100644
index 51c0298..0000000
--- a/content/browser/download/byte_stream_input_stream.cc
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/download/byte_stream_input_stream.h"
-
-#include "base/bind.h"
-#include "components/download/public/common/download_task_runner.h"
-#include "content/browser/byte_stream.h"
-
-namespace content {
-
-ByteStreamInputStream::ByteStreamInputStream(
-    std::unique_ptr<ByteStreamReader> stream_reader)
-    : stream_reader_(
-          stream_reader.release(),
-          base::OnTaskRunnerDeleter(download::GetDownloadTaskRunner())),
-      completion_status_(download::DOWNLOAD_INTERRUPT_REASON_NONE) {}
-
-ByteStreamInputStream::~ByteStreamInputStream() = default;
-
-bool ByteStreamInputStream::IsEmpty() {
-  return !stream_reader_;
-}
-
-void ByteStreamInputStream::RegisterDataReadyCallback(
-    const mojo::SimpleWatcher::ReadyCallback& callback) {
-  if (stream_reader_) {
-    stream_reader_->RegisterCallback(
-        base::BindRepeating(callback, MOJO_RESULT_OK));
-  }
-}
-
-void ByteStreamInputStream::ClearDataReadyCallback() {
-  if (stream_reader_)
-    stream_reader_->RegisterCallback(base::RepeatingClosure());
-}
-
-download::InputStream::StreamState ByteStreamInputStream::Read(
-    scoped_refptr<net::IOBuffer>* data,
-    size_t* length) {
-  if (!stream_reader_)
-    return download::InputStream::EMPTY;
-
-  ByteStreamReader::StreamState state = stream_reader_->Read(data, length);
-  switch (state) {
-    case ByteStreamReader::STREAM_EMPTY:
-      return download::InputStream::EMPTY;
-    case ByteStreamReader::STREAM_HAS_DATA:
-      return download::InputStream::HAS_DATA;
-    case ByteStreamReader::STREAM_COMPLETE:
-      completion_status_ = static_cast<download::DownloadInterruptReason>(
-          stream_reader_->GetStatus());
-      return download::InputStream::COMPLETE;
-  }
-  return download::InputStream::EMPTY;
-}
-
-download::DownloadInterruptReason ByteStreamInputStream::GetCompletionStatus() {
-  return completion_status_;
-}
-
-}  // namespace content
diff --git a/content/browser/download/byte_stream_input_stream.h b/content/browser/download/byte_stream_input_stream.h
deleted file mode 100644
index 3ec4cbc..0000000
--- a/content/browser/download/byte_stream_input_stream.h
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_BROWSER_DOWNLOAD_BYTE_STREAM_INPUT_STREAM_H_
-#define CONTENT_BROWSER_DOWNLOAD_BYTE_STREAM_INPUT_STREAM_H_
-
-#include "components/download/public/common/input_stream.h"
-#include "content/common/content_export.h"
-
-namespace content {
-
-class ByteStreamReader;
-
-// Download input stream backed by a ByteStreamReader.
-class CONTENT_EXPORT ByteStreamInputStream : public download::InputStream {
- public:
-  explicit ByteStreamInputStream(
-      std::unique_ptr<ByteStreamReader> stream_reader);
-  ~ByteStreamInputStream() override;
-
-  // download::InputStream
-  bool IsEmpty() override;
-  void RegisterDataReadyCallback(
-      const mojo::SimpleWatcher::ReadyCallback& callback) override;
-  void ClearDataReadyCallback() override;
-  download::InputStream::StreamState Read(scoped_refptr<net::IOBuffer>* data,
-                                          size_t* length) override;
-  download::DownloadInterruptReason GetCompletionStatus() override;
-
- private:
-  // ByteStreamReader to read from.
-  std::unique_ptr<ByteStreamReader, base::OnTaskRunnerDeleter> stream_reader_;
-
-  // Status when the response completes.
-  download::DownloadInterruptReason completion_status_;
-
-  DISALLOW_COPY_AND_ASSIGN(ByteStreamInputStream);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_BROWSER_DOWNLOAD_BYTE_STREAM_INPUT_STREAM_H_
diff --git a/content/browser/download/download_manager_impl.cc b/content/browser/download/download_manager_impl.cc
index 58d870d..cfaae06 100644
--- a/content/browser/download/download_manager_impl.cc
+++ b/content/browser/download/download_manager_impl.cc
@@ -36,14 +36,12 @@
 #include "components/download/public/common/download_url_loader_factory_getter_impl.h"
 #include "components/download/public/common/download_url_parameters.h"
 #include "components/download/public/common/download_utils.h"
+#include "components/download/public/common/input_stream.h"
 #include "components/download/public/common/url_download_handler_factory.h"
 #include "content/browser/blob_storage/chrome_blob_storage_context.h"
-#include "content/browser/byte_stream.h"
 #include "content/browser/child_process_security_policy_impl.h"
 #include "content/browser/data_url_loader_factory.h"
 #include "content/browser/devtools/devtools_instrumentation.h"
-#include "content/browser/download/byte_stream_input_stream.h"
-#include "content/browser/download/download_utils.h"
 #include "content/browser/download/file_download_url_loader_factory_getter.h"
 #include "content/browser/download/file_system_download_url_loader_factory_getter.h"
 #include "content/browser/download/network_download_url_loader_factory_getter.h"
@@ -138,14 +136,12 @@
           base::Time::Now(), base::WrapUnique(new download::DownloadSaveInfo)));
   failed_created_info->url_chain.push_back(params->url());
   failed_created_info->result = reason;
-  std::unique_ptr<ByteStreamReader> empty_byte_stream;
   base::PostTask(
       FROM_HERE, {BrowserThread::UI},
-      base::BindOnce(
-          &DownloadManager::StartDownload, download_manager,
-          std::move(failed_created_info),
-          std::make_unique<ByteStreamInputStream>(std::move(empty_byte_stream)),
-          nullptr, params->callback()));
+      base::BindOnce(&DownloadManager::StartDownload, download_manager,
+                     std::move(failed_created_info),
+                     std::make_unique<download::InputStream>(), nullptr,
+                     params->callback()));
 }
 
 class DownloadItemFactoryImpl : public download::DownloadItemFactory {
diff --git a/content/browser/download/download_manager_impl_unittest.cc b/content/browser/download/download_manager_impl_unittest.cc
index add7114..4a5f4fe 100644
--- a/content/browser/download/download_manager_impl_unittest.cc
+++ b/content/browser/download/download_manager_impl_unittest.cc
@@ -36,8 +36,7 @@
 #include "components/download/public/common/download_request_handle_interface.h"
 #include "components/download/public/common/mock_download_file.h"
 #include "components/download/public/common/mock_download_item_impl.h"
-#include "content/browser/byte_stream.h"
-#include "content/browser/download/byte_stream_input_stream.h"
+#include "components/download/public/common/mock_input_stream.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/download_manager_delegate.h"
 #include "content/public/browser/storage_partition.h"
@@ -66,7 +65,6 @@
 }
 
 namespace content {
-class ByteStreamReader;
 
 namespace {
 
@@ -356,14 +354,6 @@
   MOCK_METHOD2(SelectFileDialogDisplayed, void(DownloadManager*, int32_t));
 };
 
-class MockByteStreamReader : public ByteStreamReader {
- public:
-  ~MockByteStreamReader() override {}
-  MOCK_METHOD2(Read, StreamState(scoped_refptr<net::IOBuffer>*, size_t*));
-  MOCK_CONST_METHOD0(GetStatus, int());
-  MOCK_METHOD1(RegisterCallback, void(const base::Closure&));
-};
-
 class TestInProgressManager : public download::InProgressDownloadManager {
  public:
   TestInProgressManager();
@@ -570,7 +560,6 @@
 TEST_F(DownloadManagerTest, StartDownload) {
   std::unique_ptr<download::DownloadCreateInfo> info(
       new download::DownloadCreateInfo);
-  std::unique_ptr<ByteStreamReader> stream(new MockByteStreamReader);
   // Random value, a non 0 value means history db is properly loaded, and new
   // downloads should be persisted to the in-progress db.
   uint32_t local_id(5);
@@ -592,8 +581,8 @@
               ApplicationClientIdForFileScanning())
       .WillRepeatedly(Return("client-id"));
   download::MockDownloadFile* mock_file = new download::MockDownloadFile;
-  auto input_stream =
-      std::make_unique<ByteStreamInputStream>(std::move(stream));
+  auto input_stream = std::make_unique<download::MockInputStream>();
+  EXPECT_CALL(*input_stream, IsEmpty()).WillRepeatedly(Return(false));
   EXPECT_CALL(*mock_download_file_factory_.get(),
               MockCreateFile(Ref(*info->save_info.get()), input_stream.get()))
       .WillOnce(Return(mock_file));
@@ -610,7 +599,6 @@
 TEST_F(DownloadManagerTest, StartDownloadWithoutHistoryDB) {
   std::unique_ptr<download::DownloadCreateInfo> info(
       new download::DownloadCreateInfo);
-  std::unique_ptr<ByteStreamReader> stream(new MockByteStreamReader);
   base::FilePath download_path(FILE_PATH_LITERAL("download/path"));
   OnInProgressDownloadManagerInitialized();
   EXPECT_FALSE(download_manager_->GetDownload(1));
@@ -629,8 +617,8 @@
               ApplicationClientIdForFileScanning())
       .WillRepeatedly(Return("client-id"));
   download::MockDownloadFile* mock_file = new download::MockDownloadFile;
-  auto input_stream =
-      std::make_unique<ByteStreamInputStream>(std::move(stream));
+  auto input_stream = std::make_unique<download::MockInputStream>();
+  EXPECT_CALL(*input_stream, IsEmpty()).WillRepeatedly(Return(false));
   EXPECT_CALL(*mock_download_file_factory_.get(),
               MockCreateFile(Ref(*info->save_info.get()), input_stream.get()))
       .WillOnce(Return(mock_file));
diff --git a/content/browser/download/download_utils.cc b/content/browser/download/download_utils.cc
deleted file mode 100644
index 1d5fc46d..0000000
--- a/content/browser/download/download_utils.cc
+++ /dev/null
@@ -1,42 +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 "content/browser/download/download_utils.h"
-
-#include "base/format_macros.h"
-#include "base/process/process_handle.h"
-#include "base/single_thread_task_runner.h"
-#include "base/strings/stringprintf.h"
-#include "base/task/post_task.h"
-#include "components/download/database/in_progress/download_entry.h"
-#include "components/download/public/common/download_create_info.h"
-#include "components/download/public/common/download_interrupt_reasons_utils.h"
-#include "components/download/public/common/download_save_info.h"
-#include "components/download/public/common/download_url_parameters.h"
-#include "components/download/public/common/download_utils.h"
-#include "content/browser/blob_storage/chrome_blob_storage_context.h"
-#include "content/browser/resource_context_impl.h"
-#include "content/public/browser/browser_context.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/child_process_security_policy.h"
-#include "content/public/browser/download_manager_delegate.h"
-#include "content/public/browser/render_frame_host.h"
-#include "content/public/browser/render_process_host.h"
-#include "net/base/elements_upload_data_stream.h"
-#include "net/base/upload_bytes_element_reader.h"
-#include "net/http/http_request_headers.h"
-#include "net/url_request/url_request_context.h"
-#include "net/url_request/url_request_context_getter.h"
-
-namespace content {
-
-storage::BlobStorageContext* BlobStorageContextGetter(
-    ResourceContext* resource_context) {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  ChromeBlobStorageContext* blob_context =
-      GetChromeBlobStorageContextForResourceContext(resource_context);
-  return blob_context->context();
-}
-
-}  // namespace content
diff --git a/content/browser/download/download_utils.h b/content/browser/download/download_utils.h
deleted file mode 100644
index 2c9b103..0000000
--- a/content/browser/download/download_utils.h
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_BROWSER_DOWNLOAD_DOWNLOAD_UTILS_H_
-#define CONTENT_BROWSER_DOWNLOAD_DOWNLOAD_UTILS_H_
-
-#include <memory>
-
-#include "base/memory/ref_counted.h"
-#include "base/optional.h"
-#include "content/common/content_export.h"
-
-namespace storage {
-class BlobStorageContext;
-}
-
-namespace content {
-
-class ResourceContext;
-
-storage::BlobStorageContext* BlobStorageContextGetter(
-    ResourceContext* resource_context);
-
-}  // namespace content
-
-#endif  // CONTENT_BROWSER_DOWNLOAD_DOWNLOAD_UTILS_H_
diff --git a/content/browser/file_url_loader_factory.cc b/content/browser/file_url_loader_factory.cc
index 150b96a..2470df9 100644
--- a/content/browser/file_url_loader_factory.cc
+++ b/content/browser/file_url_loader_factory.cc
@@ -226,6 +226,7 @@
   }
 
   void OnConnectionError() {
+    lister_.reset();
     data_producer_.reset();
     binding_.Close();
     client_.reset();
diff --git a/content/browser/indexed_db/indexed_db_backing_store_unittest.cc b/content/browser/indexed_db/indexed_db_backing_store_unittest.cc
index 033fcfc..d07766b3 100644
--- a/content/browser/indexed_db/indexed_db_backing_store_unittest.cc
+++ b/content/browser/indexed_db/indexed_db_backing_store_unittest.cc
@@ -178,8 +178,7 @@
 
     idb_context_ = base::MakeRefCounted<IndexedDBContextImpl>(
         temp_dir_.GetPath(), special_storage_policy_, quota_manager_proxy_,
-        base::DefaultClock::GetInstance());
-    idb_context_->SetTaskRunnerForTesting(
+        base::DefaultClock::GetInstance(),
         base::SequencedTaskRunnerHandle::Get());
 
     CreateFactoryAndBackingStore();
@@ -260,6 +259,16 @@
     }
     if (temp_dir_.IsValid())
       ASSERT_TRUE(temp_dir_.Delete());
+
+    // Wait until the context has fully destroyed.
+    scoped_refptr<base::SequencedTaskRunner> task_runner =
+        idb_context_->TaskRunner();
+    idb_context_.reset();
+    {
+      base::RunLoop loop;
+      task_runner->PostTask(FROM_HERE, loop.QuitClosure());
+      loop.Run();
+    }
   }
 
   TestableIndexedDBBackingStore* backing_store() { return backing_store_; }
diff --git a/content/browser/indexed_db/indexed_db_context_impl.cc b/content/browser/indexed_db/indexed_db_context_impl.cc
index 0305f70..40af0a6 100644
--- a/content/browser/indexed_db/indexed_db_context_impl.cc
+++ b/content/browser/indexed_db/indexed_db_context_impl.cc
@@ -85,15 +85,21 @@
     const base::FilePath& data_path,
     scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy,
     scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy,
-    base::Clock* clock)
-    : force_keep_session_state_(false),
+    base::Clock* clock,
+    scoped_refptr<base::SequencedTaskRunner> custom_task_runner)
+    : IndexedDBContext(
+          custom_task_runner
+              ? custom_task_runner
+              : (base::CreateSequencedTaskRunner(
+                    {base::ThreadPool(), base::MayBlock(),
+                     base::WithBaseSyncPrimitives(),
+                     base::TaskPriority::USER_VISIBLE,
+                     // BLOCK_SHUTDOWN to support clearing session-only storage.
+                     base::TaskShutdownBehavior::BLOCK_SHUTDOWN}))),
+      force_keep_session_state_(false),
       special_storage_policy_(special_storage_policy),
       quota_manager_proxy_(quota_manager_proxy),
-      task_runner_(base::CreateSequencedTaskRunner(
-          {base::ThreadPool(), base::MayBlock(), base::WithBaseSyncPrimitives(),
-           base::TaskPriority::USER_VISIBLE,
-           // BLOCK_SHUTDOWN to support clearing session-only storage.
-           base::TaskShutdownBehavior::BLOCK_SHUTDOWN})),
+      task_runner_(owning_task_runner()),
       clock_(clock) {
   IDB_TRACE("init");
   if (!data_path.empty())
@@ -435,11 +441,6 @@
   return GetLevelDBPath(origin);
 }
 
-void IndexedDBContextImpl::SetTaskRunnerForTesting(
-    scoped_refptr<base::SequencedTaskRunner> task_runner) {
-  task_runner_ = std::move(task_runner);
-}
-
 void IndexedDBContextImpl::ResetCachesForTesting() {
   origin_set_.reset();
   origin_size_map_.clear();
@@ -532,11 +533,9 @@
 }
 
 IndexedDBContextImpl::~IndexedDBContextImpl() {
-  if (indexeddb_factory_.get()) {
-    TaskRunner()->PostTask(FROM_HERE,
-                           base::BindOnce(&IndexedDBFactory::ContextDestroyed,
-                                          std::move(indexeddb_factory_)));
-  }
+  DCHECK(TaskRunner()->RunsTasksInCurrentSequence());
+  if (indexeddb_factory_.get())
+    indexeddb_factory_->ContextDestroyed();
 }
 
 void IndexedDBContextImpl::Shutdown() {
diff --git a/content/browser/indexed_db/indexed_db_context_impl.h b/content/browser/indexed_db/indexed_db_context_impl.h
index 001d7f7..e4b5c4e 100644
--- a/content/browser/indexed_db/indexed_db_context_impl.h
+++ b/content/browser/indexed_db/indexed_db_context_impl.h
@@ -73,11 +73,13 @@
   static const base::FilePath::CharType kIndexedDBDirectory[];
 
   // If |data_path| is empty, nothing will be saved to disk.
+  // |task_runner| is optional, and only set during testing.
   IndexedDBContextImpl(
       const base::FilePath& data_path,
       scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy,
       scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy,
-      base::Clock* clock);
+      base::Clock* clock,
+      scoped_refptr<base::SequencedTaskRunner> custom_task_runner);
 
   IndexedDBFactoryImpl* GetIDBFactory();
 
@@ -134,10 +136,6 @@
   size_t GetConnectionCount(const url::Origin& origin);
   int GetOriginBlobFileCount(const url::Origin& origin);
 
-  // TODO(jsbell): Update tests to eliminate the need for this.
-  void SetTaskRunnerForTesting(
-      scoped_refptr<base::SequencedTaskRunner> task_runner);
-
   // For unit tests allow to override the |data_path_|.
   void set_data_path_for_testing(const base::FilePath& data_path) {
     data_path_ = data_path;
diff --git a/content/browser/indexed_db/indexed_db_dispatcher_host_unittest.cc b/content/browser/indexed_db/indexed_db_dispatcher_host_unittest.cc
index 6542d66e..c4dd860a 100644
--- a/content/browser/indexed_db/indexed_db_dispatcher_host_unittest.cc
+++ b/content/browser/indexed_db/indexed_db_dispatcher_host_unittest.cc
@@ -190,7 +190,8 @@
             CreateAndReturnTempDir(&temp_dir_),
             special_storage_policy_,
             quota_manager_->proxy(),
-            base::DefaultClock::GetInstance())),
+            base::DefaultClock::GetInstance(),
+            nullptr)),
         host_(new IndexedDBDispatcherHost(
                   kFakeProcessId,
                   context_impl_,
diff --git a/content/browser/indexed_db/indexed_db_factory_unittest.cc b/content/browser/indexed_db/indexed_db_factory_unittest.cc
index e8159858..615dba4 100644
--- a/content/browser/indexed_db/indexed_db_factory_unittest.cc
+++ b/content/browser/indexed_db/indexed_db_factory_unittest.cc
@@ -112,25 +112,25 @@
     context_ = base::MakeRefCounted<IndexedDBContextImpl>(
         CreateAndReturnTempDir(&temp_dir_),
         /*special_storage_policy=*/nullptr, quota_manager_proxy_.get(),
-        base::DefaultClock::GetInstance());
-    context_->SetTaskRunnerForTesting(base::SequencedTaskRunnerHandle::Get());
+        base::DefaultClock::GetInstance(),
+        base::SequencedTaskRunnerHandle::Get());
   }
 
   void SetupInMemoryContext() {
     context_ = base::MakeRefCounted<IndexedDBContextImpl>(
         base::FilePath(),
         /*special_storage_policy=*/nullptr, quota_manager_proxy_.get(),
-        base::DefaultClock::GetInstance());
-    context_->SetTaskRunnerForTesting(base::SequencedTaskRunnerHandle::Get());
+        base::DefaultClock::GetInstance(),
+        base::SequencedTaskRunnerHandle::Get());
   }
 
   void SetupContextWithFactories(indexed_db::LevelDBFactory* factory,
                                  base::Clock* clock) {
     context_ = base::MakeRefCounted<IndexedDBContextImpl>(
         CreateAndReturnTempDir(&temp_dir_),
-        /*special_storage_policy=*/nullptr, quota_manager_proxy_.get(), clock);
+        /*special_storage_policy=*/nullptr, quota_manager_proxy_.get(), clock,
+        base::SequencedTaskRunnerHandle::Get());
     context_->SetLevelDBFactoryForTesting(factory);
-    context_->SetTaskRunnerForTesting(base::SequencedTaskRunnerHandle::Get());
   }
 
   // Runs through the upgrade flow to create a basic database connection. There
diff --git a/content/browser/indexed_db/indexed_db_quota_client_unittest.cc b/content/browser/indexed_db/indexed_db_quota_client_unittest.cc
index d329731..b9c452b 100644
--- a/content/browser/indexed_db/indexed_db_quota_client_unittest.cc
+++ b/content/browser/indexed_db/indexed_db_quota_client_unittest.cc
@@ -57,7 +57,8 @@
     idb_context_ = new IndexedDBContextImpl(
         browser_context_->GetPath(),
         browser_context_->GetSpecialStoragePolicy(), quota_manager->proxy(),
-        base::DefaultClock::GetInstance());
+        base::DefaultClock::GetInstance(),
+        base::SequencedTaskRunnerHandle::Get());
     base::RunLoop().RunUntilIdle();
     setup_temp_dir();
   }
diff --git a/content/browser/indexed_db/indexed_db_unittest.cc b/content/browser/indexed_db/indexed_db_unittest.cc
index ae047b4..f90ccc9 100644
--- a/content/browser/indexed_db/indexed_db_unittest.cc
+++ b/content/browser/indexed_db/indexed_db_unittest.cc
@@ -90,7 +90,8 @@
             CreateAndReturnTempDir(&temp_dir_),
             /*special_storage_policy=*/special_storage_policy_.get(),
             quota_manager_proxy_.get(),
-            base::DefaultClock::GetInstance())) {
+            base::DefaultClock::GetInstance(),
+            base::SequencedTaskRunnerHandle::Get())) {
     special_storage_policy_->AddSessionOnly(kSessionOnlyOrigin.GetURL());
   }
   ~IndexedDBTest() override {
diff --git a/content/browser/storage_partition_impl.cc b/content/browser/storage_partition_impl.cc
index 435ff14..f5bf993 100644
--- a/content/browser/storage_partition_impl.cc
+++ b/content/browser/storage_partition_impl.cc
@@ -837,7 +837,7 @@
   base::FilePath path = in_memory ? base::FilePath() : partition_path;
   partition->indexed_db_context_ = new IndexedDBContextImpl(
       path, context->GetSpecialStoragePolicy(), quota_manager_proxy,
-      base::DefaultClock::GetInstance());
+      base::DefaultClock::GetInstance(), /*task_runner=*/nullptr);
 
   partition->cache_storage_context_ = new CacheStorageContextImpl(context);
   partition->cache_storage_context_->Init(
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 6eb306c8..5d0e901 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -282,6 +282,24 @@
   return a->frame_tree_node()->depth() < b->frame_tree_node()->depth();
 }
 
+bool AreValidRegisterProtocolHandlerArguments(const std::string& protocol,
+                                              const GURL& url,
+                                              const url::Origin& origin) {
+  ChildProcessSecurityPolicyImpl* policy =
+      ChildProcessSecurityPolicyImpl::GetInstance();
+  if (policy->IsPseudoScheme(protocol))
+    return false;
+
+  url::Origin url_origin = url::Origin::Create(url);
+  if (url_origin.opaque())
+    return false;
+
+  if (!url_origin.IsSameOriginWith(origin))
+    return false;
+
+  return true;
+}
+
 }  // namespace
 
 std::unique_ptr<WebContents> WebContents::Create(
@@ -4846,10 +4864,12 @@
   if (!delegate_)
     return;
 
-  ChildProcessSecurityPolicyImpl* policy =
-      ChildProcessSecurityPolicyImpl::GetInstance();
-  if (policy->IsPseudoScheme(protocol))
+  if (!AreValidRegisterProtocolHandlerArguments(
+          protocol, url, source->GetLastCommittedOrigin())) {
+    ReceivedBadMessage(source->GetProcess(),
+                       bad_message::REGISTER_PROTOCOL_HANDLER_INVALID_URL);
     return;
+  }
 
   delegate_->RegisterProtocolHandler(this, protocol, url, user_gesture);
 }
@@ -4863,10 +4883,12 @@
   if (!delegate_)
     return;
 
-  ChildProcessSecurityPolicyImpl* policy =
-      ChildProcessSecurityPolicyImpl::GetInstance();
-  if (policy->IsPseudoScheme(protocol))
+  if (!AreValidRegisterProtocolHandlerArguments(
+          protocol, url, source->GetLastCommittedOrigin())) {
+    ReceivedBadMessage(source->GetProcess(),
+                       bad_message::REGISTER_PROTOCOL_HANDLER_INVALID_URL);
     return;
+  }
 
   delegate_->UnregisterProtocolHandler(this, protocol, url, user_gesture);
 }
diff --git a/content/browser/web_contents/web_contents_impl_unittest.cc b/content/browser/web_contents/web_contents_impl_unittest.cc
index f1bcb7f..2e17c2c9 100644
--- a/content/browser/web_contents/web_contents_impl_unittest.cc
+++ b/content/browser/web_contents/web_contents_impl_unittest.cc
@@ -3384,6 +3384,8 @@
  public:
   MOCK_METHOD2(HandleContextMenu,
                bool(RenderFrameHost*, const ContextMenuParams&));
+  MOCK_METHOD4(RegisterProtocolHandler,
+               void(WebContents*, const std::string&, const GURL&, bool));
 };
 
 }  // namespace
@@ -3402,4 +3404,61 @@
   contents()->SetDelegate(nullptr);
 }
 
+TEST_F(WebContentsImplTest, RegisterProtocolHandlerDifferentOrigin) {
+  MockWebContentsDelegate delegate;
+  contents()->SetDelegate(&delegate);
+
+  GURL url("https://www.google.com");
+  GURL handler_url1("https://www.google.com/handler/%s");
+  GURL handler_url2("https://www.example.com/handler/%s");
+
+  contents()->NavigateAndCommit(url);
+
+  // Only the first call to RegisterProtocolHandler should register because the
+  // other call has a handler from a different origin.
+  EXPECT_CALL(delegate,
+              RegisterProtocolHandler(contents(), "mailto", handler_url1, true))
+      .Times(1);
+
+  {
+    FrameHostMsg_RegisterProtocolHandler message(
+        main_test_rfh()->GetRoutingID(), "mailto", handler_url1,
+        base::string16(), /*user_gesture=*/true);
+    contents()->OnMessageReceived(main_test_rfh(), message);
+  }
+
+  {
+    FrameHostMsg_RegisterProtocolHandler message(
+        main_test_rfh()->GetRoutingID(), "mailto", handler_url2,
+        base::string16(), /*user_gesture=*/true);
+    contents()->OnMessageReceived(main_test_rfh(), message);
+  }
+
+  contents()->SetDelegate(nullptr);
+}
+
+TEST_F(WebContentsImplTest, RegisterProtocolHandlerDataURL) {
+  MockWebContentsDelegate delegate;
+  contents()->SetDelegate(&delegate);
+
+  GURL data("data:text/html,<html><body><b>hello world</b></body></html>");
+  GURL data_handler(data.spec() + "%s");
+
+  contents()->NavigateAndCommit(data);
+
+  // Data URLs should fail.
+  EXPECT_CALL(delegate,
+              RegisterProtocolHandler(contents(), "mailto", data_handler, true))
+      .Times(0);
+
+  {
+    FrameHostMsg_RegisterProtocolHandler message(
+        main_test_rfh()->GetRoutingID(), "mailto", data_handler,
+        base::string16(), /*user_gesture=*/true);
+    contents()->OnMessageReceived(main_test_rfh(), message);
+  }
+
+  contents()->SetDelegate(nullptr);
+}
+
 }  // namespace content
diff --git a/content/browser/web_package/bundled_exchanges_reader.cc b/content/browser/web_package/bundled_exchanges_reader.cc
index 3089625..3c0d18f 100644
--- a/content/browser/web_package/bundled_exchanges_reader.cc
+++ b/content/browser/web_package/bundled_exchanges_reader.cc
@@ -215,10 +215,13 @@
                                                   base::File file) {
   base::File::Error error = parser_.OpenFile(std::move(file));
   if (base::File::FILE_OK != error) {
-    PostTask(FROM_HERE,
-             base::BindOnce(std::move(callback),
-                            data_decoder::mojom::BundleMetadataParseError::New(
-                                base::File::ErrorToString(error))));
+    PostTask(
+        FROM_HERE,
+        base::BindOnce(
+            std::move(callback),
+            data_decoder::mojom::BundleMetadataParseError::New(
+                data_decoder::mojom::BundleParseErrorType::kParserInternalError,
+                GURL() /* fallback_url */, base::File::ErrorToString(error))));
   } else {
     parser_.ParseMetadata(
         base::BindOnce(&BundledExchangesReader::OnMetadataParsed,
diff --git a/content/browser/web_package/bundled_exchanges_reader_unittest.cc b/content/browser/web_package/bundled_exchanges_reader_unittest.cc
index d01ba71..efb1af4a 100644
--- a/content/browser/web_package/bundled_exchanges_reader_unittest.cc
+++ b/content/browser/web_package/bundled_exchanges_reader_unittest.cc
@@ -163,7 +163,9 @@
     items.push_back(std::move(item));
 
     data_decoder::mojom::BundleMetadataPtr metadata =
-        data_decoder::mojom::BundleMetadata::New(std::move(items), GURL());
+        data_decoder::mojom::BundleMetadata::New(GURL() /* primary_url */,
+                                                 std::move(items),
+                                                 GURL() /* manifest_url */);
     factory_->RunMetadataCallback(std::move(metadata));
     run_loop.Run();
   }
diff --git a/content/browser/websockets/websocket_connector_impl.cc b/content/browser/websockets/websocket_connector_impl.cc
index 875b6ee..02a03fc5 100644
--- a/content/browser/websockets/websocket_connector_impl.cc
+++ b/content/browser/websockets/websocket_connector_impl.cc
@@ -25,8 +25,7 @@
     const std::vector<std::string>& requested_protocols,
     const GURL& site_for_cookies,
     const base::Optional<std::string>& user_agent,
-    network::mojom::WebSocketHandshakeClientPtr handshake_client,
-    network::mojom::WebSocketClientPtr websocket_client) {
+    network::mojom::WebSocketHandshakeClientPtr handshake_client) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   RenderProcessHost* process = RenderProcessHost::FromID(process_id_);
   if (!process) {
@@ -41,7 +40,7 @@
         frame,
         base::BindOnce(ConnectCalledByContentBrowserClient, requested_protocols,
                        site_for_cookies, process_id_, frame_id_, origin_,
-                       options, std::move(websocket_client)),
+                       options),
         url, site_for_cookies, user_agent, std::move(handshake_client));
     return;
   }
@@ -53,7 +52,7 @@
   process->GetStoragePartition()->GetNetworkContext()->CreateWebSocket(
       url, requested_protocols, site_for_cookies, std::move(headers),
       process_id_, frame_id_, origin_, options, std::move(handshake_client),
-      std::move(websocket_client), nullptr, nullptr);
+      nullptr, nullptr);
 }
 
 void WebSocketConnectorImpl::ConnectCalledByContentBrowserClient(
@@ -63,7 +62,6 @@
     int frame_id,
     const url::Origin& origin,
     uint32_t options,
-    network::mojom::WebSocketClientPtr websocket_client,
     const GURL& url,
     std::vector<network::mojom::HttpHeaderPtr> additional_headers,
     network::mojom::WebSocketHandshakeClientPtr handshake_client,
@@ -77,7 +75,6 @@
   process->GetStoragePartition()->GetNetworkContext()->CreateWebSocket(
       url, requested_protocols, site_for_cookies, std::move(additional_headers),
       process_id, frame_id, origin, options, std::move(handshake_client),
-      std::move(websocket_client), std::move(auth_handler),
-      std::move(trusted_header_client));
+      std::move(auth_handler), std::move(trusted_header_client));
 }
 }  // namespace content
diff --git a/content/browser/websockets/websocket_connector_impl.h b/content/browser/websockets/websocket_connector_impl.h
index e57b4c30..2c60d1fd 100644
--- a/content/browser/websockets/websocket_connector_impl.h
+++ b/content/browser/websockets/websocket_connector_impl.h
@@ -34,12 +34,12 @@
   ~WebSocketConnectorImpl() override;
 
   // WebSocketConnector implementation
-  void Connect(const GURL& url,
-               const std::vector<std::string>& requested_protocols,
-               const GURL& site_for_cookies,
-               const base::Optional<std::string>& user_agent,
-               network::mojom::WebSocketHandshakeClientPtr handshake_client,
-               network::mojom::WebSocketClientPtr websocket_client) override;
+  void Connect(
+      const GURL& url,
+      const std::vector<std::string>& requested_protocols,
+      const GURL& site_for_cookies,
+      const base::Optional<std::string>& user_agent,
+      network::mojom::WebSocketHandshakeClientPtr handshake_client) override;
 
  private:
   static void ConnectCalledByContentBrowserClient(
@@ -49,7 +49,6 @@
       int frame_id,
       const url::Origin& origin,
       uint32_t options,
-      network::mojom::WebSocketClientPtr websocket_client,
       const GURL& url,
       std::vector<network::mojom::HttpHeaderPtr> additional_headers,
       network::mojom::WebSocketHandshakeClientPtr handshake_client,
diff --git a/content/browser/worker_host/shared_worker_host_unittest.cc b/content/browser/worker_host/shared_worker_host_unittest.cc
index f119850..1821588 100644
--- a/content/browser/worker_host/shared_worker_host_unittest.cc
+++ b/content/browser/worker_host/shared_worker_host_unittest.cc
@@ -59,8 +59,8 @@
     std::string content_security_policy;
     blink::mojom::ContentSecurityPolicyType content_security_policy_type =
         blink::mojom::ContentSecurityPolicyType::kReport;
-    blink::mojom::IPAddressSpace creation_address_space =
-        blink::mojom::IPAddressSpace::kPublic;
+    network::mojom::IPAddressSpace creation_address_space =
+        network::mojom::IPAddressSpace::kPublic;
     blink::mojom::SharedWorkerCreationContextType creation_context_type =
         blink::mojom::SharedWorkerCreationContextType::kSecure;
 
diff --git a/content/browser/worker_host/shared_worker_instance.cc b/content/browser/worker_host/shared_worker_instance.cc
index 49a2e26..6c9321a 100644
--- a/content/browser/worker_host/shared_worker_instance.cc
+++ b/content/browser/worker_host/shared_worker_instance.cc
@@ -14,7 +14,7 @@
     const url::Origin& constructor_origin,
     const std::string& content_security_policy,
     blink::mojom::ContentSecurityPolicyType security_policy_type,
-    blink::mojom::IPAddressSpace creation_address_space,
+    network::mojom::IPAddressSpace creation_address_space,
     blink::mojom::SharedWorkerCreationContextType creation_context_type)
     : url_(url),
       name_(name),
diff --git a/content/browser/worker_host/shared_worker_instance.h b/content/browser/worker_host/shared_worker_instance.h
index 1930f44..c7a7305 100644
--- a/content/browser/worker_host/shared_worker_instance.h
+++ b/content/browser/worker_host/shared_worker_instance.h
@@ -8,8 +8,8 @@
 #include <string>
 
 #include "content/common/content_export.h"
+#include "services/network/public/mojom/ip_address_space.mojom.h"
 #include "third_party/blink/public/mojom/csp/content_security_policy.mojom.h"
-#include "third_party/blink/public/mojom/net/ip_address_space.mojom.h"
 #include "third_party/blink/public/mojom/worker/shared_worker_creation_context_type.mojom.h"
 #include "url/gurl.h"
 #include "url/origin.h"
@@ -26,7 +26,7 @@
       const url::Origin& constructor_origin,
       const std::string& content_security_policy,
       blink::mojom::ContentSecurityPolicyType content_security_policy_type,
-      blink::mojom::IPAddressSpace creation_address_space,
+      network::mojom::IPAddressSpace creation_address_space,
       blink::mojom::SharedWorkerCreationContextType creation_context_type);
   SharedWorkerInstance(const SharedWorkerInstance& other);
   ~SharedWorkerInstance();
@@ -50,7 +50,7 @@
   blink::mojom::ContentSecurityPolicyType content_security_policy_type() const {
     return content_security_policy_type_;
   }
-  blink::mojom::IPAddressSpace creation_address_space() const {
+  network::mojom::IPAddressSpace creation_address_space() const {
     return creation_address_space_;
   }
   blink::mojom::SharedWorkerCreationContextType creation_context_type() const {
@@ -68,7 +68,7 @@
 
   const std::string content_security_policy_;
   const blink::mojom::ContentSecurityPolicyType content_security_policy_type_;
-  const blink::mojom::IPAddressSpace creation_address_space_;
+  const network::mojom::IPAddressSpace creation_address_space_;
   const blink::mojom::SharedWorkerCreationContextType creation_context_type_;
 };
 
diff --git a/content/browser/worker_host/shared_worker_instance_unittest.cc b/content/browser/worker_host/shared_worker_instance_unittest.cc
index 1415b7c..657cb8b 100644
--- a/content/browser/worker_host/shared_worker_instance_unittest.cc
+++ b/content/browser/worker_host/shared_worker_instance_unittest.cc
@@ -23,7 +23,7 @@
     return SharedWorkerInstance(
         script_url, name, constructor_origin, std::string(),
         blink::mojom::ContentSecurityPolicyType::kReport,
-        blink::mojom::IPAddressSpace::kPublic,
+        network::mojom::IPAddressSpace::kPublic,
         blink::mojom::SharedWorkerCreationContextType::kNonsecure);
   }
 
@@ -262,10 +262,10 @@
 }
 
 TEST_F(SharedWorkerInstanceTest, AddressSpace) {
-  const blink::mojom::IPAddressSpace kAddressSpaces[] = {
-      blink::mojom::IPAddressSpace::kLocal,
-      blink::mojom::IPAddressSpace::kPrivate,
-      blink::mojom::IPAddressSpace::kPublic};
+  const network::mojom::IPAddressSpace kAddressSpaces[] = {
+      network::mojom::IPAddressSpace::kLocal,
+      network::mojom::IPAddressSpace::kPrivate,
+      network::mojom::IPAddressSpace::kPublic};
   for (auto address_space : kAddressSpaces) {
     SharedWorkerInstance instance(
         GURL("http://example.com/w.js"), "name",
diff --git a/content/browser/worker_host/shared_worker_service_impl_unittest.cc b/content/browser/worker_host/shared_worker_service_impl_unittest.cc
index 44eea2c..403123fc9 100644
--- a/content/browser/worker_host/shared_worker_service_impl_unittest.cc
+++ b/content/browser/worker_host/shared_worker_service_impl_unittest.cc
@@ -49,7 +49,7 @@
   blink::mojom::SharedWorkerInfoPtr info(blink::mojom::SharedWorkerInfo::New(
       url, name, std::string(),
       blink::mojom::ContentSecurityPolicyType::kReport,
-      blink::mojom::IPAddressSpace::kPublic));
+      network::mojom::IPAddressSpace::kPublic));
 
   mojo::MessagePipe message_pipe;
   *local_port = MessagePortChannel(std::move(message_pipe.handle0));
diff --git a/content/child/blink_platform_impl.cc b/content/child/blink_platform_impl.cc
index bd81bb3..d1f825ac 100644
--- a/content/child/blink_platform_impl.cc
+++ b/content/child/blink_platform_impl.cc
@@ -482,30 +482,6 @@
      ui::SCALE_FACTOR_NONE, true},
     {"DocumentXMLTreeViewer.js", IDR_DOCUMENTXMLTREEVIEWER_JS,
      ui::SCALE_FACTOR_NONE, true},
-#ifdef IDR_PICKER_COMMON_JS
-    {"pickerCommon.js", IDR_PICKER_COMMON_JS, ui::SCALE_FACTOR_NONE, true},
-    {"pickerCommon.css", IDR_PICKER_COMMON_CSS, ui::SCALE_FACTOR_NONE, true},
-    {"calendarPicker.js", IDR_CALENDAR_PICKER_JS, ui::SCALE_FACTOR_NONE, true},
-    {"calendarPicker.css", IDR_CALENDAR_PICKER_CSS, ui::SCALE_FACTOR_NONE,
-     true},
-    {"calendar_picker_refresh.css", IDR_CALENDAR_PICKER_REFRESH_CSS,
-     ui::SCALE_FACTOR_NONE, true},
-    {"listPicker.js", IDR_LIST_PICKER_JS, ui::SCALE_FACTOR_NONE, true},
-    {"listPicker.css", IDR_LIST_PICKER_CSS, ui::SCALE_FACTOR_NONE, true},
-    {"pickerButton.css", IDR_PICKER_BUTTON_CSS, ui::SCALE_FACTOR_NONE, true},
-    {"suggestionPicker.js", IDR_SUGGESTION_PICKER_JS, ui::SCALE_FACTOR_NONE,
-     true},
-    {"suggestionPicker.css", IDR_SUGGESTION_PICKER_CSS, ui::SCALE_FACTOR_NONE,
-     true},
-    {"color_picker_common.js", IDR_COLOR_PICKER_COMMON_JS,
-     ui::SCALE_FACTOR_NONE, true},
-    {"colorSuggestionPicker.js", IDR_COLOR_SUGGESTION_PICKER_JS,
-     ui::SCALE_FACTOR_NONE, true},
-    {"colorSuggestionPicker.css", IDR_COLOR_SUGGESTION_PICKER_CSS,
-     ui::SCALE_FACTOR_NONE, true},
-    {"color_picker.js", IDR_COLOR_PICKER_JS, ui::SCALE_FACTOR_NONE, true},
-    {"color_picker.css", IDR_COLOR_PICKER_CSS, ui::SCALE_FACTOR_NONE, true},
-#endif
     {"input_alert.svg", IDR_VALIDATION_BUBBLE_ICON, ui::SCALE_FACTOR_NONE,
      true},
     {"validation_bubble.css", IDR_VALIDATION_BUBBLE_CSS, ui::SCALE_FACTOR_NONE,
diff --git a/content/public/app/content_browser_manifest.cc b/content/public/app/content_browser_manifest.cc
index f57ec8f..955d38e 100644
--- a/content/public/app/content_browser_manifest.cc
+++ b/content/public/app/content_browser_manifest.cc
@@ -261,6 +261,7 @@
                   "device.mojom.VibrationManager",
                   "device.mojom.VRService",
                   "discardable_memory.mojom.DiscardableSharedMemoryManager",
+                  "media.mojom.FuchsiaCdmProvider",
                   "media.mojom.ImageCapture",
                   "media.mojom.InterfaceFactory",
                   "media.mojom.MediaMetricsProvider",
diff --git a/content/public/browser/indexed_db_context.h b/content/public/browser/indexed_db_context.h
index 9a271d1f..98f70bf 100644
--- a/content/public/browser/indexed_db_context.h
+++ b/content/public/browser/indexed_db_context.h
@@ -11,7 +11,7 @@
 #include <vector>
 
 #include "base/files/file_path.h"
-#include "base/memory/ref_counted.h"
+#include "base/memory/ref_counted_delete_on_sequence.h"
 #include "content/common/content_export.h"
 
 namespace base {
@@ -30,7 +30,8 @@
 // Call these methods only via the exposed TaskRunner.
 // Refcounted because this class is used throughout the codebase on different
 // threads.
-class IndexedDBContext : public base::RefCountedThreadSafe<IndexedDBContext> {
+class IndexedDBContext
+    : public base::RefCountedDeleteOnSequence<IndexedDBContext> {
  public:
   // Only call the below methods by posting to this TaskRunner.
   virtual base::SequencedTaskRunner* TaskRunner() = 0;
@@ -56,7 +57,13 @@
   virtual void SetForceKeepSessionState() = 0;
 
  protected:
-  friend class base::RefCountedThreadSafe<IndexedDBContext>;
+  friend class base::RefCountedDeleteOnSequence<IndexedDBContext>;
+  friend class base::DeleteHelper<IndexedDBContext>;
+
+  IndexedDBContext(scoped_refptr<base::SequencedTaskRunner> owning_task_runner)
+      : base::RefCountedDeleteOnSequence<IndexedDBContext>(
+            std::move(owning_task_runner)) {}
+
   virtual ~IndexedDBContext() {}
 };
 
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn
index 491992f..45daafa 100644
--- a/content/renderer/BUILD.gn
+++ b/content/renderer/BUILD.gn
@@ -620,6 +620,8 @@
       "render_view_fuchsia.cc",
       "renderer_main_platform_delegate_fuchsia.cc",
     ]
+
+    deps += [ "//media/fuchsia/cdm" ]
   }
 
   if (enable_media_remoting) {
diff --git a/content/renderer/loader/web_url_loader_impl.cc b/content/renderer/loader/web_url_loader_impl.cc
index 73959d75..8f2ebbd 100644
--- a/content/renderer/loader/web_url_loader_impl.cc
+++ b/content/renderer/loader/web_url_loader_impl.cc
@@ -348,29 +348,16 @@
     base::WeakPtr<ResourceDispatcher> resource_dispatcher,
     scoped_refptr<network::SharedURLLoaderFactory> loader_factory)
     : resource_dispatcher_(std::move(resource_dispatcher)),
-      loader_factory_(std::move(loader_factory)) {}
+      loader_factory_(std::move(loader_factory)) {
+  DCHECK(resource_dispatcher_);
+  DCHECK(loader_factory_);
+}
 
 WebURLLoaderFactoryImpl::~WebURLLoaderFactoryImpl() = default;
 
 std::unique_ptr<blink::WebURLLoader> WebURLLoaderFactoryImpl::CreateURLLoader(
     const blink::WebURLRequest& request,
     std::unique_ptr<WebResourceLoadingTaskRunnerHandle> task_runner_handle) {
-  if (!loader_factory_) {
-    // In some tests like RenderViewTests loader_factory_ is not available.
-    // These tests can still use data URLs to bypass the ResourceDispatcher.
-    if (!task_runner_handle) {
-      // TODO(altimin): base::ThreadTaskRunnerHandle::Get is deprecated in
-      // the renderer. Fix this for frame and non-frame clients.
-      task_runner_handle =
-          WebResourceLoadingTaskRunnerHandle::CreateUnprioritized(
-              base::ThreadTaskRunnerHandle::Get());
-    }
-
-    return std::make_unique<WebURLLoaderImpl>(resource_dispatcher_.get(),
-                                              std::move(task_runner_handle),
-                                              nullptr /* factory */);
-  }
-
   DCHECK(task_runner_handle);
   DCHECK(resource_dispatcher_);
   return std::make_unique<WebURLLoaderImpl>(resource_dispatcher_.get(),
@@ -583,14 +570,14 @@
       defers_loading_(NOT_DEFERRING),
       request_id_(-1),
       url_loader_factory_(std::move(url_loader_factory)) {
-  DCHECK(url_loader_factory_ || !resource_dispatcher);
+  DCHECK(resource_dispatcher_);
+  DCHECK(url_loader_factory_);
 }
 
 void WebURLLoaderImpl::Context::Cancel() {
   TRACE_EVENT_WITH_FLOW0("loading", "WebURLLoaderImpl::Context::Cancel", this,
                          TRACE_EVENT_FLAG_FLOW_IN);
-  if (resource_dispatcher_ && // NULL in unittest.
-      request_id_ != -1) {
+  if (request_id_ != -1) {
     resource_dispatcher_->Cancel(request_id_, task_runner_);
     request_id_ = -1;
   }
diff --git a/content/renderer/media/media_factory.cc b/content/renderer/media/media_factory.cc
index bc044e9..615b3b7 100644
--- a/content/renderer/media/media_factory.cc
+++ b/content/renderer/media/media_factory.cc
@@ -65,7 +65,7 @@
 #endif
 
 #if defined(OS_FUCHSIA)
-#include "media/cdm/fuchsia/fuchsia_cdm_factory.h"
+#include "media/fuchsia/cdm/fuchsia_cdm_factory.h"
 #elif BUILDFLAG(ENABLE_MOJO_CDM)
 #include "media/mojo/clients/mojo_cdm_factory.h"  // nogncheck
 #else
@@ -610,7 +610,7 @@
     return cdm_factory_.get();
 
 #if defined(OS_FUCHSIA)
-  cdm_factory_ = std::make_unique<media::FuchsiaCdmFactory>();
+  cdm_factory_ = std::make_unique<media::FuchsiaCdmFactory>(remote_interfaces_);
 #elif BUILDFLAG(ENABLE_MOJO_CDM)
   cdm_factory_ =
       std::make_unique<media::MojoCdmFactory>(GetMediaInterfaceFactory());
diff --git a/content/renderer/media/stream/mock_mojo_media_stream_dispatcher_host.cc b/content/renderer/media/stream/mock_mojo_media_stream_dispatcher_host.cc
deleted file mode 100644
index b28f661..0000000
--- a/content/renderer/media/stream/mock_mojo_media_stream_dispatcher_host.cc
+++ /dev/null
@@ -1,106 +0,0 @@
-// Copyright (c) 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 "content/renderer/media/stream/mock_mojo_media_stream_dispatcher_host.h"
-
-#include "base/strings/string_number_conversions.h"
-#include "third_party/blink/public/mojom/mediastream/media_stream.mojom-shared.h"
-
-namespace content {
-
-MockMojoMediaStreamDispatcherHost::MockMojoMediaStreamDispatcherHost()
-    : binding_(this) {}
-
-MockMojoMediaStreamDispatcherHost::~MockMojoMediaStreamDispatcherHost() {}
-
-blink::mojom::MediaStreamDispatcherHostPtr
-MockMojoMediaStreamDispatcherHost::CreateInterfacePtrAndBind() {
-  blink::mojom::MediaStreamDispatcherHostPtr dispatcher_host;
-  binding_.Bind(mojo::MakeRequest(&dispatcher_host));
-  return dispatcher_host;
-}
-
-void MockMojoMediaStreamDispatcherHost::GenerateStream(
-    int32_t request_id,
-    const blink::StreamControls& controls,
-    bool user_gesture,
-    blink::mojom::StreamSelectionInfoPtr audio_stream_selection_info_ptr,
-    GenerateStreamCallback callback) {
-  request_id_ = request_id;
-  audio_devices_.clear();
-  video_devices_.clear();
-  ++request_stream_counter_;
-
-  blink::mojom::StreamSelectionStrategy strategy =
-      audio_stream_selection_info_ptr->strategy;
-  if (controls.audio.requested &&
-      (strategy == blink::mojom::StreamSelectionStrategy::SEARCH_BY_DEVICE_ID ||
-       strategy == blink::mojom::StreamSelectionStrategy::FORCE_NEW_STREAM)) {
-    blink::MediaStreamDevice audio_device;
-    audio_device.id = controls.audio.device_id + session_id_.ToString();
-    audio_device.name = "microphone";
-    audio_device.type = controls.audio.stream_type;
-    audio_device.set_session_id(session_id_);
-    audio_device.matched_output_device_id =
-        "associated_output_device_id" + session_id_.ToString();
-    audio_devices_.push_back(audio_device);
-  }
-
-  if (controls.video.requested) {
-    blink::MediaStreamDevice video_device;
-    video_device.id = controls.video.device_id + session_id_.ToString();
-    video_device.name = "usb video camera";
-    video_device.type = controls.video.stream_type;
-    video_device.video_facing = media::MEDIA_VIDEO_FACING_USER;
-    video_device.set_session_id(session_id_);
-    video_devices_.push_back(video_device);
-  }
-
-  if (do_not_run_cb_) {
-    generate_stream_cb_ = std::move(callback);
-  } else {
-    std::move(callback).Run(blink::mojom::MediaStreamRequestResult::OK,
-                            "dummy" + base::NumberToString(request_id_),
-                            audio_devices_, video_devices_);
-  }
-}
-
-void MockMojoMediaStreamDispatcherHost::CancelRequest(int32_t request_id) {
-  EXPECT_EQ(request_id, request_id_);
-}
-
-void MockMojoMediaStreamDispatcherHost::StopStreamDevice(
-    const std::string& device_id,
-    const base::Optional<base::UnguessableToken>& session_id) {
-  base::UnguessableToken actual_session_id =
-      session_id.value_or(base::UnguessableToken());
-  for (const blink::MediaStreamDevice& device : audio_devices_) {
-    if (device.id == device_id && device.session_id() == actual_session_id) {
-      ++stop_audio_device_counter_;
-      return;
-    }
-  }
-  for (const blink::MediaStreamDevice& device : video_devices_) {
-    if (device.id == device_id && device.session_id() == actual_session_id) {
-      ++stop_video_device_counter_;
-      return;
-    }
-  }
-  NOTREACHED();
-}
-
-void MockMojoMediaStreamDispatcherHost::OpenDevice(
-    int32_t request_id,
-    const std::string& device_id,
-    blink::mojom::MediaStreamType type,
-    OpenDeviceCallback callback) {
-  blink::MediaStreamDevice device;
-  device.id = device_id;
-  device.type = type;
-  device.set_session_id(session_id_);
-  std::move(callback).Run(true /* success */,
-                          "dummy" + base::NumberToString(request_id), device);
-}
-
-}  // namespace content
diff --git a/content/renderer/media/stream/mock_mojo_media_stream_dispatcher_host.h b/content/renderer/media/stream/mock_mojo_media_stream_dispatcher_host.h
deleted file mode 100644
index 438bc5be..0000000
--- a/content/renderer/media/stream/mock_mojo_media_stream_dispatcher_host.h
+++ /dev/null
@@ -1,81 +0,0 @@
-// Copyright (c) 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_RENDERER_MEDIA_STREAM_MOCK_MOJO_MEDIA_STREAM_DISPATCHER_HOST_H_
-#define CONTENT_RENDERER_MEDIA_STREAM_MOCK_MOJO_MEDIA_STREAM_DISPATCHER_HOST_H_
-
-#include <string>
-
-#include "base/macros.h"
-#include "mojo/public/cpp/bindings/binding.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "third_party/blink/public/common/mediastream/media_stream_controls.h"
-#include "third_party/blink/public/common/mediastream/media_stream_request.h"
-#include "third_party/blink/public/mojom/mediastream/media_stream.mojom.h"
-
-namespace content {
-
-class MockMojoMediaStreamDispatcherHost
-    : public blink::mojom::MediaStreamDispatcherHost {
- public:
-  MockMojoMediaStreamDispatcherHost();
-  ~MockMojoMediaStreamDispatcherHost() override;
-
-  blink::mojom::MediaStreamDispatcherHostPtr CreateInterfacePtrAndBind();
-
-  void GenerateStream(
-      int32_t request_id,
-      const blink::StreamControls& controls,
-      bool user_gesture,
-      blink::mojom::StreamSelectionInfoPtr audio_stream_selection_info_ptr,
-      GenerateStreamCallback callback) override;
-  void CancelRequest(int32_t request_id) override;
-  void StopStreamDevice(
-      const std::string& device_id,
-      const base::Optional<base::UnguessableToken>& session_id) override;
-  void OpenDevice(int32_t request_id,
-                  const std::string& device_id,
-                  blink::mojom::MediaStreamType type,
-                  OpenDeviceCallback callback) override;
-
-  MOCK_METHOD1(CloseDevice, void(const std::string&));
-  MOCK_METHOD3(SetCapturingLinkSecured,
-               void(const base::Optional<base::UnguessableToken>&,
-                    blink::mojom::MediaStreamType,
-                    bool));
-  MOCK_METHOD1(OnStreamStarted, void(const std::string&));
-
-  void ResetSessionId() { session_id_ = base::UnguessableToken::Create(); }
-  void DoNotRunCallback() { do_not_run_cb_ = true; }
-  const base::UnguessableToken& session_id() { return session_id_; }
-
-  int request_stream_counter() const { return request_stream_counter_; }
-  int stop_audio_device_counter() const { return stop_audio_device_counter_; }
-  int stop_video_device_counter() const { return stop_video_device_counter_; }
-
-  const blink::MediaStreamDevices& audio_devices() const {
-    return audio_devices_;
-  }
-  const blink::MediaStreamDevices& video_devices() const {
-    return video_devices_;
-  }
-
- private:
-  int request_id_ = -1;
-  int request_stream_counter_ = 0;
-  int stop_audio_device_counter_ = 0;
-  int stop_video_device_counter_ = 0;
-  base::UnguessableToken session_id_;
-  bool do_not_run_cb_ = false;
-  blink::MediaStreamDevices audio_devices_;
-  blink::MediaStreamDevices video_devices_;
-  GenerateStreamCallback generate_stream_cb_;
-  mojo::Binding<blink::mojom::MediaStreamDispatcherHost> binding_;
-
-  DISALLOW_COPY_AND_ASSIGN(MockMojoMediaStreamDispatcherHost);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_RENDERER_MEDIA_STREAM_MOCK_MOJO_MEDIA_STREAM_DISPATCHER_HOST_H_
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 89375f2..8bfe2b60 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -212,8 +212,6 @@
     "../public/test/web_contents_binding_set_test_binder.h",
     "../public/test/web_contents_tester.cc",
     "../public/test/web_contents_tester.h",
-    "../renderer/media/stream/mock_mojo_media_stream_dispatcher_host.cc",
-    "../renderer/media/stream/mock_mojo_media_stream_dispatcher_host.h",
     "../renderer/media/webrtc/mock_data_channel_impl.cc",
     "../renderer/media/webrtc/mock_data_channel_impl.h",
     "../renderer/media/webrtc/mock_peer_connection_dependency_factory.cc",
diff --git a/content/test/test_blink_web_unit_test_support.cc b/content/test/test_blink_web_unit_test_support.cc
index 0b2109fd..12785ae9 100644
--- a/content/test/test_blink_web_unit_test_support.cc
+++ b/content/test/test_blink_web_unit_test_support.cc
@@ -24,7 +24,6 @@
 #include "content/app/mojo/mojo_init.h"
 #include "content/child/child_process.h"
 #include "content/public/common/service_names.mojom.h"
-#include "content/renderer/loader/web_url_loader_impl.h"
 #include "content/renderer/mojo/blink_interface_provider_impl.h"
 #include "content/test/mock_clipboard_host.h"
 #include "media/base/media.h"
@@ -103,12 +102,7 @@
       std::unique_ptr<blink::scheduler::WebResourceLoadingTaskRunnerHandle>
           task_runner_handle) override {
     DCHECK(platform_);
-    // This loader should be used only for process-local resources such as
-    // data URLs.
-    auto default_loader = std::make_unique<content::WebURLLoaderImpl>(
-        nullptr, std::move(task_runner_handle), nullptr);
-    return platform_->GetURLLoaderMockFactory()->CreateURLLoader(
-        std::move(default_loader));
+    return platform_->GetURLLoaderMockFactory()->CreateURLLoader();
   }
 
  private:
diff --git a/extensions/browser/api/web_request/web_request_proxying_websocket.cc b/extensions/browser/api/web_request/web_request_proxying_websocket.cc
index 6a8553d..3766c52 100644
--- a/extensions/browser/api/web_request/web_request_proxying_websocket.cc
+++ b/extensions/browser/api/web_request/web_request_proxying_websocket.cc
@@ -193,6 +193,7 @@
 
 void WebRequestProxyingWebSocket::OnConnectionEstablished(
     network::mojom::WebSocketPtr websocket,
+    mojo::PendingReceiver<network::mojom::WebSocketClient> client_receiver,
     const std::string& selected_protocol,
     const std::string& extensions,
     uint64_t receive_quota_threshold) {
@@ -203,8 +204,8 @@
       browser_context_, &info_, net::ERR_WS_UPGRADE);
 
   forwarding_handshake_client_->OnConnectionEstablished(
-      std::move(websocket), selected_protocol, extensions,
-      receive_quota_threshold);
+      std::move(websocket), std::move(client_receiver), selected_protocol,
+      extensions, receive_quota_threshold);
 
   // Deletes |this|.
   proxies_->RemoveProxy(this);
@@ -374,8 +375,6 @@
 
   // Here we detect mojo connection errors on |handshake_client|. See also
   // CreateWebSocket in //network/services/public/mojom/network_context.mojom.
-  // Here we don't have |connection_client| so using |handshake_client| is the
-  // best.
   network::mojom::WebSocketHandshakeClientPtr handshake_client;
   binding_as_handshake_client_.Bind(mojo::MakeRequest(&handshake_client));
   binding_as_handshake_client_.set_connection_error_with_reason_handler(
diff --git a/extensions/browser/api/web_request/web_request_proxying_websocket.h b/extensions/browser/api/web_request/web_request_proxying_websocket.h
index fe5e2d4..4de3822 100644
--- a/extensions/browser/api/web_request/web_request_proxying_websocket.h
+++ b/extensions/browser/api/web_request/web_request_proxying_websocket.h
@@ -18,6 +18,7 @@
 #include "extensions/browser/api/web_request/web_request_info.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "net/base/network_delegate.h"
 #include "services/network/public/cpp/resource_request.h"
 #include "services/network/public/cpp/resource_response.h"
@@ -61,10 +62,12 @@
       network::mojom::WebSocketHandshakeRequestPtr request) override;
   void OnResponseReceived(
       network::mojom::WebSocketHandshakeResponsePtr response) override;
-  void OnConnectionEstablished(network::mojom::WebSocketPtr websocket,
-                               const std::string& selected_protocol,
-                               const std::string& extensions,
-                               uint64_t receive_quota_threshold) override;
+  void OnConnectionEstablished(
+      network::mojom::WebSocketPtr websocket,
+      mojo::PendingReceiver<network::mojom::WebSocketClient> client_receiver,
+      const std::string& selected_protocol,
+      const std::string& extensions,
+      uint64_t receive_quota_threshold) override;
 
   // network::mojom::AuthenticationHandler method:
   void OnAuthRequired(const net::AuthChallengeInfo& auth_info,
diff --git a/extensions/browser/extension_function_histogram_value.h b/extensions/browser/extension_function_histogram_value.h
index 60f57a6..e4b0ca2 100644
--- a/extensions/browser/extension_function_histogram_value.h
+++ b/extensions/browser/extension_function_histogram_value.h
@@ -1426,6 +1426,7 @@
   ACTION_ENABLE = 1363,
   ACTION_DISABLE = 1364,
   FILEMANAGERPRIVATEINTERNAL_IMPORTCROSTINIIMAGE = 1365,
+  AUTOTESTPRIVATE_GETSHELFITEMS = 1366,
   // Last entry: Add new entries above, then run:
   // python tools/metrics/histograms/update_extension_histograms.py
   ENUM_BOUNDARY
diff --git a/fuchsia/base/agent_manager.cc b/fuchsia/base/agent_manager.cc
index a777b1d..730f8b7 100644
--- a/fuchsia/base/agent_manager.cc
+++ b/fuchsia/base/agent_manager.cc
@@ -28,8 +28,9 @@
                                        it->second.services.NewRequest(),
                                        it->second.controller.NewRequest());
     it->second.services.set_error_handler(
-        [agent = agent.as_string()](zx_status_t status) {
-          ZX_LOG(FATAL, status) << "Agent disconnected: " << agent;
+        [this, agent = agent.as_string()](zx_status_t status) {
+          ZX_LOG(WARNING, status) << "Agent disconnected: " << agent;
+          agents_.erase(agent);
         });
   }
   it->second.services->ConnectToService(interface.as_string(),
diff --git a/fuchsia/engine/BUILD.gn b/fuchsia/engine/BUILD.gn
index 4c0d86b..da6e822 100644
--- a/fuchsia/engine/BUILD.gn
+++ b/fuchsia/engine/BUILD.gn
@@ -80,6 +80,8 @@
     "//fuchsia/base",
     "//fuchsia/base:message_port",
     "//fuchsia/base:modular",
+    "//media/fuchsia/cdm/service",
+    "//media/fuchsia/mojom",
     "//mojo/public/cpp/bindings",
     "//services/network/public/cpp",
     "//services/service_manager/sandbox",
@@ -119,6 +121,8 @@
     "browser/web_engine_browser_main.h",
     "browser/web_engine_browser_main_parts.cc",
     "browser/web_engine_browser_main_parts.h",
+    "browser/web_engine_cdm_service.cc",
+    "browser/web_engine_cdm_service.h",
     "browser/web_engine_content_browser_client.cc",
     "browser/web_engine_content_browser_client.h",
     "browser/web_engine_devtools_manager_delegate.cc",
diff --git a/fuchsia/engine/browser/DEPS b/fuchsia/engine/browser/DEPS
index 77a16fc..9785678 100644
--- a/fuchsia/engine/browser/DEPS
+++ b/fuchsia/engine/browser/DEPS
@@ -4,6 +4,9 @@
   "+content/public/common",
   "+content/public/browser",
   "+content/public/test",
+  "+media/base",
+  "+media/fuchsia/cdm/service",
+  "+media/fuchsia/mojom",
   "+mojo/public/cpp/bindings",
   "+mojo/public/cpp/system",
   "+third_party/blink/public/common/associated_interfaces",
diff --git a/fuchsia/engine/browser/web_engine_cdm_service.cc b/fuchsia/engine/browser/web_engine_cdm_service.cc
new file mode 100644
index 0000000..b8919bc0
--- /dev/null
+++ b/fuchsia/engine/browser/web_engine_cdm_service.cc
@@ -0,0 +1,92 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "fuchsia/engine/browser/web_engine_cdm_service.h"
+
+#include <fuchsia/media/drm/cpp/fidl.h>
+#include <string>
+
+#include "base/bind.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/frame_service_base.h"
+#include "content/public/browser/provision_fetcher_factory.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/storage_partition.h"
+#include "media/base/provision_fetcher.h"
+#include "media/fuchsia/mojom/fuchsia_cdm_provider.mojom.h"
+
+namespace {
+class FuchsiaCdmProviderImpl
+    : public content::FrameServiceBase<media::mojom::FuchsiaCdmProvider> {
+ public:
+  FuchsiaCdmProviderImpl(media::FuchsiaCdmManager* cdm_manager,
+                         media::CreateFetcherCB create_fetcher_cb,
+                         content::RenderFrameHost* render_frame_host,
+                         media::mojom::FuchsiaCdmProviderRequest request);
+  ~FuchsiaCdmProviderImpl() final;
+
+  // media::mojom::FuchsiaCdmProvider implementation.
+  void CreateCdmInterface(
+      const std::string& key_system,
+      fidl::InterfaceRequest<fuchsia::media::drm::ContentDecryptionModule>
+          request) final;
+
+ private:
+  media::FuchsiaCdmManager* const cdm_manager_;
+  const media::CreateFetcherCB create_fetcher_cb_;
+
+  DISALLOW_COPY_AND_ASSIGN(FuchsiaCdmProviderImpl);
+};
+
+FuchsiaCdmProviderImpl::FuchsiaCdmProviderImpl(
+    media::FuchsiaCdmManager* cdm_manager,
+    media::CreateFetcherCB create_fetcher_cb,
+    content::RenderFrameHost* render_frame_host,
+    media::mojom::FuchsiaCdmProviderRequest request)
+    : FrameServiceBase(render_frame_host, std::move(request)),
+      cdm_manager_(cdm_manager),
+      create_fetcher_cb_(std::move(create_fetcher_cb)) {
+  DCHECK(cdm_manager_);
+}
+
+FuchsiaCdmProviderImpl::~FuchsiaCdmProviderImpl() = default;
+
+void FuchsiaCdmProviderImpl::CreateCdmInterface(
+    const std::string& key_system,
+    fidl::InterfaceRequest<fuchsia::media::drm::ContentDecryptionModule>
+        request) {
+  cdm_manager_->CreateAndProvision(key_system, origin(), create_fetcher_cb_,
+                                   std::move(request));
+}
+
+void BindFuchsiaCdmProvider(media::FuchsiaCdmManager* cdm_manager,
+                            media::mojom::FuchsiaCdmProviderRequest request,
+                            content::RenderFrameHost* const frame_host) {
+  scoped_refptr<network::SharedURLLoaderFactory> loader_factory =
+      content::BrowserContext::GetDefaultStoragePartition(
+          frame_host->GetProcess()->GetBrowserContext())
+          ->GetURLLoaderFactoryForBrowserProcess();
+
+  // The object will delete itself when connection to the frame is broken.
+  new FuchsiaCdmProviderImpl(
+      cdm_manager,
+      base::BindRepeating(&content::CreateProvisionFetcher,
+                          std::move(loader_factory)),
+      frame_host, std::move(request));
+}
+}  // namespace
+
+WebEngineCdmService::WebEngineCdmService(
+    service_manager::BinderRegistryWithArgs<content::RenderFrameHost*>*
+        registry)
+    : registry_(registry) {
+  DCHECK(registry_);
+  registry_->AddInterface(
+      base::BindRepeating(&BindFuchsiaCdmProvider, &cdm_manager_));
+}
+
+WebEngineCdmService::~WebEngineCdmService() {
+  registry_->RemoveInterface<media::mojom::FuchsiaCdmProvider>();
+}
diff --git a/fuchsia/engine/browser/web_engine_cdm_service.h b/fuchsia/engine/browser/web_engine_cdm_service.h
new file mode 100644
index 0000000..5cb1336
--- /dev/null
+++ b/fuchsia/engine/browser/web_engine_cdm_service.h
@@ -0,0 +1,32 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef FUCHSIA_ENGINE_BROWSER_WEB_ENGINE_CDM_SERVICE_H_
+#define FUCHSIA_ENGINE_BROWSER_WEB_ENGINE_CDM_SERVICE_H_
+
+#include "media/fuchsia/cdm/service/fuchsia_cdm_manager.h"
+#include "services/service_manager/public/cpp/binder_registry.h"
+
+namespace content {
+class RenderFrameHost;
+}
+
+class WebEngineCdmService {
+ public:
+  explicit WebEngineCdmService(
+      service_manager::BinderRegistryWithArgs<content::RenderFrameHost*>*
+          registry);
+  ~WebEngineCdmService();
+
+ private:
+  media::FuchsiaCdmManager cdm_manager_;
+
+  // Not owned pointer. |registry_| must outlive |this|.
+  service_manager::BinderRegistryWithArgs<content::RenderFrameHost*>* const
+      registry_;
+
+  DISALLOW_COPY_AND_ASSIGN(WebEngineCdmService);
+};
+
+#endif  // FUCHSIA_ENGINE_BROWSER_WEB_ENGINE_CDM_SERVICE_H_
diff --git a/fuchsia/engine/browser/web_engine_content_browser_client.cc b/fuchsia/engine/browser/web_engine_content_browser_client.cc
index f6621b5..175d42a4 100644
--- a/fuchsia/engine/browser/web_engine_content_browser_client.cc
+++ b/fuchsia/engine/browser/web_engine_content_browser_client.cc
@@ -16,7 +16,7 @@
 
 WebEngineContentBrowserClient::WebEngineContentBrowserClient(
     fidl::InterfaceRequest<fuchsia::web::Context> request)
-    : request_(std::move(request)) {}
+    : request_(std::move(request)), cdm_service_(&mojo_service_registry_) {}
 
 WebEngineContentBrowserClient::~WebEngineContentBrowserClient() = default;
 
@@ -60,3 +60,11 @@
   // Disable WebSQL support since it's being removed from the web platform.
   web_prefs->databases_enabled = false;
 }
+
+void WebEngineContentBrowserClient::BindInterfaceRequestFromFrame(
+    content::RenderFrameHost* render_frame_host,
+    const std::string& interface_name,
+    mojo::ScopedMessagePipeHandle interface_pipe) {
+  mojo_service_registry_.BindInterface(
+      interface_name, std::move(interface_pipe), render_frame_host);
+}
diff --git a/fuchsia/engine/browser/web_engine_content_browser_client.h b/fuchsia/engine/browser/web_engine_content_browser_client.h
index 7309282..ec0eecf 100644
--- a/fuchsia/engine/browser/web_engine_content_browser_client.h
+++ b/fuchsia/engine/browser/web_engine_content_browser_client.h
@@ -12,6 +12,8 @@
 
 #include "base/macros.h"
 #include "content/public/browser/content_browser_client.h"
+#include "fuchsia/engine/browser/web_engine_cdm_service.h"
+#include "services/service_manager/public/cpp/binder_registry.h"
 
 class WebEngineBrowserMainParts;
 
@@ -31,6 +33,10 @@
   std::string GetUserAgent() override;
   void OverrideWebkitPrefs(content::RenderViewHost* rvh,
                            content::WebPreferences* web_prefs) override;
+  void BindInterfaceRequestFromFrame(
+      content::RenderFrameHost* render_frame_host,
+      const std::string& interface_name,
+      mojo::ScopedMessagePipeHandle interface_pipe) override;
 
  private:
   fidl::InterfaceRequest<fuchsia::web::Context> request_;
@@ -38,6 +44,10 @@
   // Owned by content::BrowserMainLoop.
   WebEngineBrowserMainParts* main_parts_;
 
+  service_manager::BinderRegistryWithArgs<content::RenderFrameHost*>
+      mojo_service_registry_;
+  WebEngineCdmService cdm_service_;
+
   DISALLOW_COPY_AND_ASSIGN(WebEngineContentBrowserClient);
 };
 
diff --git a/ios/chrome/app/strings/ios_strings.grd b/ios/chrome/app/strings/ios_strings.grd
index 4763b5b..83e9890 100644
--- a/ios/chrome/app/strings/ios_strings.grd
+++ b/ios/chrome/app/strings/ios_strings.grd
@@ -204,6 +204,12 @@
       <message name="IDS_IOS_ACCOUNT_UNIFIED_CONSENT_OK_BUTTON" desc="Title of the button to validate the user consent [Length: 15m] [iOS only]">
         YES, I'M IN
       </message>
+      <message name="IDS_IOS_ADD_CREDIT_CARD_INVALID_CARD_NUMBER_ALERT" desc="The title of the alert view displaying invalid card number when a user enters invalid card number for the new credit card to save. [iOS only]">
+          Invalid Card Number
+      </message>
+      <message name="IDS_IOS_ADD_CREDIT_CARD_INVALID_EXPIRATION_DATE_ALERT" desc="The title of the alert view displaying invalid expiration date when a user enters invalid expiration date for the new credit card to save. [iOS only]">
+          Invalid Expiration Date
+      </message>
       <message name="IDS_IOS_ADVANCED_SIGNIN_SETTINGS_CANCEL_SYNC_ALERT_BACK_BUTTON" desc="Alert button title to ask if the user really wants to cancel sign-in and sync. This button would let the user return to the sync settings, and let them choose again.">
         Back
       </message>
diff --git a/ios/chrome/browser/infobars/infobar_badge_tab_helper_unittest.mm b/ios/chrome/browser/infobars/infobar_badge_tab_helper_unittest.mm
index 11df463..7c7232e 100644
--- a/ios/chrome/browser/infobars/infobar_badge_tab_helper_unittest.mm
+++ b/ios/chrome/browser/infobars/infobar_badge_tab_helper_unittest.mm
@@ -86,7 +86,8 @@
   self.bannerIsPresenting = YES;
   [self.infobarCoordinator presentInfobarBannerAnimated:NO completion:nil];
 }
-
+- (void)infobarManagerWillChange {
+}
 - (void)setUserInteractionEnabled:(BOOL)enabled {
 }
 - (void)updateLayoutAnimated:(BOOL)animated {
diff --git a/ios/chrome/browser/infobars/infobar_container_ios.h b/ios/chrome/browser/infobars/infobar_container_ios.h
index 0ab746de..22ac6903 100644
--- a/ios/chrome/browser/infobars/infobar_container_ios.h
+++ b/ios/chrome/browser/infobars/infobar_container_ios.h
@@ -21,6 +21,13 @@
                       id<InfobarContainerConsumer> legacyConsumer);
   ~InfoBarContainerIOS() override;
 
+  // Changes the InfoBarManager for which this container is showing infobars.
+  // This will hide all current infobars, remove them from the container, add
+  // the infobars from |infobar_manager|, and show them all. If
+  // |infobar_manager| is nullptr, it will hide all current Infobars but won't
+  // be able to present new ones.
+  void ChangeInfoBarManager(infobars::InfoBarManager* infobar_manager);
+
  protected:
   void PlatformSpecificAddInfoBar(infobars::InfoBar* infobar,
                                   size_t position) override;
diff --git a/ios/chrome/browser/infobars/infobar_container_ios.mm b/ios/chrome/browser/infobars/infobar_container_ios.mm
index 52c6ed8..d9f7f04 100644
--- a/ios/chrome/browser/infobars/infobar_container_ios.mm
+++ b/ios/chrome/browser/infobars/infobar_container_ios.mm
@@ -24,6 +24,12 @@
   RemoveAllInfoBarsForDestruction();
 }
 
+void InfoBarContainerIOS::ChangeInfoBarManager(
+    infobars::InfoBarManager* infobar_manager) {
+  [consumer_ infobarManagerWillChange];
+  InfoBarContainer::ChangeInfoBarManager(infobar_manager);
+}
+
 void InfoBarContainerIOS::PlatformSpecificAddInfoBar(infobars::InfoBar* infobar,
                                                      size_t position) {
   InfoBarIOS* infobar_ios = static_cast<InfoBarIOS*>(infobar);
diff --git a/ios/chrome/browser/overlays/overlay_presenter_impl.mm b/ios/chrome/browser/overlays/overlay_presenter_impl.mm
index 9fdfe2d..94f7fbb 100644
--- a/ios/chrome/browser/overlays/overlay_presenter_impl.mm
+++ b/ios/chrome/browser/overlays/overlay_presenter_impl.mm
@@ -279,10 +279,12 @@
 
 void OverlayPresenterImpl::RequestAddedToQueue(OverlayRequestQueueImpl* queue,
                                                OverlayRequest* request) {
-  // If |queue| is active and the added request is the front request, trigger
-  // the UI presentation for that request.
-  if (queue == GetActiveQueue() && request == queue->front_request())
+  // If |queue| is active, the added request is frontmost, and an overlay is not
+  // currently being presented, trigger the UI presentation for that request.
+  if (queue == GetActiveQueue() && request == queue->front_request() &&
+      !presenting_) {
     PresentOverlayForActiveRequest();
+  }
 }
 
 void OverlayPresenterImpl::QueuedRequestCancelled(
diff --git a/ios/chrome/browser/passwords/ios_chrome_password_manager_client.h b/ios/chrome/browser/passwords/ios_chrome_password_manager_client.h
index 2e91b129..e248491 100644
--- a/ios/chrome/browser/passwords/ios_chrome_password_manager_client.h
+++ b/ios/chrome/browser/passwords/ios_chrome_password_manager_client.h
@@ -116,6 +116,7 @@
   password_manager::PasswordManagerMetricsRecorder* GetMetricsRecorder()
       override;
   signin::IdentityManager* GetIdentityManager() override;
+  scoped_refptr<network::SharedURLLoaderFactory> GetURLLoaderFactory() override;
   password_manager::PasswordRequirementsService*
   GetPasswordRequirementsService() override;
   bool IsIsolationForPasswordSitesEnabled() const override;
diff --git a/ios/chrome/browser/passwords/ios_chrome_password_manager_client.mm b/ios/chrome/browser/passwords/ios_chrome_password_manager_client.mm
index f59a1f6d..9627ee73 100644
--- a/ios/chrome/browser/passwords/ios_chrome_password_manager_client.mm
+++ b/ios/chrome/browser/passwords/ios_chrome_password_manager_client.mm
@@ -35,6 +35,7 @@
 #include "ios/chrome/browser/translate/chrome_ios_translate_client.h"
 #include "net/cert/cert_status_flags.h"
 #include "services/metrics/public/cpp/ukm_recorder.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "url/gurl.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -224,6 +225,11 @@
   return IdentityManagerFactory::GetForBrowserState(delegate_.browserState);
 }
 
+scoped_refptr<network::SharedURLLoaderFactory>
+IOSChromePasswordManagerClient::GetURLLoaderFactory() {
+  return (delegate_.browserState)->GetSharedURLLoaderFactory();
+}
+
 password_manager::PasswordRequirementsService*
 IOSChromePasswordManagerClient::GetPasswordRequirementsService() {
   return IOSPasswordRequirementsServiceFactory::GetForBrowserState(
diff --git a/ios/chrome/browser/ui/authentication/signin_earlgrey_utils.mm b/ios/chrome/browser/ui/authentication/signin_earlgrey_utils.mm
index 9e7c27b..7d2f515 100644
--- a/ios/chrome/browser/ui/authentication/signin_earlgrey_utils.mm
+++ b/ios/chrome/browser/ui/authentication/signin_earlgrey_utils.mm
@@ -35,8 +35,7 @@
 - (ChromeIdentity*)fakeManagedIdentity {
   return [FakeChromeIdentity identityWithEmail:@"foo@managed.com"
                                         gaiaID:@"fooManagedID"
-                                          name:@"Fake Managed"
-                                  hostedDomain:@"managed.com"];
+                                          name:@"Fake Managed"];
 }
 
 - (void)checkSignedInWithIdentity:(ChromeIdentity*)identity {
diff --git a/ios/chrome/browser/ui/bookmarks/BUILD.gn b/ios/chrome/browser/ui/bookmarks/BUILD.gn
index 0278e436..37c276f 100644
--- a/ios/chrome/browser/ui/bookmarks/BUILD.gn
+++ b/ios/chrome/browser/ui/bookmarks/BUILD.gn
@@ -48,7 +48,6 @@
   ]
   deps = [
     ":bookmarks_ui",
-    "resources:bookmark_bar_shadow",
     "resources:bookmark_blue_check",
     "resources:bookmark_blue_folder",
     "resources:bookmark_blue_new_folder",
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.h b/ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.h
index 1f19529..ea47c5e38 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.h
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.h
@@ -48,9 +48,6 @@
 // Returns whether the bookmark menu should be presented in a slide in panel.
 BOOL bookmarkMenuIsInSlideInPanel();
 
-// Creates a drop shadow with the given width.
-UIView* dropShadowWithWidth(CGFloat width);
-
 #pragma mark - Updating Bookmarks
 
 // Creates the bookmark if |node| is NULL. Otherwise updates |node|.
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.mm b/ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.mm
index f6e1aa0..8d97fe25 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.mm
@@ -108,16 +108,6 @@
   return !IsIPadIdiom() || IsCompactTablet();
 }
 
-UIView* dropShadowWithWidth(CGFloat width) {
-  UIImage* shadowImage = [UIImage imageNamed:@"bookmark_bar_shadow"];
-  UIImageView* shadow = [[UIImageView alloc] initWithImage:shadowImage];
-  CGRect shadowFrame = CGRectMake(0, 0, width, 4);
-  shadow.frame = shadowFrame;
-  shadow.autoresizingMask =
-      UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleWidth;
-  return shadow;
-}
-
 #pragma mark - Updating Bookmarks
 
 // Deletes all subnodes of |node|, including |node|, that are in |bookmarks|.
diff --git a/ios/chrome/browser/ui/bookmarks/resources/BUILD.gn b/ios/chrome/browser/ui/bookmarks/resources/BUILD.gn
index 235b01f..ebac1550 100644
--- a/ios/chrome/browser/ui/bookmarks/resources/BUILD.gn
+++ b/ios/chrome/browser/ui/bookmarks/resources/BUILD.gn
@@ -4,19 +4,9 @@
 
 import("//build/config/ios/asset_catalog.gni")
 
-imageset("bookmark_bar_shadow") {
-  sources = [
-    "bookmark_bar_shadow.imageset/Contents.json",
-    "bookmark_bar_shadow.imageset/bookmark_bar_shadow.png",
-    "bookmark_bar_shadow.imageset/bookmark_bar_shadow@2x.png",
-    "bookmark_bar_shadow.imageset/bookmark_bar_shadow@3x.png",
-  ]
-}
-
 imageset("bookmark_blue_check") {
   sources = [
     "bookmark_blue_check.imageset/Contents.json",
-    "bookmark_blue_check.imageset/bookmark_blue_check.png",
     "bookmark_blue_check.imageset/bookmark_blue_check@2x.png",
     "bookmark_blue_check.imageset/bookmark_blue_check@3x.png",
   ]
@@ -25,7 +15,6 @@
 imageset("bookmark_blue_folder") {
   sources = [
     "bookmark_blue_folder.imageset/Contents.json",
-    "bookmark_blue_folder.imageset/bookmark_blue_folder.png",
     "bookmark_blue_folder.imageset/bookmark_blue_folder@2x.png",
     "bookmark_blue_folder.imageset/bookmark_blue_folder@3x.png",
   ]
@@ -34,7 +23,6 @@
 imageset("bookmark_blue_new_folder") {
   sources = [
     "bookmark_blue_new_folder.imageset/Contents.json",
-    "bookmark_blue_new_folder.imageset/bookmark_blue_new_folder.png",
     "bookmark_blue_new_folder.imageset/bookmark_blue_new_folder@2x.png",
     "bookmark_blue_new_folder.imageset/bookmark_blue_new_folder@3x.png",
   ]
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_bar_innershadow.imageset/bookmark_bar_innershadow.png b/ios/chrome/browser/ui/bookmarks/resources/bookmark_bar_innershadow.imageset/bookmark_bar_innershadow.png
deleted file mode 100644
index 05d4bcb..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_bar_innershadow.imageset/bookmark_bar_innershadow.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_bar_innershadow.imageset/bookmark_bar_innershadow@2x.png b/ios/chrome/browser/ui/bookmarks/resources/bookmark_bar_innershadow.imageset/bookmark_bar_innershadow@2x.png
deleted file mode 100644
index 0af9884d..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_bar_innershadow.imageset/bookmark_bar_innershadow@2x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_bar_innershadow.imageset/bookmark_bar_innershadow@3x.png b/ios/chrome/browser/ui/bookmarks/resources/bookmark_bar_innershadow.imageset/bookmark_bar_innershadow@3x.png
deleted file mode 100644
index 862854e..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_bar_innershadow.imageset/bookmark_bar_innershadow@3x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_bar_shadow.imageset/Contents.json b/ios/chrome/browser/ui/bookmarks/resources/bookmark_bar_shadow.imageset/Contents.json
deleted file mode 100644
index b99f4db6..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_bar_shadow.imageset/Contents.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
-    "images": [
-        {
-            "idiom": "universal",
-            "scale": "1x",
-            "filename": "bookmark_bar_shadow.png"
-        },
-        {
-            "idiom": "universal",
-            "scale": "2x",
-            "filename": "bookmark_bar_shadow@2x.png"
-        },
-        {
-            "idiom": "universal",
-            "scale": "3x",
-            "filename": "bookmark_bar_shadow@3x.png"
-        }
-    ],
-    "info": {
-        "version": 1,
-        "author": "xcode"
-    }
-}
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_bar_shadow.imageset/bookmark_bar_shadow.png b/ios/chrome/browser/ui/bookmarks/resources/bookmark_bar_shadow.imageset/bookmark_bar_shadow.png
deleted file mode 100644
index cea41ee..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_bar_shadow.imageset/bookmark_bar_shadow.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_bar_shadow.imageset/bookmark_bar_shadow@2x.png b/ios/chrome/browser/ui/bookmarks/resources/bookmark_bar_shadow.imageset/bookmark_bar_shadow@2x.png
deleted file mode 100644
index ace8517..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_bar_shadow.imageset/bookmark_bar_shadow@2x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_bar_shadow.imageset/bookmark_bar_shadow@3x.png b/ios/chrome/browser/ui/bookmarks/resources/bookmark_bar_shadow.imageset/bookmark_bar_shadow@3x.png
deleted file mode 100644
index da197d31..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_bar_shadow.imageset/bookmark_bar_shadow@3x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_black_delete.imageset/bookmark_black_delete.png b/ios/chrome/browser/ui/bookmarks/resources/bookmark_black_delete.imageset/bookmark_black_delete.png
deleted file mode 100644
index 4c8bcbe..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_black_delete.imageset/bookmark_black_delete.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_black_delete.imageset/bookmark_black_delete@2x.png b/ios/chrome/browser/ui/bookmarks/resources/bookmark_black_delete.imageset/bookmark_black_delete@2x.png
deleted file mode 100644
index ecd52c8..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_black_delete.imageset/bookmark_black_delete@2x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_black_delete.imageset/bookmark_black_delete@3x.png b/ios/chrome/browser/ui/bookmarks/resources/bookmark_black_delete.imageset/bookmark_black_delete@3x.png
deleted file mode 100644
index a18dde6..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_black_delete.imageset/bookmark_black_delete@3x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_black_edit.imageset/bookmark_black_edit.png b/ios/chrome/browser/ui/bookmarks/resources/bookmark_black_edit.imageset/bookmark_black_edit.png
deleted file mode 100644
index b4dc78b5..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_black_edit.imageset/bookmark_black_edit.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_black_edit.imageset/bookmark_black_edit@2x.png b/ios/chrome/browser/ui/bookmarks/resources/bookmark_black_edit.imageset/bookmark_black_edit@2x.png
deleted file mode 100644
index 63bfa124..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_black_edit.imageset/bookmark_black_edit@2x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_black_edit.imageset/bookmark_black_edit@3x.png b/ios/chrome/browser/ui/bookmarks/resources/bookmark_black_edit.imageset/bookmark_black_edit@3x.png
deleted file mode 100644
index 52ef7d83..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_black_edit.imageset/bookmark_black_edit@3x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_black_move.imageset/bookmark_black_move.png b/ios/chrome/browser/ui/bookmarks/resources/bookmark_black_move.imageset/bookmark_black_move.png
deleted file mode 100644
index 1ec68561..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_black_move.imageset/bookmark_black_move.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_black_move.imageset/bookmark_black_move@2x.png b/ios/chrome/browser/ui/bookmarks/resources/bookmark_black_move.imageset/bookmark_black_move@2x.png
deleted file mode 100644
index c5368772..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_black_move.imageset/bookmark_black_move@2x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_black_move.imageset/bookmark_black_move@3x.png b/ios/chrome/browser/ui/bookmarks/resources/bookmark_black_move.imageset/bookmark_black_move@3x.png
deleted file mode 100644
index 298c8299..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_black_move.imageset/bookmark_black_move@3x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_black_select.imageset/bookmark_black_select.png b/ios/chrome/browser/ui/bookmarks/resources/bookmark_black_select.imageset/bookmark_black_select.png
deleted file mode 100644
index 452ac4f9..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_black_select.imageset/bookmark_black_select.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_black_select.imageset/bookmark_black_select@2x.png b/ios/chrome/browser/ui/bookmarks/resources/bookmark_black_select.imageset/bookmark_black_select@2x.png
deleted file mode 100644
index 84fcee9..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_black_select.imageset/bookmark_black_select@2x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_black_select.imageset/bookmark_black_select@3x.png b/ios/chrome/browser/ui/bookmarks/resources/bookmark_black_select.imageset/bookmark_black_select@3x.png
deleted file mode 100644
index bb4031e..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_black_select.imageset/bookmark_black_select@3x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_blue_check.imageset/bookmark_blue_check.png b/ios/chrome/browser/ui/bookmarks/resources/bookmark_blue_check.imageset/bookmark_blue_check.png
deleted file mode 100644
index 2d47a4ee..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_blue_check.imageset/bookmark_blue_check.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_blue_folder.imageset/bookmark_blue_folder.png b/ios/chrome/browser/ui/bookmarks/resources/bookmark_blue_folder.imageset/bookmark_blue_folder.png
deleted file mode 100644
index 147bb25a..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_blue_folder.imageset/bookmark_blue_folder.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_blue_new_folder.imageset/bookmark_blue_new_folder.png b/ios/chrome/browser/ui/bookmarks/resources/bookmark_blue_new_folder.imageset/bookmark_blue_new_folder.png
deleted file mode 100644
index 5fbdafdaa..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_blue_new_folder.imageset/bookmark_blue_new_folder.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_back.imageset/bookmark_gray_back.png b/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_back.imageset/bookmark_gray_back.png
deleted file mode 100644
index f72e2cd..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_back.imageset/bookmark_gray_back.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_back.imageset/bookmark_gray_back@2x.png b/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_back.imageset/bookmark_gray_back@2x.png
deleted file mode 100644
index be0201a..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_back.imageset/bookmark_gray_back@2x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_back.imageset/bookmark_gray_back@3x.png b/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_back.imageset/bookmark_gray_back@3x.png
deleted file mode 100644
index 4e7d220..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_back.imageset/bookmark_gray_back@3x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_check.imageset/bookmark_gray_check.png b/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_check.imageset/bookmark_gray_check.png
deleted file mode 100644
index 3e5951a..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_check.imageset/bookmark_gray_check.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_check.imageset/bookmark_gray_check@2x.png b/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_check.imageset/bookmark_gray_check@2x.png
deleted file mode 100644
index 8a6c404..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_check.imageset/bookmark_gray_check@2x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_check.imageset/bookmark_gray_check@3x.png b/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_check.imageset/bookmark_gray_check@3x.png
deleted file mode 100644
index 7bb0bea..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_check.imageset/bookmark_gray_check@3x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_close.imageset/bookmark_gray_close.png b/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_close.imageset/bookmark_gray_close.png
deleted file mode 100644
index 7ba7e9f5..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_close.imageset/bookmark_gray_close.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_close.imageset/bookmark_gray_close@2x.png b/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_close.imageset/bookmark_gray_close@2x.png
deleted file mode 100644
index 2ff3b35..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_close.imageset/bookmark_gray_close@2x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_close.imageset/bookmark_gray_close@3x.png b/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_close.imageset/bookmark_gray_close@3x.png
deleted file mode 100644
index 8cfde0c..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_close.imageset/bookmark_gray_close@3x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_edit.imageset/bookmark_gray_edit.png b/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_edit.imageset/bookmark_gray_edit.png
deleted file mode 100644
index 5cae726..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_edit.imageset/bookmark_gray_edit.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_edit.imageset/bookmark_gray_edit@2x.png b/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_edit.imageset/bookmark_gray_edit@2x.png
deleted file mode 100644
index 1511051..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_edit.imageset/bookmark_gray_edit@2x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_edit.imageset/bookmark_gray_edit@3x.png b/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_edit.imageset/bookmark_gray_edit@3x.png
deleted file mode 100644
index bbe26a0..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_edit.imageset/bookmark_gray_edit@3x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_folder.imageset/bookmark_gray_folder.png b/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_folder.imageset/bookmark_gray_folder.png
deleted file mode 100644
index 97182c5b..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_folder.imageset/bookmark_gray_folder.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_folder.imageset/bookmark_gray_folder@2x.png b/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_folder.imageset/bookmark_gray_folder@2x.png
deleted file mode 100644
index 22fc7e0..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_folder.imageset/bookmark_gray_folder@2x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_folder.imageset/bookmark_gray_folder@3x.png b/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_folder.imageset/bookmark_gray_folder@3x.png
deleted file mode 100644
index 3d8b900..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_folder.imageset/bookmark_gray_folder@3x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_folder_new.imageset/bookmark_gray_folder_new.png b/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_folder_new.imageset/bookmark_gray_folder_new.png
deleted file mode 100644
index e0c6f58..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_folder_new.imageset/bookmark_gray_folder_new.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_folder_new.imageset/bookmark_gray_folder_new@2x.png b/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_folder_new.imageset/bookmark_gray_folder_new@2x.png
deleted file mode 100644
index 6a11c243..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_folder_new.imageset/bookmark_gray_folder_new@2x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_folder_new.imageset/bookmark_gray_folder_new@3x.png b/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_folder_new.imageset/bookmark_gray_folder_new@3x.png
deleted file mode 100644
index b74a084..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_folder_new.imageset/bookmark_gray_folder_new@3x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_menu.imageset/bookmark_gray_menu.png b/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_menu.imageset/bookmark_gray_menu.png
deleted file mode 100644
index 460a60f7..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_menu.imageset/bookmark_gray_menu.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_menu.imageset/bookmark_gray_menu@2x.png b/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_menu.imageset/bookmark_gray_menu@2x.png
deleted file mode 100644
index 1e8a6441..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_menu.imageset/bookmark_gray_menu@2x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_menu.imageset/bookmark_gray_menu@3x.png b/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_menu.imageset/bookmark_gray_menu@3x.png
deleted file mode 100644
index 95c0bf3e..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_menu.imageset/bookmark_gray_menu@3x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_new_folder.imageset/bookmark_gray_new_folder.png b/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_new_folder.imageset/bookmark_gray_new_folder.png
deleted file mode 100644
index 00d3ff1..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_new_folder.imageset/bookmark_gray_new_folder.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_new_folder.imageset/bookmark_gray_new_folder@2x.png b/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_new_folder.imageset/bookmark_gray_new_folder@2x.png
deleted file mode 100644
index 3cbba7180..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_new_folder.imageset/bookmark_gray_new_folder@2x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_new_folder.imageset/bookmark_gray_new_folder@3x.png b/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_new_folder.imageset/bookmark_gray_new_folder@3x.png
deleted file mode 100644
index 01d693a..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_new_folder.imageset/bookmark_gray_new_folder@3x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_star_large.imageset/bookmark_gray_star_large.png b/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_star_large.imageset/bookmark_gray_star_large.png
deleted file mode 100644
index 1db35bb..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_star_large.imageset/bookmark_gray_star_large.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_star_large.imageset/bookmark_gray_star_large@2x.png b/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_star_large.imageset/bookmark_gray_star_large@2x.png
deleted file mode 100644
index 2c53758..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_star_large.imageset/bookmark_gray_star_large@2x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_star_large.imageset/bookmark_gray_star_large@3x.png b/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_star_large.imageset/bookmark_gray_star_large@3x.png
deleted file mode 100644
index dcc23a52..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_gray_star_large.imageset/bookmark_gray_star_large@3x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_more.imageset/bookmark_more.png b/ios/chrome/browser/ui/bookmarks/resources/bookmark_more.imageset/bookmark_more.png
deleted file mode 100644
index 980f1682..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_more.imageset/bookmark_more.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_more.imageset/bookmark_more@2x.png b/ios/chrome/browser/ui/bookmarks/resources/bookmark_more.imageset/bookmark_more@2x.png
deleted file mode 100644
index aa2a88a..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_more.imageset/bookmark_more@2x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_more.imageset/bookmark_more@3x.png b/ios/chrome/browser/ui/bookmarks/resources/bookmark_more.imageset/bookmark_more@3x.png
deleted file mode 100644
index 44f9cbc..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_more.imageset/bookmark_more@3x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_white_close.imageset/bookmark_white_close.png b/ios/chrome/browser/ui/bookmarks/resources/bookmark_white_close.imageset/bookmark_white_close.png
deleted file mode 100644
index 6ae9ed8..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_white_close.imageset/bookmark_white_close.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_white_close.imageset/bookmark_white_close@2x.png b/ios/chrome/browser/ui/bookmarks/resources/bookmark_white_close.imageset/bookmark_white_close@2x.png
deleted file mode 100644
index fdae85c..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_white_close.imageset/bookmark_white_close@2x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_white_close.imageset/bookmark_white_close@3x.png b/ios/chrome/browser/ui/bookmarks/resources/bookmark_white_close.imageset/bookmark_white_close@3x.png
deleted file mode 100644
index 781785a..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_white_close.imageset/bookmark_white_close@3x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_white_delete.imageset/bookmark_white_delete.png b/ios/chrome/browser/ui/bookmarks/resources/bookmark_white_delete.imageset/bookmark_white_delete.png
deleted file mode 100644
index 6e10ce0..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_white_delete.imageset/bookmark_white_delete.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_white_delete.imageset/bookmark_white_delete@2x.png b/ios/chrome/browser/ui/bookmarks/resources/bookmark_white_delete.imageset/bookmark_white_delete@2x.png
deleted file mode 100644
index 3c8390d6..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_white_delete.imageset/bookmark_white_delete@2x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_white_delete.imageset/bookmark_white_delete@3x.png b/ios/chrome/browser/ui/bookmarks/resources/bookmark_white_delete.imageset/bookmark_white_delete@3x.png
deleted file mode 100644
index c3ff901..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_white_delete.imageset/bookmark_white_delete@3x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_white_edit.imageset/bookmark_white_edit.png b/ios/chrome/browser/ui/bookmarks/resources/bookmark_white_edit.imageset/bookmark_white_edit.png
deleted file mode 100644
index 5d88317..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_white_edit.imageset/bookmark_white_edit.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_white_edit.imageset/bookmark_white_edit@2x.png b/ios/chrome/browser/ui/bookmarks/resources/bookmark_white_edit.imageset/bookmark_white_edit@2x.png
deleted file mode 100644
index 47d3a8d..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_white_edit.imageset/bookmark_white_edit@2x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_white_edit.imageset/bookmark_white_edit@3x.png b/ios/chrome/browser/ui/bookmarks/resources/bookmark_white_edit.imageset/bookmark_white_edit@3x.png
deleted file mode 100644
index 701f39d..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_white_edit.imageset/bookmark_white_edit@3x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_white_move.imageset/bookmark_white_move.png b/ios/chrome/browser/ui/bookmarks/resources/bookmark_white_move.imageset/bookmark_white_move.png
deleted file mode 100644
index d0857534..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_white_move.imageset/bookmark_white_move.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_white_move.imageset/bookmark_white_move@2x.png b/ios/chrome/browser/ui/bookmarks/resources/bookmark_white_move.imageset/bookmark_white_move@2x.png
deleted file mode 100644
index 30b7d69a..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_white_move.imageset/bookmark_white_move@2x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/bookmarks/resources/bookmark_white_move.imageset/bookmark_white_move@3x.png b/ios/chrome/browser/ui/bookmarks/resources/bookmark_white_move.imageset/bookmark_white_move@3x.png
deleted file mode 100644
index e9def55..0000000
--- a/ios/chrome/browser/ui/bookmarks/resources/bookmark_white_move.imageset/bookmark_white_move@3x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/download/BUILD.gn b/ios/chrome/browser/ui/download/BUILD.gn
index 1bef19c..14adc6f 100644
--- a/ios/chrome/browser/ui/download/BUILD.gn
+++ b/ios/chrome/browser/ui/download/BUILD.gn
@@ -149,15 +149,19 @@
 
   sources = [
     "ar_quick_look_egtest.mm",
+    "download_manager_egtest.mm",
     "pass_kit_egtest.mm",
   ]
 
   deps = [
     "//ios/chrome/app/strings:ios_strings_grit",
+    "//ios/chrome/browser:chrome_url_constants",
     "//ios/chrome/browser/download:features",
     "//ios/chrome/browser/download:mime_types",
     "//ios/chrome/browser/download:test_support",
+    "//ios/chrome/test:eg_test_support+eg2",
     "//ios/chrome/test/earl_grey:eg_test_support+eg2",
+    "//ios/testing:embedded_test_server_support",
     "//ios/testing/earl_grey:eg_test_support+eg2",
     "//ios/third_party/earl_grey2:test_lib",
     "//ios/web/public/test:element_selector",
diff --git a/ios/chrome/browser/ui/download/download_manager_egtest.mm b/ios/chrome/browser/ui/download/download_manager_egtest.mm
index 8a7358298..fe5a101 100644
--- a/ios/chrome/browser/ui/download/download_manager_egtest.mm
+++ b/ios/chrome/browser/ui/download/download_manager_egtest.mm
@@ -2,22 +2,18 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#import <EarlGrey/EarlGrey.h>
-
 #include "base/bind.h"
 #import "base/test/ios/wait_util.h"
 #include "ios/chrome/browser/chrome_url_constants.h"
 #include "ios/chrome/grit/ios_strings.h"
-#import "ios/chrome/test/app/chrome_test_util.h"
-#import "ios/chrome/test/app/tab_test_util.h"
 #import "ios/chrome/test/earl_grey/chrome_actions.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"
 #import "ios/chrome/test/scoped_eg_synchronization_disabler.h"
+#import "ios/testing/earl_grey/earl_grey_test.h"
 #include "ios/testing/embedded_test_server_handlers.h"
-#import "ios/web/public/test/earl_grey/web_view_matchers.h"
 #include "ios/web/public/test/element_selector.h"
 #include "net/test/embedded_test_server/http_request.h"
 #include "net/test/embedded_test_server/http_response.h"
diff --git a/ios/chrome/browser/ui/infobars/BUILD.gn b/ios/chrome/browser/ui/infobars/BUILD.gn
index 225fd41..dd4ef79f 100644
--- a/ios/chrome/browser/ui/infobars/BUILD.gn
+++ b/ios/chrome/browser/ui/infobars/BUILD.gn
@@ -18,6 +18,7 @@
     "//ios/chrome/browser",
     "//ios/chrome/browser/infobars",
     "//ios/chrome/browser/infobars:badge",
+    "//ios/chrome/browser/infobars:public",
     "//ios/chrome/browser/ui/commands",
     "//ios/chrome/browser/ui/coordinators:chrome_coordinators",
     "//ios/chrome/browser/ui/fullscreen",
diff --git a/ios/chrome/browser/ui/infobars/coordinators/infobar_confirm_coordinator.mm b/ios/chrome/browser/ui/infobars/coordinators/infobar_confirm_coordinator.mm
index 605d620d..35af3796 100644
--- a/ios/chrome/browser/ui/infobars/coordinators/infobar_confirm_coordinator.mm
+++ b/ios/chrome/browser/ui/infobars/coordinators/infobar_confirm_coordinator.mm
@@ -68,7 +68,7 @@
     // from memory.
     self.delegate->RemoveInfoBar();
     _confirmInfobarDelegate = nil;
-    [self.infobarContainer childCoordinatorStopped];
+    [self.infobarContainer childCoordinatorStopped:self.infobarType];
   }
 }
 
diff --git a/ios/chrome/browser/ui/infobars/coordinators/infobar_password_coordinator.mm b/ios/chrome/browser/ui/infobars/coordinators/infobar_password_coordinator.mm
index eb954ec55..634b8b7 100644
--- a/ios/chrome/browser/ui/infobars/coordinators/infobar_password_coordinator.mm
+++ b/ios/chrome/browser/ui/infobars/coordinators/infobar_password_coordinator.mm
@@ -97,7 +97,7 @@
     // from memory.
     self.delegate->RemoveInfoBar();
     _passwordInfoBarDelegate = nil;
-    [self.infobarContainer childCoordinatorStopped];
+    [self.infobarContainer childCoordinatorStopped:self.infobarType];
   }
 }
 
diff --git a/ios/chrome/browser/ui/infobars/infobar_container.h b/ios/chrome/browser/ui/infobars/infobar_container.h
index e34834fd..1468725 100644
--- a/ios/chrome/browser/ui/infobars/infobar_container.h
+++ b/ios/chrome/browser/ui/infobars/infobar_container.h
@@ -7,15 +7,15 @@
 
 #import <Foundation/Foundation.h>
 
+enum class InfobarType;
+
 // Protocol for the InfobarCoordinators to communicate with the InfobarContainer
 // Coordinator.
 @protocol InfobarContainer
 
-// Informs the InfobarContainer Coordinator that its child coordinator has
-// stopped.
-// TODO(crbug.com/961343): Add support to indicate which Coordinator has
-// stopped.
-- (void)childCoordinatorStopped;
+// Informs the InfobarContainer Coordinator that its child coordinator of type
+// |infobarType| has stopped.
+- (void)childCoordinatorStopped:(InfobarType)infobarType;
 
 @end
 
diff --git a/ios/chrome/browser/ui/infobars/infobar_container_consumer.h b/ios/chrome/browser/ui/infobars/infobar_container_consumer.h
index 981de45..ab6e7cf 100644
--- a/ios/chrome/browser/ui/infobars/infobar_container_consumer.h
+++ b/ios/chrome/browser/ui/infobars/infobar_container_consumer.h
@@ -15,6 +15,11 @@
 // Adds |infoBarDelegate|'s Infobar to the InfobarContainer.
 - (void)addInfoBarWithDelegate:(id<InfobarUIDelegate>)infoBarDelegate;
 
+// Informs InfobarContainerConsumer that the backing infobarManager will change.
+// This most likely means that the WebState is changing and a new set of
+// Infobars will/may be presented.
+- (void)infobarManagerWillChange;
+
 // Sets the Infobar container user interaction to |enabled|.
 - (void)setUserInteractionEnabled:(BOOL)enabled;
 
diff --git a/ios/chrome/browser/ui/infobars/infobar_container_coordinator.mm b/ios/chrome/browser/ui/infobars/infobar_container_coordinator.mm
index 20d98f4..d618a25 100644
--- a/ios/chrome/browser/ui/infobars/infobar_container_coordinator.mm
+++ b/ios/chrome/browser/ui/infobars/infobar_container_coordinator.mm
@@ -8,6 +8,7 @@
 
 #import "base/mac/foundation_util.h"
 #include "ios/chrome/browser/infobars/infobar_manager_impl.h"
+#import "ios/chrome/browser/infobars/infobar_type.h"
 #import "ios/chrome/browser/ui/commands/application_commands.h"
 #import "ios/chrome/browser/ui/commands/command_dispatcher.h"
 #import "ios/chrome/browser/ui/fullscreen/fullscreen_controller_factory.h"
@@ -43,6 +44,10 @@
 // TODO(crbug.com/927064): Remove this once the legacy container is no longer
 // needed.
 @property(nonatomic, assign) BOOL legacyContainerFullscrenSupportDisabled;
+// infobarCoordinators holds all InfobarCoordinators this ContainerCoordinator
+// can display.
+@property(nonatomic, strong)
+    NSMutableDictionary<NSNumber*, InfobarCoordinator*>* infobarCoordinators;
 
 @end
 
@@ -56,6 +61,7 @@
                               browserState:browserState];
   if (self) {
     _webStateList = webStateList;
+    _infobarCoordinators = [NSMutableDictionary dictionary];
   }
   return self;
 }
@@ -134,10 +140,27 @@
 - (void)dismissInfobarBannerAnimated:(BOOL)animated
                           completion:(void (^)())completion {
   DCHECK(IsInfobarUIRebootEnabled());
-  InfobarCoordinator* infobarCoordinator =
-      static_cast<InfobarCoordinator*>(self.activeChildCoordinator);
-  [infobarCoordinator dismissInfobarBannerAnimated:animated
-                                        completion:completion];
+
+  for (InfobarCoordinator* infobarCoordinator in
+       [self.infobarCoordinators allValues]) {
+    if (infobarCoordinator.infobarBannerState !=
+        InfobarBannerPresentationState::NotPresented) {
+      // Since only one Banner can be presented at any time, dismiss it.
+      [infobarCoordinator dismissInfobarBannerAnimated:animated
+                                            completion:completion];
+      return;
+    }
+  }
+  // If no banner was presented make sure the completion block still runs.
+  if (completion)
+    completion();
+}
+
+#pragma mark - ChromeCoordinator
+
+- (MutableCoordinatorArray*)childCoordinators {
+  return static_cast<MutableCoordinatorArray*>(
+      [self.infobarCoordinators allValues]);
 }
 
 #pragma mark - Accessors
@@ -159,9 +182,15 @@
 
 - (InfobarBannerPresentationState)infobarBannerState {
   DCHECK(IsInfobarUIRebootEnabled());
-  InfobarCoordinator* infobarCoordinator =
-      static_cast<InfobarCoordinator*>(self.activeChildCoordinator);
-  return infobarCoordinator.infobarBannerState;
+  for (InfobarCoordinator* infobarCoordinator in
+       [self.infobarCoordinators allValues]) {
+    if (infobarCoordinator.infobarBannerState !=
+        InfobarBannerPresentationState::NotPresented) {
+      // Since only one Banner can be presented at any time, early return.
+      return infobarCoordinator.infobarBannerState;
+    }
+  }
+  return InfobarBannerPresentationState::NotPresented;
 }
 
 #pragma mark - InfobarConsumer
@@ -171,6 +200,10 @@
   InfobarCoordinator* infobarCoordinator =
       static_cast<InfobarCoordinator*>(infoBarDelegate);
 
+  NSNumber* infobarKey =
+      [NSNumber numberWithInt:static_cast<int>(infoBarDelegate.infobarType)];
+  self.infobarCoordinators[infobarKey] = infobarCoordinator;
+
   // Present the InfobarBanner, and set the Coordinator and View hierarchies.
   [infobarCoordinator start];
   infobarCoordinator.badgeDelegate = self.mediator;
@@ -181,7 +214,6 @@
   if (!infobarCoordinator.bannerWasPresented)
     [infobarCoordinator presentInfobarBannerAnimated:YES completion:nil];
   self.infobarViewController = infobarCoordinator.bannerViewController;
-  [self.childCoordinators addObject:infobarCoordinator];
 
   // Dismisses the presented InfobarCoordinator banner after
   // kInfobarBannerPresentationDurationInSeconds seconds.
@@ -195,6 +227,10 @@
   }
 }
 
+- (void)infobarManagerWillChange {
+  self.infobarCoordinators = [NSMutableDictionary dictionary];
+}
+
 - (void)setUserInteractionEnabled:(BOOL)enabled {
   [self.infobarViewController.view setUserInteractionEnabled:enabled];
 }
@@ -207,18 +243,17 @@
 
 #pragma mark InfobarContainer
 
-- (void)childCoordinatorStopped {
+- (void)childCoordinatorStopped:(InfobarType)infobarType {
   DCHECK(IsInfobarUIRebootEnabled());
-  // TODO(crbug.com/961343): When more than one InfobarCoordinator can exist
-  // concurrently, delete only the one that stopped.
-  [self.childCoordinators removeAllObjects];
+  NSNumber* infobarKey = [NSNumber numberWithInt:static_cast<int>(infobarType)];
+  [self.infobarCoordinators removeObjectForKey:infobarKey];
 }
 
 #pragma mark - InfobarCommands
 
 - (void)displayModalInfobar {
-  InfobarCoordinator* infobarCoordinator =
-      static_cast<InfobarCoordinator*>(self.activeChildCoordinator);
+  NSArray* allCoordinators = [self.infobarCoordinators allValues];
+  InfobarCoordinator* infobarCoordinator = [allCoordinators lastObject];
   [infobarCoordinator presentInfobarModal];
 }
 
diff --git a/ios/chrome/browser/ui/infobars/infobar_container_coordinator_unittest.mm b/ios/chrome/browser/ui/infobars/infobar_container_coordinator_unittest.mm
index 41aa87fe..ded3d4d 100644
--- a/ios/chrome/browser/ui/infobars/infobar_container_coordinator_unittest.mm
+++ b/ios/chrome/browser/ui/infobars/infobar_container_coordinator_unittest.mm
@@ -134,6 +134,22 @@
         coordinator_, std::move(infobar_delegate_)));
   }
 
+  // Adds an Infobar to the InfobarManager, triggering an InfobarBanner
+  // presentation.
+  void AddSecondInfobar() {
+    // Setup the InfobarCoordinator and InfobarDelegate.
+    TestInfoBarDelegate* test_infobar_delegate =
+        new TestInfoBarDelegate(@"Title 2");
+    InfobarConfirmCoordinator* coordinator = [[InfobarConfirmCoordinator alloc]
+        initWithInfoBarDelegate:test_infobar_delegate
+                           type:InfobarType::kInfobarTypePasswordSave];
+    std::unique_ptr<ConfirmInfoBarDelegate> infobar_delegate =
+        std::unique_ptr<ConfirmInfoBarDelegate>(test_infobar_delegate);
+
+    GetInfobarManager()->AddInfoBar(
+        std::make_unique<InfoBarIOS>(coordinator, std::move(infobar_delegate)));
+  }
+
   void AddSecondWebstate() {
     std::unique_ptr<web::TestWebState> second_web_state =
         std::make_unique<web::TestWebState>();
@@ -455,10 +471,9 @@
             InfobarBannerPresentationState::NotPresented);
 }
 
-// Tests that the ChildCoordinator is deleted once it stops.
-// TODO(crbug.com/961343): Update test when more than one Child Coordinator is
-// supported.
-TEST_F(InfobarContainerCoordinatorTest, TestInfobarChildCoordinatorCount) {
+// Tests that the ChildCoordinators are deleted once the Webstate is closed.
+TEST_F(InfobarContainerCoordinatorTest,
+       TestInfobarChildCoordinatorCountWebstate) {
   AddInfobar();
 
   EXPECT_TRUE(base::test::ios::WaitUntilConditionOrTimeout(
@@ -482,6 +497,25 @@
                InfobarBannerPresentationState::NotPresented;
       }));
 
+  AddSecondInfobar();
+  EXPECT_TRUE(base::test::ios::WaitUntilConditionOrTimeout(
+      base::test::ios::kWaitForUIElementTimeout, ^bool {
+        return infobar_container_coordinator_.infobarBannerState ==
+               InfobarBannerPresentationState::Presented;
+      }));
+  ASSERT_EQ(infobar_container_coordinator_.infobarBannerState,
+            InfobarBannerPresentationState::Presented);
+  ASSERT_EQ(NSUInteger(2),
+            infobar_container_coordinator_.childCoordinators.count);
+
+  [infobar_container_coordinator_ dismissInfobarBannerAnimated:NO
+                                                    completion:nil];
+  ASSERT_TRUE(base::test::ios::WaitUntilConditionOrTimeout(
+      base::test::ios::kWaitForUIElementTimeout, ^bool {
+        return infobar_container_coordinator_.infobarBannerState ==
+               InfobarBannerPresentationState::NotPresented;
+      }));
+
   web_state_list_->CloseWebStateAt(0, 0);
 
   ASSERT_TRUE(base::test::ios::WaitUntilConditionOrTimeout(
@@ -494,3 +528,53 @@
   ASSERT_EQ(NSUInteger(0),
             infobar_container_coordinator_.childCoordinators.count);
 }
+
+// Tests that the ChildCoordinators are deleted once they stop.
+TEST_F(InfobarContainerCoordinatorTest, TestInfobarChildCoordinatorCountStop) {
+  AddInfobar();
+
+  EXPECT_TRUE(base::test::ios::WaitUntilConditionOrTimeout(
+      base::test::ios::kWaitForUIElementTimeout, ^bool {
+        return infobar_container_coordinator_.infobarBannerState ==
+               InfobarBannerPresentationState::Presented;
+      }));
+  ASSERT_EQ(infobar_container_coordinator_.infobarBannerState,
+            InfobarBannerPresentationState::Presented);
+
+  ASSERT_EQ(NSUInteger(1),
+            infobar_container_coordinator_.childCoordinators.count);
+  ASSERT_EQ(infobar_container_coordinator_.infobarBannerState,
+            InfobarBannerPresentationState::Presented);
+
+  [infobar_container_coordinator_ dismissInfobarBannerAnimated:NO
+                                                    completion:nil];
+  ASSERT_TRUE(base::test::ios::WaitUntilConditionOrTimeout(
+      base::test::ios::kWaitForUIElementTimeout, ^bool {
+        return infobar_container_coordinator_.infobarBannerState ==
+               InfobarBannerPresentationState::NotPresented;
+      }));
+
+  AddSecondInfobar();
+  EXPECT_TRUE(base::test::ios::WaitUntilConditionOrTimeout(
+      base::test::ios::kWaitForUIElementTimeout, ^bool {
+        return infobar_container_coordinator_.infobarBannerState ==
+               InfobarBannerPresentationState::Presented;
+      }));
+  ASSERT_EQ(infobar_container_coordinator_.infobarBannerState,
+            InfobarBannerPresentationState::Presented);
+  ASSERT_EQ(NSUInteger(2),
+            infobar_container_coordinator_.childCoordinators.count);
+
+  [infobar_container_coordinator_ dismissInfobarBannerAnimated:NO
+                                                    completion:nil];
+  ASSERT_TRUE(base::test::ios::WaitUntilConditionOrTimeout(
+      base::test::ios::kWaitForUIElementTimeout, ^bool {
+        return infobar_container_coordinator_.infobarBannerState ==
+               InfobarBannerPresentationState::NotPresented;
+      }));
+
+  // Stop the first Coordinator.
+  [coordinator_ stop];
+  ASSERT_EQ(NSUInteger(1),
+            infobar_container_coordinator_.childCoordinators.count);
+}
diff --git a/ios/chrome/browser/ui/infobars/legacy_infobar_container_view_controller.mm b/ios/chrome/browser/ui/infobars/legacy_infobar_container_view_controller.mm
index 863c52e..93b76c9 100644
--- a/ios/chrome/browser/ui/infobars/legacy_infobar_container_view_controller.mm
+++ b/ios/chrome/browser/ui/infobars/legacy_infobar_container_view_controller.mm
@@ -92,6 +92,11 @@
   ]];
 }
 
+- (void)infobarManagerWillChange {
+  // NO-OP. This legacy container doesn't need to clean up any state after the
+  // InfobarManager has changed.
+}
+
 - (void)setUserInteractionEnabled:(BOOL)enabled {
   [self.view setUserInteractionEnabled:enabled];
 }
diff --git a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_row.mm b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_row.mm
index fe8c33d..f08518fe 100644
--- a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_row.mm
+++ b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_row.mm
@@ -55,6 +55,10 @@
   if (self) {
     self.isAccessibilityElement = YES;
     self.backgroundColor = UIColor.clearColor;
+    self.selectedBackgroundView = [[UIView alloc] initWithFrame:CGRectZero];
+    self.selectedBackgroundView.backgroundColor = color::IncognitoDynamicColor(
+        _incognito, [UIColor colorNamed:kTableViewRowHighlightColor],
+        [UIColor colorNamed:kTableViewRowHighlightDarkColor]);
 
     _incognito = incognito;
 
@@ -143,27 +147,6 @@
   _imageView.frame = frame;
 }
 
-- (void)updateHighlightBackground:(BOOL)highlighted {
-  // Set the background color to match the color of selected table view cells
-  // when their selection style is UITableViewCellSelectionStyleGray.
-  if (highlighted) {
-    self.backgroundColor = _incognito ? [UIColor colorWithWhite:1 alpha:0.1]
-                                      : [UIColor colorWithWhite:0 alpha:0.05];
-  } else {
-    self.backgroundColor = [UIColor clearColor];
-  }
-}
-
-- (void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated {
-  [super setHighlighted:highlighted animated:animated];
-  [self updateHighlightBackground:highlighted];
-}
-
-- (void)setHighlighted:(BOOL)highlighted {
-  [super setHighlighted:highlighted];
-  [self updateHighlightBackground:highlighted];
-}
-
 - (void)setTabMatch:(BOOL)tabMatch {
   _tabMatch = tabMatch;
   [self updateTrailingButtonImages];
diff --git a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_row_cell.mm b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_row_cell.mm
index bdc2bf3..132c29e 100644
--- a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_row_cell.mm
+++ b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_row_cell.mm
@@ -66,6 +66,11 @@
               reuseIdentifier:(NSString*)reuseIdentifier {
   self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
   if (self) {
+    self.selectedBackgroundView = [[UIView alloc] initWithFrame:CGRectZero];
+    self.selectedBackgroundView.backgroundColor = color::IncognitoDynamicColor(
+        _incognito, [UIColor colorNamed:kTableViewRowHighlightColor],
+        [UIColor colorNamed:kTableViewRowHighlightDarkColor]);
+
     _textTruncatingLabel =
         [[OmniboxPopupTruncatingLabel alloc] initWithFrame:CGRectZero];
     _textTruncatingLabel.translatesAutoresizingMaskIntoConstraints = NO;
diff --git a/ios/chrome/browser/ui/popup_menu/cells/popup_menu_navigation_item.mm b/ios/chrome/browser/ui/popup_menu/cells/popup_menu_navigation_item.mm
index 643315a..7e539bd 100644
--- a/ios/chrome/browser/ui/popup_menu/cells/popup_menu_navigation_item.mm
+++ b/ios/chrome/browser/ui/popup_menu/cells/popup_menu_navigation_item.mm
@@ -7,6 +7,7 @@
 #include "base/logging.h"
 #import "ios/chrome/browser/ui/popup_menu/public/popup_menu_ui_constants.h"
 #import "ios/chrome/browser/ui/table_view/chrome_table_view_styler.h"
+#import "ios/chrome/common/colors/semantic_color_names.h"
 #import "ios/chrome/common/ui_util/constraints_ui_util.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -17,7 +18,6 @@
 const CGFloat kImageSize = 16;
 const CGFloat kImageCornerRadius = 2;
 const CGFloat kFaviconBackgroundSize = 28;
-const CGFloat kFaviconBackgroundColorAlpha = 0.03;
 const CGFloat kFaviconBackgroundCornerRadius = 7;
 const CGFloat kCellHeight = 44;
 const CGFloat kIconTextMargin = 11;
@@ -87,7 +87,7 @@
   if (self) {
     UIView* selectedBackgroundView = [[UIView alloc] init];
     selectedBackgroundView.backgroundColor =
-        [UIColor colorWithWhite:0 alpha:kSelectedItemBackgroundAlpha];
+        [UIColor colorNamed:kTableViewRowHighlightColor];
     self.selectedBackgroundView = selectedBackgroundView;
 
     _titleLabel = [[UILabel alloc] init];
@@ -98,7 +98,7 @@
     UIView* faviconBackground = [[UIView alloc] init];
     faviconBackground.translatesAutoresizingMaskIntoConstraints = NO;
     faviconBackground.backgroundColor =
-        [UIColor colorWithWhite:0 alpha:kFaviconBackgroundColorAlpha];
+        [UIColor colorNamed:kFaviconBackgroundColor];
     faviconBackground.layer.cornerRadius = kFaviconBackgroundCornerRadius;
 
     _faviconImageView = [[UIImageView alloc] init];
diff --git a/ios/chrome/browser/ui/popup_menu/public/cells/BUILD.gn b/ios/chrome/browser/ui/popup_menu/public/cells/BUILD.gn
index 6013cbc..298ea6ca0 100644
--- a/ios/chrome/browser/ui/popup_menu/public/cells/BUILD.gn
+++ b/ios/chrome/browser/ui/popup_menu/public/cells/BUILD.gn
@@ -10,6 +10,7 @@
     "popup_menu_item.h",
   ]
   deps = [
+    "resources:popup_menu_separator_color",
     "//ios/chrome/browser/ui/table_view/cells",
   ]
   libs = [ "UIKit.framework" ]
diff --git a/ios/chrome/browser/ui/popup_menu/public/cells/popup_menu_footer_item.mm b/ios/chrome/browser/ui/popup_menu/public/cells/popup_menu_footer_item.mm
index 73de9a4..c43672a 100644
--- a/ios/chrome/browser/ui/popup_menu/public/cells/popup_menu_footer_item.mm
+++ b/ios/chrome/browser/ui/popup_menu/public/cells/popup_menu_footer_item.mm
@@ -42,7 +42,8 @@
   if (self) {
     UIView* separator = [[UIView alloc] init];
     separator.translatesAutoresizingMaskIntoConstraints = NO;
-    separator.backgroundColor = [UIColor colorWithWhite:0 alpha:0.05];
+    separator.backgroundColor =
+        [UIColor colorNamed:@"popup_menu_separator_color"];
     [self.contentView addSubview:separator];
     [NSLayoutConstraint activateConstraints:@[
       [separator.heightAnchor constraintEqualToConstant:kSeparatorHeight],
diff --git a/ios/chrome/browser/ui/popup_menu/public/cells/resources/BUILD.gn b/ios/chrome/browser/ui/popup_menu/public/cells/resources/BUILD.gn
new file mode 100644
index 0000000..d83028a
--- /dev/null
+++ b/ios/chrome/browser/ui/popup_menu/public/cells/resources/BUILD.gn
@@ -0,0 +1,11 @@
+# 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.
+
+import("//build/config/ios/asset_catalog.gni")
+
+colorset("popup_menu_separator_color") {
+  sources = [
+    "popup_menu_separator_color.colorset/Contents.json",
+  ]
+}
diff --git a/ios/chrome/browser/ui/popup_menu/public/cells/resources/popup_menu_separator_color.colorset/Contents.json b/ios/chrome/browser/ui/popup_menu/public/cells/resources/popup_menu_separator_color.colorset/Contents.json
new file mode 100644
index 0000000..5c1e209
--- /dev/null
+++ b/ios/chrome/browser/ui/popup_menu/public/cells/resources/popup_menu_separator_color.colorset/Contents.json
@@ -0,0 +1,38 @@
+{
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  },
+  "colors" : [
+    {
+      "idiom" : "universal",
+      "color" : {
+        "color-space" : "display-p3",
+        "components" : {
+          "red" : "0xE8",
+          "alpha" : "1.000",
+          "blue" : "0xEC",
+          "green" : "0xEA"
+        }
+      }
+    },
+    {
+      "idiom" : "universal",
+      "appearances" : [
+        {
+          "appearance" : "luminosity",
+          "value" : "dark"
+        }
+      ],
+      "color" : {
+        "color-space" : "display-p3",
+        "components" : {
+          "red" : "0x47",
+          "alpha" : "1.000",
+          "blue" : "0x50",
+          "green" : "0x4C"
+        }
+      }
+    }
+  ]
+}
\ No newline at end of file
diff --git a/ios/chrome/browser/ui/settings/autofill/BUILD.gn b/ios/chrome/browser/ui/settings/autofill/BUILD.gn
index edf65ca..ef46670 100644
--- a/ios/chrome/browser/ui/settings/autofill/BUILD.gn
+++ b/ios/chrome/browser/ui/settings/autofill/BUILD.gn
@@ -5,8 +5,14 @@
 source_set("autofill") {
   configs += [ "//build/config/compiler:enable_arc" ]
   sources = [
+    "autofill_add_credit_card_coordinator.h",
+    "autofill_add_credit_card_coordinator.mm",
+    "autofill_add_credit_card_mediator.h",
+    "autofill_add_credit_card_mediator.mm",
+    "autofill_add_credit_card_mediator_delegate.h",
     "autofill_add_credit_card_view_controller.h",
     "autofill_add_credit_card_view_controller.mm",
+    "autofill_add_credit_card_view_controller_delegate.h",
     "autofill_credit_card_edit_table_view_controller.h",
     "autofill_credit_card_edit_table_view_controller.mm",
     "autofill_credit_card_table_view_controller.h",
@@ -31,10 +37,12 @@
     "//ios/chrome/browser/autofill",
     "//ios/chrome/browser/browser_state",
     "//ios/chrome/browser/ui:feature_flags",
+    "//ios/chrome/browser/ui/alert_coordinator",
     "//ios/chrome/browser/ui/autofill",
     "//ios/chrome/browser/ui/autofill:autofill_ui",
     "//ios/chrome/browser/ui/autofill/cells",
     "//ios/chrome/browser/ui/commands",
+    "//ios/chrome/browser/ui/coordinators:chrome_coordinators",
     "//ios/chrome/browser/ui/settings:settings_root",
     "//ios/chrome/browser/ui/settings/autofill/cells",
     "//ios/chrome/browser/ui/settings/cells",
diff --git a/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_coordinator.h b/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_coordinator.h
new file mode 100644
index 0000000..da1ba61
--- /dev/null
+++ b/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_coordinator.h
@@ -0,0 +1,17 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_UI_SETTINGS_AUTOFILL_AUTOFILL_ADD_CREDIT_CARD_COORDINATOR_H_
+#define IOS_CHROME_BROWSER_UI_SETTINGS_AUTOFILL_AUTOFILL_ADD_CREDIT_CARD_COORDINATOR_H_
+
+#include <UIKit/UIKit.h>
+
+#import "ios/chrome/browser/ui/coordinators/chrome_coordinator.h"
+
+// The coordinator for add credit card screen.
+@interface AutofillAddCreditCardCoordinator : ChromeCoordinator
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_UI_SETTINGS_AUTOFILL_AUTOFILL_ADD_CREDIT_CARD_COORDINATOR_H_
diff --git a/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_coordinator.mm b/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_coordinator.mm
new file mode 100644
index 0000000..78e4f25
--- /dev/null
+++ b/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_coordinator.mm
@@ -0,0 +1,98 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_coordinator.h"
+
+#include "components/autofill/core/browser/personal_data_manager.h"
+#import "components/autofill/ios/browser/personal_data_manager_observer_bridge.h"
+#include "ios/chrome/browser/autofill/personal_data_manager_factory.h"
+#import "ios/chrome/browser/ui/alert_coordinator/alert_coordinator.h"
+#import "ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_mediator.h"
+#import "ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_mediator_delegate.h"
+#import "ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_view_controller.h"
+#include "ios/chrome/grit/ios_strings.h"
+#include "ui/base/l10n/l10n_util_mac.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+@interface AutofillAddCreditCardCoordinator () <AddCreditCardMediatorDelegate>
+
+// Displays message for invalid credit card data.
+@property(nonatomic, strong) AlertCoordinator* alertCoordinator;
+
+// The view controller attached to this coordinator.
+@property(nonatomic, strong)
+    AutofillAddCreditCardViewController* addCreditCardViewController;
+
+// The mediator for the view controller attatched to this coordinator.
+@property(nonatomic, strong) AutofillAddCreditCardMediator* mediator;
+
+@end
+
+@implementation AutofillAddCreditCardCoordinator
+
+- (void)start {
+  autofill::PersonalDataManager* personalDataManager =
+      autofill::PersonalDataManagerFactory::GetForBrowserState(
+          self.browserState);
+
+  self.mediator = [[AutofillAddCreditCardMediator alloc]
+         initWithDelegate:self
+      personalDataManager:personalDataManager];
+
+  self.addCreditCardViewController =
+      [[AutofillAddCreditCardViewController alloc]
+          initWithDelegate:self.mediator];
+
+  UINavigationController* navigationController = [[UINavigationController alloc]
+      initWithRootViewController:self.addCreditCardViewController];
+
+  [self.baseViewController presentViewController:navigationController
+                                        animated:YES
+                                      completion:nil];
+}
+
+- (void)stop {
+  [self.addCreditCardViewController.navigationController
+      dismissViewControllerAnimated:YES
+                         completion:nil];
+  self.addCreditCardViewController = nil;
+  self.mediator = nil;
+}
+
+#pragma mark - AddCreditCardMediatorDelegate
+
+- (void)creditCardMediatorDidFinish:(AutofillAddCreditCardMediator*)mediator {
+  [self stop];
+}
+
+- (void)creditCardMediatorHasInvalidCardNumber:
+    (AutofillAddCreditCardMediator*)mediator {
+  [self showAlertWithMessage:
+            l10n_util::GetNSString(
+                IDS_IOS_ADD_CREDIT_CARD_INVALID_CARD_NUMBER_ALERT)];
+}
+
+- (void)creditCardMediatorHasInvalidExpirationDate:
+    (AutofillAddCreditCardMediator*)mediator {
+  [self showAlertWithMessage:
+            l10n_util::GetNSString(
+                IDS_IOS_ADD_CREDIT_CARD_INVALID_EXPIRATION_DATE_ALERT)];
+}
+
+#pragma mark - Helper Methods
+
+// Shows alert with received message by |AlertCoordinator|.
+- (void)showAlertWithMessage:(NSString*)message {
+  self.alertCoordinator = [[AlertCoordinator alloc]
+      initWithBaseViewController:self.addCreditCardViewController
+                           title:message
+                         message:nil];
+
+  [self.alertCoordinator start];
+}
+
+@end
diff --git a/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_mediator.h b/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_mediator.h
new file mode 100644
index 0000000..66eaafd
--- /dev/null
+++ b/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_mediator.h
@@ -0,0 +1,32 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_UI_SETTINGS_AUTOFILL_AUTOFILL_ADD_CREDIT_CARD_MEDIATOR_H_
+#define IOS_CHROME_BROWSER_UI_SETTINGS_AUTOFILL_AUTOFILL_ADD_CREDIT_CARD_MEDIATOR_H_
+
+#import <Foundation/Foundation.h>
+
+#import "ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_mediator_delegate.h"
+#import "ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_view_controller_delegate.h"
+
+namespace autofill {
+class PersonalDataManager;
+}
+
+// The Mediator for validating and saving the credit card.
+@interface AutofillAddCreditCardMediator
+    : NSObject <AddCreditCardViewControllerDelegate>
+
+// Designated initializer. |addCreditCardMediatorDelegate| and |dataManager|
+// should not be nil.
+- (instancetype)initWithDelegate:(id<AddCreditCardMediatorDelegate>)
+                                     addCreditCardMediatorDelegate
+             personalDataManager:(autofill::PersonalDataManager*)dataManager
+    NS_DESIGNATED_INITIALIZER;
+
+- (instancetype)init NS_UNAVAILABLE;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_UI_SETTINGS_AUTOFILL_AUTOFILL_ADD_CREDIT_CARD_MEDIATOR_H_
diff --git a/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_mediator.mm b/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_mediator.mm
new file mode 100644
index 0000000..5c560fb0
--- /dev/null
+++ b/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_mediator.mm
@@ -0,0 +1,92 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_mediator.h"
+
+#include "base/strings/sys_string_conversions.h"
+#include "components/autofill/core/browser/data_model/credit_card.h"
+#include "components/autofill/core/browser/personal_data_manager.h"
+#include "ios/chrome/browser/application_context.h"
+#import "ios/chrome/browser/ui/autofill/autofill_ui_type.h"
+#import "ios/chrome/browser/ui/autofill/autofill_ui_type_util.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+@interface AutofillAddCreditCardMediator ()
+
+// Used for adding new CreditCard object.
+@property(nonatomic, assign) autofill::PersonalDataManager* personalDataManager;
+
+// This property is for an interface which sends a response about saving the
+// credit card either the credit card is valid or it is invalid.
+@property(nonatomic, weak) id<AddCreditCardMediatorDelegate>
+    addCreditCardMediatorDelegate;
+
+@end
+
+@implementation AutofillAddCreditCardMediator
+
+- (instancetype)initWithDelegate:(id<AddCreditCardMediatorDelegate>)
+                                     addCreditCardMediatorDelegate
+             personalDataManager:(autofill::PersonalDataManager*)dataManager {
+  self = [super init];
+
+  if (self) {
+    DCHECK(dataManager);
+    _personalDataManager = dataManager;
+    _addCreditCardMediatorDelegate = addCreditCardMediatorDelegate;
+  }
+
+  return self;
+}
+
+#pragma mark - AddCreditCardViewControllerDelegate
+
+- (void)addCreditCardViewController:(UIViewController*)viewController
+        addCreditCardWithHolderName:(NSString*)cardHolderName
+                         cardNumber:(NSString*)cardNumber
+                    expirationMonth:(NSString*)expirationMonth
+                     expirationYear:(NSString*)expirationYear {
+  autofill::CreditCard creditCard = autofill::CreditCard();
+
+  const std::string& appLocal = GetApplicationContext()->GetApplicationLocale();
+  creditCard.SetInfo(autofill::AutofillType(AutofillTypeFromAutofillUIType(
+                         AutofillUITypeCreditCardHolderFullName)),
+                     base::SysNSStringToUTF16(cardHolderName), appLocal);
+
+  creditCard.SetInfo(autofill::AutofillType(AutofillTypeFromAutofillUIType(
+                         AutofillUITypeCreditCardNumber)),
+                     base::SysNSStringToUTF16(cardNumber), appLocal);
+
+  creditCard.SetInfo(autofill::AutofillType(AutofillTypeFromAutofillUIType(
+                         AutofillUITypeCreditCardExpMonth)),
+                     base::SysNSStringToUTF16(expirationMonth), appLocal);
+
+  creditCard.SetInfo(autofill::AutofillType(AutofillTypeFromAutofillUIType(
+                         AutofillUITypeCreditCardExpYear)),
+                     base::SysNSStringToUTF16(expirationYear), appLocal);
+
+  if (!creditCard.HasValidCardNumber()) {
+    [self.addCreditCardMediatorDelegate
+        creditCardMediatorHasInvalidCardNumber:self];
+    return;
+  }
+
+  if (!creditCard.HasValidExpirationDate()) {
+    [self.addCreditCardMediatorDelegate
+        creditCardMediatorHasInvalidExpirationDate:self];
+    return;
+  }
+
+  self.personalDataManager->AddCreditCard(creditCard);
+  [self.addCreditCardMediatorDelegate creditCardMediatorDidFinish:self];
+}
+
+- (void)addCreditCardViewControllerDidCancel:(UIViewController*)viewController {
+  [self.addCreditCardMediatorDelegate creditCardMediatorDidFinish:self];
+}
+
+@end
diff --git a/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_mediator_delegate.h b/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_mediator_delegate.h
new file mode 100644
index 0000000..35d5d61
--- /dev/null
+++ b/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_mediator_delegate.h
@@ -0,0 +1,27 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_UI_SETTINGS_AUTOFILL_AUTOFILL_ADD_CREDIT_CARD_MEDIATOR_DELEGATE_H_
+#define IOS_CHROME_BROWSER_UI_SETTINGS_AUTOFILL_AUTOFILL_ADD_CREDIT_CARD_MEDIATOR_DELEGATE_H_
+
+@class AutofillAddCreditCardMediator;
+
+// This delegate is notified of the result of saving a credit card.
+@protocol AddCreditCardMediatorDelegate
+
+// Notifies that the credit card number is invalid.
+- (void)creditCardMediatorHasInvalidCardNumber:
+    (AutofillAddCreditCardMediator*)mediator;
+
+// Notifies that the credit card expiration date is invalid.
+- (void)creditCardMediatorHasInvalidExpirationDate:
+    (AutofillAddCreditCardMediator*)mediator;
+
+// Notifies that the credit card is valid or the user cancel the view
+// controller.
+- (void)creditCardMediatorDidFinish:(AutofillAddCreditCardMediator*)mediator;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_UI_SETTINGS_AUTOFILL_AUTOFILL_ADD_CREDIT_CARD_MEDIATOR_DELEGATE_H_
diff --git a/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_view_controller.h b/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_view_controller.h
index dd2c67cf..53226d84 100644
--- a/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_view_controller.h
+++ b/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_view_controller.h
@@ -7,14 +7,20 @@
 
 #import <UIKit/UIKit.h>
 
+#import "ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_view_controller_delegate.h"
 #import "ios/chrome/browser/ui/settings/settings_root_table_view_controller.h"
 
 // The view controller for adding new credit card.
 @interface AutofillAddCreditCardViewController : SettingsRootTableViewController
 
-// Initializes a AutofillAddCreditCardViewController with
-// A default style and |ChromeTableViewControllerStyleNoAppBar|.
-- (instancetype)init;
+// Initializes a AutofillAddCreditCardViewController with passed delegate.
+- (instancetype)initWithDelegate:
+    (id<AddCreditCardViewControllerDelegate>)delegate NS_DESIGNATED_INITIALIZER;
+
+- (instancetype)initWithTableViewStyle:(UITableViewStyle)style
+                           appBarStyle:
+                               (ChromeTableViewControllerStyle)appBarStyle
+    NS_UNAVAILABLE;
 
 @end
 
diff --git a/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_view_controller.mm b/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_view_controller.mm
index 80ed308..245ebe7c 100644
--- a/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_view_controller.mm
@@ -5,6 +5,7 @@
 #import "ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_view_controller.h"
 
 #include "base/feature_list.h"
+#include "base/mac/foundation_util.h"
 #import "ios/chrome/browser/ui/autofill/cells/autofill_edit_item.h"
 #import "ios/chrome/browser/ui/table_view/cells/table_view_text_button_item.h"
 #import "ios/chrome/browser/ui/table_view/cells/table_view_text_edit_item.h"
@@ -37,14 +38,28 @@
 
 }  // namespace
 
+@interface AutofillAddCreditCardViewController ()
+
+// The AddCreditCardViewControllerDelegate for this ViewController.
+@property(nonatomic, weak) id<AddCreditCardViewControllerDelegate> delegate;
+
+@end
+
 @implementation AutofillAddCreditCardViewController
 
-- (instancetype)init {
+- (instancetype)initWithDelegate:
+    (id<AddCreditCardViewControllerDelegate>)delegate {
   UITableViewStyle style = base::FeatureList::IsEnabled(kSettingsRefresh)
                                ? UITableViewStylePlain
                                : UITableViewStyleGrouped;
-  return [super initWithTableViewStyle:style
+  self = [super initWithTableViewStyle:style
                            appBarStyle:ChromeTableViewControllerStyleNoAppBar];
+
+  if (self) {
+    _delegate = delegate;
+  }
+
+  return self;
 }
 
 - (void)viewDidLoad {
@@ -66,7 +81,7 @@
       initWithTitle:l10n_util::GetNSString(IDS_IOS_NAVIGATION_BAR_ADD_BUTTON)
               style:UIBarButtonItemStyleDone
              target:self
-             action:nil];
+             action:@selector(didTapAddButton:)];
   [self loadModel];
 }
 
@@ -139,9 +154,46 @@
 
 #pragma mark - Private
 
+// Reads the data from text fields and sends it to the mediator.
+- (void)didTapAddButton:(id)sender {
+  NSString* cardHolderName = [self readTextFromItemtype:ItemTypeName
+                                      sectionIdentifier:SectionIdentifierName];
+
+  NSString* cardNumber =
+      [self readTextFromItemtype:ItemTypeCardNumber
+               sectionIdentifier:SectionIdentifierCreditCardDetails];
+
+  NSString* expirationMonth =
+      [self readTextFromItemtype:ItemTypeExpirationMonth
+               sectionIdentifier:SectionIdentifierCreditCardDetails];
+
+  NSString* expirationYear =
+      [self readTextFromItemtype:ItemTypeExpirationYear
+               sectionIdentifier:SectionIdentifierCreditCardDetails];
+
+  [self.delegate addCreditCardViewController:self
+                 addCreditCardWithHolderName:cardHolderName
+                                  cardNumber:cardNumber
+                             expirationMonth:expirationMonth
+                              expirationYear:expirationYear];
+}
+
+// Reads and returns the data from the item with passed |itemType| and
+// |sectionIdentifier|.
+- (NSString*)readTextFromItemtype:(NSInteger)itemType
+                sectionIdentifier:(NSInteger)sectionIdentifier {
+  NSIndexPath* path =
+      [self.tableViewModel indexPathForItemType:itemType
+                              sectionIdentifier:sectionIdentifier];
+  AutofillEditItem* item = base::mac::ObjCCastStrict<AutofillEditItem>(
+      [self.tableViewModel itemAtIndexPath:path]);
+  NSString* text = item.textFieldValue;
+  return text;
+}
+
 // Dimisses this view controller.
 - (void)handleCancelButton:(id)sender {
-  [self.navigationController dismissViewControllerAnimated:YES completion:nil];
+  [self.delegate addCreditCardViewControllerDidCancel:self];
 }
 
 // Returns initialized tableViewItem with passed arguments.
diff --git a/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_view_controller_delegate.h b/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_view_controller_delegate.h
new file mode 100644
index 0000000..0d8dbac0
--- /dev/null
+++ b/ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_view_controller_delegate.h
@@ -0,0 +1,26 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_UI_SETTINGS_AUTOFILL_AUTOFILL_ADD_CREDIT_CARD_VIEW_CONTROLLER_DELEGATE_H_
+#define IOS_CHROME_BROWSER_UI_SETTINGS_AUTOFILL_AUTOFILL_ADD_CREDIT_CARD_VIEW_CONTROLLER_DELEGATE_H_
+
+@class UIViewController;
+
+// Delegate manages adding a new credit card.
+@protocol AddCreditCardViewControllerDelegate
+
+// Receives a credit card data. Implement this method to save a new credit card.
+- (void)addCreditCardViewController:(UIViewController*)viewController
+        addCreditCardWithHolderName:(NSString*)cardHolderName
+                         cardNumber:(NSString*)cardNumber
+                    expirationMonth:(NSString*)expirationMonth
+                     expirationYear:(NSString*)expirationYear;
+
+// Notifies the class which conform this delegate for cancel button tap in
+// received view controller.
+- (void)addCreditCardViewControllerDidCancel:(UIViewController*)viewController;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_UI_SETTINGS_AUTOFILL_AUTOFILL_ADD_CREDIT_CARD_VIEW_CONTROLLER_DELEGATE_H_
diff --git a/ios/chrome/browser/ui/settings/autofill/autofill_credit_card_table_view_controller.mm b/ios/chrome/browser/ui/settings/autofill/autofill_credit_card_table_view_controller.mm
index 43bff2b..8871589 100644
--- a/ios/chrome/browser/ui/settings/autofill/autofill_credit_card_table_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/autofill/autofill_credit_card_table_view_controller.mm
@@ -17,7 +17,7 @@
 #include "ios/chrome/browser/application_context.h"
 #include "ios/chrome/browser/autofill/personal_data_manager_factory.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
-#import "ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_view_controller.h"
+#import "ios/chrome/browser/ui/settings/autofill/autofill_add_credit_card_coordinator.h"
 #import "ios/chrome/browser/ui/settings/autofill/autofill_credit_card_edit_table_view_controller.h"
 #import "ios/chrome/browser/ui/settings/autofill/cells/autofill_data_item.h"
 #import "ios/chrome/browser/ui/settings/autofill/features.h"
@@ -78,6 +78,10 @@
 // Button to add a new credit card.
 @property(nonatomic, strong) UIBarButtonItem* addPaymentMethodButton;
 
+// Coordinator to add new credit card.
+@property(nonatomic, strong)
+    AutofillAddCreditCardCoordinator* addCreditCardCoordinator;
+
 @end
 
 @implementation AutofillCreditCardTableViewController
@@ -424,13 +428,12 @@
 // credit card details.
 - (void)handleAddPayment:(id)sender {
   DCHECK(base::FeatureList::IsEnabled(kSettingsAddPaymentMethod));
-  AutofillAddCreditCardViewController* addCreditCardViewController =
-      [[AutofillAddCreditCardViewController alloc] init];
 
-  UINavigationController* navigationController = [[UINavigationController alloc]
-      initWithRootViewController:addCreditCardViewController];
+  self.addCreditCardCoordinator = [[AutofillAddCreditCardCoordinator alloc]
+      initWithBaseViewController:self
+                    browserState:_browserState];
 
-  [self presentViewController:navigationController animated:YES completion:nil];
+  [self.addCreditCardCoordinator start];
 }
 
 #pragma mark PersonalDataManagerObserver
diff --git a/ios/chrome/browser/ui/table_view/cells/BUILD.gn b/ios/chrome/browser/ui/table_view/cells/BUILD.gn
index a24bc9a..67305a9 100644
--- a/ios/chrome/browser/ui/table_view/cells/BUILD.gn
+++ b/ios/chrome/browser/ui/table_view/cells/BUILD.gn
@@ -46,7 +46,6 @@
     "resources:table_view_cell_chevron",
     "resources:table_view_cell_edit_icon",
     "resources:table_view_cell_favicon_background",
-    "resources:table_view_favicon_background_color",
     "//base",
     "//base:i18n",
     "//ios/chrome/app/strings",
diff --git a/ios/chrome/browser/ui/table_view/cells/resources/BUILD.gn b/ios/chrome/browser/ui/table_view/cells/resources/BUILD.gn
index 5de516c..b98df7d1 100644
--- a/ios/chrome/browser/ui/table_view/cells/resources/BUILD.gn
+++ b/ios/chrome/browser/ui/table_view/cells/resources/BUILD.gn
@@ -38,9 +38,3 @@
     "table_view_cell_edit_icon.imageset/table_view_cell_edit_icon@3x.png",
   ]
 }
-
-colorset("table_view_favicon_background_color") {
-  sources = [
-    "table_view_favicon_background_color.colorset/Contents.json",
-  ]
-}
diff --git a/ios/chrome/browser/ui/table_view/cells/table_view_url_item.mm b/ios/chrome/browser/ui/table_view/cells/table_view_url_item.mm
index 6d193d3f..8b9a052 100644
--- a/ios/chrome/browser/ui/table_view/cells/table_view_url_item.mm
+++ b/ios/chrome/browser/ui/table_view/cells/table_view_url_item.mm
@@ -150,7 +150,7 @@
     _faviconContainerView =
         [[UIImageView alloc] initWithImage:containerBackground];
     _faviconContainerView.tintColor =
-        [UIColor colorNamed:@"table_view_favicon_background_color"];
+        [UIColor colorNamed:kFaviconBackgroundColor];
 
     _faviconView = [[FaviconView alloc] init];
     _faviconView.contentMode = UIViewContentModeScaleAspectFit;
diff --git a/ios/chrome/browser/web/stop_loading_egtest.mm b/ios/chrome/browser/web/stop_loading_egtest.mm
index 33f6db3..159f6ae 100644
--- a/ios/chrome/browser/web/stop_loading_egtest.mm
+++ b/ios/chrome/browser/web/stop_loading_egtest.mm
@@ -78,15 +78,6 @@
 
 @implementation StopLoadingTestCase
 
-- (void)tearDown {
-  // |testStopLoading| Disables synchronization, so make sure that it is enabled
-  // if that test has failed and did not enable it back.
-  [[GREYConfiguration sharedInstance]
-          setValue:@YES
-      forConfigKey:kGREYConfigKeySynchronizationEnabled];
-  [super tearDown];
-}
-
 // Tests that tapping "Stop" button stops the loading.
 - (void)testStopLoading {
   // Load a page which never finishes loading.
@@ -107,35 +98,32 @@
     // Disable EG synchronization so the framework does not wait until the tab
     // loading spinner becomes idle (which will not happen until the stop button
     // is tapped).
-    [[GREYConfiguration sharedInstance]
-            setValue:@NO
-        forConfigKey:kGREYConfigKeySynchronizationEnabled];
-  }
-
-  // Wait until the page is half loaded.
-  [ChromeEarlGrey waitForWebStateContainingText:kPageText];
-
-  // On iPhone Stop/Reload button is a part of tools menu, so open it.
-  if (![ChromeEarlGrey isIPadIdiom]) {
+    ScopedSynchronizationDisabler disabler;
+    // Wait until the page is half loaded.
+    [ChromeEarlGrey waitForWebStateContainingText:kPageText];
+    // Verify that stop button is visible and reload button is hidden.
+    [[EarlGrey selectElementWithMatcher:chrome_test_util::StopButton()]
+        assertWithMatcher:grey_sufficientlyVisible()];
+    [[EarlGrey selectElementWithMatcher:chrome_test_util::ReloadButton()]
+        assertWithMatcher:grey_notVisible()];
+    // Stop the page loading.
+    [[EarlGrey selectElementWithMatcher:chrome_test_util::StopButton()]
+        performAction:grey_tap()];
+  } else {
+    // Wait until the page is half loaded.
+    [ChromeEarlGrey waitForWebStateContainingText:kPageText];
+    // On iPhone Stop/Reload button is a part of tools menu, so open it.
     [ChromeEarlGreyUI openToolsMenu];
+    // Verify that stop button is visible and reload button is hidden.
+    [[EarlGrey selectElementWithMatcher:chrome_test_util::StopButton()]
+        assertWithMatcher:grey_sufficientlyVisible()];
+    [[EarlGrey selectElementWithMatcher:chrome_test_util::ReloadButton()]
+        assertWithMatcher:grey_notVisible()];
+    // Stop the page loading.
+    [[EarlGrey selectElementWithMatcher:chrome_test_util::StopButton()]
+        performAction:grey_tap()];
   }
 
-  // Verify that stop button is visible and reload button is hidden.
-  [[EarlGrey selectElementWithMatcher:chrome_test_util::StopButton()]
-      assertWithMatcher:grey_sufficientlyVisible()];
-  [[EarlGrey selectElementWithMatcher:chrome_test_util::ReloadButton()]
-      assertWithMatcher:grey_notVisible()];
-
-  // Stop the page loading.
-  [[EarlGrey selectElementWithMatcher:chrome_test_util::StopButton()]
-      performAction:grey_tap()];
-
-  // Enable synchronization back. The spinner should become idle and test
-  // should wait for it.
-  [[GREYConfiguration sharedInstance]
-          setValue:@YES
-      forConfigKey:kGREYConfigKeySynchronizationEnabled];
-
   // Verify that stop button is hidden and reload button is visible.
   if (![ChromeEarlGrey isIPadIdiom]) {
     [ChromeEarlGreyUI openToolsMenu];
diff --git a/ios/chrome/common/colors/OWNERS b/ios/chrome/common/colors/OWNERS
index d4af1cd..5988968 100644
--- a/ios/chrome/common/colors/OWNERS
+++ b/ios/chrome/common/colors/OWNERS
@@ -1,4 +1,4 @@
-javierrobles@chromium.com
+javierrobles@chromium.org
 rkgibson@google.com
 
 # TEAM: ios-directory-owners@chromium.org
diff --git a/ios/chrome/common/colors/resources/BUILD.gn b/ios/chrome/common/colors/resources/BUILD.gn
index 941dde8..4b27783 100644
--- a/ios/chrome/common/colors/resources/BUILD.gn
+++ b/ios/chrome/common/colors/resources/BUILD.gn
@@ -11,6 +11,7 @@
     ":blue_color",
     ":blue_dark_color",
     ":disabled_tint_color",
+    ":favicon_background_color",
     ":green_color",
     ":green_dark_color",
     ":mdc_ink_color",
@@ -60,6 +61,12 @@
   ]
 }
 
+colorset("favicon_background_color") {
+  sources = [
+    "favicon_background_color.colorset/Contents.json",
+  ]
+}
+
 colorset("green_color") {
   sources = [
     "green_color.colorset/Contents.json",
diff --git a/ios/chrome/browser/ui/table_view/cells/resources/table_view_favicon_background_color.colorset/Contents.json b/ios/chrome/common/colors/resources/favicon_background_color.colorset/Contents.json
similarity index 100%
rename from ios/chrome/browser/ui/table_view/cells/resources/table_view_favicon_background_color.colorset/Contents.json
rename to ios/chrome/common/colors/resources/favicon_background_color.colorset/Contents.json
diff --git a/ios/chrome/common/colors/semantic_color_names.h b/ios/chrome/common/colors/semantic_color_names.h
index a7916905..48757ff8 100644
--- a/ios/chrome/common/colors/semantic_color_names.h
+++ b/ios/chrome/common/colors/semantic_color_names.h
@@ -11,6 +11,8 @@
 
 extern NSString* const kBackgroundColor;
 extern NSString* const kDisabledTintColor;
+// Background color used in the rounded squares behind favicons.
+extern NSString* const kFaviconBackgroundColor;
 extern NSString* const kMDCInkColor;
 extern NSString* const kScrimBackgroundColor;
 extern NSString* const kSolidButtonTextColor;
diff --git a/ios/chrome/common/colors/semantic_color_names.mm b/ios/chrome/common/colors/semantic_color_names.mm
index d5080121..f64342c 100644
--- a/ios/chrome/common/colors/semantic_color_names.mm
+++ b/ios/chrome/common/colors/semantic_color_names.mm
@@ -11,6 +11,7 @@
 #pragma mark - Element Colors
 NSString* const kBackgroundColor = @"background_color";
 NSString* const kDisabledTintColor = @"disabled_tint_color";
+NSString* const kFaviconBackgroundColor = @"favicon_background_color";
 NSString* const kMDCInkColor = @"mdc_ink_color";
 NSString* const kScrimBackgroundColor = @"scrim_background_color";
 NSString* const kSolidButtonTextColor = @"solid_button_text_color";
diff --git a/ios/public/provider/chrome/browser/signin/chrome_identity.h b/ios/public/provider/chrome/browser/signin/chrome_identity.h
index 94e4169..c755a07 100644
--- a/ios/public/provider/chrome/browser/signin/chrome_identity.h
+++ b/ios/public/provider/chrome/browser/signin/chrome_identity.h
@@ -28,12 +28,6 @@
 // between apps.
 @property(strong, nonatomic, readonly) NSString* hashedGaiaID;
 
-// Returns the cached hosted domain for the identity (fetched asynchronously).
-// If the value has not been fetched, this property will be nil. Otherwise it
-// will be the hosted domain or an empty string if the account is a consumer
-// account (e.g. gmail.com).
-@property(strong, nonatomic, readonly) NSString* hostedDomain;
-
 @end
 
 #endif  // IOS_PUBLIC_PROVIDER_CHROME_BROWSER_SIGNIN_CHROME_IDENTITY_H_
diff --git a/ios/public/provider/chrome/browser/signin/fake_chrome_identity.h b/ios/public/provider/chrome/browser/signin/fake_chrome_identity.h
index d2584bc..dc32605 100644
--- a/ios/public/provider/chrome/browser/signin/fake_chrome_identity.h
+++ b/ios/public/provider/chrome/browser/signin/fake_chrome_identity.h
@@ -16,13 +16,6 @@
                                   gaiaID:(NSString*)gaiaID
                                     name:(NSString*)name;
 
-// Returns a ChromeIdentity based on |email|, |gaiaID|, |name| and
-// |hostedDomain|. The |hashedGaiaID| property will be derived from |name|.
-+ (FakeChromeIdentity*)identityWithEmail:(NSString*)email
-                                  gaiaID:(NSString*)gaiaID
-                                    name:(NSString*)name
-                            hostedDomain:(NSString*)hostedDomain;
-
 @end
 
 #endif  // IOS_PUBLIC_PROVIDER_CHROME_BROWSER_SIGNIN_FAKE_CHROME_IDENTITY_H_
diff --git a/ios/public/provider/chrome/browser/signin/fake_chrome_identity.mm b/ios/public/provider/chrome/browser/signin/fake_chrome_identity.mm
index a916fecc..2302a68 100644
--- a/ios/public/provider/chrome/browser/signin/fake_chrome_identity.mm
+++ b/ios/public/provider/chrome/browser/signin/fake_chrome_identity.mm
@@ -8,14 +8,11 @@
 #error "This file requires ARC support."
 #endif
 
-#include "components/signin/public/identity_manager/account_info.h"
-
 @implementation FakeChromeIdentity {
   NSString* _userEmail;
   NSString* _gaiaID;
   NSString* _userFullName;
   NSString* _hashedGaiaID;
-  NSString* _hostedDomain;
 }
 
 + (FakeChromeIdentity*)identityWithEmail:(NSString*)email
@@ -23,31 +20,18 @@
                                     name:(NSString*)name {
   return [[FakeChromeIdentity alloc] initWithEmail:email
                                             gaiaID:gaiaID
-                                              name:name
-                                      hostedDomain:@(kNoHostedDomainFound)];
-}
-
-+ (FakeChromeIdentity*)identityWithEmail:(NSString*)email
-                                  gaiaID:(NSString*)gaiaID
-                                    name:(NSString*)name
-                            hostedDomain:(NSString*)hostedDomain {
-  return [[FakeChromeIdentity alloc] initWithEmail:email
-                                            gaiaID:gaiaID
-                                              name:name
-                                      hostedDomain:hostedDomain];
+                                              name:name];
 }
 
 - (instancetype)initWithEmail:(NSString*)email
                        gaiaID:(NSString*)gaiaID
-                         name:(NSString*)name
-                 hostedDomain:(NSString*)hostedDomain {
+                         name:(NSString*)name {
   self = [super init];
   if (self) {
     _userEmail = [email copy];
     _gaiaID = [gaiaID copy];
     _userFullName = [name copy];
     _hashedGaiaID = [NSString stringWithFormat:@"%@_hashID", name];
-    _hostedDomain = hostedDomain;
   }
   return self;
 }
@@ -68,8 +52,4 @@
   return _hashedGaiaID;
 }
 
-- (NSString*)hostedDomain {
-  return _hostedDomain;
-}
-
 @end
diff --git a/ios/web_view/internal/passwords/web_view_password_manager_client.h b/ios/web_view/internal/passwords/web_view_password_manager_client.h
index 2411e50..67f7c75 100644
--- a/ios/web_view/internal/passwords/web_view_password_manager_client.h
+++ b/ios/web_view/internal/passwords/web_view_password_manager_client.h
@@ -101,6 +101,7 @@
   password_manager::PasswordManagerMetricsRecorder* GetMetricsRecorder()
       override;
   signin::IdentityManager* GetIdentityManager() override;
+  scoped_refptr<network::SharedURLLoaderFactory> GetURLLoaderFactory() override;
   bool IsIsolationForPasswordSitesEnabled() const override;
   bool IsNewTabPage() const override;
 
diff --git a/ios/web_view/internal/passwords/web_view_password_manager_client.mm b/ios/web_view/internal/passwords/web_view_password_manager_client.mm
index f6e1b77..75d5159 100644
--- a/ios/web_view/internal/passwords/web_view_password_manager_client.mm
+++ b/ios/web_view/internal/passwords/web_view_password_manager_client.mm
@@ -21,6 +21,7 @@
 #include "ios/web_view/internal/passwords/web_view_password_store_factory.h"
 #include "ios/web_view/internal/web_view_browser_state.h"
 #include "net/cert/cert_status_flags.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "url/gurl.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -186,6 +187,12 @@
   return nullptr;
 }
 
+scoped_refptr<network::SharedURLLoaderFactory>
+WebViewPasswordManagerClient::GetURLLoaderFactory() {
+  NOTREACHED();
+  return nullptr;
+}
+
 void WebViewPasswordManagerClient::PromptUserToEnableAutosignin() {
   // TODO(crbug.com/435048): Implement this method.
 }
diff --git a/media/cdm/BUILD.gn b/media/cdm/BUILD.gn
index 0eceda9..d49e488 100644
--- a/media/cdm/BUILD.gn
+++ b/media/cdm/BUILD.gn
@@ -104,13 +104,6 @@
       ]
     }
   }
-
-  if (is_fuchsia) {
-    sources += [
-      "fuchsia/fuchsia_cdm_factory.cc",
-      "fuchsia/fuchsia_cdm_factory.h",
-    ]
-  }
 }
 
 static_library("cdm_paths") {
diff --git a/media/cdm/fuchsia/fuchsia_cdm_factory.cc b/media/cdm/fuchsia/fuchsia_cdm_factory.cc
deleted file mode 100644
index 612afdd..0000000
--- a/media/cdm/fuchsia/fuchsia_cdm_factory.cc
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "media/cdm/fuchsia/fuchsia_cdm_factory.h"
-
-#include "media/base/bind_to_current_loop.h"
-#include "media/base/key_systems.h"
-#include "media/cdm/aes_decryptor.h"
-#include "url/origin.h"
-
-namespace media {
-
-FuchsiaCdmFactory::FuchsiaCdmFactory() = default;
-
-FuchsiaCdmFactory::~FuchsiaCdmFactory() = default;
-
-void FuchsiaCdmFactory::Create(
-    const std::string& key_system,
-    const url::Origin& security_origin,
-    const CdmConfig& cdm_config,
-    const SessionMessageCB& session_message_cb,
-    const SessionClosedCB& session_closed_cb,
-    const SessionKeysChangeCB& session_keys_change_cb,
-    const SessionExpirationUpdateCB& session_expiration_update_cb,
-    const CdmCreatedCB& cdm_created_cb) {
-  CdmCreatedCB bound_cdm_created_cb = BindToCurrentLoop(cdm_created_cb);
-
-  if (security_origin.opaque()) {
-    std::move(bound_cdm_created_cb).Run(nullptr, "Invalid origin.");
-    return;
-  }
-
-  if (CanUseAesDecryptor(key_system)) {
-    auto cdm = base::MakeRefCounted<AesDecryptor>(
-        session_message_cb, session_closed_cb, session_keys_change_cb,
-        session_expiration_update_cb);
-    std::move(bound_cdm_created_cb).Run(cdm, std::string());
-    return;
-  }
-
-  // TODO(yucliu): Create CDM with platform support.
-  std::move(bound_cdm_created_cb).Run(nullptr, "Unsupported key system.");
-}
-
-}  // namespace media
diff --git a/media/fuchsia/OWNERS b/media/fuchsia/OWNERS
new file mode 100644
index 0000000..50612805
--- /dev/null
+++ b/media/fuchsia/OWNERS
@@ -0,0 +1,3 @@
+sergeyu@chromium.org
+yucliu@chromium.org
+wez@chromium.org
diff --git a/media/fuchsia/cdm/BUILD.gn b/media/fuchsia/cdm/BUILD.gn
new file mode 100644
index 0000000..b0fbc767
--- /dev/null
+++ b/media/fuchsia/cdm/BUILD.gn
@@ -0,0 +1,21 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+assert(is_fuchsia)
+
+source_set("cdm") {
+  sources = [
+    "fuchsia_cdm.cc",
+    "fuchsia_cdm.h",
+    "fuchsia_cdm_factory.cc",
+    "fuchsia_cdm_factory.h",
+  ]
+
+  deps = [
+    "//media",
+    "//media/fuchsia/mojom",
+    "//services/service_manager/public/cpp",
+    "//third_party/fuchsia-sdk/sdk:media_drm",
+  ]
+}
diff --git a/media/fuchsia/cdm/DEPS b/media/fuchsia/cdm/DEPS
new file mode 100644
index 0000000..5860594d
--- /dev/null
+++ b/media/fuchsia/cdm/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+services/service_manager/public",
+]
diff --git a/media/fuchsia/cdm/fuchsia_cdm.cc b/media/fuchsia/cdm/fuchsia_cdm.cc
new file mode 100644
index 0000000..c478eeb
--- /dev/null
+++ b/media/fuchsia/cdm/fuchsia_cdm.cc
@@ -0,0 +1,94 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/fuchsia/cdm/fuchsia_cdm.h"
+
+#include "base/logging.h"
+#include "media/base/callback_registry.h"
+#include "media/base/cdm_promise.h"
+
+namespace media {
+
+FuchsiaCdm::SessionCallbacks::SessionCallbacks() = default;
+FuchsiaCdm::SessionCallbacks::SessionCallbacks(SessionCallbacks&&) = default;
+FuchsiaCdm::SessionCallbacks::~SessionCallbacks() = default;
+FuchsiaCdm::SessionCallbacks& FuchsiaCdm::SessionCallbacks::operator=(
+    SessionCallbacks&&) = default;
+
+FuchsiaCdm::FuchsiaCdm(fuchsia::media::drm::ContentDecryptionModulePtr cdm,
+                       SessionCallbacks callbacks)
+    : cdm_(std::move(cdm)), session_callbacks_(std::move(callbacks)) {
+  DCHECK(cdm_);
+}
+
+FuchsiaCdm::~FuchsiaCdm() = default;
+
+void FuchsiaCdm::SetServerCertificate(
+    const std::vector<uint8_t>& certificate,
+    std::unique_ptr<SimpleCdmPromise> promise) {
+  NOTIMPLEMENTED();
+  promise->reject(CdmPromise::Exception::NOT_SUPPORTED_ERROR, 0,
+                  "not implemented");
+}
+
+void FuchsiaCdm::CreateSessionAndGenerateRequest(
+    CdmSessionType session_type,
+    EmeInitDataType init_data_type,
+    const std::vector<uint8_t>& init_data,
+    std::unique_ptr<NewSessionCdmPromise> promise) {
+  NOTIMPLEMENTED();
+  promise->reject(CdmPromise::Exception::NOT_SUPPORTED_ERROR, 0,
+                  "not implemented");
+}
+
+void FuchsiaCdm::LoadSession(CdmSessionType session_type,
+                             const std::string& session_id,
+                             std::unique_ptr<NewSessionCdmPromise> promise) {
+  NOTIMPLEMENTED();
+  promise->reject(CdmPromise::Exception::NOT_SUPPORTED_ERROR, 0,
+                  "not implemented");
+}
+
+void FuchsiaCdm::UpdateSession(const std::string& session_id,
+                               const std::vector<uint8_t>& response,
+                               std::unique_ptr<SimpleCdmPromise> promise) {
+  NOTIMPLEMENTED();
+  promise->reject(CdmPromise::Exception::NOT_SUPPORTED_ERROR, 0,
+                  "not implemented");
+}
+
+void FuchsiaCdm::CloseSession(const std::string& session_id,
+                              std::unique_ptr<SimpleCdmPromise> promise) {
+  NOTIMPLEMENTED();
+  promise->reject(CdmPromise::Exception::NOT_SUPPORTED_ERROR, 0,
+                  "not implemented");
+}
+
+void FuchsiaCdm::RemoveSession(const std::string& session_id,
+                               std::unique_ptr<SimpleCdmPromise> promise) {
+  NOTIMPLEMENTED();
+  promise->reject(CdmPromise::Exception::NOT_SUPPORTED_ERROR, 0,
+                  "not implemented");
+}
+
+CdmContext* FuchsiaCdm::GetCdmContext() {
+  return this;
+}
+
+std::unique_ptr<CallbackRegistration> FuchsiaCdm::RegisterEventCB(
+    EventCB event_cb) {
+  NOTIMPLEMENTED();
+  return nullptr;
+}
+
+Decryptor* FuchsiaCdm::GetDecryptor() {
+  NOTIMPLEMENTED();
+  return nullptr;
+}
+
+int FuchsiaCdm::GetCdmId() const {
+  return kInvalidCdmId;
+}
+
+}  // namespace media
diff --git a/media/fuchsia/cdm/fuchsia_cdm.h b/media/fuchsia/cdm/fuchsia_cdm.h
new file mode 100644
index 0000000..52e8f221
--- /dev/null
+++ b/media/fuchsia/cdm/fuchsia_cdm.h
@@ -0,0 +1,73 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MEDIA_FUCHSIA_CDM_FUCHSIA_CDM_H_
+#define MEDIA_FUCHSIA_CDM_FUCHSIA_CDM_H_
+
+#include <fuchsia/media/drm/cpp/fidl.h>
+
+#include "base/macros.h"
+#include "media/base/cdm_context.h"
+#include "media/base/content_decryption_module.h"
+
+namespace media {
+
+class FuchsiaCdm : public ContentDecryptionModule, public CdmContext {
+ public:
+  struct SessionCallbacks {
+    SessionCallbacks();
+    SessionCallbacks(SessionCallbacks&&);
+    ~SessionCallbacks();
+
+    SessionCallbacks& operator=(SessionCallbacks&&);
+
+    SessionMessageCB message_cb;
+    SessionClosedCB closed_cb;
+    SessionKeysChangeCB keys_change_cb;
+    SessionExpirationUpdateCB expiration_update_cb;
+
+    DISALLOW_COPY_AND_ASSIGN(SessionCallbacks);
+  };
+
+  FuchsiaCdm(fuchsia::media::drm::ContentDecryptionModulePtr cdm,
+             SessionCallbacks callbacks);
+
+  // ContentDecryptionModule implementation:
+  void SetServerCertificate(const std::vector<uint8_t>& certificate,
+                            std::unique_ptr<SimpleCdmPromise> promise) override;
+  void CreateSessionAndGenerateRequest(
+      CdmSessionType session_type,
+      EmeInitDataType init_data_type,
+      const std::vector<uint8_t>& init_data,
+      std::unique_ptr<NewSessionCdmPromise> promise) override;
+  void LoadSession(CdmSessionType session_type,
+                   const std::string& session_id,
+                   std::unique_ptr<NewSessionCdmPromise> promise) override;
+  void UpdateSession(const std::string& session_id,
+                     const std::vector<uint8_t>& response,
+                     std::unique_ptr<SimpleCdmPromise> promise) override;
+  void CloseSession(const std::string& session_id,
+                    std::unique_ptr<SimpleCdmPromise> promise) override;
+  void RemoveSession(const std::string& session_id,
+                     std::unique_ptr<SimpleCdmPromise> promise) override;
+  CdmContext* GetCdmContext() override;
+
+  // CdmContext implementation:
+  std::unique_ptr<CallbackRegistration> RegisterEventCB(
+      EventCB event_cb) override;
+  Decryptor* GetDecryptor() override;
+  int GetCdmId() const override;
+
+ private:
+  ~FuchsiaCdm() override;
+
+  fuchsia::media::drm::ContentDecryptionModulePtr cdm_;
+  SessionCallbacks session_callbacks_;
+
+  DISALLOW_COPY_AND_ASSIGN(FuchsiaCdm);
+};
+
+}  // namespace media
+
+#endif  // MEDIA_FUCHSIA_CDM_FUCHSIA_CDM_H_
diff --git a/media/fuchsia/cdm/fuchsia_cdm_factory.cc b/media/fuchsia/cdm/fuchsia_cdm_factory.cc
new file mode 100644
index 0000000..6e80599
--- /dev/null
+++ b/media/fuchsia/cdm/fuchsia_cdm_factory.cc
@@ -0,0 +1,70 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/fuchsia/cdm/fuchsia_cdm_factory.h"
+
+#include <fuchsia/media/drm/cpp/fidl.h>
+
+#include "base/bind.h"
+#include "media/base/bind_to_current_loop.h"
+#include "media/base/cdm_config.h"
+#include "media/base/key_systems.h"
+#include "media/cdm/aes_decryptor.h"
+#include "media/fuchsia/cdm/fuchsia_cdm.h"
+#include "services/service_manager/public/cpp/interface_provider.h"
+#include "url/origin.h"
+
+namespace media {
+
+FuchsiaCdmFactory::FuchsiaCdmFactory(
+    service_manager::InterfaceProvider* interface_provider)
+    : interface_provider_(interface_provider) {
+  DCHECK(interface_provider_);
+}
+
+FuchsiaCdmFactory::~FuchsiaCdmFactory() = default;
+
+void FuchsiaCdmFactory::Create(
+    const std::string& key_system,
+    const url::Origin& security_origin,
+    const CdmConfig& cdm_config,
+    const SessionMessageCB& session_message_cb,
+    const SessionClosedCB& session_closed_cb,
+    const SessionKeysChangeCB& session_keys_change_cb,
+    const SessionExpirationUpdateCB& session_expiration_update_cb,
+    const CdmCreatedCB& cdm_created_cb) {
+  CdmCreatedCB bound_cdm_created_cb = BindToCurrentLoop(cdm_created_cb);
+
+  if (security_origin.opaque()) {
+    std::move(bound_cdm_created_cb).Run(nullptr, "Invalid origin.");
+    return;
+  }
+
+  if (CanUseAesDecryptor(key_system)) {
+    auto cdm = base::MakeRefCounted<AesDecryptor>(
+        session_message_cb, session_closed_cb, session_keys_change_cb,
+        session_expiration_update_cb);
+    std::move(bound_cdm_created_cb).Run(std::move(cdm), "");
+    return;
+  }
+
+  if (!cdm_provider_)
+    interface_provider_->GetInterface(mojo::MakeRequest(&cdm_provider_));
+
+  fuchsia::media::drm::ContentDecryptionModulePtr cdm_ptr;
+  cdm_provider_->CreateCdmInterface(key_system, cdm_ptr.NewRequest());
+
+  FuchsiaCdm::SessionCallbacks callbacks;
+  callbacks.message_cb = session_message_cb;
+  callbacks.closed_cb = session_closed_cb;
+  callbacks.keys_change_cb = session_keys_change_cb;
+  callbacks.expiration_update_cb = session_expiration_update_cb;
+
+  auto cdm = base::MakeRefCounted<FuchsiaCdm>(std::move(cdm_ptr),
+                                              std::move(callbacks));
+
+  std::move(bound_cdm_created_cb).Run(std::move(cdm), "");
+}
+
+}  // namespace media
diff --git a/media/cdm/fuchsia/fuchsia_cdm_factory.h b/media/fuchsia/cdm/fuchsia_cdm_factory.h
similarity index 64%
rename from media/cdm/fuchsia/fuchsia_cdm_factory.h
rename to media/fuchsia/cdm/fuchsia_cdm_factory.h
index 4e41d22e..6fdba9d 100644
--- a/media/cdm/fuchsia/fuchsia_cdm_factory.h
+++ b/media/fuchsia/cdm/fuchsia_cdm_factory.h
@@ -2,18 +2,25 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef MEDIA_CDM_FUCHSIA_FUCHSIA_CDM_FACTORY_H_
-#define MEDIA_CDM_FUCHSIA_FUCHSIA_CDM_FACTORY_H_
+#ifndef MEDIA_FUCHSIA_CDM_FUCHSIA_CDM_FACTORY_H_
+#define MEDIA_FUCHSIA_CDM_FUCHSIA_CDM_FACTORY_H_
 
 #include "base/macros.h"
 #include "media/base/cdm_factory.h"
 #include "media/base/media_export.h"
+#include "media/fuchsia/mojom/fuchsia_cdm_provider.mojom.h"
+
+namespace service_manager {
+class InterfaceProvider;
+}
 
 namespace media {
 
 class MEDIA_EXPORT FuchsiaCdmFactory : public CdmFactory {
  public:
-  FuchsiaCdmFactory();
+  // |interface_provider| must outlive this class.
+  explicit FuchsiaCdmFactory(
+      service_manager::InterfaceProvider* interface_provider);
   ~FuchsiaCdmFactory() final;
 
   // CdmFactory implementation.
@@ -27,9 +34,12 @@
               const CdmCreatedCB& cdm_created_cb) final;
 
  private:
+  service_manager::InterfaceProvider* const interface_provider_;
+  media::mojom::FuchsiaCdmProviderPtr cdm_provider_;
+
   DISALLOW_COPY_AND_ASSIGN(FuchsiaCdmFactory);
 };
 
 }  // namespace media
 
-#endif  // MEDIA_CDM_FUCHSIA_FUCHSIA_CDM_FACTORY_H_
+#endif  // MEDIA_FUCHSIA_CDM_FUCHSIA_CDM_FACTORY_H_
diff --git a/media/fuchsia/cdm/service/BUILD.gn b/media/fuchsia/cdm/service/BUILD.gn
new file mode 100644
index 0000000..36335eff
--- /dev/null
+++ b/media/fuchsia/cdm/service/BUILD.gn
@@ -0,0 +1,19 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+assert(is_fuchsia)
+
+source_set("service") {
+  sources = [
+    "fuchsia_cdm_manager.cc",
+    "fuchsia_cdm_manager.h",
+  ]
+
+  deps = [
+    "//media",
+    "//media/fuchsia/mojom",
+    "//third_party/fuchsia-sdk/sdk:media_drm",
+    "//url",
+  ]
+}
diff --git a/media/fuchsia/cdm/service/fuchsia_cdm_manager.cc b/media/fuchsia/cdm/service/fuchsia_cdm_manager.cc
new file mode 100644
index 0000000..c467da4
--- /dev/null
+++ b/media/fuchsia/cdm/service/fuchsia_cdm_manager.cc
@@ -0,0 +1,25 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/fuchsia/cdm/service/fuchsia_cdm_manager.h"
+
+#include "base/logging.h"
+#include "url/origin.h"
+
+namespace media {
+
+FuchsiaCdmManager::FuchsiaCdmManager() = default;
+
+FuchsiaCdmManager::~FuchsiaCdmManager() = default;
+
+void FuchsiaCdmManager::CreateAndProvision(
+    const std::string& key_system,
+    const url::Origin& origin,
+    CreateFetcherCB create_fetcher_cb,
+    fidl::InterfaceRequest<fuchsia::media::drm::ContentDecryptionModule>
+        request) {
+  NOTIMPLEMENTED();
+}
+
+}  // namespace media
diff --git a/media/fuchsia/cdm/service/fuchsia_cdm_manager.h b/media/fuchsia/cdm/service/fuchsia_cdm_manager.h
new file mode 100644
index 0000000..2f84d3a
--- /dev/null
+++ b/media/fuchsia/cdm/service/fuchsia_cdm_manager.h
@@ -0,0 +1,37 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MEDIA_FUCHSIA_CDM_SERVICE_FUCHSIA_CDM_MANAGER_H_
+#define MEDIA_FUCHSIA_CDM_SERVICE_FUCHSIA_CDM_MANAGER_H_
+
+#include <fuchsia/media/drm/cpp/fidl.h>
+#include <string>
+
+#include "media/base/provision_fetcher.h"
+
+namespace url {
+class Origin;
+}  // namespace url
+
+namespace media {
+
+// Create and connect to Fuchsia CDM service. It will provision the origin if
+// needed. It will chain all the concurrent provision requests and make sure we
+// only send one provision request to server.
+class FuchsiaCdmManager {
+ public:
+  FuchsiaCdmManager();
+  ~FuchsiaCdmManager();
+
+  void CreateAndProvision(
+      const std::string& key_system,
+      const url::Origin& origin,
+      CreateFetcherCB create_fetcher_cb,
+      fidl::InterfaceRequest<fuchsia::media::drm::ContentDecryptionModule>
+          request);
+};
+
+}  // namespace media
+
+#endif  // MEDIA_FUCHSIA_CDM_SERVICE_FUCHSIA_CDM_MANAGER_H_
diff --git a/media/fuchsia/mojom/BUILD.gn b/media/fuchsia/mojom/BUILD.gn
new file mode 100644
index 0000000..d61221b
--- /dev/null
+++ b/media/fuchsia/mojom/BUILD.gn
@@ -0,0 +1,11 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//mojo/public/tools/bindings/mojom.gni")
+
+mojom("mojom") {
+  sources = [
+    "fuchsia_cdm_provider.mojom",
+  ]
+}
diff --git a/media/fuchsia/mojom/DEPS b/media/fuchsia/mojom/DEPS
new file mode 100644
index 0000000..76ac064
--- /dev/null
+++ b/media/fuchsia/mojom/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+fuchsia/mojom",
+]
diff --git a/media/fuchsia/mojom/OWNERS b/media/fuchsia/mojom/OWNERS
new file mode 100644
index 0000000..ae29a36aa
--- /dev/null
+++ b/media/fuchsia/mojom/OWNERS
@@ -0,0 +1,6 @@
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
+per-file *_mojom_traits*.*=set noparent
+per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS
+per-file *.typemap=set noparent
+per-file *.typemap=file://ipc/SECURITY_OWNERS
diff --git a/media/fuchsia/mojom/cdm_request.typemap b/media/fuchsia/mojom/cdm_request.typemap
new file mode 100644
index 0000000..fd1b4d9
--- /dev/null
+++ b/media/fuchsia/mojom/cdm_request.typemap
@@ -0,0 +1,16 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+mojom = "//media/fuchsia/mojom/fuchsia_cdm_provider.mojom"
+os_whitelist = [ "fuchsia" ]
+public_headers = [ "fuchsia/media/drm/cpp/fidl.h" ]
+traits_headers = [ "//media/fuchsia/mojom/cdm_request_mojom_traits.h" ]
+sources = [
+  "//media/fuchsia/mojom/cdm_request_mojom_traits.h",
+]
+public_deps = [
+  "//fuchsia/mojom:traits",
+  "//third_party/fuchsia-sdk/sdk:media_drm",
+]
+type_mappings = [ "media.mojom.CdmRequest=fidl::InterfaceRequest<fuchsia::media::drm::ContentDecryptionModule>[move_only]" ]
diff --git a/media/fuchsia/mojom/cdm_request_mojom_traits.h b/media/fuchsia/mojom/cdm_request_mojom_traits.h
new file mode 100644
index 0000000..c9c2e6c
--- /dev/null
+++ b/media/fuchsia/mojom/cdm_request_mojom_traits.h
@@ -0,0 +1,24 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MEDIA_FUCHSIA_MOJOM_CDM_REQUEST_MOJOM_TRAITS_H_
+#define MEDIA_FUCHSIA_MOJOM_CDM_REQUEST_MOJOM_TRAITS_H_
+
+#include <fuchsia/media/drm/cpp/fidl.h>
+
+#include "fuchsia/mojom/fidl_interface_request_mojom_traits.h"
+
+namespace mojo {
+
+template <>
+struct StructTraits<
+    media::mojom::CdmRequestDataView,
+    fidl::InterfaceRequest<fuchsia::media::drm::ContentDecryptionModule>>
+    : public FidlInterfaceRequestStructTraits<
+          media::mojom::CdmRequestDataView,
+          fuchsia::media::drm::ContentDecryptionModule> {};
+
+}  // namespace mojo
+
+#endif  // MEDIA_FUCHSIA_MOJOM_CDM_REQUEST_MOJOM_TRAITS_H_
diff --git a/media/fuchsia/mojom/fuchsia_cdm_provider.mojom b/media/fuchsia/mojom/fuchsia_cdm_provider.mojom
new file mode 100644
index 0000000..2971aa3
--- /dev/null
+++ b/media/fuchsia/mojom/fuchsia_cdm_provider.mojom
@@ -0,0 +1,21 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module media.mojom;
+
+// Mojo struct for
+// fidl::InterfaceRequest<fuchsia::media::drm::ContentDecryptionModule>.
+struct CdmRequest {
+  handle request;
+};
+
+// Interface for asking privileged process to create connection to
+// fuchsia CDM service.
+interface FuchsiaCdmProvider {
+  // Create connection to fuchsia::media::drm::ContentDecryptionModule for
+  // |key_system|.
+  // Implementation should make sure the persistent storage are isolated
+  // for different web origins.
+  CreateCdmInterface(string key_system, CdmRequest cdm_request);
+};
diff --git a/media/fuchsia/mojom/typemaps.gni b/media/fuchsia/mojom/typemaps.gni
new file mode 100644
index 0000000..e25ac04
--- /dev/null
+++ b/media/fuchsia/mojom/typemaps.gni
@@ -0,0 +1,5 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+typemaps = [ "//media/fuchsia/mojom/cdm_request.typemap" ]
diff --git a/mojo/public/tools/bindings/chromium_bindings_configuration.gni b/mojo/public/tools/bindings/chromium_bindings_configuration.gni
index 81d0ecb..6e8bc9e 100644
--- a/mojo/public/tools/bindings/chromium_bindings_configuration.gni
+++ b/mojo/public/tools/bindings/chromium_bindings_configuration.gni
@@ -26,6 +26,7 @@
   "//gpu/ipc/common/typemaps.gni",
   "//ipc/typemaps.gni",
   "//media/capture/mojom/typemaps.gni",
+  "//media/fuchsia/mojom/typemaps.gni",
   "//media/learning/mojo/public/cpp/typemaps.gni",
   "//media/mojo/mojom/typemaps.gni",
   "//mojo/public/cpp/base/typemaps.gni",
diff --git a/net/http/http_network_session.cc b/net/http/http_network_session.cc
index 4ce2d3fe..437fa0b7 100644
--- a/net/http/http_network_session.cc
+++ b/net/http/http_network_session.cc
@@ -374,8 +374,7 @@
   *alpn_protos = next_protos_;
 }
 
-void HttpNetworkSession::GetSSLConfig(const HttpRequestInfo& request,
-                                      SSLConfig* server_config,
+void HttpNetworkSession::GetSSLConfig(SSLConfig* server_config,
                                       SSLConfig* proxy_config) const {
   GetAlpnProtos(&server_config->alpn_protos);
   server_config->ignore_certificate_errors = params_.ignore_certificate_errors;
diff --git a/net/http/http_network_session.h b/net/http/http_network_session.h
index 0538207..af70598 100644
--- a/net/http/http_network_session.h
+++ b/net/http/http_network_session.h
@@ -265,11 +265,8 @@
   // Populates |*alpn_protos| with protocols to be used with ALPN.
   void GetAlpnProtos(NextProtoVector* alpn_protos) const;
 
-  // Populates |server_config| and |proxy_config| based on this session and
-  // |request|.
-  void GetSSLConfig(const HttpRequestInfo& request,
-                    SSLConfig* server_config,
-                    SSLConfig* proxy_config) const;
+  // Populates |server_config| and |proxy_config| based on this session.
+  void GetSSLConfig(SSLConfig* server_config, SSLConfig* proxy_config) const;
 
   // Dumps memory allocation stats. |parent_dump_absolute_name| is the name
   // used by the parent MemoryAllocatorDump in the memory dump hierarchy.
diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc
index 9aea7f0..00360b4f 100644
--- a/net/http/http_network_transaction.cc
+++ b/net/http/http_network_transaction.cc
@@ -182,8 +182,7 @@
   start_timeticks_ = base::TimeTicks::Now();
 #endif  // BUILDFLAG(ENABLE_REPORTING)
 
-  // Now that we have an HttpRequestInfo object, update server_ssl_config_.
-  session_->GetSSLConfig(*request_, &server_ssl_config_, &proxy_ssl_config_);
+  session_->GetSSLConfig(&server_ssl_config_, &proxy_ssl_config_);
 
   if (request_->load_flags & LOAD_DISABLE_CERT_NETWORK_FETCHES) {
     server_ssl_config_.disable_cert_verification_network_fetches = true;
diff --git a/net/http/http_stream_factory.cc b/net/http/http_stream_factory.cc
index e7df1dd..d6c8189 100644
--- a/net/http/http_stream_factory.cc
+++ b/net/http/http_stream_factory.cc
@@ -203,7 +203,7 @@
 
   SSLConfig server_ssl_config;
   SSLConfig proxy_ssl_config;
-  session_->GetSSLConfig(request_info, &server_ssl_config, &proxy_ssl_config);
+  session_->GetSSLConfig(&server_ssl_config, &proxy_ssl_config);
 
   auto job_controller = std::make_unique<JobController>(
       this, nullptr, session_, job_factory_.get(), request_info,
diff --git a/pdf/document_layout.cc b/pdf/document_layout.cc
index dee08058..604a2e3f 100644
--- a/pdf/document_layout.cc
+++ b/pdf/document_layout.cc
@@ -5,10 +5,12 @@
 #include "pdf/document_layout.h"
 
 #include "base/logging.h"
-#include "pdf/draw_utils/coordinates.h"
 
 namespace chrome_pdf {
 
+const draw_utils::PageInsetSizes DocumentLayout::kSingleViewInsets{
+    /*left=*/5, /*top=*/3, /*right=*/5, /*bottom=*/7};
+
 DocumentLayout::DocumentLayout() = default;
 
 DocumentLayout::DocumentLayout(const DocumentLayout& other) = default;
@@ -25,6 +27,36 @@
   default_page_orientation_ = (default_page_orientation_ - 1) % 4;
 }
 
+std::vector<pp::Rect> DocumentLayout::GetTwoUpViewLayout(
+    const std::vector<pp::Rect>& page_rects) {
+  std::vector<pp::Rect> formatted_rects(page_rects.size());
+  // Reset the current layout's height for new two-up view layout.
+  size_.set_height(0);
+
+  for (size_t i = 0; i < page_rects.size(); ++i) {
+    draw_utils::PageInsetSizes page_insets =
+        draw_utils::GetPageInsetsForTwoUpView(
+            i, page_rects.size(), kSingleViewInsets, kHorizontalSeparator);
+    const pp::Size& page_size = page_rects[i].size();
+
+    if (i % 2 == 0) {
+      formatted_rects[i] = draw_utils::GetLeftRectForTwoUpView(
+          page_size, {size_.width(), size_.height()}, page_insets);
+    } else {
+      formatted_rects[i] = draw_utils::GetRightRectForTwoUpView(
+          page_size, {size_.width(), size_.height()}, page_insets);
+      EnlargeHeight(
+          std::max(page_size.height(), page_rects[i - 1].size().height()));
+    }
+  }
+
+  if (page_rects.size() % 2 == 1) {
+    EnlargeHeight(page_rects.back().size().height());
+  }
+
+  return formatted_rects;
+}
+
 void DocumentLayout::EnlargeHeight(int height) {
   DCHECK_GE(height, 0);
   size_.Enlarge(0, height);
diff --git a/pdf/document_layout.h b/pdf/document_layout.h
index 6859575e..117d8a7 100644
--- a/pdf/document_layout.h
+++ b/pdf/document_layout.h
@@ -5,6 +5,10 @@
 #ifndef PDF_DOCUMENT_LAYOUT_H_
 #define PDF_DOCUMENT_LAYOUT_H_
 
+#include <vector>
+
+#include "pdf/draw_utils/coordinates.h"
+#include "ppapi/cpp/rect.h"
 #include "ppapi/cpp/size.h"
 
 namespace chrome_pdf {
@@ -13,10 +17,12 @@
 // (possibly rotated) in a non-overlapping vertical sequence.
 //
 // All layout units are pixels.
-//
-// TODO(crbug.com/51472): Support multiple columns.
 class DocumentLayout final {
  public:
+  static const draw_utils::PageInsetSizes kSingleViewInsets;
+  static constexpr int32_t kBottomSeparator = 4;
+  static constexpr int32_t kHorizontalSeparator = 1;
+
   DocumentLayout();
 
   DocumentLayout(const DocumentLayout& other);
@@ -45,6 +51,12 @@
   // Sets the layout's total size.
   void set_size(const pp::Size& size) { size_ = size; }
 
+  // Given |page_rects| and the layout's size is set to a single-view layout,
+  // return |page_rects| formatted for two-up view and update the layout's size
+  // to the size of the new two-up view layout.
+  std::vector<pp::Rect> GetTwoUpViewLayout(
+      const std::vector<pp::Rect>& page_rects);
+
   // Increases the layout's total height by |height|.
   void EnlargeHeight(int height);
 
diff --git a/pdf/document_layout_unittest.cc b/pdf/document_layout_unittest.cc
index 8185464..1d7d0a8 100644
--- a/pdf/document_layout_unittest.cc
+++ b/pdf/document_layout_unittest.cc
@@ -25,6 +25,10 @@
   return lhs == rhs;
 }
 
+inline bool PpRectEq(const pp::Rect& lhs, const pp::Rect& rhs) {
+  return lhs == rhs;
+}
+
 TEST_F(DocumentLayoutTest, DefaultConstructor) {
   EXPECT_EQ(layout_.default_page_orientation(), 0);
   EXPECT_PRED2(PpSizeEq, layout_.size(), pp::Size(0, 0));
@@ -108,6 +112,55 @@
   EXPECT_PRED2(PpSizeEq, layout_.size(), pp::Size(0, 16));
 }
 
+TEST_F(DocumentLayoutTest, GetTwoUpViewLayout) {
+  std::vector<pp::Rect> two_up_view_layout;
+
+  // Test case where the widest page is on the right.
+  std::vector<pp::Rect> page_rects{{0, 10, 826, 1066},
+                                   {0, 1076, 1066, 826},
+                                   {0, 1902, 826, 1066},
+                                   {0, 2968, 826, 900}};
+  layout_.set_size({1066, 0});
+  two_up_view_layout = layout_.GetTwoUpViewLayout(page_rects);
+  ASSERT_EQ(4u, two_up_view_layout.size());
+  EXPECT_PRED2(PpRectEq, pp::Rect(245, 3, 820, 1056), two_up_view_layout[0]);
+  EXPECT_PRED2(PpRectEq, pp::Rect(1067, 3, 1060, 816), two_up_view_layout[1]);
+  EXPECT_PRED2(PpRectEq, pp::Rect(245, 1069, 820, 1056), two_up_view_layout[2]);
+  EXPECT_PRED2(PpRectEq, pp::Rect(1067, 1069, 820, 890), two_up_view_layout[3]);
+  EXPECT_PRED2(PpSizeEq, pp::Size(1066, 2132), layout_.size());
+
+  // Test case where the widest page is on the left.
+  page_rects = {{0, 5, 1066, 826},
+                {0, 831, 820, 1056},
+                {0, 1887, 820, 890},
+                {0, 2777, 826, 1066}};
+  layout_.set_size({1066, 0});
+  two_up_view_layout = layout_.GetTwoUpViewLayout(page_rects);
+  ASSERT_EQ(4u, two_up_view_layout.size());
+  EXPECT_PRED2(PpRectEq, pp::Rect(5, 3, 1060, 816), two_up_view_layout[0]);
+  EXPECT_PRED2(PpRectEq, pp::Rect(1067, 3, 814, 1046), two_up_view_layout[1]);
+  EXPECT_PRED2(PpRectEq, pp::Rect(251, 1059, 814, 880), two_up_view_layout[2]);
+  EXPECT_PRED2(PpRectEq, pp::Rect(1067, 1059, 820, 1056),
+               two_up_view_layout[3]);
+  EXPECT_PRED2(PpSizeEq, pp::Size(1066, 2122), layout_.size());
+
+  // Test case where there's an odd # of pages.
+  page_rects = {{0, 5, 200, 300},
+                {0, 305, 400, 200},
+                {0, 505, 300, 600},
+                {0, 1105, 250, 500},
+                {0, 1605, 300, 400}};
+  layout_.set_size({400, 0});
+  two_up_view_layout = layout_.GetTwoUpViewLayout(page_rects);
+  ASSERT_EQ(5u, two_up_view_layout.size());
+  EXPECT_PRED2(PpRectEq, pp::Rect(205, 3, 194, 290), two_up_view_layout[0]);
+  EXPECT_PRED2(PpRectEq, pp::Rect(401, 3, 394, 190), two_up_view_layout[1]);
+  EXPECT_PRED2(PpRectEq, pp::Rect(105, 303, 294, 590), two_up_view_layout[2]);
+  EXPECT_PRED2(PpRectEq, pp::Rect(401, 303, 244, 490), two_up_view_layout[3]);
+  EXPECT_PRED2(PpRectEq, pp::Rect(105, 903, 290, 390), two_up_view_layout[4]);
+  EXPECT_PRED2(PpSizeEq, pp::Size(400, 1300), layout_.size());
+}
+
 TEST_F(DocumentLayoutDeathTest, EnlargeHeightNegativeIncrement) {
   EXPECT_DCHECK_DEATH(layout_.EnlargeHeight(-5));
 }
diff --git a/pdf/pdfium/pdfium_engine.cc b/pdf/pdfium/pdfium_engine.cc
index 095aa219..272d97c 100644
--- a/pdf/pdfium/pdfium_engine.cc
+++ b/pdf/pdfium/pdfium_engine.cc
@@ -79,17 +79,6 @@
 
 namespace {
 
-constexpr int32_t kPageShadowTop = 3;
-constexpr int32_t kPageShadowBottom = 7;
-constexpr int32_t kPageShadowLeft = 5;
-constexpr int32_t kPageShadowRight = 5;
-
-constexpr draw_utils::PageInsetSizes kSingleViewInsets{
-    kPageShadowLeft, kPageShadowTop, kPageShadowRight, kPageShadowBottom};
-
-constexpr int32_t kBottomSeparator = 4;
-constexpr int32_t kHorizontalSeparator = 1;
-
 constexpr int32_t kHighlightColorR = 153;
 constexpr int32_t kHighlightColorG = 193;
 constexpr int32_t kHighlightColorB = 218;
@@ -2242,14 +2231,16 @@
   // Calculate document size and all page sizes.
   std::vector<pp::Rect> page_rects;
   pp::Size page_size = GetPageSize(0);
-  page_size.Enlarge(kPageShadowLeft + kPageShadowRight,
-                    kPageShadowTop + kPageShadowBottom);
+  page_size.Enlarge(DocumentLayout::kSingleViewInsets.left +
+                        DocumentLayout::kSingleViewInsets.right,
+                    DocumentLayout::kSingleViewInsets.top +
+                        DocumentLayout::kSingleViewInsets.bottom);
   pp::Size old_document_size = layout_.size();
   layout_.set_size(pp::Size(page_size.width(), 0));
   for (int i = 0; i < num_pages; ++i) {
     if (i != 0) {
       // Add space for bottom separator.
-      layout_.EnlargeHeight(kBottomSeparator);
+      layout_.EnlargeHeight(DocumentLayout::kBottomSeparator);
     }
 
     pp::Rect rect(pp::Point(0, layout_.size().height()), page_size);
@@ -2261,8 +2252,10 @@
   // Create blank pages.
   for (int i = 1; i < num_pages; ++i) {
     pp::Rect page_rect(page_rects[i]);
-    page_rect.Inset(kPageShadowLeft, kPageShadowTop, kPageShadowRight,
-                    kPageShadowBottom);
+    page_rect.Inset(DocumentLayout::kSingleViewInsets.left,
+                    DocumentLayout::kSingleViewInsets.top,
+                    DocumentLayout::kSingleViewInsets.right,
+                    DocumentLayout::kSingleViewInsets.bottom);
     double width_in_points =
         ConvertUnitDouble(page_rect.width(), kPixelsPerInch, kPointsPerInch);
     double height_in_points =
@@ -2407,6 +2400,16 @@
   }
 }
 
+void PDFiumEngine::LoadPagesInTwoUpView(std::vector<pp::Rect> page_rects,
+                                        bool reload) {
+  std::vector<pp::Rect> two_up_view_layout =
+      layout_.GetTwoUpViewLayout(page_rects);
+
+  for (size_t i = 0; i < two_up_view_layout.size(); ++i) {
+    AppendPageRectToPages(two_up_view_layout[i], i, reload);
+  }
+}
+
 void PDFiumEngine::LoadPageInfo(bool reload) {
   if (!doc_loader_)
     return;
@@ -2424,7 +2427,7 @@
   for (size_t i = 0; i < new_page_count; ++i) {
     if (i != 0) {
       // Add space for bottom separator.
-      layout_.EnlargeHeight(kBottomSeparator);
+      layout_.EnlargeHeight(DocumentLayout::kBottomSeparator);
     }
 
     // Get page availability. If |reload| == true and the page is not new,
@@ -2452,7 +2455,11 @@
     layout_.AppendPageRect(size);
   }
 
-  LoadPagesInSingleView(std::move(page_rects), reload);
+  if (two_up_view_) {
+    LoadPagesInTwoUpView(std::move(page_rects), reload);
+  } else {
+    LoadPagesInSingleView(std::move(page_rects), reload);
+  }
 
   // Remove pages that do not exist anymore.
   if (pages_.size() > new_page_count) {
@@ -2642,10 +2649,11 @@
 
   if (two_up_view_) {
     return draw_utils::GetPageInsetsForTwoUpView(
-        page_index, num_of_pages, kSingleViewInsets, kHorizontalSeparator);
+        page_index, num_of_pages, DocumentLayout::kSingleViewInsets,
+        DocumentLayout::kHorizontalSeparator);
   }
 
-  return kSingleViewInsets;
+  return DocumentLayout::kSingleViewInsets;
 }
 
 void PDFiumEngine::EnlargePage(size_t page_index,
@@ -2789,8 +2797,8 @@
     // If in two-up view, only need to draw the left empty space for left pages
     // since the gap between the left and right page will be drawn by the left
     // page.
-    pp::Rect left_in_screen = GetScreenRect(
-        draw_utils::GetLeftFillRect(page_rect, inset_sizes, kBottomSeparator));
+    pp::Rect left_in_screen = GetScreenRect(draw_utils::GetLeftFillRect(
+        page_rect, inset_sizes, DocumentLayout::kBottomSeparator));
     left_in_screen = left_in_screen.Intersect(dirty_in_screen);
 
     FPDFBitmap_FillRect(bitmap, left_in_screen.x() - dirty_in_screen.x(),
@@ -2801,7 +2809,8 @@
 
   if (page_rect.right() < layout_.size().width()) {
     pp::Rect right_in_screen = GetScreenRect(draw_utils::GetRightFillRect(
-        page_rect, inset_sizes, layout_.size().width(), kBottomSeparator));
+        page_rect, inset_sizes, layout_.size().width(),
+        DocumentLayout::kBottomSeparator));
     right_in_screen = right_in_screen.Intersect(dirty_in_screen);
 
     FPDFBitmap_FillRect(bitmap, right_in_screen.x() - dirty_in_screen.x(),
@@ -2824,7 +2833,7 @@
     bottom_in_screen = bottom_in_screen.Intersect(dirty_in_screen);
   } else {
     bottom_in_screen = GetScreenRect(draw_utils::GetBottomFillRect(
-        page_rect, inset_sizes, kBottomSeparator));
+        page_rect, inset_sizes, DocumentLayout::kBottomSeparator));
     bottom_in_screen = bottom_in_screen.Intersect(dirty_in_screen);
   }
 
@@ -2993,7 +3002,7 @@
 
   return GetScreenRect(draw_utils::GetSurroundingRect(
       page_rect.y(), max_page_height, inset_sizes, layout_.size().width(),
-      kBottomSeparator));
+      DocumentLayout::kBottomSeparator));
 }
 
 pp::Rect PDFiumEngine::GetScreenRect(const pp::Rect& rect) const {
diff --git a/pdf/pdfium/pdfium_engine.h b/pdf/pdfium/pdfium_engine.h
index ee8c7e0d..c45a3d5 100644
--- a/pdf/pdfium/pdfium_engine.h
+++ b/pdf/pdfium/pdfium_engine.h
@@ -243,6 +243,10 @@
   // |pages_|.
   void LoadPagesInSingleView(std::vector<pp::Rect> page_rects, bool reload);
 
+  // Formats the pages of |page_rects| for two-up view and appends them to
+  // |pages_|.
+  void LoadPagesInTwoUpView(std::vector<pp::Rect> page_rects, bool reload);
+
   // Loads information about the pages in the document and calculate the
   // document size.
   void LoadPageInfo(bool reload);
diff --git a/services/data_decoder/bundled_exchanges_parser.cc b/services/data_decoder/bundled_exchanges_parser.cc
index 4a250c9..93c91b4 100644
--- a/services/data_decoder/bundled_exchanges_parser.cc
+++ b/services/data_decoder/bundled_exchanges_parser.cc
@@ -38,8 +38,17 @@
 // The initial buffer size for reading an item from the response section.
 constexpr uint64_t kInitialBufferSizeForResponse = 4096;
 
+// Step 2. of
+// https://wicg.github.io/webpackage/draft-yasskin-wpack-bundled-exchanges.html#load-metadata
 const uint8_t kBundleMagicBytes[] = {
-    0x84, 0x48, 0xF0, 0x9F, 0x8C, 0x90, 0xF0, 0x9F, 0x93, 0xA6,
+    0x86, 0x48, 0xF0, 0x9F, 0x8C, 0x90, 0xF0, 0x9F, 0x93, 0xA6,
+};
+
+// Step 7. of
+// https://wicg.github.io/webpackage/draft-yasskin-wpack-bundled-exchanges.html#load-metadata
+// We use an implementation-specific version string "b1\0\0".
+const uint8_t kVersionB1MagicBytes[] = {
+    0x44, 0x62, 0x31, 0x00, 0x00,
 };
 
 // Section names.
@@ -49,6 +58,7 @@
 // https://tools.ietf.org/html/draft-ietf-cbor-7049bis-05#section-3.1
 enum class CBORType {
   kByteString = 2,
+  kTextString = 3,
   kArray = 4,
 };
 
@@ -173,6 +183,17 @@
     return result;
   }
 
+  base::Optional<base::StringPiece> ReadString(size_t n) {
+    auto bytes = ReadBytes(n);
+    if (!bytes)
+      return base::nullopt;
+    base::StringPiece str(reinterpret_cast<const char*>(bytes->data()),
+                          bytes->size());
+    if (!base::IsStringUTF8(str))
+      return base::nullopt;
+    return str;
+  }
+
   // Parses the type and argument of a CBOR item from the input head. If parsed
   // successfully and the type matches |expected_type|, returns the argument.
   // Otherwise returns nullopt.
@@ -269,23 +290,23 @@
   void DidGetSize(uint64_t size) {
     size_ = size;
 
-    // In the next step, we will parse `magic`, `section-lengths`, and the CBOR
-    // header of `sections`.
+    // In the next step, we will parse `magic`, `version`, and the CBOR
+    // header of `primary-url`.
     // https://wicg.github.io/webpackage/draft-yasskin-wpack-bundled-exchanges.html#top-level
-    const uint64_t length =
-        std::min(size, sizeof(kBundleMagicBytes) + kMaxSectionLengthsCBORSize +
-                           kMaxCBORItemHeaderSize * 2);
+    const uint64_t length = std::min(size, sizeof(kBundleMagicBytes) +
+                                               sizeof(kVersionB1MagicBytes) +
+                                               kMaxCBORItemHeaderSize);
     data_source_->Read(0, length,
-                       base::BindOnce(&MetadataParser::ParseBundleHeader,
+                       base::BindOnce(&MetadataParser::ParseMagicBytes,
                                       weak_factory_.GetWeakPtr(), length));
   }
 
-  // Step 1-15 of
+  // Step 1-4 of
   // https://wicg.github.io/webpackage/draft-yasskin-wpack-bundled-exchanges.html#load-metadata
-  void ParseBundleHeader(uint64_t expected_data_length,
-                         const base::Optional<std::vector<uint8_t>>& data) {
+  void ParseMagicBytes(uint64_t expected_data_length,
+                       const base::Optional<std::vector<uint8_t>>& data) {
     if (!data || data->size() != expected_data_length) {
-      RunErrorCallbackAndDestroy("Error reading bundle header.");
+      RunErrorCallbackAndDestroy("Error reading bundle magic bytes.");
       return;
     }
 
@@ -294,9 +315,9 @@
     InputReader input(*data);
 
     // Step 2. "If reading 10 bytes from stream returns an error or doesn't
-    // return the bytes with hex encoding "84 48 F0 9F 8C 90 F0 9F 93 A6"
-    // (the CBOR encoding of the 4-item array initial byte and 8-byte bytestring
-    // initial byte, followed by 🌐📦 in UTF-8), return an error."
+    // return the bytes with hex encoding "86 48 F0 9F 8C 90 F0 9F 93 A6"
+    // (the CBOR encoding of the 6-item array initial byte and 8-byte bytestring
+    // initial byte, followed by 🌐📦 in UTF-8), return a "format error"."
     const auto magic = input.ReadBytes(sizeof(kBundleMagicBytes));
     if (!magic ||
         !std::equal(magic->begin(), magic->end(), std::begin(kBundleMagicBytes),
@@ -305,43 +326,125 @@
       return;
     }
 
-    // Step 3. "Let sectionLengthsLength be the result of getting the length of
+    // Step 3. "Let version be the result of reading 5 bytes from stream. If
+    // this is an error, return a "format error"."
+    const auto version = input.ReadBytes(sizeof(kVersionB1MagicBytes));
+    if (!version) {
+      RunErrorCallbackAndDestroy("Cannot read version bytes.");
+      return;
+    }
+    if (!std::equal(version->begin(), version->end(),
+                    std::begin(kVersionB1MagicBytes),
+                    std::end(kVersionB1MagicBytes))) {
+      version_mismatch_ = true;
+      // Continue parsing until Step 7 where we get a fallback URL, and
+      // then return "version error" with the fallback URL.
+    }
+
+    // Step 4. "Let urlType and urlLength be the result of reading the type and
+    // argument of a CBOR item from stream (Section 3.5.3). If this is an error
+    // or urlType is not 3 (a CBOR text string), return a "format error"."
+    const auto url_length = input.ReadCBORHeader(CBORType::kTextString);
+    if (!url_length) {
+      RunErrorCallbackAndDestroy("Cannot parse the size of fallback URL.");
+      return;
+    }
+
+    // In the next step, we will parse the content of `primary-url`,
+    // `section-lengths`, and the CBOR header of `sections`.
+    const uint64_t length = std::min(
+        size_ - input.CurrentOffset(),
+        *url_length + kMaxSectionLengthsCBORSize + kMaxCBORItemHeaderSize * 2);
+    data_source_->Read(input.CurrentOffset(), length,
+                       base::BindOnce(&MetadataParser::ParseBundleHeader,
+                                      weak_factory_.GetWeakPtr(), length,
+                                      *url_length, input.CurrentOffset()));
+  }
+
+  // Step 5-20 of
+  // https://wicg.github.io/webpackage/draft-yasskin-wpack-bundled-exchanges.html#load-metadata
+  void ParseBundleHeader(uint64_t expected_data_length,
+                         uint64_t url_length,
+                         uint64_t offset_in_stream,
+                         const base::Optional<std::vector<uint8_t>>& data) {
+    if (!data || data->size() != expected_data_length) {
+      RunErrorCallbackAndDestroy("Error reading bundle header.");
+      return;
+    }
+    InputReader input(*data);
+
+    // Step 5. "Let fallbackUrlBytes be the result of reading urlLength bytes
+    // from stream. If this is an error, return a "format error"."
+    const auto fallback_url_string = input.ReadString(url_length);
+    if (!fallback_url_string) {
+      RunErrorCallbackAndDestroy("Cannot read fallback URL.");
+      return;
+    }
+
+    // Step 6. "Let fallbackUrl be the result of parsing ([URL]) the UTF-8
+    // decoding of fallbackUrlBytes with no base URL. If either the UTF-8
+    // decoding or parsing fails, return a "format error"."
+    // Note: ReadString() ensures that |fallback_url_string| is a valid UTF-8.
+    GURL fallback_url(*fallback_url_string);
+    if (!fallback_url.is_valid()) {
+      RunErrorCallbackAndDestroy("Cannot parse fallback URL.");
+      return;
+    }
+
+    // "Note: From this point forward, errors also include the fallback URL to
+    // help clients recover."
+    fallback_url_ = std::move(fallback_url);
+
+    // Step 7. "If version does not have the hex encoding "44 31 00 00 00" (the
+    // CBOR encoding of a 4-byte byte string holding an ASCII "1" followed by
+    // three 0 bytes), return a "version error" with fallbackUrl. "
+    // Note: We use an implementation-specific version string
+    // kVersionB1MagicBytes.
+    if (version_mismatch_) {
+      RunErrorCallbackAndDestroy(
+          "Version error: this implementation only supports "
+          "bundle format of version b1.",
+          mojom::BundleParseErrorType::kVersionError);
+      return;
+    }
+
+    // Step 8. "Let sectionLengthsLength be the result of getting the length of
     // the CBOR bytestring header from stream (Section 3.5.2). If this is an
-    // error, return that error."
+    // error, return a "format error" with fallbackUrl."
     const auto section_lengths_length =
         input.ReadCBORHeader(CBORType::kByteString);
     if (!section_lengths_length) {
       RunErrorCallbackAndDestroy("Cannot parse the size of section-lengths.");
       return;
     }
-    // Step 4. "If sectionLengthsLength is 8192 (8*1024) or greater, return an
-    // error."
+    // Step 9. "If sectionLengthsLength is 8192 (8*1024) or greater, return a
+    // "format error" with fallbackUrl."
     if (*section_lengths_length >= kMaxSectionLengthsCBORSize) {
       RunErrorCallbackAndDestroy(
           "The section-lengths CBOR must be smaller than 8192 bytes.");
       return;
     }
 
-    // Step 5. "Let sectionLengthsBytes be the result of reading
+    // Step 10. "Let sectionLengthsBytes be the result of reading
     // sectionLengthsLength bytes from stream. If sectionLengthsBytes is an
-    // error, return that error."
+    // error, return a "format error" with fallbackUrl."
     const auto section_lengths_bytes = input.ReadBytes(*section_lengths_length);
     if (!section_lengths_bytes) {
       RunErrorCallbackAndDestroy("Cannot read section-lengths.");
       return;
     }
 
-    // Step 6. "Let sectionLengths be the result of parsing one CBOR item
+    // Step 11. "Let sectionLengths be the result of parsing one CBOR item
     // (Section 3.5) from sectionLengthsBytes, matching the section-lengths
     // rule in the CDDL ([I-D.ietf-cbor-cddl]) above. If sectionLengths is an
-    // error, return an error."
+    // error, return a "format error" with fallbackUrl."
     const auto section_lengths = ParseSectionLengths(*section_lengths_bytes);
     if (!section_lengths) {
       RunErrorCallbackAndDestroy("Cannot parse section-lengths.");
       return;
     }
 
-    // Step 7. "Let (sectionsType, numSections) be the result of parsing the
+    // Step 12. "Let (sectionsType, numSections) be the result of parsing the
     // type and argument of a CBOR item from stream (Section 3.5.3)."
     const auto num_sections = input.ReadCBORHeader(CBORType::kArray);
     if (!num_sections) {
@@ -349,44 +452,46 @@
       return;
     }
 
-    // Step 8. "If sectionsType is not 4 (a CBOR array) or numSections is not
-    // half of the length of sectionLengths, return an error."
+    // Step 13. "If sectionsType is not 4 (a CBOR array) or numSections is not
+    // half of the length of sectionLengths, return a "format error" with
+    // fallbackUrl."
     if (*num_sections != section_lengths->size()) {
       RunErrorCallbackAndDestroy("Unexpected number of sections.");
       return;
     }
 
-    // Step 9. "Let sectionsStart be the current offset within stream."
-    const uint64_t sections_start = input.CurrentOffset();
+    // Step 14. "Let sectionsStart be the current offset within stream."
+    // Note: This doesn't exceed |size_|.
+    const uint64_t sections_start = offset_in_stream + input.CurrentOffset();
 
-    // Step 10. "Let knownSections be the subset of the Section 6.2 that this
+    // Step 15. "Let knownSections be the subset of the Section 6.2 that this
     // client has implemented."
-    // Step 11. "Let ignoredSections be an empty set."
+    // Step 16. "Let ignoredSections be an empty set."
 
     // This implementation doesn't use knownSections nor ignoredSections.
 
-    // Step 12. "Let sectionOffsets be an empty map ([INFRA]) from section names
+    // Step 17. "Let sectionOffsets be an empty map ([INFRA]) from section names
     // to (offset, length) pairs. These offsets are relative to the start of
     // stream."
 
     // |section_offsets_| is defined as a class member field.
 
-    // Step 13. "Let currentOffset be sectionsStart."
+    // Step 18. "Let currentOffset be sectionsStart."
     uint64_t current_offset = sections_start;
 
-    // Step 14. "For each ("name", length) pair of adjacent elements in
+    // Step 19. "For each ("name", length) pair of adjacent elements in
     // sectionLengths:"
     for (const auto& pair : *section_lengths) {
       const std::string& name = pair.first;
       const uint64_t length = pair.second;
-      // Step 14.1. "If "name"'s specification in knownSections says not to
+      // Step 19.1. "If "name"'s specification in knownSections says not to
       // process other sections, add those sections' names to ignoredSections."
 
       // There're no such sections at the moment.
 
-      // Step 14.2. "If sectionOffsets["name"] exists, return an error. That is,
-      // duplicate sections are forbidden."
-      // Step 14.3. "Set sectionOffsets["name"] to (currentOffset, length)."
+      // Step 19.2. "If sectionOffsets["name"] exists, return a "format error"
+      // with fallbackUrl. That is, duplicate sections are forbidden."
+      // Step 19.3. "Set sectionOffsets["name"] to (currentOffset, length)."
       bool added = section_offsets_
                        .insert(std::make_pair(
                            name, std::make_pair(current_offset, length)))
@@ -396,7 +501,7 @@
         return;
       }
 
-      // Step 14.4. "Set currentOffset to currentOffset + length."
+      // Step 19.4. "Set currentOffset to currentOffset + length."
       if (!base::CheckAdd(current_offset, length)
                .AssignIfValid(&current_offset) ||
           current_offset > size_) {
@@ -405,9 +510,10 @@
       }
     }
 
-    // Step 15. "If the "responses" section is not last in sectionLengths,
-    // return an error. This allows a streaming parser to assume that it'll
-    // know the requests by the time their responses arrive."
+    // Step 20. "If the "responses" section is not last in sectionLengths,
+    // return a "format error" with fallbackUrl. This allows a streaming parser
+    // to assume that it'll know the requests by the time their responses
+    // arrive."
     if (section_lengths->empty() ||
         section_lengths->back().first != kResponsesSection) {
       RunErrorCallbackAndDestroy(
@@ -618,8 +724,8 @@
     }
 
     // We're done.
-    RunSuccessCallbackAndDestroy(
-        mojom::BundleMetadata::New(std::move(items_), manifest_url_));
+    RunSuccessCallbackAndDestroy(mojom::BundleMetadata::New(
+        fallback_url_, std::move(items_), manifest_url_));
   }
 
   void RunSuccessCallbackAndDestroy(mojom::BundleMetadataPtr metadata) {
@@ -627,9 +733,14 @@
     delete this;
   }
 
-  void RunErrorCallbackAndDestroy(const std::string& message) {
-    std::move(callback_).Run(nullptr,
-                             mojom::BundleMetadataParseError::New(message));
+  void RunErrorCallbackAndDestroy(
+      const base::Optional<std::string>& error_message,
+      mojom::BundleParseErrorType error_type =
+          mojom::BundleParseErrorType::kFormatError) {
+    mojom::BundleMetadataParseErrorPtr err =
+        mojom::BundleMetadataParseError::New(error_type, fallback_url_,
+                                             *error_message);
+    std::move(callback_).Run(nullptr, std::move(err));
     delete this;
   }
 
@@ -641,6 +752,8 @@
   scoped_refptr<SharedBundleDataSource> data_source_;
   ParseMetadataCallback callback_;
   uint64_t size_;
+  bool version_mismatch_ = false;
+  GURL fallback_url_;
   // name -> (offset, length)
   std::map<std::string, std::pair<uint64_t, uint64_t>> section_offsets_;
   std::vector<mojom::BundleIndexItemPtr> items_;
@@ -814,9 +927,12 @@
     delete this;
   }
 
-  void RunErrorCallbackAndDestroy(const std::string& message) {
-    std::move(callback_).Run(nullptr,
-                             mojom::BundleResponseParseError::New(message));
+  void RunErrorCallbackAndDestroy(
+      const std::string& message,
+      mojom::BundleParseErrorType error_type =
+          mojom::BundleParseErrorType::kFormatError) {
+    std::move(callback_).Run(
+        nullptr, mojom::BundleResponseParseError::New(error_type, message));
     delete this;
   }
 
diff --git a/services/data_decoder/bundled_exchanges_parser_unittest.cc b/services/data_decoder/bundled_exchanges_parser_unittest.cc
index 700c90f5..24cb78b 100644
--- a/services/data_decoder/bundled_exchanges_parser_unittest.cc
+++ b/services/data_decoder/bundled_exchanges_parser_unittest.cc
@@ -18,6 +18,8 @@
 
 namespace {
 
+constexpr char kFallbackUrl[] = "https://test.example.com/";
+
 std::string GetTestFileContents(const base::FilePath& path) {
   base::FilePath test_data_dir;
   base::PathService::Get(base::DIR_SOURCE_ROOT, &test_data_dir);
@@ -62,7 +64,10 @@
   mojo::ReceiverSet<mojom::BundleDataSource> receivers_;
 };
 
-mojom::BundleMetadataPtr ParseBundle(TestDataSource* data_source) {
+using ParseBundleResult =
+    std::pair<mojom::BundleMetadataPtr, mojom::BundleMetadataParseErrorPtr>;
+
+ParseBundleResult ParseBundle(TestDataSource* data_source) {
   mojo::PendingRemote<mojom::BundleDataSource> source_remote;
   data_source->AddReceiver(source_remote.InitWithNewPipeAndPassReceiver());
 
@@ -72,17 +77,25 @@
   data_decoder::mojom::BundledExchangesParser& parser = parser_impl;
 
   base::RunLoop run_loop;
-  mojom::BundleMetadataPtr result;
+  ParseBundleResult result;
   parser.ParseMetadata(base::BindLambdaForTesting(
       [&result, &run_loop](mojom::BundleMetadataPtr metadata,
                            mojom::BundleMetadataParseErrorPtr error) {
-        result = std::move(metadata);
+        result = std::make_pair(std::move(metadata), std::move(error));
         run_loop.QuitClosure().Run();
       }));
   run_loop.Run();
+  EXPECT_TRUE((result.first && !result.second) ||
+              (!result.first && result.second));
   return result;
 }
 
+void ExpectFormatErrorWithFallbackURL(ParseBundleResult result) {
+  ASSERT_TRUE(result.second);
+  EXPECT_EQ(result.second->type, mojom::BundleParseErrorType::kFormatError);
+  EXPECT_EQ(result.second->fallback_url, kFallbackUrl);
+}
+
 mojom::BundleResponsePtr ParseResponse(TestDataSource* data_source,
                                        const mojom::BundleIndexItemPtr& item) {
   mojo::PendingRemote<mojom::BundleDataSource> source_remote;
@@ -111,12 +124,16 @@
  public:
   using Headers = std::vector<std::pair<std::string, std::string>>;
 
+  explicit BundleBuilder(const std::string& fallback_url)
+      : fallback_url_(fallback_url) {
+    writer_config_.allow_invalid_utf8_for_testing = true;
+  }
+
   void AddExchange(const Headers& request_headers,
                    const Headers& response_headers,
                    base::StringPiece payload) {
     cbor::Value::ArrayValue response_array;
-    response_array.emplace_back(
-        *cbor::Writer::Write(CreateHeaderMap(response_headers)));
+    response_array.emplace_back(Encode(CreateHeaderMap(response_headers)));
     response_array.emplace_back(CreateByteString(payload));
     cbor::Value response(response_array);
 
@@ -134,7 +151,7 @@
   std::vector<uint8_t> CreateBundle() {
     AddSection("index", cbor::Value(index_));
     AddSection("responses", cbor::Value(responses_));
-    return *cbor::Writer::Write(CreateTopLevel());
+    return Encode(CreateTopLevel());
   }
 
  private:
@@ -154,16 +171,25 @@
     toplevel_array.emplace_back(
         CreateByteString(u8"\U0001F310\U0001F4E6"));  // "🌐📦"
     toplevel_array.emplace_back(
-        *cbor::Writer::Write(cbor::Value(section_lengths_)));
+        CreateByteString(base::StringPiece("b1\0\0", 4)));
+    toplevel_array.emplace_back(
+        cbor::Value::InvalidUTF8StringValueForTesting(fallback_url_));
+    toplevel_array.emplace_back(Encode(cbor::Value(section_lengths_)));
     toplevel_array.emplace_back(sections_);
     toplevel_array.emplace_back(CreateByteString(""));  // length (ignored)
     return cbor::Value(toplevel_array);
   }
 
-  static int64_t EncodedLength(const cbor::Value& value) {
-    return cbor::Writer::Write(value)->size();
+  std::vector<uint8_t> Encode(const cbor::Value& value) {
+    return *cbor::Writer::Write(value, writer_config_);
   }
 
+  int64_t EncodedLength(const cbor::Value& value) {
+    return Encode(value).size();
+  }
+
+  cbor::Writer::Config writer_config_;
+  std::string fallback_url_;
   cbor::Value::ArrayValue section_lengths_;
   cbor::Value::ArrayValue sections_;
   cbor::Value::ArrayValue index_;
@@ -178,10 +204,10 @@
 };
 
 TEST_F(BundledExchangeParserTest, EmptyBundle) {
-  BundleBuilder builder;
+  BundleBuilder builder(kFallbackUrl);
   TestDataSource data_source(builder.CreateBundle());
 
-  mojom::BundleMetadataPtr metadata = ParseBundle(&data_source);
+  mojom::BundleMetadataPtr metadata = ParseBundle(&data_source).first;
   ASSERT_TRUE(metadata);
   const auto& index = metadata->index;
 
@@ -189,40 +215,68 @@
 }
 
 TEST_F(BundledExchangeParserTest, WrongMagic) {
-  BundleBuilder builder;
+  BundleBuilder builder(kFallbackUrl);
   std::vector<uint8_t> bundle = builder.CreateBundle();
   bundle[3] ^= 1;
   TestDataSource data_source(bundle);
 
-  ASSERT_FALSE(ParseBundle(&data_source));
+  mojom::BundleMetadataParseErrorPtr error = ParseBundle(&data_source).second;
+  ASSERT_TRUE(error);
+  EXPECT_EQ(error->type, mojom::BundleParseErrorType::kFormatError);
+  EXPECT_TRUE(error->fallback_url.is_empty());
+}
+
+TEST_F(BundledExchangeParserTest, UnknownVersion) {
+  BundleBuilder builder(kFallbackUrl);
+  std::vector<uint8_t> bundle = builder.CreateBundle();
+  // Modify the version string from "b1\0\0" to "q1\0\0".
+  ASSERT_EQ(bundle[11], 'b');
+  bundle[11] = 'q';
+  TestDataSource data_source(bundle);
+
+  mojom::BundleMetadataParseErrorPtr error = ParseBundle(&data_source).second;
+  ASSERT_TRUE(error);
+  EXPECT_EQ(error->type, mojom::BundleParseErrorType::kVersionError);
+  EXPECT_EQ(error->fallback_url, kFallbackUrl);
+}
+
+TEST_F(BundledExchangeParserTest, FallbackURLIsNotUTF8) {
+  BundleBuilder builder("https://test.example.com/\xcc");
+  std::vector<uint8_t> bundle = builder.CreateBundle();
+  TestDataSource data_source(bundle);
+
+  mojom::BundleMetadataParseErrorPtr error = ParseBundle(&data_source).second;
+  ASSERT_TRUE(error);
+  EXPECT_EQ(error->type, mojom::BundleParseErrorType::kFormatError);
+  EXPECT_TRUE(error->fallback_url.is_empty());
 }
 
 TEST_F(BundledExchangeParserTest, SectionLengthsTooLarge) {
-  BundleBuilder builder;
+  BundleBuilder builder(kFallbackUrl);
   std::string too_long_section_name(8192, 'x');
   builder.AddSection(too_long_section_name, cbor::Value(0));
   TestDataSource data_source(builder.CreateBundle());
 
-  ASSERT_FALSE(ParseBundle(&data_source));
+  ExpectFormatErrorWithFallbackURL(ParseBundle(&data_source));
 }
 
 TEST_F(BundledExchangeParserTest, DuplicateSectionName) {
-  BundleBuilder builder;
+  BundleBuilder builder(kFallbackUrl);
   builder.AddSection("foo", cbor::Value(0));
   builder.AddSection("foo", cbor::Value(0));
   TestDataSource data_source(builder.CreateBundle());
 
-  ASSERT_FALSE(ParseBundle(&data_source));
+  ExpectFormatErrorWithFallbackURL(ParseBundle(&data_source));
 }
 
 TEST_F(BundledExchangeParserTest, SingleEntry) {
-  BundleBuilder builder;
+  BundleBuilder builder(kFallbackUrl);
   builder.AddExchange(
       {{":method", "GET"}, {":url", "https://test.example.com/"}},
       {{":status", "200"}, {"content-type", "text/plain"}}, "payload");
   TestDataSource data_source(builder.CreateBundle());
 
-  mojom::BundleMetadataPtr metadata = ParseBundle(&data_source);
+  mojom::BundleMetadataPtr metadata = ParseBundle(&data_source).first;
   ASSERT_TRUE(metadata);
   const auto& index = metadata->index;
 
@@ -240,62 +294,57 @@
 }
 
 TEST_F(BundledExchangeParserTest, InvalidRequestURL) {
-  BundleBuilder builder;
+  BundleBuilder builder(kFallbackUrl);
   builder.AddExchange({{":method", "GET"}, {":url", ""}},
                       {{":status", "200"}, {"content-type", "text/plain"}},
                       "payload");
   TestDataSource data_source(builder.CreateBundle());
 
-  mojom::BundleMetadataPtr metadata = ParseBundle(&data_source);
-  ASSERT_FALSE(metadata);
+  ExpectFormatErrorWithFallbackURL(ParseBundle(&data_source));
 }
 
 TEST_F(BundledExchangeParserTest, RequestURLHasCredentials) {
-  BundleBuilder builder;
+  BundleBuilder builder(kFallbackUrl);
   builder.AddExchange(
       {{":method", "GET"}, {":url", "https://user:passwd@test.example.com/"}},
       {{":status", "200"}, {"content-type", "text/plain"}}, "payload");
   TestDataSource data_source(builder.CreateBundle());
 
-  mojom::BundleMetadataPtr metadata = ParseBundle(&data_source);
-  ASSERT_FALSE(metadata);
+  ExpectFormatErrorWithFallbackURL(ParseBundle(&data_source));
 }
 
 TEST_F(BundledExchangeParserTest, RequestURLHasFragment) {
-  BundleBuilder builder;
+  BundleBuilder builder(kFallbackUrl);
   builder.AddExchange(
       {{":method", "GET"}, {":url", "https://test.example.com/#fragment"}},
       {{":status", "200"}, {"content-type", "text/plain"}}, "payload");
   TestDataSource data_source(builder.CreateBundle());
 
-  mojom::BundleMetadataPtr metadata = ParseBundle(&data_source);
-  ASSERT_FALSE(metadata);
+  ExpectFormatErrorWithFallbackURL(ParseBundle(&data_source));
 }
 
 TEST_F(BundledExchangeParserTest, NoMethodInRequestHeaders) {
-  BundleBuilder builder;
+  BundleBuilder builder(kFallbackUrl);
   builder.AddExchange(
       {{":url", "https://test.example.com/"}},  // ":method" is missing.
       {{":status", "200"}, {"content-type", "text/plain"}}, "payload");
   TestDataSource data_source(builder.CreateBundle());
 
-  mojom::BundleMetadataPtr metadata = ParseBundle(&data_source);
-  ASSERT_FALSE(metadata);
+  ExpectFormatErrorWithFallbackURL(ParseBundle(&data_source));
 }
 
 TEST_F(BundledExchangeParserTest, MethodIsNotGET) {
-  BundleBuilder builder;
+  BundleBuilder builder(kFallbackUrl);
   builder.AddExchange(
       {{":method", "POST"}, {":url", "https://test.example.com/"}},
       {{":status", "200"}, {"content-type", "text/plain"}}, "payload");
   TestDataSource data_source(builder.CreateBundle());
 
-  mojom::BundleMetadataPtr metadata = ParseBundle(&data_source);
-  ASSERT_FALSE(metadata);
+  ExpectFormatErrorWithFallbackURL(ParseBundle(&data_source));
 }
 
 TEST_F(BundledExchangeParserTest, ExtraPseudoInRequestHeaders) {
-  BundleBuilder builder;
+  BundleBuilder builder(kFallbackUrl);
   builder.AddExchange({{":method", "GET"},
                        {":url", "https://test.example.com/"},
                        {":scheme", "https"}},
@@ -303,17 +352,17 @@
                       "payload");
   TestDataSource data_source(builder.CreateBundle());
 
-  ASSERT_FALSE(ParseBundle(&data_source));
+  ExpectFormatErrorWithFallbackURL(ParseBundle(&data_source));
 }
 
 TEST_F(BundledExchangeParserTest, NoStatusInResponseHeaders) {
-  BundleBuilder builder;
+  BundleBuilder builder(kFallbackUrl);
   builder.AddExchange(
       {{":method", "GET"}, {":url", "https://test.example.com/"}},
       {{"content-type", "text/plain"}}, "payload");  // ":status" is missing.
   TestDataSource data_source(builder.CreateBundle());
 
-  mojom::BundleMetadataPtr metadata = ParseBundle(&data_source);
+  mojom::BundleMetadataPtr metadata = ParseBundle(&data_source).first;
   ASSERT_TRUE(metadata);
   ASSERT_EQ(metadata->index.size(), 1u);
 
@@ -321,13 +370,13 @@
 }
 
 TEST_F(BundledExchangeParserTest, InvalidResponseStatus) {
-  BundleBuilder builder;
+  BundleBuilder builder(kFallbackUrl);
   builder.AddExchange(
       {{":method", "GET"}, {":url", "https://test.example.com/"}},
       {{":status", "0200"}, {"content-type", "text/plain"}}, "payload");
   TestDataSource data_source(builder.CreateBundle());
 
-  mojom::BundleMetadataPtr metadata = ParseBundle(&data_source);
+  mojom::BundleMetadataPtr metadata = ParseBundle(&data_source).first;
   ASSERT_TRUE(metadata);
   ASSERT_EQ(metadata->index.size(), 1u);
 
@@ -335,14 +384,14 @@
 }
 
 TEST_F(BundledExchangeParserTest, ExtraPseudoInResponseHeaders) {
-  BundleBuilder builder;
+  BundleBuilder builder(kFallbackUrl);
   builder.AddExchange(
       {{":method", "GET"}, {":url", "https://test.example.com/"}},
       {{":status", "200"}, {":foo", ""}, {"content-type", "text/plain"}},
       "payload");
   TestDataSource data_source(builder.CreateBundle());
 
-  mojom::BundleMetadataPtr metadata = ParseBundle(&data_source);
+  mojom::BundleMetadataPtr metadata = ParseBundle(&data_source).first;
   ASSERT_TRUE(metadata);
   ASSERT_EQ(metadata->index.size(), 1u);
 
@@ -350,13 +399,13 @@
 }
 
 TEST_F(BundledExchangeParserTest, UpperCaseCharacterInHeaderName) {
-  BundleBuilder builder;
+  BundleBuilder builder(kFallbackUrl);
   builder.AddExchange(
       {{":method", "GET"}, {":url", "https://test.example.com/"}},
       {{":status", "200"}, {"Content-Type", "text/plain"}}, "payload");
   TestDataSource data_source(builder.CreateBundle());
 
-  mojom::BundleMetadataPtr metadata = ParseBundle(&data_source);
+  mojom::BundleMetadataPtr metadata = ParseBundle(&data_source).first;
   ASSERT_TRUE(metadata);
   ASSERT_EQ(metadata->index.size(), 1u);
 
@@ -364,13 +413,13 @@
 }
 
 TEST_F(BundledExchangeParserTest, InvalidHeaderValue) {
-  BundleBuilder builder;
+  BundleBuilder builder(kFallbackUrl);
   builder.AddExchange(
       {{":method", "GET"}, {":url", "https://test.example.com/"}},
       {{":status", "200"}, {"content-type", "\n"}}, "payload");
   TestDataSource data_source(builder.CreateBundle());
 
-  mojom::BundleMetadataPtr metadata = ParseBundle(&data_source);
+  mojom::BundleMetadataPtr metadata = ParseBundle(&data_source).first;
   ASSERT_TRUE(metadata);
   ASSERT_EQ(metadata->index.size(), 1u);
 
@@ -380,7 +429,7 @@
 TEST_F(BundledExchangeParserTest, ParseGoldenFile) {
   TestDataSource data_source(base::FilePath(FILE_PATH_LITERAL("hello.wbn")));
 
-  mojom::BundleMetadataPtr metadata = ParseBundle(&data_source);
+  mojom::BundleMetadataPtr metadata = ParseBundle(&data_source).first;
   ASSERT_TRUE(metadata);
   ASSERT_EQ(metadata->index.size(), 4u);
 
diff --git a/services/data_decoder/public/cpp/safe_bundled_exchanges_parser.cc b/services/data_decoder/public/cpp/safe_bundled_exchanges_parser.cc
index dfdd19c..92b3263 100644
--- a/services/data_decoder/public/cpp/safe_bundled_exchanges_parser.cc
+++ b/services/data_decoder/public/cpp/safe_bundled_exchanges_parser.cc
@@ -60,7 +60,9 @@
   // simultaneous request is fine enough.
   if (disconnected_ || !metadata_callback_.is_null()) {
     std::move(callback).Run(
-        nullptr, mojom::BundleMetadataParseError::New(kConnectionError));
+        nullptr, mojom::BundleMetadataParseError::New(
+                     mojom::BundleParseErrorType::kParserInternalError,
+                     GURL() /* fallback_url */, kConnectionError));
     return;
   }
   metadata_callback_ = std::move(callback);
@@ -78,7 +80,9 @@
   if (disconnected_ ||
       response_callbacks_.contains(response_callback_next_id_)) {
     std::move(callback).Run(
-        nullptr, mojom::BundleResponseParseError::New(kConnectionError));
+        nullptr, mojom::BundleResponseParseError::New(
+                     mojom::BundleParseErrorType::kParserInternalError,
+                     kConnectionError));
     return;
   }
   size_t callback_id = response_callback_next_id_++;
@@ -93,10 +97,14 @@
   disconnected_ = true;
   if (!metadata_callback_.is_null())
     std::move(metadata_callback_)
-        .Run(nullptr, mojom::BundleMetadataParseError::New(kConnectionError));
+        .Run(nullptr, mojom::BundleMetadataParseError::New(
+                          mojom::BundleParseErrorType::kParserInternalError,
+                          GURL() /* fallback_url */, kConnectionError));
   for (auto& callback : response_callbacks_)
     std::move(callback.second)
-        .Run(nullptr, mojom::BundleResponseParseError::New(kConnectionError));
+        .Run(nullptr, mojom::BundleResponseParseError::New(
+                          mojom::BundleParseErrorType::kParserInternalError,
+                          kConnectionError));
   response_callbacks_.clear();
 }
 
diff --git a/services/data_decoder/public/mojom/bundled_exchanges_parser.mojom b/services/data_decoder/public/mojom/bundled_exchanges_parser.mojom
index 25e47f0..3356c8d 100644
--- a/services/data_decoder/public/mojom/bundled_exchanges_parser.mojom
+++ b/services/data_decoder/public/mojom/bundled_exchanges_parser.mojom
@@ -38,16 +38,26 @@
   Read(uint64 offset, uint64 length) => (array<uint8>? buffer);
 };
 
+enum BundleParseErrorType {
+  kParserInternalError,
+  kFormatError,
+  kVersionError,
+};
+
 struct BundleMetadataParseError {
+  BundleParseErrorType type;
+  url.mojom.Url fallback_url;
   string message;
-  // TODO(crbug.com/969596): Add fields for error type and fallback URL.
 };
 
 struct BundleResponseParseError {
+  BundleParseErrorType type;
   string message;
 };
 
+// https://wicg.github.io/webpackage/draft-yasskin-wpack-bundled-exchanges.html#semantics-load-metadata
 struct BundleMetadata {
+  url.mojom.Url primary_url;
   array<BundleIndexItem> index;
   url.mojom.Url manifest_url;
 };
diff --git a/services/device/nfc/android/java/src/org/chromium/device/nfc/NfcImpl.java b/services/device/nfc/android/java/src/org/chromium/device/nfc/NfcImpl.java
index bab5e852..ee7de36 100644
--- a/services/device/nfc/android/java/src/org/chromium/device/nfc/NfcImpl.java
+++ b/services/device/nfc/android/java/src/org/chromium/device/nfc/NfcImpl.java
@@ -557,17 +557,20 @@
         try {
             mTagHandler.connect();
             message = mTagHandler.read();
+            if (message == null) {
+                Log.w(TAG, "Cannot read data from NFC tag. Tag is empty.");
+                return;
+            }
             if (message.getByteArrayLength() > NdefMessage.MAX_SIZE) {
                 Log.w(TAG, "Cannot read data from NFC tag. NdefMessage exceeds allowed size.");
                 return;
             }
+            notifyMatchingWatchers(message, mTagHandler.compatibility());
         } catch (TagLostException e) {
             Log.w(TAG, "Cannot read data from NFC tag. Tag is lost.");
         } catch (FormatException | IllegalStateException | IOException e) {
             Log.w(TAG, "Cannot read data from NFC tag. IO_ERROR.");
         }
-
-        if (message != null) notifyMatchingWatchers(message, mTagHandler.compatibility());
     }
 
     /**
diff --git a/services/identity/identity_accessor_impl.cc b/services/identity/identity_accessor_impl.cc
index a148f98..cecd3bf9 100644
--- a/services/identity/identity_accessor_impl.cc
+++ b/services/identity/identity_accessor_impl.cc
@@ -100,7 +100,8 @@
   OnAccountStateChange(primary_account_info.account_id);
 }
 
-void IdentityAccessorImpl::OnAccountStateChange(const std::string& account_id) {
+void IdentityAccessorImpl::OnAccountStateChange(
+    const CoreAccountId& account_id) {
   base::Optional<AccountInfo> account_info =
       identity_manager_
           ->FindExtendedAccountInfoForAccountWithRefreshTokenByAccountId(
diff --git a/services/identity/identity_accessor_impl.h b/services/identity/identity_accessor_impl.h
index da7b2e3..cedd2cd 100644
--- a/services/identity/identity_accessor_impl.h
+++ b/services/identity/identity_accessor_impl.h
@@ -59,7 +59,7 @@
 
   // Notified when there is a change in the state of the account
   // corresponding to |account_id|.
-  void OnAccountStateChange(const std::string& account_id);
+  void OnAccountStateChange(const CoreAccountId& account_id);
 
   // Gets the current state of the account represented by |account_info|.
   AccountState GetStateOfAccount(const CoreAccountInfo& account_info);
diff --git a/services/network/chunked_data_pipe_upload_data_stream_unittest.cc b/services/network/chunked_data_pipe_upload_data_stream_unittest.cc
index b9a0e794..dfb0872 100644
--- a/services/network/chunked_data_pipe_upload_data_stream_unittest.cc
+++ b/services/network/chunked_data_pipe_upload_data_stream_unittest.cc
@@ -11,9 +11,9 @@
 
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/test/scoped_task_environment.h"
 #include "mojo/public/cpp/system/data_pipe.h"
 #include "mojo/public/cpp/system/data_pipe_utils.h"
 #include "net/base/completion_once_callback.h"
@@ -55,7 +55,8 @@
   }
 
  protected:
-  base::MessageLoopForIO message_loop_;
+  base::test::ScopedTaskEnvironment scoped_task_environment_{
+      base::test::ScopedTaskEnvironment::MainThreadType::IO};
   std::unique_ptr<TestChunkedDataPipeGetter> chunked_data_pipe_getter_;
   std::unique_ptr<ChunkedDataPipeUploadDataStream> chunked_upload_stream_;
 
diff --git a/services/network/data_pipe_element_reader_unittest.cc b/services/network/data_pipe_element_reader_unittest.cc
index cc13e67b..599c342 100644
--- a/services/network/data_pipe_element_reader_unittest.cc
+++ b/services/network/data_pipe_element_reader_unittest.cc
@@ -11,9 +11,9 @@
 
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/test/scoped_task_environment.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "mojo/public/cpp/system/data_pipe.h"
 #include "mojo/public/cpp/system/data_pipe_utils.h"
@@ -91,7 +91,8 @@
       : element_reader_(nullptr, data_pipe_getter_.GetDataPipeGetterPtr()) {}
 
  protected:
-  base::MessageLoopForIO message_loop_;
+  base::test::ScopedTaskEnvironment scoped_task_environment_{
+      base::test::ScopedTaskEnvironment::MainThreadType::IO};
   PassThroughDataPipeGetter data_pipe_getter_;
   DataPipeElementReader element_reader_;
 };
diff --git a/services/network/network_context.cc b/services/network/network_context.cc
index 8cee3ac..7ccb067 100644
--- a/services/network/network_context.cc
+++ b/services/network/network_context.cc
@@ -1245,7 +1245,6 @@
     const url::Origin& origin,
     uint32_t options,
     mojom::WebSocketHandshakeClientPtr handshake_client,
-    mojom::WebSocketClientPtr client,
     mojom::AuthenticationHandlerPtr auth_handler,
     mojom::TrustedHeaderClientPtr header_client) {
 #if !defined(OS_IOS)
@@ -1254,7 +1253,7 @@
   websocket_factory_->CreateWebSocket(
       url, requested_protocols, site_for_cookies, std::move(additional_headers),
       process_id, render_frame_id, origin, options, std::move(handshake_client),
-      std::move(client), std::move(auth_handler), std::move(header_client));
+      std::move(auth_handler), std::move(header_client));
 #endif  // !defined(OS_IOS)
 }
 
diff --git a/services/network/network_context.h b/services/network/network_context.h
index d2a93d3b..f921eb6 100644
--- a/services/network/network_context.h
+++ b/services/network/network_context.h
@@ -271,7 +271,6 @@
                        const url::Origin& origin,
                        uint32_t options,
                        mojom::WebSocketHandshakeClientPtr handshake_client,
-                       mojom::WebSocketClientPtr client,
                        mojom::AuthenticationHandlerPtr auth_handler,
                        mojom::TrustedHeaderClientPtr header_client) override;
   void CreateNetLogExporter(mojom::NetLogExporterRequest request) override;
diff --git a/services/network/public/mojom/BUILD.gn b/services/network/public/mojom/BUILD.gn
index 012e70b9..2a3ab723 100644
--- a/services/network/public/mojom/BUILD.gn
+++ b/services/network/public/mojom/BUILD.gn
@@ -87,6 +87,7 @@
     "host_resolver.mojom",
     "http_raw_headers.mojom",
     "http_request_headers.mojom",
+    "ip_address_space.mojom",
     "mdns_responder.mojom",
     "net_log.mojom",
     "network_change_manager.mojom",
diff --git a/third_party/blink/public/mojom/net/ip_address_space.mojom b/services/network/public/mojom/ip_address_space.mojom
similarity index 95%
rename from third_party/blink/public/mojom/net/ip_address_space.mojom
rename to services/network/public/mojom/ip_address_space.mojom
index c094297..6f08b39 100644
--- a/third_party/blink/public/mojom/net/ip_address_space.mojom
+++ b/services/network/public/mojom/ip_address_space.mojom
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-module blink.mojom;
+module network.mojom;
 
 // Represents AddressSpace from the "CORS and RFC1918" spec. The ordering is
 // important, as it's used to determine whether preflights are required, as per
diff --git a/services/network/public/mojom/network_context.mojom b/services/network/public/mojom/network_context.mojom
index 58b18e0..b9e1d666 100644
--- a/services/network/public/mojom/network_context.mojom
+++ b/services/network/public/mojom/network_context.mojom
@@ -864,15 +864,12 @@
   // performance impact because of the extra process hops, so use should be
   // minimized.
   //
-  // Detect mojo connection errors on |handshake_client| in the caller side.
+  // Detect mojo connection errors on |handshake_client| until the connection
+  // is established.
   // Do *NOT* interpret mojo connection errors on |auth_handler| and
   // |header_client| as WebSocket connection errors. They are disconnected when
   // the connection is established, and due to message ordering uncertainty we
-  // cannot know what happened. |handshake_client| doesn't have such an issue
-  // because OnConnectionEstablished will be called when the connection is
-  // established, but it is still recommended to rely only on
-  // |connection_client| because |connection_client| can be disconnected with
-  // custom reasons.
+  // cannot know what happened.
   CreateWebSocket(
         url.mojom.Url url,
         array<string> requested_protocols,
@@ -883,7 +880,6 @@
         url.mojom.Origin origin,
         uint32 options,
         WebSocketHandshakeClient handshake_client,
-        WebSocketClient connection_client,
         AuthenticationHandler? auth_handler,
         TrustedHeaderClient? header_client);
 
diff --git a/services/network/public/mojom/websocket.mojom b/services/network/public/mojom/websocket.mojom
index d17451e..a4e893f 100644
--- a/services/network/public/mojom/websocket.mojom
+++ b/services/network/public/mojom/websocket.mojom
@@ -68,6 +68,7 @@
   // AddReceiveFlowControlQuota() to the browser per receiving this value
   // so that the browser can continue sending remaining data to the renderer.
   OnConnectionEstablished(WebSocket socket,
+                          pending_receiver<WebSocketClient> client_receiver,
                           string selected_protocol,
                           string extensions,
                           uint64 receive_quota_threshold);
diff --git a/services/network/restricted_cookie_manager_unittest.cc b/services/network/restricted_cookie_manager_unittest.cc
index 446be4d..ce4cca7 100644
--- a/services/network/restricted_cookie_manager_unittest.cc
+++ b/services/network/restricted_cookie_manager_unittest.cc
@@ -7,10 +7,10 @@
 #include <algorithm>
 
 #include "base/bind.h"
-#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/test/bind_test_util.h"
 #include "base/test/scoped_feature_list.h"
+#include "base/test/scoped_task_environment.h"
 #include "base/time/time.h"
 #include "mojo/core/embedder/embedder.h"
 #include "net/base/features.h"
@@ -250,7 +250,8 @@
     return recording_client_.recorded_activity();
   }
 
-  base::MessageLoopForIO message_loop_;
+  base::test::ScopedTaskEnvironment scoped_task_environment_{
+      base::test::ScopedTaskEnvironment::MainThreadType::IO};
   net::CookieMonster cookie_monster_;
   CookieSettings cookie_settings_;
   RecordingNetworkContextClient recording_client_;
diff --git a/services/network/test/test_network_context.h b/services/network/test/test_network_context.h
index 4646c33d..670d2b8 100644
--- a/services/network/test/test_network_context.h
+++ b/services/network/test/test_network_context.h
@@ -146,7 +146,6 @@
                        const url::Origin& origin,
                        uint32_t options,
                        mojom::WebSocketHandshakeClientPtr handshake_client,
-                       mojom::WebSocketClientPtr client,
                        mojom::AuthenticationHandlerPtr auth_handler,
                        mojom::TrustedHeaderClientPtr header_client) override {}
   void LookUpProxyForURL(
diff --git a/services/network/websocket.cc b/services/network/websocket.cc
index 70409f1..c715b3a 100644
--- a/services/network/websocket.cc
+++ b/services/network/websocket.cc
@@ -167,11 +167,13 @@
   }
   DVLOG(3) << "receive_quota_threshold is " << receive_quota_threshold;
   impl_->handshake_client_->OnConnectionEstablished(
-      std::move(websocket_to_pass), selected_protocol, extensions,
-      receive_quota_threshold);
+      std::move(websocket_to_pass), mojo::MakeRequest(&impl_->client_),
+      selected_protocol, extensions, receive_quota_threshold);
   impl_->handshake_client_ = nullptr;
   impl_->auth_handler_ = nullptr;
   impl_->header_client_ = nullptr;
+  impl_->client_.set_connection_error_handler(
+      base::BindOnce(&WebSocket::OnConnectionError, base::Unretained(impl_)));
 }
 
 void WebSocket::WebSocketEventHandler::OnDataFrame(
@@ -342,7 +344,6 @@
     const url::Origin& origin,
     uint32_t options,
     mojom::WebSocketHandshakeClientPtr handshake_client,
-    mojom::WebSocketClientPtr client,
     mojom::AuthenticationHandlerPtr auth_handler,
     mojom::TrustedHeaderClientPtr header_client,
     WebSocketThrottler::PendingConnection pending_connection_tracker,
@@ -350,7 +351,6 @@
     : delegate_(std::move(delegate)),
       binding_(this),
       handshake_client_(std::move(handshake_client)),
-      client_(std::move(client)),
       auth_handler_(std::move(auth_handler)),
       header_client_(std::move(header_client)),
       pending_connection_tracker_(std::move(pending_connection_tracker)),
@@ -360,7 +360,6 @@
       frame_id_(frame_id),
       origin_(std::move(origin)) {
   DCHECK(handshake_client_);
-  DCHECK(client_);
   if (auth_handler_) {
     // Make sure the request dies if |auth_handler_| has an error, otherwise
     // requests can hang.
@@ -375,8 +374,6 @@
   }
   handshake_client_.set_connection_error_handler(
       base::BindOnce(&WebSocket::OnConnectionError, base::Unretained(this)));
-  client_.set_connection_error_handler(
-      base::BindOnce(&WebSocket::OnConnectionError, base::Unretained(this)));
   if (delay_ > base::TimeDelta()) {
     base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
         FROM_HERE,
diff --git a/services/network/websocket.h b/services/network/websocket.h
index 113accb9..cdfe2b77 100644
--- a/services/network/websocket.h
+++ b/services/network/websocket.h
@@ -73,7 +73,6 @@
             const url::Origin& origin,
             uint32_t options,
             mojom::WebSocketHandshakeClientPtr handshake_client,
-            mojom::WebSocketClientPtr client,
             mojom::AuthenticationHandlerPtr auth_handler,
             mojom::TrustedHeaderClientPtr header_client,
             WebSocketThrottler::PendingConnection pending_connection_tracker,
diff --git a/services/network/websocket_factory.cc b/services/network/websocket_factory.cc
index 715e3b7a..d6ef78ac 100644
--- a/services/network/websocket_factory.cc
+++ b/services/network/websocket_factory.cc
@@ -101,12 +101,11 @@
     const url::Origin& origin,
     uint32_t options,
     mojom::WebSocketHandshakeClientPtr handshake_client,
-    mojom::WebSocketClientPtr client,
     mojom::AuthenticationHandlerPtr auth_handler,
     mojom::TrustedHeaderClientPtr header_client) {
   if (throttler_.HasTooManyPendingConnections(process_id)) {
     // Too many websockets!
-    client.ResetWithReason(
+    handshake_client.ResetWithReason(
         mojom::WebSocket::kInsufficientResources,
         "Error in connection establishment: net::ERR_INSUFFICIENT_RESOURCES");
     return;
@@ -115,7 +114,7 @@
       std::make_unique<Delegate>(this, process_id), url, requested_protocols,
       site_for_cookies, std::move(additional_headers), process_id,
       render_frame_id, origin, options, std::move(handshake_client),
-      std::move(client), std::move(auth_handler), std::move(header_client),
+      std::move(auth_handler), std::move(header_client),
       throttler_.IssuePendingConnectionTracker(process_id),
       throttler_.CalculateDelay(process_id)));
 }
diff --git a/services/network/websocket_factory.h b/services/network/websocket_factory.h
index c0a3785..ab0c36b 100644
--- a/services/network/websocket_factory.h
+++ b/services/network/websocket_factory.h
@@ -36,7 +36,6 @@
                        const url::Origin& origin,
                        uint32_t options,
                        mojom::WebSocketHandshakeClientPtr handshake_client,
-                       mojom::WebSocketClientPtr client,
                        mojom::AuthenticationHandlerPtr auth_handler,
                        mojom::TrustedHeaderClientPtr header_client);
 
diff --git a/services/test/data/bundled_exchanges/generate-test-wbns.sh b/services/test/data/bundled_exchanges/generate-test-wbns.sh
index bc45ea3..d7159fc 100755
--- a/services/test/data/bundled_exchanges/generate-test-wbns.sh
+++ b/services/test/data/bundled_exchanges/generate-test-wbns.sh
@@ -12,7 +12,8 @@
     exit 1
 fi
 
-gen-bundle -baseURL https://test.example.org/ \
+gen-bundle -version b1 \
+           -baseURL https://test.example.org/ \
            -dir hello/ \
            -manifestURL manifest.webmanifest \
            -o hello.wbn
diff --git a/services/test/data/bundled_exchanges/hello.wbn b/services/test/data/bundled_exchanges/hello.wbn
index 78f912e..a1f9221 100644
--- a/services/test/data/bundled_exchanges/hello.wbn
+++ b/services/test/data/bundled_exchanges/hello.wbn
Binary files differ
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json
index 24e1a8e..5db6f906 100644
--- a/testing/buildbot/chromium.linux.json
+++ b/testing/buildbot/chromium.linux.json
@@ -7644,6 +7644,25 @@
     ],
     "gtest_tests": [
       {
+        "args": [
+          "--ozone-platform=headless"
+        ],
+        "experiment_percentage": 100,
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Ubuntu-16.04"
+            }
+          ]
+        },
+        "test": "content_unittests"
+      },
+      {
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
diff --git a/testing/buildbot/filters/bfcache.content_browsertests.filter b/testing/buildbot/filters/bfcache.content_browsertests.filter
index 60b5394..4a0d44e 100644
--- a/testing/buildbot/filters/bfcache.content_browsertests.filter
+++ b/testing/buildbot/filters/bfcache.content_browsertests.filter
@@ -1,6 +1,28 @@
-# These tests currently fail when run with --enable-features=BackForwardCache
--BackForwardCacheMetricsBrowserTest.Features_MainFrame_CrossOriginNavigation
+# These tests currently fail when run with --enable-features=BackForwardCache.
+
+# Terminating renderer for bad IPC message, reason 205.
+-NavigationControllerBrowserTest.VerifyBlockedErrorPageURL_SessionHistory
+
+# Same-document navigation pointing to a URL that would cause a redirect if it
+# was reloaded. It never happen, because the document is restored directly.
+-NavigationControllerBrowserTest.SiteInstanceChangeOnHistoryNavigation
+
+# Expect an iframe to load again. It isn't because the page was restored from
+# the BackForwardCache.
 -BackForwardCacheMetricsBrowserTest.Features_SameOriginSubframes_CrossOriginNavigation
+-NavigationControllerBrowserTest.FrameNavigationEntry_DynamicSubframeHistoryFallback
+-NavigationControllerBrowserTest.FrameNavigationEntry_RecreatedSubframeBackForward
+-NavigationControllerBrowserTest.FrameNavigationEntry_SubframeHistoryFallback
+
+# Create a URLLoaderInterceptor. It should cause the navigation to fail, but it
+# isn't using an URLLoader anymore.
+-RenderFrameHostManagerTest.ErrorPageNavigationHistoryNavigationSuccess
+-RenderFrameHostManagerTest.ErrorPageNavigationHistoryNavigationFailure
+
+# Document expects javascript to run again from the beginning.
+-WebContentsImplBrowserTest.JavaScriptDialogsInMainAndSubframes
+
+# See https://crbug.com/989922.
 -DumpAccessibilityEventsTest.AccessibilityEventsTbodyFocus/linux
 -DumpAccessibilityEventsTest.AccessibilityEventsTfootFocus/linux
 -DumpAccessibilityEventsTest.AccessibilityEventsTheadFocus/linux
@@ -30,31 +52,42 @@
 -DumpAccessibilityTreeTest.AccessibilityTableTbodyTfoot/linux
 -DumpAccessibilityTreeTest.AccessibilityTableThColHeader/linux
 -DumpAccessibilityTreeTest.AccessibilityTableThRowHeader/linux
--DynamicIsolatedOriginTest.LockedProcessNotReusedForNonisolatedSameSiteNavigation
--DynamicIsolatedOriginTest.MainFrameNavigations
--NavigationControllerBrowserTest.FrameNavigationEntry_DynamicSubframeHistoryFallback
--NavigationControllerBrowserTest.FrameNavigationEntry_RecreatedSubframeBackForward
--NavigationControllerBrowserTest.FrameNavigationEntry_SubframeHistoryFallback
--NavigationControllerBrowserTest.HistoryBackTwiceFromRendererWithoutUserGesture
--NavigationControllerBrowserTest.NoDialogsFromSwappedOutFrames
+
+# Histogram not recorded. It will probably be fixed by https://crbug.com/976697.
+-NavigationHandleImplBrowserTest.StartToCommitMetrics
+
+# render_view_impl.cc. Check failed: !frame_widget_.
 -NavigationControllerBrowserTest.PageStateAfterForwardInCompetingFrames
 -NavigationControllerBrowserTest.PageStateWithIframeAfterForwardInCompetingFrames
--NavigationControllerBrowserTest.SiteInstanceChangeOnHistoryNavigation
--NavigationControllerBrowserTest.UtilizationOfSpareRenderProcessHost
--NavigationControllerBrowserTest.VerifyBlockedErrorPageURL_SessionHistory
 -NavigationControllerHistoryInterventionBrowserTest.NoUserActivationSetSkipOnBackForwardCrossSite
--NavigationHandleImplBrowserTest.StartToCommitMetrics
--RFHMProcessPerTabTest.BackFromWebUI
+-NavigationControllerHistoryInterventionBrowserTest.NoUserActivationSetSkipOnBackForwardCrossSite
 -RenderFrameHostManagerTest.BackForwardNotStale
+
+# Javascript dialog is shown from a page in the BackForwardCache.
+-NavigationControllerBrowserTest.NoDialogsFromSwappedOutFrames
+
+# history.back(); history.back() causes the tab to go back twice instead of
+# once. The navigations are now committing synchronously, which is too fast.
+-NavigationControllerBrowserTest.HistoryBackTwiceFromRendererWithoutUserGesture
+
+# Test expects the RenderFrameHost to be deleted after a navigation. It is now
+# stored into the BackForwardCache instead. It isn't deleted.
 -RenderFrameHostManagerTest.CleanupOnCrossProcessNavigation
--RenderFrameHostManagerTest.DeleteSpeculativeRFHPendingCommitOfPendingEntryOnInterrupted2
--RenderFrameHostManagerTest.DontSelectInvalidFiles
--RenderFrameHostManagerTest.ErrorPageNavigationHistoryNavigationFailure
--RenderFrameHostManagerTest.ErrorPageNavigationHistoryNavigationSuccess
 -RenderFrameHostManagerTest.LastCommittedOrigin
+-SitePerProcessBrowserTest.PendingDeletionCheckCompletedOnSubtree
+-SitePerProcessBrowserTest.SlowUnloadHandlerInIframe
+-WebContentsBindingSetBrowserTest.CloseOnFrameDeletion
+
+# This test waits for a network request after a back navigation. It won't be
+# made, because the document is restored from the BackForwardCache.
+-RenderFrameHostManagerTest.DeleteSpeculativeRFHPendingCommitOfPendingEntryOnInterrupted2
+
+# Wait for the old process to exit. It won't, because it is still used by a
+# bfcached document.
+-DynamicIsolatedOriginTest.LockedProcessNotReusedForNonisolatedSameSiteNavigation
+-RenderFrameHostManagerTest.DontSelectInvalidFiles
 -RenderFrameHostManagerTest.NavigateWithUnassignedSiteInstance
 -RenderFrameHostManagerTest.PostMessageFromSubframeUnloadHandler
--RenderFrameHostManagerTest.RenderViewInitAfterNewProxyAndProcessKill
 -RenderFrameHostManagerTest.RestoreFileAccessForHistoryNavigation
 -RenderFrameHostManagerTest.RestoreSubframeFileAccessForHistoryNavigation
 -RenderFrameHostManagerTest.UnloadPushStateOnCrossProcessNavigation
@@ -63,19 +96,29 @@
 -RenderFrameHostManagerUnloadBrowserTest.SubframeTerminationPing_Image
 -RenderFrameHostManagerUnloadBrowserTest.SubframeTerminationPing_SendBeacon
 -RenderProcessHostTest.KeepAliveRendererProcess
--SecFetchBrowserTest.BackNavigation
--SessionHistoryTest.GoBackToCrossSitePostWithRedirect
--SitePerProcessBrowserTest.PartialUnloadHandler
--SitePerProcessBrowserTest.PendingDeletionCheckCompletedOnSubtree
--SitePerProcessBrowserTest.RenderViewHostIsNotReusedAfterDelayedSwapOutACK
--SitePerProcessBrowserTest.SlowUnloadHandlerInIframe
 -SitePerProcessBrowserTest.SubframePendingAndBackToSameSiteInstance
 -SitePerProcessBrowserTest.SwapOutACKArrivesPriorToProcessShutdownRequest
--SitePerProcessBrowserTest.TwoCrossSitePendingNavigationsAndMainFrameWins
+
+# Expect the swapped out RenderFrameHost to have a replacement proxy. This won't
+# happen when the BackForwardCache is used to store the old document.
+-RenderFrameHostManagerTest.RenderViewInitAfterNewProxyAndProcessKill
+
+# Waiting for unload handler, but they aren't executed.
+-SitePerProcessBrowserTest.PartialUnloadHandler
 -SitePerProcessBrowserTest.Unload_ABAB
--WebContentsBindingSetBrowserTest.CloseOnFrameDeletion
--WebContentsImplBrowserTest.JavaScriptDialogsInMainAndSubframes
+
+# Expect the old RenderView to be removed. It isn't, because it it still used
+# by a bfcached document.
+-SitePerProcessBrowserTest.RenderViewHostIsNotReusedAfterDelayedSwapOutACK
+
+# Check failed: false. Navigation in an inactive frame
+-SitePerProcessBrowserTest.TwoCrossSitePendingNavigationsAndMainFrameWins
+
+# Unload handler not run => Title not updated.
 -WebContentsImplBrowserTest.SetTitleOnUnload
+
+# FATAL:casting.h Security DCHECK failed: IsA<Derived>(from).
+# In content::RenderFrameProxy::OnSetFrameOwnerProperties()
 -WebContentsSplitCacheBrowserTestEnabled.SplitCacheDedicatedWorkers/0
 -WebContentsSplitCacheBrowserTestEnabled.SplitCacheDedicatedWorkers/1
 -WebContentsSplitCacheWithFrameOriginBrowserTest.SplitCache
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl
index 5482843..7207fad5 100644
--- a/testing/buildbot/test_suites.pyl
+++ b/testing/buildbot/test_suites.pyl
@@ -4357,6 +4357,12 @@
     'ozone_linux_gtests': {
       'services_unittests': {},
       'ozone_unittests': {},
+      'content_unittests': {
+        'experiment_percentage': 100,
+        'args': [
+          '--ozone-platform=headless',
+        ],
+      },
     },
 
     'performance_smoke_test_isolated_scripts': {
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 2940ce06..c1c14dc4 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -915,6 +915,26 @@
             ]
         }
     ],
+    "AutofillSaveCardBubbleStringExperiment": [
+        {
+            "platforms": [
+                "linux",
+                "mac",
+                "windows"
+            ],
+            "experiments": [
+                {
+                    "name": "EnabledConfirmAndSaveCardVariation",
+                    "params": {
+                        "AutofillSaveCreditCardUsesImprovedMessaging": "Confirm & Save Card"
+                    },
+                    "enable_features": [
+                        "AutofillSaveCreditCardUsesImprovedMessaging"
+                    ]
+                }
+            ]
+        }
+    ],
     "AutofillSmallFormSupport": [
         {
             "platforms": [
@@ -2474,6 +2494,27 @@
             ]
         }
     ],
+    "HarfBuzzPdfSubsetter": [
+        {
+            "platforms": [
+                "android",
+                "android_webview",
+                "chromeos",
+                "ios",
+                "linux",
+                "mac",
+                "windows"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "HarfBuzzPdfSubsetter"
+                    ]
+                }
+            ]
+        }
+    ],
     "HeapProfiling": [
         {
             "platforms": [
@@ -2739,6 +2780,21 @@
             ]
         }
     ],
+    "IsolatePasswordSites": [
+        {
+            "platforms": [
+                "android"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "site-isolation-for-password-sites"
+                    ]
+                }
+            ]
+        }
+    ],
     "JankTrackingSweepLine": [
         {
             "platforms": [
@@ -6178,6 +6234,22 @@
             ]
         }
     ],
+    "WebRTC-Audio-NetEqDecelerationTargetLevelOffset": [
+        {
+            "platforms": [
+                "android",
+                "windows",
+                "mac",
+                "chromeos",
+                "linux"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled-85"
+                }
+            ]
+        }
+    ],
     "WebRTC-Audio-NetEqDelayHistogram": [
         {
             "platforms": [
diff --git a/third_party/blink/public/BUILD.gn b/third_party/blink/public/BUILD.gn
index 4a8bf8fd..c209683 100644
--- a/third_party/blink/public/BUILD.gn
+++ b/third_party/blink/public/BUILD.gn
@@ -378,7 +378,6 @@
     "web/modules/mediastream/media_stream_constraints_util_audio.h",
     "web/modules/mediastream/media_stream_constraints_util_sets.h",
     "web/modules/mediastream/media_stream_constraints_util_video_content.h",
-    "web/modules/mediastream/media_stream_constraints_util_video_device.h",
     "web/modules/mediastream/media_stream_video_capturer_source.h",
     "web/modules/mediastream/media_stream_video_sink.h",
     "web/modules/mediastream/media_stream_video_source.h",
diff --git a/third_party/blink/public/mojom/BUILD.gn b/third_party/blink/public/mojom/BUILD.gn
index 7d3a1cc..f1a525d 100644
--- a/third_party/blink/public/mojom/BUILD.gn
+++ b/third_party/blink/public/mojom/BUILD.gn
@@ -83,7 +83,6 @@
     "native_file_system/native_file_system_file_writer.mojom",
     "native_file_system/native_file_system_manager.mojom",
     "native_file_system/native_file_system_transfer_token.mojom",
-    "net/ip_address_space.mojom",
     "notifications/notification.mojom",
     "notifications/notification_service.mojom",
     "oom_intervention/oom_intervention.mojom",
diff --git a/third_party/blink/public/mojom/websockets/websocket_connector.mojom b/third_party/blink/public/mojom/websockets/websocket_connector.mojom
index 4e40af5..2a3c2fd 100644
--- a/third_party/blink/public/mojom/websockets/websocket_connector.mojom
+++ b/third_party/blink/public/mojom/websockets/websocket_connector.mojom
@@ -13,12 +13,11 @@
   // Starts an opening handshake.
   // |user_agent| is a "user-agent" request header value. For other params, see
   // CreateWebSocket in //services/network/public/mojom/network_context.mojom.
-  // It is recommended to detect mojo connection errors on |connection_client|,
-  // not on |handshake_client|. See network_context.mojom for details.
+  // It is recommended to detect mojo connection errors on |handshake_client|
+  // until the connection is established. See network_context.mojom for details.
   Connect(url.mojom.Url url,
           array<string> requested_protocols,
           url.mojom.Url site_for_cookies,
           string? user_agent,
-          network.mojom.WebSocketHandshakeClient handshake_client,
-          network.mojom.WebSocketClient connection_client);
+          network.mojom.WebSocketHandshakeClient handshake_client);
 };
diff --git a/third_party/blink/public/mojom/worker/shared_worker_info.mojom b/third_party/blink/public/mojom/worker/shared_worker_info.mojom
index 52c7eb7..68ceaa6 100644
--- a/third_party/blink/public/mojom/worker/shared_worker_info.mojom
+++ b/third_party/blink/public/mojom/worker/shared_worker_info.mojom
@@ -4,7 +4,7 @@
 
 module blink.mojom;
 
-import "third_party/blink/public/mojom/net/ip_address_space.mojom";
+import "services/network/public/mojom/ip_address_space.mojom";
 import "third_party/blink/public/mojom/csp/content_security_policy.mojom";
 import "url/mojom/url.mojom";
 
@@ -17,5 +17,5 @@
   string name;
   string content_security_policy;
   blink.mojom.ContentSecurityPolicyType content_security_policy_type;
-  blink.mojom.IPAddressSpace creation_address_space;
+  network.mojom.IPAddressSpace creation_address_space;
 };
diff --git a/third_party/blink/public/platform/web_url_loader_mock_factory.h b/third_party/blink/public/platform/web_url_loader_mock_factory.h
index 839e94c2..d4ebb0c0 100644
--- a/third_party/blink/public/platform/web_url_loader_mock_factory.h
+++ b/third_party/blink/public/platform/web_url_loader_mock_factory.h
@@ -27,10 +27,7 @@
   virtual ~WebURLLoaderMockFactory() = default;
 
   // Create a WebURLLoader that takes care of mocked requests.
-  // Non-mocked request are forwarded to given loader which should not
-  // be nullptr.
-  virtual std::unique_ptr<WebURLLoader> CreateURLLoader(
-      std::unique_ptr<WebURLLoader>) = 0;
+  virtual std::unique_ptr<WebURLLoader> CreateURLLoader() = 0;
 
   // Registers a response and the file to be served when the specified URL
   // is loaded. If no file is specified then the response content will be empty.
diff --git a/third_party/blink/public/web/DEPS b/third_party/blink/public/web/DEPS
index 0d71106..1399844 100644
--- a/third_party/blink/public/web/DEPS
+++ b/third_party/blink/public/web/DEPS
@@ -22,6 +22,7 @@
     "+services/metrics/public/cpp/ukm_source_id.h",
     "+services/network/public/mojom/cors.mojom-shared.h",
     "+services/network/public/mojom/cors_origin_pattern.mojom-shared.h",
+    "+services/network/public/mojom/ip_address_space.mojom-shared.h",
     "+services/network/public/mojom/referrer_policy.mojom-shared.h",
     "+services/service_manager/public",
     "+ui/events/types",
diff --git a/third_party/blink/public/web/web_embedded_worker_start_data.h b/third_party/blink/public/web/web_embedded_worker_start_data.h
index ab763a60..cb2c66bd 100644
--- a/third_party/blink/public/web/web_embedded_worker_start_data.h
+++ b/third_party/blink/public/web/web_embedded_worker_start_data.h
@@ -32,8 +32,8 @@
 #define THIRD_PARTY_BLINK_PUBLIC_WEB_WEB_EMBEDDED_WORKER_START_DATA_H_
 
 #include "base/unguessable_token.h"
+#include "services/network/public/mojom/ip_address_space.mojom-shared.h"
 #include "third_party/blink/public/common/privacy_preferences.h"
-#include "third_party/blink/public/mojom/net/ip_address_space.mojom-shared.h"
 #include "third_party/blink/public/mojom/service_worker/service_worker_registration.mojom-shared.h"
 #include "third_party/blink/public/platform/web_content_security_policy.h"
 #include "third_party/blink/public/platform/web_string.h"
@@ -61,7 +61,7 @@
   base::UnguessableToken devtools_worker_token;
   WebSettings::V8CacheOptions v8_cache_options;
 
-  mojom::IPAddressSpace address_space;
+  network::mojom::IPAddressSpace address_space;
 
   PrivacyPreferences privacy_preferences;
 
diff --git a/third_party/blink/public/web/web_shared_worker.h b/third_party/blink/public/web/web_shared_worker.h
index 47ff8341..4f10c16 100644
--- a/third_party/blink/public/web/web_shared_worker.h
+++ b/third_party/blink/public/web/web_shared_worker.h
@@ -36,16 +36,12 @@
 #include "base/unguessable_token.h"
 #include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h"
 #include "mojo/public/cpp/system/message_pipe.h"
+#include "services/network/public/mojom/ip_address_space.mojom-shared.h"
 #include "third_party/blink/public/common/privacy_preferences.h"
 #include "third_party/blink/public/mojom/csp/content_security_policy.mojom-shared.h"
-#include "third_party/blink/public/mojom/net/ip_address_space.mojom-shared.h"
 #include "third_party/blink/public/platform/task_type.h"
 #include "third_party/blink/public/platform/web_common.h"
 
-namespace base {
-class SingleThreadTaskRunner;
-}
-
 namespace network {
 class SharedURLLoaderFactory;
 }
@@ -74,7 +70,7 @@
       const WebString& user_agent,
       const WebString& content_security_policy,
       mojom::ContentSecurityPolicyType,
-      mojom::IPAddressSpace,
+      network::mojom::IPAddressSpace,
       const base::UnguessableToken& devtools_worker_token,
       PrivacyPreferences privacy_preferences,
       scoped_refptr<network::SharedURLLoaderFactory> loader_factory,
@@ -92,9 +88,6 @@
   virtual void BindDevToolsAgent(
       mojo::ScopedInterfaceEndpointHandle devtools_agent_host_ptr_info,
       mojo::ScopedInterfaceEndpointHandle devtools_agent_request) = 0;
-
-  virtual scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner(
-      TaskType) = 0;
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/bindings/core/v8/isolated_world_csp.cc b/third_party/blink/renderer/bindings/core/v8/isolated_world_csp.cc
index 1b69a3c..4bd4625 100644
--- a/third_party/blink/renderer/bindings/core/v8/isolated_world_csp.cc
+++ b/third_party/blink/renderer/bindings/core/v8/isolated_world_csp.cc
@@ -65,7 +65,7 @@
   // since isolated worlds don't have their own ExecutionContext, these are not
   // supported.
   void SetSandboxFlags(SandboxFlags) override {}
-  void SetAddressSpace(mojom::IPAddressSpace) override {}
+  void SetAddressSpace(network::mojom::IPAddressSpace) override {}
   void SetRequireTrustedTypes() override {}
   void AddInsecureRequestPolicy(WebInsecureRequestPolicy) override {}
 
diff --git a/third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value_threaded_test.cc b/third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value_threaded_test.cc
index da781be..f7726284 100644
--- a/third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value_threaded_test.cc
+++ b/third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value_threaded_test.cc
@@ -26,11 +26,8 @@
   // Start a worker.
   WorkerReportingProxy proxy;
   WorkerThreadForTest worker_thread(proxy);
-  ParentExecutionContextTaskRunners* parent_execution_context_task_runners =
-      ParentExecutionContextTaskRunners::Create(&scope.GetDocument());
   worker_thread.StartWithSourceCode(scope.GetDocument().GetSecurityOrigin(),
-                                    "/* no worker script */",
-                                    parent_execution_context_task_runners);
+                                    "/* no worker script */");
 
   // Create a serialized script value that contains transferred array buffer
   // contents.
diff --git a/third_party/blink/renderer/bindings/scripts/web_idl/composition_parts.py b/third_party/blink/renderer/bindings/scripts/web_idl/composition_parts.py
index c372d94..f13f4c6 100644
--- a/third_party/blink/renderer/bindings/scripts/web_idl/composition_parts.py
+++ b/third_party/blink/renderer/bindings/scripts/web_idl/composition_parts.py
@@ -101,10 +101,10 @@
                                       and all(
                                           isinstance(component, Component)
                                           for component in components))
-        assert (component or components) and not (component and components)
-        if components:
+        assert int(component is not None) + int(components is not None) == 1
+        if components is not None:
             self._components = list(components)
-        else:
+        elif component is not None:
             self._components = [component]
 
     @property
diff --git a/third_party/blink/renderer/bindings/scripts/web_idl/database.py b/third_party/blink/renderer/bindings/scripts/web_idl/database.py
index 8f7dcb7..0823095 100644
--- a/third_party/blink/renderer/bindings/scripts/web_idl/database.py
+++ b/third_party/blink/renderer/bindings/scripts/web_idl/database.py
@@ -3,6 +3,7 @@
 # found in the LICENSE file.
 
 from .typedef import Typedef
+from .union import Union
 from .user_defined_type import UserDefinedType
 
 
@@ -30,7 +31,7 @@
         INTERFACE = 'interface'
         NAMESPACE = 'namespace'
         TYPEDEF = 'typedef'
-        UNION_TYPE = 'union type'
+        UNION = 'union'
 
         _ALL_ENTRIES = (
             CALLBACK_FUNCTION,
@@ -40,7 +41,7 @@
             INTERFACE,
             NAMESPACE,
             TYPEDEF,
-            UNION_TYPE,
+            UNION,
         )
 
         @classmethod
@@ -53,7 +54,7 @@
             self._defs[kind] = {}
 
     def register(self, kind, user_defined_type):
-        assert isinstance(user_defined_type, (UserDefinedType, Typedef))
+        assert isinstance(user_defined_type, (Typedef, Union, UserDefinedType))
         assert kind in DatabaseBody.Kind.itervalues()
         try:
             self.find_by_identifier(user_defined_type.identifier)
@@ -130,7 +131,7 @@
     @property
     def union_types(self):
         """Returns all union type definitions."""
-        return self._view_by_kind(Database._Kind.UNION_TYPE)
+        return self._view_by_kind(Database._Kind.UNION)
 
     def _view_by_kind(self, kind):
         return self._impl.find_by_kind(kind).viewvalues()
diff --git a/third_party/blink/renderer/bindings/scripts/web_idl/idl_compiler.py b/third_party/blink/renderer/bindings/scripts/web_idl/idl_compiler.py
index 595740d..aea5100 100644
--- a/third_party/blink/renderer/bindings/scripts/web_idl/idl_compiler.py
+++ b/third_party/blink/renderer/bindings/scripts/web_idl/idl_compiler.py
@@ -2,6 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+from .composition_parts import Identifier
 from .database import Database
 from .database import DatabaseBody
 from .dictionary import Dictionary
@@ -9,6 +10,7 @@
 from .idl_type import IdlTypeFactory
 from .reference import RefByIdFactory
 from .typedef import Typedef
+from .union import Union
 from .user_defined_type import UserDefinedType
 
 
@@ -74,6 +76,7 @@
         self._merge_interface_mixins()
         # Process inheritances.
         self._process_interface_inheritances()
+
         # Updates on IRs are finished.  Create API objects.
         self._create_public_objects()
 
@@ -81,6 +84,9 @@
         self._resolve_references_to_idl_def()
         self._resolve_references_to_idl_type()
 
+        # Build union API objects.
+        self._create_public_unions()
+
         return Database(self._db)
 
     def _merge_partial_interfaces(self):
@@ -223,3 +229,37 @@
             ref.set_target_object(idl_type)
 
         self._ref_to_idl_type_factory.for_each(resolve)
+
+    def _create_public_unions(self):
+        all_union_types = []  # all instances of UnionType
+
+        def collect_unions(idl_type):
+            if idl_type.is_union:
+                all_union_types.append(idl_type)
+
+        self._idl_type_factory.for_each(collect_unions)
+
+        def unique_key(union_type):
+            """
+            Returns an unique (but meaningless) key.  Returns the same key for
+            the identical union types.
+            """
+            key_pieces = sorted([
+                idl_type.syntactic_form
+                for idl_type in union_type.flattened_member_types
+            ])
+            if union_type.does_include_nullable_type:
+                key_pieces.append('type null')  # something unique
+            return '|'.join(key_pieces)
+
+        grouped_unions = {}  # {unique key: list of union types, ...}
+        for union_type in all_union_types:
+            key = unique_key(union_type)
+            grouped_unions.setdefault(key, []).append(union_type)
+
+        for key, union_types in grouped_unions.iteritems():
+            self._db.register(
+                DatabaseBody.Kind.UNION,
+                Union(
+                    Identifier(key),  # dummy identifier
+                    union_types))
diff --git a/third_party/blink/renderer/bindings/scripts/web_idl/union.py b/third_party/blink/renderer/bindings/scripts/web_idl/union.py
new file mode 100644
index 0000000..c28677b6
--- /dev/null
+++ b/third_party/blink/renderer/bindings/scripts/web_idl/union.py
@@ -0,0 +1,130 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+from .composition_parts import WithCodeGeneratorInfo
+from .composition_parts import WithComponent
+from .composition_parts import WithDebugInfo
+from .composition_parts import WithIdentifier
+from .idl_type import IdlType
+
+
+class Union(WithIdentifier, WithCodeGeneratorInfo, WithComponent,
+            WithDebugInfo):
+    """
+    Union class makes a group of union types with the same flattened member
+    types and the same result whether it includes a nullable type or not.
+
+    For example, the following union types will be grouped into one Union
+    instance.
+      (A? or B or C), (A or B? or C), ((A or B) or C?), (A or (B or C?)), ...
+    All these unions have the same set of flattened member types (A, B, C) and
+    include a nullable type.
+
+    However, all following union types will be grouped into separate Union
+    instances.
+      (A or B), ([X] A or B), ([Y] A or B)
+    IdlType(A), IdlType([X] A), and IdlType([Y] A) are all distinguished from
+    each other as they behave differently.  Bindings code generators are
+    expected to define an implementation class for each Union instance.
+    """
+
+    def __init__(self, identifier, union_types):
+        """
+        Args:
+            union_types: Union types of which this object consists.  All types
+                in |union_types| must have the same flattened_member_types and
+                the same value of does_include_nullable_type.
+        """
+        assert isinstance(union_types, (list, tuple))
+        assert len(union_types) > 0
+        assert all(
+            isinstance(union_type, IdlType) and union_type.is_union
+            for union_type in union_types)
+
+        flattened_members = union_types[0].flattened_member_types
+        does_include_nullable_type = union_types[0].does_include_nullable_type
+
+        nullable_members = set()
+        typedef_members = set()
+        union_members = set()
+        for union_type in union_types:
+            assert union_type.flattened_member_types == flattened_members
+            assert (union_type.does_include_nullable_type ==
+                    does_include_nullable_type)
+            for direct_member in union_type.member_types:
+                if direct_member.is_nullable:
+                    nullable_members.add(direct_member)
+                if direct_member.is_typedef:
+                    typedef_members.add(direct_member)
+                if direct_member.is_union:
+                    union_members.add(direct_member)
+
+        sort_key = lambda x: x.syntactic_form
+
+        WithIdentifier.__init__(self, identifier)
+        WithCodeGeneratorInfo.__init__(self)
+        # TODO(yukishiino): Set components to the components of member types.
+        WithComponent.__init__(self, components=[])
+        WithDebugInfo.__init__(self)
+
+        # Sort improves reproducibility.
+        self._flattened_members = tuple(
+            sorted(flattened_members, key=sort_key))
+        self._does_include_nullable_type = does_include_nullable_type
+        self._nullable_members = tuple(sorted(nullable_members, key=sort_key))
+        self._typedef_members = tuple(sorted(typedef_members, key=sort_key))
+        self._union_members = tuple(sorted(union_members, key=sort_key))
+
+    @property
+    def flattened_member_types(self):
+        """
+        Returns the same list of flattened member types as
+        IdlType.flattened_member_types.
+        """
+        return self._flattened_members
+
+    @property
+    def does_include_nullable_type(self):
+        """
+        Returns true if any of member type is nullable or a member union
+        includes a nullable type.
+        """
+        return self._does_include_nullable_type
+
+    @property
+    def nullable_member_types(self):
+        """
+        Returns a list of nullable types which are direct members of union types
+        of which this object consists.
+
+        Given the following unions,
+          (A? or B or C), (A or B? or C), (A or B or CN) where typedef C? CN;
+        nullable_member_types returns a list of IdlType(A?) and IdlType(B?).
+        """
+        return self._nullable_members
+
+    @property
+    def typedef_member_types(self):
+        """
+        Returns a list of typedef types which are direct members of union types
+        of which this object consists.
+
+        Given the following unions,
+          (AT or B), (A or BT) where typedef A AT, and typedef B BT;
+        typedef_member_types returns a list of IdlType(AT) and IdlType(BT).
+        """
+        return self._typedef_members
+
+    @property
+    def union_member_types(self):
+        """
+        Returns a list of union types which are direct members of union types of
+        which this object consists.
+
+        Given the following unions,
+          ((A or B) or C), (A or (B or C))
+        union_member_types returns a list of IdlType(A or B) and
+        IdlType(B or C).
+        """
+        return self._union_members
diff --git a/third_party/blink/renderer/core/css/style_sheet_collection.h b/third_party/blink/renderer/core/css/style_sheet_collection.h
index f6acf062..efdf51c 100644
--- a/third_party/blink/renderer/core/css/style_sheet_collection.h
+++ b/third_party/blink/renderer/core/css/style_sheet_collection.h
@@ -43,13 +43,14 @@
 class StyleSheet;
 
 class CORE_EXPORT StyleSheetCollection
-    : public GarbageCollected<StyleSheetCollection>,
+    : public GarbageCollectedFinalized<StyleSheetCollection>,
       public NameClient {
  public:
   friend class ActiveDocumentStyleSheetCollector;
   friend class ImportedDocumentStyleSheetCollector;
 
   StyleSheetCollection();
+  virtual ~StyleSheetCollection() = default;
 
   const ActiveStyleSheetVector& ActiveAuthorStyleSheets() const {
     return active_author_style_sheets_;
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc
index 1e2d641..a52941f8f 100644
--- a/third_party/blink/renderer/core/dom/document.cc
+++ b/third_party/blink/renderer/core/dom/document.cc
@@ -41,13 +41,13 @@
 #include "services/metrics/public/cpp/ukm_builders.h"
 #include "services/metrics/public/cpp/ukm_source_id.h"
 #include "services/metrics/public/mojom/ukm_interface.mojom-blink.h"
+#include "services/network/public/mojom/ip_address_space.mojom-blink.h"
 #include "services/resource_coordinator/public/mojom/coordination_unit.mojom-blink.h"
 #include "services/service_manager/public/cpp/interface_provider.h"
 #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
 #include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/mojom/frame/document_interface_broker.mojom-blink.h"
 #include "third_party/blink/public/mojom/insecure_input/insecure_input_service.mojom-blink.h"
-#include "third_party/blink/public/mojom/net/ip_address_space.mojom-blink.h"
 #include "third_party/blink/public/mojom/ukm/ukm.mojom-blink.h"
 #include "third_party/blink/public/platform/interface_provider.h"
 #include "third_party/blink/public/platform/platform.h"
@@ -6875,16 +6875,16 @@
   // https://wicg.github.io/cors-rfc1918/#csp).
   if (initializer.IsHostedInReservedIPRange()) {
     SetAddressSpace(GetSecurityOrigin()->IsLocalhost()
-                        ? mojom::IPAddressSpace::kLocal
-                        : mojom::IPAddressSpace::kPrivate);
+                        ? network::mojom::IPAddressSpace::kLocal
+                        : network::mojom::IPAddressSpace::kPrivate);
   } else if (GetSecurityOrigin()->IsLocal()) {
     // "Local" security origins (like 'file://...') are treated as having
     // a local address space.
     //
     // TODO(mkwst): It's not entirely clear that this is a good idea.
-    SetAddressSpace(mojom::IPAddressSpace::kLocal);
+    SetAddressSpace(network::mojom::IPAddressSpace::kLocal);
   } else {
-    SetAddressSpace(mojom::IPAddressSpace::kPublic);
+    SetAddressSpace(network::mojom::IPAddressSpace::kPublic);
   }
 
   if (Settings* settings = initializer.GetSettings()) {
diff --git a/third_party/blink/renderer/core/dom/text.cc b/third_party/blink/renderer/core/dom/text.cc
index d6d073af..d270af5 100644
--- a/third_party/blink/renderer/core/dom/text.cc
+++ b/third_party/blink/renderer/core/dom/text.cc
@@ -400,7 +400,7 @@
     } else {
       layout_text->SetStyle(std::move(new_style));
       if (NeedsStyleRecalc())
-        layout_text->SetText(DataImpl());
+        layout_text->SetTextIfNeeded(DataImpl());
     }
   } else if (new_style && (NeedsStyleRecalc() || change.ReattachLayoutTree() ||
                            GetForceReattachLayoutTree() ||
diff --git a/third_party/blink/renderer/core/editing/commands/insert_paragraph_separator_command_test.cc b/third_party/blink/renderer/core/editing/commands/insert_paragraph_separator_command_test.cc
index 6c4433d5..f93883a 100644
--- a/third_party/blink/renderer/core/editing/commands/insert_paragraph_separator_command_test.cc
+++ b/third_party/blink/renderer/core/editing/commands/insert_paragraph_separator_command_test.cc
@@ -31,7 +31,7 @@
 
   EXPECT_EQ(
       "<table contenteditable>"
-      "    <colgroup style=\"-webkit-appearance:radio;\">|<br></colgroup>"
+      "|    <colgroup style=\"-webkit-appearance:radio;\"></colgroup>"
       "</table>",
       GetSelectionTextFromBody());
 }
@@ -53,7 +53,7 @@
   command->Apply();
   EXPECT_EQ(
       "<table contenteditable>"
-      "    <colgroup style=\"-webkit-appearance:radio;\">|<br>"
+      "|    <colgroup style=\"-webkit-appearance:radio;\">"
       "        <col>"
       "    </colgroup>"
       "</table>",
diff --git a/third_party/blink/renderer/core/execution_context/security_context.cc b/third_party/blink/renderer/core/execution_context/security_context.cc
index b87c486a..4baf981 100644
--- a/third_party/blink/renderer/core/execution_context/security_context.cc
+++ b/third_party/blink/renderer/core/execution_context/security_context.cc
@@ -90,7 +90,7 @@
     : sandbox_flags_(sandbox_flags),
       security_origin_(std::move(origin)),
       feature_policy_(std::move(feature_policy)),
-      address_space_(mojom::IPAddressSpace::kPublic),
+      address_space_(network::mojom::IPAddressSpace::kPublic),
       insecure_request_policy_(kLeaveInsecureRequestsAlone),
       require_safe_types_(false) {}
 
@@ -153,13 +153,13 @@
 
 String SecurityContext::addressSpaceForBindings() const {
   switch (address_space_) {
-    case mojom::IPAddressSpace::kPublic:
+    case network::mojom::IPAddressSpace::kPublic:
       return "public";
 
-    case mojom::IPAddressSpace::kPrivate:
+    case network::mojom::IPAddressSpace::kPrivate:
       return "private";
 
-    case mojom::IPAddressSpace::kLocal:
+    case network::mojom::IPAddressSpace::kLocal:
       return "local";
   }
   NOTREACHED();
diff --git a/third_party/blink/renderer/core/execution_context/security_context.h b/third_party/blink/renderer/core/execution_context/security_context.h
index 0324d2a..4aad2bb 100644
--- a/third_party/blink/renderer/core/execution_context/security_context.h
+++ b/third_party/blink/renderer/core/execution_context/security_context.h
@@ -40,6 +40,12 @@
 
 #include <memory>
 
+namespace network {
+namespace mojom {
+enum class IPAddressSpace : int32_t;
+}
+}  // namespace network
+
 namespace blink {
 
 class ContentSecurityPolicy;
@@ -57,7 +63,6 @@
 namespace mojom {
 enum class FeaturePolicyDisposition : int32_t;
 enum class FeaturePolicyFeature : int32_t;
-enum class IPAddressSpace : int32_t;
 }
 
 // Defines the security properties (such as the security origin, content
@@ -93,8 +98,10 @@
   WebSandboxFlags GetSandboxFlags() const { return sandbox_flags_; }
   bool IsSandboxed(WebSandboxFlags mask) const;
 
-  void SetAddressSpace(mojom::IPAddressSpace space) { address_space_ = space; }
-  mojom::IPAddressSpace AddressSpace() const { return address_space_; }
+  void SetAddressSpace(network::mojom::IPAddressSpace space) {
+    address_space_ = space;
+  }
+  network::mojom::IPAddressSpace AddressSpace() const { return address_space_; }
   String addressSpaceForBindings() const;
 
   void SetRequireTrustedTypes();
@@ -180,7 +187,7 @@
  private:
   Member<ContentSecurityPolicy> content_security_policy_;
 
-  mojom::IPAddressSpace address_space_;
+  network::mojom::IPAddressSpace address_space_;
   WebInsecureRequestPolicy insecure_request_policy_;
   bool mixed_autoupgrade_opt_out_;
   InsecureNavigationsSet insecure_navigations_to_upgrade_;
diff --git a/third_party/blink/renderer/core/exported/web_shared_worker_impl.cc b/third_party/blink/renderer/core/exported/web_shared_worker_impl.cc
index 66e8f49..0beea4bb8 100644
--- a/third_party/blink/renderer/core/exported/web_shared_worker_impl.cc
+++ b/third_party/blink/renderer/core/exported/web_shared_worker_impl.cc
@@ -77,9 +77,7 @@
     WebSharedWorkerClient* client,
     const base::UnguessableToken& appcache_host_id)
     : client_(client),
-      creation_address_space_(mojom::IPAddressSpace::kPublic),
-      parent_execution_context_task_runners_(
-          ParentExecutionContextTaskRunners::Create()),
+      creation_address_space_(network::mojom::IPAddressSpace::kPublic),
       appcache_host_(MakeGarbageCollected<ApplicationCacheHostForSharedWorker>(
           appcache_host_id,
           Thread::Current()->GetTaskRunner())) {
@@ -197,7 +195,7 @@
     const WebString& user_agent,
     const WebString& content_security_policy,
     mojom::ContentSecurityPolicyType policy_type,
-    mojom::IPAddressSpace creation_address_space,
+    network::mojom::IPAddressSpace creation_address_space,
     const base::UnguessableToken& devtools_worker_token,
     PrivacyPreferences privacy_preferences,
     scoped_refptr<network::SharedURLLoaderFactory> loader_factory,
@@ -313,7 +311,7 @@
     const FetchClientSettingsObjectSnapshot& outside_settings_object) {
   DCHECK(IsMainThread());
   reporting_proxy_ = MakeGarbageCollected<SharedWorkerReportingProxy>(
-      this, parent_execution_context_task_runners_);
+      this, ParentExecutionContextTaskRunners::Create());
   worker_thread_ = std::make_unique<SharedWorkerThread>(*reporting_proxy_);
 
   auto thread_startup_data = WorkerBackingThreadStartupData::CreateDefault();
@@ -324,8 +322,7 @@
       name_);
 
   GetWorkerThread()->Start(std::move(global_scope_creation_params),
-                           thread_startup_data, std::move(devtools_params),
-                           parent_execution_context_task_runners_);
+                           thread_startup_data, std::move(devtools_params));
 
   GetWorkerThread()->FetchAndRunClassicScript(
       script_request_url_, outside_settings_object.CopyData(),
@@ -360,11 +357,6 @@
           std::move(devtools_agent_request)));
 }
 
-scoped_refptr<base::SingleThreadTaskRunner> WebSharedWorkerImpl::GetTaskRunner(
-    TaskType task_type) {
-  return parent_execution_context_task_runners_->Get(task_type);
-}
-
 std::unique_ptr<WebSharedWorker> WebSharedWorker::Create(
     WebSharedWorkerClient* client,
     const base::UnguessableToken& appcache_host_id) {
diff --git a/third_party/blink/renderer/core/exported/web_shared_worker_impl.h b/third_party/blink/renderer/core/exported/web_shared_worker_impl.h
index 2bef34f6..0f0ef49 100644
--- a/third_party/blink/renderer/core/exported/web_shared_worker_impl.h
+++ b/third_party/blink/renderer/core/exported/web_shared_worker_impl.h
@@ -37,10 +37,10 @@
 
 #include "base/memory/scoped_refptr.h"
 #include "base/memory/weak_ptr.h"
+#include "services/network/public/mojom/ip_address_space.mojom-blink.h"
 #include "services/service_manager/public/mojom/interface_provider.mojom-blink.h"
 #include "third_party/blink/public/common/privacy_preferences.h"
 #include "third_party/blink/public/mojom/csp/content_security_policy.mojom-blink.h"
-#include "third_party/blink/public/mojom/net/ip_address_space.mojom-blink.h"
 #include "third_party/blink/public/mojom/worker/worker_content_settings_proxy.mojom-blink.h"
 #include "third_party/blink/public/web/web_shared_worker_client.h"
 #include "third_party/blink/renderer/core/core_export.h"
@@ -50,10 +50,6 @@
 #include "third_party/blink/renderer/core/workers/worker_clients.h"
 #include "third_party/blink/renderer/core/workers/worker_thread.h"
 
-namespace base {
-class SingleThreadTaskRunner;
-}
-
 namespace network {
 class SharedURLLoaderFactory;
 }
@@ -98,7 +94,7 @@
       const WebString& user_agent,
       const WebString& content_security_policy,
       mojom::ContentSecurityPolicyType,
-      mojom::IPAddressSpace,
+      network::mojom::IPAddressSpace,
       const base::UnguessableToken& devtools_worker_token,
       PrivacyPreferences privacy_preferences,
       scoped_refptr<network::SharedURLLoaderFactory> loader_factory,
@@ -110,7 +106,6 @@
   void BindDevToolsAgent(
       mojo::ScopedInterfaceEndpointHandle devtools_agent_host_ptr_info,
       mojo::ScopedInterfaceEndpointHandle devtools_agent_request) override;
-  scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner(TaskType) override;
 
   // Callback methods for SharedWorkerReportingProxy.
   void CountFeature(WebFeature);
@@ -157,20 +152,11 @@
   WebURL script_request_url_;
   WebString name_;
   WebString user_agent_;
-  mojom::IPAddressSpace creation_address_space_;
+  network::mojom::IPAddressSpace creation_address_space_;
 
   service_manager::mojom::blink::InterfaceProviderPtrInfo
       pending_interface_provider_;
 
-  // SharedWorker can sometimes run tasks that are initiated by/associated with
-  // a document's frame but these documents can be from a different process. So
-  // we intentionally populate the task runners with default task runners of the
-  // main thread. Note that |shadow_page_| should not be used as it's a dummy
-  // document for loading that doesn't represent the frame of any associated
-  // document.
-  Persistent<ParentExecutionContextTaskRunners>
-      parent_execution_context_task_runners_;
-
   Persistent<ApplicationCacheHostForSharedWorker> appcache_host_;
 
   base::WeakPtrFactory<WebSharedWorkerImpl> weak_ptr_factory_{this};
diff --git a/third_party/blink/renderer/core/frame/csp/content_security_policy.cc b/third_party/blink/renderer/core/frame/csp/content_security_policy.cc
index ba49eb0..3bad077 100644
--- a/third_party/blink/renderer/core/frame/csp/content_security_policy.cc
+++ b/third_party/blink/renderer/core/frame/csp/content_security_policy.cc
@@ -28,7 +28,7 @@
 #include <memory>
 #include <utility>
 
-#include "third_party/blink/public/mojom/net/ip_address_space.mojom-blink.h"
+#include "services/network/public/mojom/ip_address_space.mojom-blink.h"
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/public/platform/task_type.h"
 #include "third_party/blink/public/platform/web_url_request.h"
@@ -201,7 +201,7 @@
     delegate_->SetSandboxFlags(sandbox_mask_);
   }
   if (treat_as_public_address_)
-    delegate_->SetAddressSpace(mojom::IPAddressSpace::kPublic);
+    delegate_->SetAddressSpace(network::mojom::IPAddressSpace::kPublic);
 
   if (require_trusted_types_)
     delegate_->SetRequireTrustedTypes();
diff --git a/third_party/blink/renderer/core/frame/csp/content_security_policy.h b/third_party/blink/renderer/core/frame/csp/content_security_policy.h
index cb2b5a4..f155b3b 100644
--- a/third_party/blink/renderer/core/frame/csp/content_security_policy.h
+++ b/third_party/blink/renderer/core/frame/csp/content_security_policy.h
@@ -97,7 +97,7 @@
 
   // Directives support.
   virtual void SetSandboxFlags(SandboxFlags) = 0;
-  virtual void SetAddressSpace(mojom::IPAddressSpace) = 0;
+  virtual void SetAddressSpace(network::mojom::IPAddressSpace) = 0;
   virtual void SetRequireTrustedTypes() = 0;
   virtual void AddInsecureRequestPolicy(WebInsecureRequestPolicy) = 0;
 
diff --git a/third_party/blink/renderer/core/frame/csp/content_security_policy_test.cc b/third_party/blink/renderer/core/frame/csp/content_security_policy_test.cc
index 6919bd0..85bb02e0 100644
--- a/third_party/blink/renderer/core/frame/csp/content_security_policy_test.cc
+++ b/third_party/blink/renderer/core/frame/csp/content_security_policy_test.cc
@@ -4,8 +4,8 @@
 
 #include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
 
+#include "services/network/public/mojom/ip_address_space.mojom-blink.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/mojom/net/ip_address_space.mojom-blink.h"
 #include "third_party/blink/public/platform/web_insecure_request_policy.h"
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/frame/csp/csp_directive_list.h"
@@ -101,26 +101,30 @@
 
 TEST_F(ContentSecurityPolicyTest, ParseEnforceTreatAsPublicAddressDisabled) {
   ScopedCorsRFC1918ForTest cors_rfc1918(false);
-  execution_context->SetAddressSpace(mojom::IPAddressSpace::kPrivate);
-  EXPECT_EQ(mojom::IPAddressSpace::kPrivate, execution_context->AddressSpace());
+  execution_context->SetAddressSpace(network::mojom::IPAddressSpace::kPrivate);
+  EXPECT_EQ(network::mojom::IPAddressSpace::kPrivate,
+            execution_context->AddressSpace());
 
   csp->DidReceiveHeader("treat-as-public-address",
                         kContentSecurityPolicyHeaderTypeEnforce,
                         kContentSecurityPolicyHeaderSourceHTTP);
   csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
-  EXPECT_EQ(mojom::IPAddressSpace::kPrivate, execution_context->AddressSpace());
+  EXPECT_EQ(network::mojom::IPAddressSpace::kPrivate,
+            execution_context->AddressSpace());
 }
 
 TEST_F(ContentSecurityPolicyTest, ParseEnforceTreatAsPublicAddressEnabled) {
   ScopedCorsRFC1918ForTest cors_rfc1918(true);
-  execution_context->SetAddressSpace(mojom::IPAddressSpace::kPrivate);
-  EXPECT_EQ(mojom::IPAddressSpace::kPrivate, execution_context->AddressSpace());
+  execution_context->SetAddressSpace(network::mojom::IPAddressSpace::kPrivate);
+  EXPECT_EQ(network::mojom::IPAddressSpace::kPrivate,
+            execution_context->AddressSpace());
 
   csp->DidReceiveHeader("treat-as-public-address",
                         kContentSecurityPolicyHeaderTypeEnforce,
                         kContentSecurityPolicyHeaderSourceHTTP);
   csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
-  EXPECT_EQ(mojom::IPAddressSpace::kPublic, execution_context->AddressSpace());
+  EXPECT_EQ(network::mojom::IPAddressSpace::kPublic,
+            execution_context->AddressSpace());
 }
 
 TEST_F(ContentSecurityPolicyTest, CopyStateFrom) {
diff --git a/third_party/blink/renderer/core/frame/csp/execution_context_csp_delegate.cc b/third_party/blink/renderer/core/frame/csp/execution_context_csp_delegate.cc
index cff5ce3..3725c34 100644
--- a/third_party/blink/renderer/core/frame/csp/execution_context_csp_delegate.cc
+++ b/third_party/blink/renderer/core/frame/csp/execution_context_csp_delegate.cc
@@ -64,7 +64,8 @@
   CHECK_EQ(flags | mask, flags);
 }
 
-void ExecutionContextCSPDelegate::SetAddressSpace(mojom::IPAddressSpace space) {
+void ExecutionContextCSPDelegate::SetAddressSpace(
+    network::mojom::IPAddressSpace space) {
   GetSecurityContext().SetAddressSpace(space);
 }
 
diff --git a/third_party/blink/renderer/core/frame/csp/execution_context_csp_delegate.h b/third_party/blink/renderer/core/frame/csp/execution_context_csp_delegate.h
index 7ab27c24..8cbee40 100644
--- a/third_party/blink/renderer/core/frame/csp/execution_context_csp_delegate.h
+++ b/third_party/blink/renderer/core/frame/csp/execution_context_csp_delegate.h
@@ -27,7 +27,7 @@
   const SecurityOrigin* GetSecurityOrigin() override;
   const KURL& Url() const override;
   void SetSandboxFlags(SandboxFlags) override;
-  void SetAddressSpace(mojom::IPAddressSpace) override;
+  void SetAddressSpace(network::mojom::IPAddressSpace) override;
   void SetRequireTrustedTypes() override;
   void AddInsecureRequestPolicy(WebInsecureRequestPolicy) override;
   std::unique_ptr<SourceLocation> GetSourceLocation() override;
diff --git a/third_party/blink/renderer/core/html/BUILD.gn b/third_party/blink/renderer/core/html/BUILD.gn
index 0ef65ce..4fb850c6 100644
--- a/third_party/blink/renderer/core/html/BUILD.gn
+++ b/third_party/blink/renderer/core/html/BUILD.gn
@@ -121,6 +121,8 @@
     "forms/checkbox_input_type.h",
     "forms/chooser_only_temporal_input_type_view.cc",
     "forms/chooser_only_temporal_input_type_view.h",
+    "forms/chooser_resource_loader.cc",
+    "forms/chooser_resource_loader.h",
     "forms/clear_button_element.cc",
     "forms/clear_button_element.h",
     "forms/color_chooser.cc",
diff --git a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
index d7a0c13..f9be017 100644
--- a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
+++ b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
@@ -1379,7 +1379,7 @@
     return !Traversal<HTMLImageElement>::FirstWithin(element);
 
   // A button element
-  if (IsHTMLButtonElement(element))
+  if (IsA<HTMLButtonElement>(element))
     return true;
 
   // An input element whose type attribute is in one of the Checkbox or Radio
diff --git a/third_party/blink/renderer/core/html/forms/chooser_resource_loader.cc b/third_party/blink/renderer/core/html/forms/chooser_resource_loader.cc
new file mode 100644
index 0000000..e5b10c3
--- /dev/null
+++ b/third_party/blink/renderer/core/html/forms/chooser_resource_loader.cc
@@ -0,0 +1,148 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/html/forms/chooser_resource_loader.h"
+
+#include "build/build_config.h"
+#include "third_party/blink/public/resources/grit/blink_resources.h"
+#include "third_party/blink/renderer/platform/data_resource_helper.h"
+
+namespace blink {
+
+String ChooserResourceLoader::GetSuggestionPickerStyleSheet() {
+#if !defined(OS_ANDROID)
+  return UncompressResourceAsString(IDR_SUGGESTION_PICKER_CSS);
+#else
+  NOTREACHED();
+  return String();
+#endif
+}
+
+String ChooserResourceLoader::GetSuggestionPickerJS() {
+#if !defined(OS_ANDROID)
+  return UncompressResourceAsString(IDR_SUGGESTION_PICKER_JS);
+#else
+  NOTREACHED();
+  return String();
+#endif
+}
+
+String ChooserResourceLoader::GetPickerButtonStyleSheet() {
+#if !defined(OS_ANDROID)
+  return UncompressResourceAsString(IDR_PICKER_BUTTON_CSS);
+#else
+  NOTREACHED();
+  return String();
+#endif
+}
+
+String ChooserResourceLoader::GetPickerCommonStyleSheet() {
+#if !defined(OS_ANDROID)
+  return UncompressResourceAsString(IDR_PICKER_COMMON_CSS);
+#else
+  NOTREACHED();
+  return String();
+#endif
+}
+
+String ChooserResourceLoader::GetPickerCommonJS() {
+#if !defined(OS_ANDROID)
+  return UncompressResourceAsString(IDR_PICKER_COMMON_JS);
+#else
+  NOTREACHED();
+  return String();
+#endif
+}
+
+String ChooserResourceLoader::GetCalendarPickerStyleSheet() {
+#if !defined(OS_ANDROID)
+  return UncompressResourceAsString(IDR_CALENDAR_PICKER_CSS);
+#else
+  NOTREACHED();
+  return String();
+#endif
+}
+
+String ChooserResourceLoader::GetCalendarPickerJS() {
+#if !defined(OS_ANDROID)
+  return UncompressResourceAsString(IDR_CALENDAR_PICKER_JS);
+#else
+  NOTREACHED();
+  return String();
+#endif
+}
+
+String ChooserResourceLoader::GetColorSuggestionPickerStyleSheet() {
+#if !defined(OS_ANDROID)
+  return UncompressResourceAsString(IDR_COLOR_SUGGESTION_PICKER_CSS);
+#else
+  NOTREACHED();
+  return String();
+#endif
+}
+
+String ChooserResourceLoader::GetColorSuggestionPickerJS() {
+#if !defined(OS_ANDROID)
+  return UncompressResourceAsString(IDR_COLOR_SUGGESTION_PICKER_JS);
+#else
+  NOTREACHED();
+  return String();
+#endif
+}
+
+String ChooserResourceLoader::GetColorPickerStyleSheet() {
+#if !defined(OS_ANDROID)
+  return UncompressResourceAsString(IDR_COLOR_PICKER_CSS);
+#else
+  NOTREACHED();
+  return String();
+#endif
+}
+
+String ChooserResourceLoader::GetCalendarPickerRefreshStyleSheet() {
+#if !defined(OS_ANDROID)
+  return UncompressResourceAsString(IDR_CALENDAR_PICKER_REFRESH_CSS);
+#else
+  NOTREACHED();
+  return String();
+#endif
+}
+
+String ChooserResourceLoader::GetColorPickerJS() {
+#if !defined(OS_ANDROID)
+  return UncompressResourceAsString(IDR_COLOR_PICKER_JS);
+#else
+  NOTREACHED();
+  return String();
+#endif
+}
+
+String ChooserResourceLoader::GetColorPickerCommonJS() {
+#if !defined(OS_ANDROID)
+  return UncompressResourceAsString(IDR_COLOR_PICKER_COMMON_JS);
+#else
+  NOTREACHED();
+  return String();
+#endif
+}
+
+String ChooserResourceLoader::GetListPickerStyleSheet() {
+#if !defined(OS_ANDROID)
+  return UncompressResourceAsString(IDR_LIST_PICKER_CSS);
+#else
+  NOTREACHED();
+  return String();
+#endif
+}
+
+String ChooserResourceLoader::GetListPickerJS() {
+#if !defined(OS_ANDROID)
+  return UncompressResourceAsString(IDR_LIST_PICKER_JS);
+#else
+  NOTREACHED();
+  return String();
+#endif
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/html/forms/chooser_resource_loader.h b/third_party/blink/renderer/core/html/forms/chooser_resource_loader.h
new file mode 100644
index 0000000..bd58bf2
--- /dev/null
+++ b/third_party/blink/renderer/core/html/forms/chooser_resource_loader.h
@@ -0,0 +1,65 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_HTML_FORMS_CHOOSER_RESOURCE_LOADER_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_HTML_FORMS_CHOOSER_RESOURCE_LOADER_H_
+
+#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+
+namespace blink {
+
+class ChooserResourceLoader {
+  STATIC_ONLY(ChooserResourceLoader);
+
+ public:
+  // Returns the picker common stylesheet as a string.
+  static String GetPickerCommonStyleSheet();
+
+  // Returns the picker common javascript as a string.
+  static String GetPickerCommonJS();
+
+  // Returns the picker button stylesheet as a string.
+  static String GetPickerButtonStyleSheet();
+
+  // Returns the suggestion picker stylesheet as a string.
+  static String GetSuggestionPickerStyleSheet();
+
+  // Returns the suggestion picker javascript as a string.
+  static String GetSuggestionPickerJS();
+
+  // Returns the suggestion picker stylesheet as a string.
+  static String GetCalendarPickerStyleSheet();
+
+  // Returns the calendar picker refresh stylesheet as a string.
+  static String GetCalendarPickerRefreshStyleSheet();
+
+  // Returns the suggestion picker javascript as a string.
+  static String GetCalendarPickerJS();
+
+  // Returns the color suggestion picker stylesheet as a string.
+  static String GetColorSuggestionPickerStyleSheet();
+
+  // Returns the color suggestion picker javascript as a string.
+  static String GetColorSuggestionPickerJS();
+
+  // Returns the color picker stylesheet as a string.
+  static String GetColorPickerStyleSheet();
+
+  // Returns the color picker javascript as a string.
+  static String GetColorPickerJS();
+
+  // Returns the color picker common javascript as a string.
+  static String GetColorPickerCommonJS();
+
+  // Returns the list picker stylesheet as a string.
+  static String GetListPickerStyleSheet();
+
+  // Returns the list picker javascript as a string.
+  static String GetListPickerJS();
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_HTML_FORMS_CHOOSER_RESOURCE_LOADER_H_
diff --git a/third_party/blink/renderer/core/html/forms/color_chooser_popup_ui_controller.cc b/third_party/blink/renderer/core/html/forms/color_chooser_popup_ui_controller.cc
index f81ad93..d5d6fe8 100644
--- a/third_party/blink/renderer/core/html/forms/color_chooser_popup_ui_controller.cc
+++ b/third_party/blink/renderer/core/html/forms/color_chooser_popup_ui_controller.cc
@@ -28,6 +28,7 @@
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
+#include "third_party/blink/renderer/core/html/forms/chooser_resource_loader.h"
 #include "third_party/blink/renderer/core/html/forms/color_chooser_client.h"
 #include "third_party/blink/renderer/core/page/chrome_client.h"
 #include "third_party/blink/renderer/core/page/page_popup.h"
@@ -98,8 +99,9 @@
 
   PagePopupClient::AddString(
       "<!DOCTYPE html><head><meta charset='UTF-8'><style>\n", data);
-  data->Append(Platform::Current()->GetDataResource("pickerCommon.css"));
-  data->Append(Platform::Current()->GetDataResource("color_picker.css"));
+  AddString(ChooserResourceLoader::GetPickerCommonStyleSheet(), data);
+  AddString(ChooserResourceLoader::GetColorPickerStyleSheet(), data);
+
   PagePopupClient::AddString(
       "</style></head><body>\n"
       "<div id='main'>Loading...</div><script>\n"
@@ -111,9 +113,9 @@
   AddProperty("zoomFactor", ZoomFactor(), data);
   AddProperty("shouldShowColorSuggestionPicker", false, data);
   PagePopupClient::AddString("};\n", data);
-  data->Append(Platform::Current()->GetDataResource("pickerCommon.js"));
-  data->Append(Platform::Current()->GetDataResource("color_picker.js"));
-  data->Append(Platform::Current()->GetDataResource("color_picker_common.js"));
+  AddString(ChooserResourceLoader::GetPickerCommonJS(), data);
+  AddString(ChooserResourceLoader::GetColorPickerJS(), data);
+  AddString(ChooserResourceLoader::GetColorPickerCommonJS(), data);
   PagePopupClient::AddString("</script></body>\n", data);
 }
 
@@ -129,12 +131,11 @@
 
   PagePopupClient::AddString(
       "<!DOCTYPE html><head><meta charset='UTF-8'><style>\n", data);
-  data->Append(Platform::Current()->GetDataResource("pickerCommon.css"));
-  data->Append(
-      Platform::Current()->GetDataResource("colorSuggestionPicker.css"));
-  if (RuntimeEnabledFeatures::FormControlsRefreshEnabled()) {
-    data->Append(Platform::Current()->GetDataResource("color_picker.css"));
-  }
+  AddString(ChooserResourceLoader::GetPickerCommonStyleSheet(), data);
+  AddString(ChooserResourceLoader::GetColorSuggestionPickerStyleSheet(), data);
+  if (RuntimeEnabledFeatures::FormControlsRefreshEnabled())
+    AddString(ChooserResourceLoader::GetColorPickerStyleSheet(), data);
+
   PagePopupClient::AddString(
       "</style></head><body>\n"
       "<div id='main'>Loading...</div><script>\n"
@@ -154,13 +155,11 @@
   AddProperty("isFormControlsRefreshEnabled",
               RuntimeEnabledFeatures::FormControlsRefreshEnabled(), data);
   PagePopupClient::AddString("};\n", data);
-  data->Append(Platform::Current()->GetDataResource("pickerCommon.js"));
-  data->Append(
-      Platform::Current()->GetDataResource("colorSuggestionPicker.js"));
-  if (RuntimeEnabledFeatures::FormControlsRefreshEnabled()) {
-    data->Append(Platform::Current()->GetDataResource("color_picker.js"));
-  }
-  data->Append(Platform::Current()->GetDataResource("color_picker_common.js"));
+  AddString(ChooserResourceLoader::GetPickerCommonJS(), data);
+  AddString(ChooserResourceLoader::GetColorSuggestionPickerJS(), data);
+  if (RuntimeEnabledFeatures::FormControlsRefreshEnabled())
+    AddString(ChooserResourceLoader::GetColorPickerJS(), data);
+  AddString(ChooserResourceLoader::GetColorPickerCommonJS(), data);
   PagePopupClient::AddString("</script></body>\n", data);
 }
 
diff --git a/third_party/blink/renderer/core/html/forms/date_time_chooser_impl.cc b/third_party/blink/renderer/core/html/forms/date_time_chooser_impl.cc
index e9dfcdc7a..6b8b5f1 100644
--- a/third_party/blink/renderer/core/html/forms/date_time_chooser_impl.cc
+++ b/third_party/blink/renderer/core/html/forms/date_time_chooser_impl.cc
@@ -33,6 +33,7 @@
 #include "third_party/blink/public/mojom/choosers/date_time_chooser.mojom-blink.h"
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
+#include "third_party/blink/renderer/core/html/forms/chooser_resource_loader.h"
 #include "third_party/blink/renderer/core/html/forms/date_time_chooser_client.h"
 #include "third_party/blink/renderer/core/input_type_names.h"
 #include "third_party/blink/renderer/core/layout/layout_theme.h"
@@ -120,15 +121,15 @@
   }
 
   AddString("<!DOCTYPE html><head><meta charset='UTF-8'><style>\n", data);
-  data->Append(Platform::Current()->GetDataResource("pickerCommon.css"));
-  if (!RuntimeEnabledFeatures::FormControlsRefreshEnabled()) {
-    data->Append(Platform::Current()->GetDataResource("pickerButton.css"));
-  }
-  data->Append(Platform::Current()->GetDataResource("suggestionPicker.css"));
-  data->Append(Platform::Current()->GetDataResource("calendarPicker.css"));
+
+  AddString(ChooserResourceLoader::GetPickerCommonStyleSheet(), data);
+  if (!RuntimeEnabledFeatures::FormControlsRefreshEnabled())
+    AddString(ChooserResourceLoader::GetPickerButtonStyleSheet(), data);
+  AddString(ChooserResourceLoader::GetSuggestionPickerStyleSheet(), data);
+  AddString(ChooserResourceLoader::GetCalendarPickerStyleSheet(), data);
   if (RuntimeEnabledFeatures::FormControlsRefreshEnabled()) {
-    data->Append(
-        Platform::Current()->GetDataResource("calendar_picker_refresh.css"));
+    AddString(ChooserResourceLoader::GetCalendarPickerRefreshStyleSheet(),
+              data);
   }
   AddString(
       "</style></head><body><div id=main>Loading...</div><script>\n"
@@ -214,9 +215,9 @@
   }
   AddString("}\n", data);
 
-  data->Append(Platform::Current()->GetDataResource("pickerCommon.js"));
-  data->Append(Platform::Current()->GetDataResource("suggestionPicker.js"));
-  data->Append(Platform::Current()->GetDataResource("calendarPicker.js"));
+  AddString(ChooserResourceLoader::GetPickerCommonJS(), data);
+  AddString(ChooserResourceLoader::GetSuggestionPickerJS(), data);
+  AddString(ChooserResourceLoader::GetCalendarPickerJS(), data);
   AddString("</script></body>\n", data);
 }
 
diff --git a/third_party/blink/renderer/core/html/forms/internal_popup_menu.cc b/third_party/blink/renderer/core/html/forms/internal_popup_menu.cc
index 620d83e..a778eca 100644
--- a/third_party/blink/renderer/core/html/forms/internal_popup_menu.cc
+++ b/third_party/blink/renderer/core/html/forms/internal_popup_menu.cc
@@ -16,6 +16,7 @@
 #include "third_party/blink/renderer/core/exported/web_view_impl.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
+#include "third_party/blink/renderer/core/html/forms/chooser_resource_loader.h"
 #include "third_party/blink/renderer/core/html/forms/html_opt_group_element.h"
 #include "third_party/blink/renderer/core/html/forms/html_option_element.h"
 #include "third_party/blink/renderer/core/html/forms/html_select_element.h"
@@ -232,8 +233,8 @@
   float scale_factor = chrome_client_->WindowToViewportScalar(1.f);
   PagePopupClient::AddString(
       "<!DOCTYPE html><head><meta charset='UTF-8'><style>\n", data);
-  data->Append(Platform::Current()->GetDataResource("pickerCommon.css"));
-  data->Append(Platform::Current()->GetDataResource("listPicker.css"));
+  AddString(ChooserResourceLoader::GetPickerCommonStyleSheet(), data);
+  AddString(ChooserResourceLoader::GetListPickerStyleSheet(), data);
   if (!RuntimeEnabledFeatures::ForceTallerSelectPopupEnabled())
     PagePopupClient::AddString("@media (any-pointer:coarse) {", data);
   int padding = static_cast<int>(roundf(4 * scale_factor));
@@ -288,8 +289,9 @@
                      : owner_element.ClientPaddingLeft().ToDouble(),
               data);
   PagePopupClient::AddString("};\n", data);
-  data->Append(Platform::Current()->GetDataResource("pickerCommon.js"));
-  data->Append(Platform::Current()->GetDataResource("listPicker.js"));
+  AddString(ChooserResourceLoader::GetPickerCommonJS(), data);
+  AddString(ChooserResourceLoader::GetListPickerJS(), data);
+
   PagePopupClient::AddString("</script></body>\n", data);
 }
 
diff --git a/third_party/blink/renderer/core/html/portal/document_portals.h b/third_party/blink/renderer/core/html/portal/document_portals.h
index 9db5ed7..5726d52 100644
--- a/third_party/blink/renderer/core/html/portal/document_portals.h
+++ b/third_party/blink/renderer/core/html/portal/document_portals.h
@@ -13,8 +13,8 @@
 
 class HTMLPortalElement;
 
-class DocumentPortals : public GarbageCollected<DocumentPortals>,
-                        public Supplement<Document> {
+class DocumentPortals final : public GarbageCollected<DocumentPortals>,
+                              public Supplement<Document> {
   USING_GARBAGE_COLLECTED_MIXIN(DocumentPortals);
 
  public:
diff --git a/third_party/blink/renderer/core/intersection_observer/element_intersection_observer_data.h b/third_party/blink/renderer/core/intersection_observer/element_intersection_observer_data.h
index ac55771..1507408 100644
--- a/third_party/blink/renderer/core/intersection_observer/element_intersection_observer_data.h
+++ b/third_party/blink/renderer/core/intersection_observer/element_intersection_observer_data.h
@@ -14,7 +14,7 @@
 class IntersectionObservation;
 class IntersectionObserver;
 
-class ElementIntersectionObserverData
+class ElementIntersectionObserverData final
     : public GarbageCollected<ElementIntersectionObserverData>,
       public NameClient {
  public:
diff --git a/third_party/blink/renderer/core/layout/layout_box.cc b/third_party/blink/renderer/core/layout/layout_box.cc
index 695917d..72cce36 100644
--- a/third_party/blink/renderer/core/layout/layout_box.cc
+++ b/third_party/blink/renderer/core/layout/layout_box.cc
@@ -3268,7 +3268,7 @@
 bool LayoutBox::AutoWidthShouldFitContent() const {
   return GetNode() &&
          (IsHTMLInputElement(*GetNode()) || IsHTMLSelectElement(*GetNode()) ||
-          IsHTMLButtonElement(*GetNode()) ||
+          IsA<HTMLButtonElement>(*GetNode()) ||
           IsHTMLTextAreaElement(*GetNode()) || IsRenderedLegend());
 }
 
diff --git a/third_party/blink/renderer/core/layout/layout_button.cc b/third_party/blink/renderer/core/layout/layout_button.cc
index 69728d6b..c743f0cd 100644
--- a/third_party/blink/renderer/core/layout/layout_button.cc
+++ b/third_party/blink/renderer/core/layout/layout_button.cc
@@ -108,6 +108,6 @@
 
 // For compatibility with IE/FF we only clip overflow on input elements.
 bool LayoutButton::HasControlClip() const {
-  return !IsHTMLButtonElement(GetNode());
+  return !IsA<HTMLButtonElement>(GetNode());
 }
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/layout_counter.cc b/third_party/blink/renderer/core/layout/layout_counter.cc
index 0d7cb55..32d2333 100644
--- a/third_party/blink/renderer/core/layout/layout_counter.cc
+++ b/third_party/blink/renderer/core/layout/layout_counter.cc
@@ -512,7 +512,7 @@
 }
 
 void LayoutCounter::UpdateCounter() {
-  SetText(OriginalText());
+  SetTextIfNeeded(OriginalText());
 }
 
 void LayoutCounter::Invalidate() {
diff --git a/third_party/blink/renderer/core/layout/layout_menu_list.cc b/third_party/blink/renderer/core/layout/layout_menu_list.cc
index 067dc92..0856171 100644
--- a/third_party/blink/renderer/core/layout/layout_menu_list.cc
+++ b/third_party/blink/renderer/core/layout/layout_menu_list.cc
@@ -283,10 +283,10 @@
     // s.impl() into the text and have things align correctly...
     // crbug.com/485982
     is_empty_ = true;
-    button_text_->SetText(StringImpl::Create(" ", 1), true);
+    button_text_->ForceSetText(StringImpl::Create(" ", 1));
   } else {
     is_empty_ = false;
-    button_text_->SetText(s.Impl(), true);
+    button_text_->ForceSetText(s.Impl());
   }
   // LayoutMenuList::ControlClipRect() depends on inner_block_->ContentsSize().
   SetNeedsPaintPropertyUpdate();
diff --git a/third_party/blink/renderer/core/layout/layout_replaced.h b/third_party/blink/renderer/core/layout/layout_replaced.h
index a945fcf3..e20d543 100644
--- a/third_party/blink/renderer/core/layout/layout_replaced.h
+++ b/third_party/blink/renderer/core/layout/layout_replaced.h
@@ -99,7 +99,8 @@
   // intrinsic size in LayoutNG.
   virtual void ComputeIntrinsicSizingInfo(IntrinsicSizingInfo&) const;
 
-  // This callback is invoked whenever the intrinsic size changed.
+  // This callback must be invoked whenever the underlying intrinsic size has
+  // changed.
   //
   // The intrinsic size can change due to the network (from the default
   // intrinsic size [see above] to the actual intrinsic size) or to some
@@ -111,7 +112,11 @@
 
   void UpdateLayout() override;
 
-  LayoutSize IntrinsicSize() const final { return intrinsic_size_; }
+  LayoutSize IntrinsicSize() const final {
+    // TODO(vmpstr): To address the intrinsic size of replaced element for
+    // display lock.
+    return ShouldApplySizeContainment() ? LayoutSize() : intrinsic_size_;
+  }
 
   void ComputePositionedLogicalWidth(
       LogicalExtentComputedValues&) const override;
diff --git a/third_party/blink/renderer/core/layout/layout_text.cc b/third_party/blink/renderer/core/layout/layout_text.cc
index 50b7c30..bc79f62 100644
--- a/third_party/blink/renderer/core/layout/layout_text.cc
+++ b/third_party/blink/renderer/core/layout/layout_text.cc
@@ -114,9 +114,8 @@
  private:
   void Fired() override {
     DCHECK(g_secure_text_timers->Contains(layout_text_));
-    layout_text_->SetText(
-        layout_text_->GetText().Impl(),
-        true /* forcing setting text as it may be masked later */);
+    // Forcing setting text as it may be masked later
+    layout_text_->ForceSetText(layout_text_->GetText().Impl());
   }
 
   LayoutText* layout_text_;
@@ -1653,9 +1652,8 @@
       FirstTextBox()->ManuallySetStartLenAndLogicalWidth(
           offset, text->length(), LayoutUnit(text_width));
       SetFirstTextBoxLogicalLeft(text_width);
-      const bool force = false;
       const bool avoid_layout_and_only_paint = true;
-      SetText(std::move(text), force, avoid_layout_and_only_paint);
+      ForceSetText(std::move(text), avoid_layout_and_only_paint);
       lines_dirty_ = false;
       valid_ng_items_ = false;
       return;
@@ -1735,7 +1733,7 @@
   }
 
   lines_dirty_ = dirtied_lines;
-  SetText(std::move(text), dirtied_lines);
+  ForceSetText(std::move(text));
 
   // TODO(layout-dev): Invalidation is currently all or nothing in LayoutNG,
   // this is probably fine for NGInlineItem reuse as recreating the individual
@@ -1746,7 +1744,7 @@
 
 void LayoutText::TransformText() {
   if (scoped_refptr<StringImpl> text_to_transform = OriginalText())
-    SetText(std::move(text_to_transform), true);
+    ForceSetText(std::move(text_to_transform));
 }
 
 static inline bool IsInlineFlowOrEmptyText(const LayoutObject* o) {
@@ -1831,14 +1829,17 @@
   }
 }
 
-void LayoutText::SetText(scoped_refptr<StringImpl> text,
-                         bool force,
-                         bool avoid_layout_and_only_paint) {
+void LayoutText::SetTextIfNeeded(scoped_refptr<StringImpl> text) {
   DCHECK(text);
 
-  if (!force && Equal(text_.Impl(), text.get()))
+  if (Equal(text_.Impl(), text.get()))
     return;
+  ForceSetText(std::move(text));
+}
 
+void LayoutText::ForceSetText(scoped_refptr<StringImpl> text,
+                              bool avoid_layout_and_only_paint) {
+  DCHECK(text);
   SetTextInternal(std::move(text));
   // If preferredLogicalWidthsDirty() of an orphan child is true,
   // LayoutObjectChildList::insertChildNode() fails to set true to owner.
diff --git a/third_party/blink/renderer/core/layout/layout_text.h b/third_party/blink/renderer/core/layout/layout_text.h
index 1ec56457..19d94d9 100644
--- a/third_party/blink/renderer/core/layout/layout_text.h
+++ b/third_party/blink/renderer/core/layout/layout_text.h
@@ -187,9 +187,9 @@
 
   PhysicalOffset FirstLineBoxTopLeft() const;
 
-  virtual void SetText(scoped_refptr<StringImpl>,
-                       bool force = false,
-                       bool avoid_layout_and_only_paint = false);
+  void SetTextIfNeeded(scoped_refptr<StringImpl>);
+  virtual void ForceSetText(scoped_refptr<StringImpl>,
+                            bool avoid_layout_and_only_paint = false);
   void SetTextWithOffset(scoped_refptr<StringImpl>,
                          unsigned offset,
                          unsigned len);
diff --git a/third_party/blink/renderer/core/layout/layout_text_fragment.cc b/third_party/blink/renderer/core/layout/layout_text_fragment.cc
index 4c58876..fa7ee60 100644
--- a/third_party/blink/renderer/core/layout/layout_text_fragment.cc
+++ b/third_party/blink/renderer/core/layout/layout_text_fragment.cc
@@ -94,7 +94,7 @@
 
 void LayoutTextFragment::SetContentString(StringImpl* str) {
   content_string_ = str;
-  SetText(str);
+  SetTextIfNeeded(str);
 }
 
 scoped_refptr<StringImpl> LayoutTextFragment::OriginalText() const {
@@ -104,10 +104,9 @@
   return result->Substring(Start(), FragmentLength());
 }
 
-void LayoutTextFragment::SetText(scoped_refptr<StringImpl> text,
-                                 bool force,
-                                 bool avoid_layout_and_only_paint) {
-  LayoutText::SetText(std::move(text), force, avoid_layout_and_only_paint);
+void LayoutTextFragment::ForceSetText(scoped_refptr<StringImpl> text,
+                                      bool avoid_layout_and_only_paint) {
+  LayoutText::ForceSetText(std::move(text), avoid_layout_and_only_paint);
 
   start_ = 0;
   fragment_length_ = TextLength();
@@ -121,21 +120,27 @@
   }
 }
 
+// Unlike |ForceSetText()|, this function is used for updating first-letter part
+// or remaining part.
 void LayoutTextFragment::SetTextFragment(scoped_refptr<StringImpl> text,
                                          unsigned start,
                                          unsigned length) {
-  LayoutText::SetText(std::move(text), false);
+  // Note, we have to call |LayoutText::ForceSetText()| here because, if we
+  // use our version we will, potentially, screw up the first-letter settings
+  // where we only use portions of the string.
+  if (!Equal(GetText().Impl(), text.get()))
+    LayoutText::ForceSetText(std::move(text));
 
   start_ = start;
   fragment_length_ = length;
 }
 
 void LayoutTextFragment::TransformText() {
-  // Note, we have to call LayoutText::setText here because, if we use our
-  // version we will, potentially, screw up the first-letter settings where
+  // Note, we have to call LayoutText::ForceSetText()| here because, if we use
+  // our version we will, potentially, screw up the first-letter settings where
   // we only use portions of the string.
   if (scoped_refptr<StringImpl> text_to_transform = OriginalText())
-    LayoutText::SetText(std::move(text_to_transform), true);
+    LayoutText::ForceSetText(std::move(text_to_transform));
 }
 
 UChar LayoutTextFragment::PreviousCharacter() const {
diff --git a/third_party/blink/renderer/core/layout/layout_text_fragment.h b/third_party/blink/renderer/core/layout/layout_text_fragment.h
index af2fb50..538fbdd 100644
--- a/third_party/blink/renderer/core/layout/layout_text_fragment.h
+++ b/third_party/blink/renderer/core/layout/layout_text_fragment.h
@@ -74,9 +74,8 @@
 
   scoped_refptr<StringImpl> OriginalText() const override;
 
-  void SetText(scoped_refptr<StringImpl>,
-               bool force = false,
-               bool avoid_layout_and_only_paint = false) override;
+  void ForceSetText(scoped_refptr<StringImpl>,
+                    bool avoid_layout_and_only_paint = false) override;
   void SetTextFragment(scoped_refptr<StringImpl>,
                        unsigned start,
                        unsigned length);
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_test.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_test.cc
index 2e844d2..64bd410 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_test.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_test.cc
@@ -923,7 +923,7 @@
   EXPECT_FALSE(layout_block_flow_->NeedsCollectInlines());
 
   LayoutText* text = ToLayoutText(layout_block_flow_->FirstChild());
-  text->SetText(String("after").Impl());
+  text->SetTextIfNeeded(String("after").Impl());
   EXPECT_TRUE(layout_block_flow_->NeedsCollectInlines());
 }
 
diff --git a/third_party/blink/renderer/core/layout/ng/list/layout_ng_list_item.cc b/third_party/blink/renderer/core/layout/ng/list/layout_ng_list_item.cc
index 1bfde5a..60052f7 100644
--- a/third_party/blink/renderer/core/layout/ng/list/layout_ng_list_item.cc
+++ b/third_party/blink/renderer/core/layout/ng/list/layout_ng_list_item.cc
@@ -121,7 +121,7 @@
   DCHECK(text);
   StringBuilder marker_text_builder;
   marker_type_ = MarkerText(&marker_text_builder, kWithSuffix);
-  text->SetText(marker_text_builder.ToString().ReleaseImpl());
+  text->SetTextIfNeeded(marker_text_builder.ToString().ReleaseImpl());
   is_marker_text_updated_ = true;
 }
 
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_inline_text.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_inline_text.cc
index 20cf37c..b5da4ce 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_inline_text.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_inline_text.cc
@@ -73,7 +73,7 @@
   bool old_preserves =
       old_style ? old_style->WhiteSpace() == EWhiteSpace::kPre : false;
   if (old_preserves != new_preserves) {
-    SetText(OriginalText(), true);
+    ForceSetText(OriginalText());
     return;
   }
 
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_root.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_root.cc
index a3152eb7..b2d4eda 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_root.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_root.cc
@@ -95,7 +95,7 @@
 
 void LayoutSVGRoot::ComputeIntrinsicSizingInfo(
     IntrinsicSizingInfo& intrinsic_sizing_info) const {
-  DCHECK(!ShouldApplySizeContainment());
+  DCHECK(!ShouldApplySizeContainment() && !DisplayLockInducesSizeContainment());
   UnscaledIntrinsicSizingInfo(intrinsic_sizing_info);
 
   intrinsic_sizing_info.size.Scale(StyleRef().EffectiveZoom());
diff --git a/third_party/blink/renderer/core/loader/frame_fetch_context_test.cc b/third_party/blink/renderer/core/loader/frame_fetch_context_test.cc
index 0dbbc54..90afdb4c 100644
--- a/third_party/blink/renderer/core/loader/frame_fetch_context_test.cc
+++ b/third_party/blink/renderer/core/loader/frame_fetch_context_test.cc
@@ -40,7 +40,6 @@
 #include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
 #include "third_party/blink/public/mojom/loader/request_context_frame_type.mojom-blink.h"
-#include "third_party/blink/public/mojom/net/ip_address_space.mojom-blink.h"
 #include "third_party/blink/public/platform/scheduler/web_scoped_virtual_time_pauser.h"
 #include "third_party/blink/public/platform/web_client_hints_type.h"
 #include "third_party/blink/public/platform/web_document_subresource_filter.h"
diff --git a/third_party/blink/renderer/core/loader/mixed_content_checker.cc b/third_party/blink/renderer/core/loader/mixed_content_checker.cc
index b6a46c1..d103a0a 100644
--- a/third_party/blink/renderer/core/loader/mixed_content_checker.cc
+++ b/third_party/blink/renderer/core/loader/mixed_content_checker.cc
@@ -30,9 +30,9 @@
 
 #include "base/feature_list.h"
 #include "base/metrics/field_trial_params.h"
+#include "services/network/public/mojom/ip_address_space.mojom-blink.h"
 #include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/mojom/loader/request_context_frame_type.mojom-blink.h"
-#include "third_party/blink/public/mojom/net/ip_address_space.mojom-blink.h"
 #include "third_party/blink/public/platform/web_content_settings_client.h"
 #include "third_party/blink/public/platform/web_insecure_request_policy.h"
 #include "third_party/blink/public/platform/web_mixed_content.h"
@@ -695,7 +695,8 @@
 
   // Just count these for the moment, don't block them.
   if (network_utils::IsReservedIPAddress(resource_ip_address) &&
-      frame->GetDocument()->AddressSpace() == mojom::IPAddressSpace::kPublic) {
+      frame->GetDocument()->AddressSpace() ==
+          network::mojom::IPAddressSpace::kPublic) {
     UseCounter::Count(frame->GetDocument(),
                       WebFeature::kMixedContentPrivateHostnameInPublicHostname);
     // We can simplify the IP checks here, as we've already verified that
diff --git a/third_party/blink/renderer/core/loader/modulescript/module_script_loader_test.cc b/third_party/blink/renderer/core/loader/modulescript/module_script_loader_test.cc
index b2fd1ad..3b198820 100644
--- a/third_party/blink/renderer/core/loader/modulescript/module_script_loader_test.cc
+++ b/third_party/blink/renderer/core/loader/modulescript/module_script_loader_test.cc
@@ -194,7 +194,7 @@
       Vector<CSPHeaderAndType>(), network::mojom::ReferrerPolicy::kDefault,
       security_origin_.get(), true /* is_secure_context */, HttpsState::kModern,
       nullptr /* worker_clients */, nullptr /* content_settings_client */,
-      mojom::IPAddressSpace::kLocal, nullptr /* origin_trial_token */,
+      network::mojom::IPAddressSpace::kLocal, nullptr /* origin_trial_token */,
       base::UnguessableToken::Create(), nullptr /* worker_settings */,
       kV8CacheOptionsDefault,
       MakeGarbageCollected<WorkletModuleResponsesMap>());
diff --git a/third_party/blink/renderer/core/loader/modulescript/module_tree_linker_registry.h b/third_party/blink/renderer/core/loader/modulescript/module_tree_linker_registry.h
index 442e8b0..ab2c73a1 100644
--- a/third_party/blink/renderer/core/loader/modulescript/module_tree_linker_registry.h
+++ b/third_party/blink/renderer/core/loader/modulescript/module_tree_linker_registry.h
@@ -14,7 +14,7 @@
 class ModuleTreeLinker;
 
 // ModuleTreeLinkerRegistry keeps active ModuleTreeLinkers alive.
-class CORE_EXPORT ModuleTreeLinkerRegistry
+class CORE_EXPORT ModuleTreeLinkerRegistry final
     : public GarbageCollected<ModuleTreeLinkerRegistry>,
       public NameClient {
  public:
diff --git a/third_party/blink/renderer/core/loader/modulescript/worker_module_script_fetcher.cc b/third_party/blink/renderer/core/loader/modulescript/worker_module_script_fetcher.cc
index 730671b..f303efc 100644
--- a/third_party/blink/renderer/core/loader/modulescript/worker_module_script_fetcher.cc
+++ b/third_party/blink/renderer/core/loader/modulescript/worker_module_script_fetcher.cc
@@ -103,13 +103,13 @@
     // TODO(https://crbug.com/955213): Make this consistent with the spec.
     // TODO(https://crbug.com/955213): Move this function to a more appropriate
     // place so that this is shareable out of worker code.
-    auto response_address_space = mojom::IPAddressSpace::kPublic;
+    auto response_address_space = network::mojom::IPAddressSpace::kPublic;
     if (network_utils::IsReservedIPAddress(
             resource->GetResponse().RemoteIPAddress())) {
-      response_address_space = mojom::IPAddressSpace::kPrivate;
+      response_address_space = network::mojom::IPAddressSpace::kPrivate;
     }
     if (SecurityOrigin::Create(response_url)->IsLocalhost())
-      response_address_space = mojom::IPAddressSpace::kLocal;
+      response_address_space = network::mojom::IPAddressSpace::kLocal;
 
     auto* response_content_security_policy =
         MakeGarbageCollected<ContentSecurityPolicy>();
diff --git a/third_party/blink/renderer/core/paint/theme_painter.cc b/third_party/blink/renderer/core/paint/theme_painter.cc
index 6d92f68..581ea5b 100644
--- a/third_party/blink/renderer/core/paint/theme_painter.cc
+++ b/third_party/blink/renderer/core/paint/theme_painter.cc
@@ -152,7 +152,7 @@
       Deprecation::CountDeprecation(
           doc, WebFeature::kCSSValueAppearanceButtonForAnchor);
       COUNT_APPEARANCE(doc, ButtonForNonButton);
-    } else if (IsHTMLButtonElement(node)) {
+    } else if (IsA<HTMLButtonElement>(node)) {
       UseCounter::Count(doc, WebFeature::kCSSValueAppearanceButtonForButton);
     } else if (IsHTMLInputElement(node) &&
                ToHTMLInputElement(node)->IsTextButton()) {
diff --git a/third_party/blink/renderer/core/script/fetch_client_settings_object_impl.cc b/third_party/blink/renderer/core/script/fetch_client_settings_object_impl.cc
index be04346..e3abce7 100644
--- a/third_party/blink/renderer/core/script/fetch_client_settings_object_impl.cc
+++ b/third_party/blink/renderer/core/script/fetch_client_settings_object_impl.cc
@@ -67,7 +67,8 @@
   return AllowedByNosniff::MimeTypeCheck::kStrict;
 }
 
-mojom::IPAddressSpace FetchClientSettingsObjectImpl::GetAddressSpace() const {
+network::mojom::IPAddressSpace FetchClientSettingsObjectImpl::GetAddressSpace()
+    const {
   return execution_context_->GetSecurityContext().AddressSpace();
 }
 
diff --git a/third_party/blink/renderer/core/script/fetch_client_settings_object_impl.h b/third_party/blink/renderer/core/script/fetch_client_settings_object_impl.h
index a01b4a1..4587ec3 100644
--- a/third_party/blink/renderer/core/script/fetch_client_settings_object_impl.h
+++ b/third_party/blink/renderer/core/script/fetch_client_settings_object_impl.h
@@ -42,7 +42,7 @@
   AllowedByNosniff::MimeTypeCheck MimeTypeCheckForClassicWorkerScript()
       const override;
 
-  mojom::IPAddressSpace GetAddressSpace() const override;
+  network::mojom::IPAddressSpace GetAddressSpace() const override;
 
   WebInsecureRequestPolicy GetInsecureRequestsPolicy() const override;
   const InsecureNavigationsSet& GetUpgradeInsecureNavigationsSet()
diff --git a/third_party/blink/renderer/core/streams/underlying_sink_base.h b/third_party/blink/renderer/core/streams/underlying_sink_base.h
index 9dd9e0bf..6e7905a 100644
--- a/third_party/blink/renderer/core/streams/underlying_sink_base.h
+++ b/third_party/blink/renderer/core/streams/underlying_sink_base.h
@@ -50,6 +50,11 @@
     ScriptWrappable::Trace(visitor);
   }
 
+ protected:
+  WritableStreamDefaultControllerInterface* Controller() const {
+    return controller_;
+  }
+
  private:
   Member<WritableStreamDefaultControllerInterface> controller_;
 };
diff --git a/third_party/blink/renderer/core/streams/writable_stream_default_controller_interface.h b/third_party/blink/renderer/core/streams/writable_stream_default_controller_interface.h
index 7cf540bf..f403214 100644
--- a/third_party/blink/renderer/core/streams/writable_stream_default_controller_interface.h
+++ b/third_party/blink/renderer/core/streams/writable_stream_default_controller_interface.h
@@ -33,7 +33,7 @@
   // Helper method
   template <typename ErrorType>
   void Error(ScriptState* script_state, ErrorType error) {
-    Error(script_state, ToV8(error, script_state).ToV8Value());
+    Error(script_state, ToV8(error, script_state));
   }
 
   virtual void Trace(Visitor*) {}
diff --git a/third_party/blink/renderer/core/workers/dedicated_worker.cc b/third_party/blink/renderer/core/workers/dedicated_worker.cc
index 2445a76..2685064 100644
--- a/third_party/blink/renderer/core/workers/dedicated_worker.cc
+++ b/third_party/blink/renderer/core/workers/dedicated_worker.cc
@@ -421,7 +421,7 @@
     const KURL& script_url,
     OffMainThreadWorkerScriptFetchOption off_main_thread_fetch_option,
     network::mojom::ReferrerPolicy referrer_policy,
-    base::Optional<mojom::IPAddressSpace> response_address_space,
+    base::Optional<network::mojom::IPAddressSpace> response_address_space,
     const String& source_code) {
   context_proxy_->StartWorkerGlobalScope(
       CreateGlobalScopeCreationParams(script_url, off_main_thread_fetch_option,
@@ -435,7 +435,7 @@
     const KURL& script_url,
     OffMainThreadWorkerScriptFetchOption off_main_thread_fetch_option,
     network::mojom::ReferrerPolicy referrer_policy,
-    base::Optional<mojom::IPAddressSpace> response_address_space) {
+    base::Optional<network::mojom::IPAddressSpace> response_address_space) {
   base::UnguessableToken parent_devtools_token;
   std::unique_ptr<WorkerSettings> settings;
   if (auto* document = DynamicTo<Document>(GetExecutionContext())) {
diff --git a/third_party/blink/renderer/core/workers/dedicated_worker.h b/third_party/blink/renderer/core/workers/dedicated_worker.h
index f778874..c845ab6 100644
--- a/third_party/blink/renderer/core/workers/dedicated_worker.h
+++ b/third_party/blink/renderer/core/workers/dedicated_worker.h
@@ -126,13 +126,13 @@
       const KURL& script_url,
       OffMainThreadWorkerScriptFetchOption,
       network::mojom::ReferrerPolicy,
-      base::Optional<mojom::IPAddressSpace> response_address_space,
+      base::Optional<network::mojom::IPAddressSpace> response_address_space,
       const String& source_code);
   std::unique_ptr<GlobalScopeCreationParams> CreateGlobalScopeCreationParams(
       const KURL& script_url,
       OffMainThreadWorkerScriptFetchOption,
       network::mojom::ReferrerPolicy,
-      base::Optional<mojom::IPAddressSpace> response_address_space);
+      base::Optional<network::mojom::IPAddressSpace> response_address_space);
   scoped_refptr<WebWorkerFetchContext> CreateWebWorkerFetchContext();
   WorkerClients* CreateWorkerClients();
   // May return nullptr.
diff --git a/third_party/blink/renderer/core/workers/dedicated_worker_global_scope.cc b/third_party/blink/renderer/core/workers/dedicated_worker_global_scope.cc
index 1325215..89d90d5 100644
--- a/third_party/blink/renderer/core/workers/dedicated_worker_global_scope.cc
+++ b/third_party/blink/renderer/core/workers/dedicated_worker_global_scope.cc
@@ -77,7 +77,7 @@
   KURL response_script_url = creation_params->script_url;
   network::mojom::ReferrerPolicy response_referrer_policy =
       creation_params->referrer_policy;
-  mojom::IPAddressSpace response_address_space =
+  network::mojom::IPAddressSpace response_address_space =
       *creation_params->response_address_space;
   auto* global_scope = MakeGarbageCollected<DedicatedWorkerGlobalScope>(
       std::move(creation_params), thread, time_origin,
@@ -114,7 +114,7 @@
 void DedicatedWorkerGlobalScope::Initialize(
     const KURL& response_url,
     network::mojom::ReferrerPolicy response_referrer_policy,
-    mojom::IPAddressSpace response_address_space,
+    network::mojom::IPAddressSpace response_address_space,
     const Vector<CSPHeaderAndType>& /* response_csp_headers */,
     const Vector<String>* /* response_origin_trial_tokens */) {
   // Step 12.3. "Set worker global scope's url to response's url."
diff --git a/third_party/blink/renderer/core/workers/dedicated_worker_global_scope.h b/third_party/blink/renderer/core/workers/dedicated_worker_global_scope.h
index a2942ee5..23ec8b9 100644
--- a/third_party/blink/renderer/core/workers/dedicated_worker_global_scope.h
+++ b/third_party/blink/renderer/core/workers/dedicated_worker_global_scope.h
@@ -78,7 +78,7 @@
   // Implements WorkerGlobalScope.
   void Initialize(const KURL& response_url,
                   network::mojom::ReferrerPolicy response_referrer_policy,
-                  mojom::IPAddressSpace response_address_space,
+                  network::mojom::IPAddressSpace response_address_space,
                   const Vector<CSPHeaderAndType>& response_csp_headers,
                   const Vector<String>* response_origin_trial_tokens) override;
   void FetchAndRunClassicScript(
diff --git a/third_party/blink/renderer/core/workers/dedicated_worker_test.cc b/third_party/blink/renderer/core/workers/dedicated_worker_test.cc
index 76e9b51..947781f 100644
--- a/third_party/blink/renderer/core/workers/dedicated_worker_test.cc
+++ b/third_party/blink/renderer/core/workers/dedicated_worker_test.cc
@@ -53,9 +53,8 @@
   void CountFeature(WebFeature feature) {
     EXPECT_TRUE(IsCurrentThread());
     GlobalScope()->CountFeature(feature);
-    PostCrossThreadTask(
-        *GetParentExecutionContextTaskRunners()->Get(TaskType::kInternalTest),
-        FROM_HERE, CrossThreadBindOnce(&test::ExitRunLoop));
+    PostCrossThreadTask(*GetParentTaskRunnerForTesting(), FROM_HERE,
+                        CrossThreadBindOnce(&test::ExitRunLoop));
   }
 
   // Emulates deprecated API use on DedicatedWorkerGlobalScope.
@@ -68,9 +67,8 @@
     String console_message = GetConsoleMessageStorage()->at(0)->Message();
     EXPECT_TRUE(console_message.Contains("deprecated"));
 
-    PostCrossThreadTask(
-        *GetParentExecutionContextTaskRunners()->Get(TaskType::kInternalTest),
-        FROM_HERE, CrossThreadBindOnce(&test::ExitRunLoop));
+    PostCrossThreadTask(*GetParentTaskRunnerForTesting(), FROM_HERE,
+                        CrossThreadBindOnce(&test::ExitRunLoop));
   }
 
   void TestTaskRunner() {
@@ -78,9 +76,8 @@
     scoped_refptr<base::SingleThreadTaskRunner> task_runner =
         GlobalScope()->GetTaskRunner(TaskType::kInternalTest);
     EXPECT_TRUE(task_runner->RunsTasksInCurrentSequence());
-    PostCrossThreadTask(
-        *GetParentExecutionContextTaskRunners()->Get(TaskType::kInternalTest),
-        FROM_HERE, CrossThreadBindOnce(&test::ExitRunLoop));
+    PostCrossThreadTask(*GetParentTaskRunnerForTesting(), FROM_HERE,
+                        CrossThreadBindOnce(&test::ExitRunLoop));
   }
 };
 
@@ -141,9 +138,10 @@
             false /* starter_secure_context */,
             CalculateHttpsState(security_origin_.get()),
             nullptr /* worker_clients */, nullptr /* content_settings_client */,
-            mojom::IPAddressSpace::kLocal, nullptr /* origin_trial_tokens */,
-            base::UnguessableToken::Create(), std::move(worker_settings),
-            kV8CacheOptionsDefault, nullptr /* worklet_module_responses_map */),
+            network::mojom::IPAddressSpace::kLocal,
+            nullptr /* origin_trial_tokens */, base::UnguessableToken::Create(),
+            std::move(worker_settings), kV8CacheOptionsDefault,
+            nullptr /* worklet_module_responses_map */),
         WorkerBackingThreadStartupData(
             WorkerBackingThreadStartupData::HeapLimitMode::kDefault,
             WorkerBackingThreadStartupData::AtomicsWaitMode::kAllow));
diff --git a/third_party/blink/renderer/core/workers/global_scope_creation_params.cc b/third_party/blink/renderer/core/workers/global_scope_creation_params.cc
index 7a5b5072..0165bcb 100644
--- a/third_party/blink/renderer/core/workers/global_scope_creation_params.cc
+++ b/third_party/blink/renderer/core/workers/global_scope_creation_params.cc
@@ -26,7 +26,7 @@
     HttpsState starter_https_state,
     WorkerClients* worker_clients,
     std::unique_ptr<WebContentSettingsClient> content_settings_client,
-    base::Optional<mojom::IPAddressSpace> response_address_space,
+    base::Optional<network::mojom::IPAddressSpace> response_address_space,
     const Vector<String>* origin_trial_tokens,
     const base::UnguessableToken& parent_devtools_token,
     std::unique_ptr<WorkerSettings> worker_settings,
diff --git a/third_party/blink/renderer/core/workers/global_scope_creation_params.h b/third_party/blink/renderer/core/workers/global_scope_creation_params.h
index 0b8874e..50220cb7 100644
--- a/third_party/blink/renderer/core/workers/global_scope_creation_params.h
+++ b/third_party/blink/renderer/core/workers/global_scope_creation_params.h
@@ -9,10 +9,10 @@
 #include "base/macros.h"
 #include "base/optional.h"
 #include "base/unguessable_token.h"
+#include "services/network/public/mojom/ip_address_space.mojom-blink.h"
 #include "services/network/public/mojom/referrer_policy.mojom-blink.h"
 #include "services/service_manager/public/mojom/interface_provider.mojom-blink.h"
 #include "third_party/blink/public/common/feature_policy/feature_policy.h"
-#include "third_party/blink/public/mojom/net/ip_address_space.mojom-blink.h"
 #include "third_party/blink/public/mojom/script/script_type.mojom-blink.h"
 #include "third_party/blink/public/platform/web_content_settings_client.h"
 #include "third_party/blink/public/platform/web_worker_fetch_context.h"
@@ -55,7 +55,7 @@
       HttpsState starter_https_state,
       WorkerClients*,
       std::unique_ptr<WebContentSettingsClient>,
-      base::Optional<mojom::IPAddressSpace>,
+      base::Optional<network::mojom::IPAddressSpace>,
       const Vector<String>* origin_trial_tokens,
       const base::UnguessableToken& parent_devtools_token,
       std::unique_ptr<WorkerSettings>,
@@ -139,7 +139,7 @@
   // Worker script response's address space. This is valid only when the worker
   // script is fetched on the main thread (i.e., when
   // |off_main_thread_fetch_option| is kDisabled).
-  base::Optional<mojom::IPAddressSpace> response_address_space;
+  base::Optional<network::mojom::IPAddressSpace> response_address_space;
 
   base::UnguessableToken parent_devtools_token;
 
diff --git a/third_party/blink/renderer/core/workers/installed_scripts_manager.cc b/third_party/blink/renderer/core/workers/installed_scripts_manager.cc
index a53e800..ecc4c90 100644
--- a/third_party/blink/renderer/core/workers/installed_scripts_manager.cc
+++ b/third_party/blink/renderer/core/workers/installed_scripts_manager.cc
@@ -30,11 +30,11 @@
   // TODO(https://crbug.com/955213): Make this consistent with the spec.
   // TODO(https://crbug.com/955213): Move this function to a more appropriate
   // place so that this is shareable out of worker code.
-  response_address_space_ = mojom::IPAddressSpace::kPublic;
+  response_address_space_ = network::mojom::IPAddressSpace::kPublic;
   if (network_utils::IsReservedIPAddress(script_url_.Host()))
-    response_address_space_ = mojom::IPAddressSpace::kPrivate;
+    response_address_space_ = network::mojom::IPAddressSpace::kPrivate;
   if (SecurityOrigin::Create(script_url_)->IsLocalhost())
-    response_address_space_ = mojom::IPAddressSpace::kLocal;
+    response_address_space_ = network::mojom::IPAddressSpace::kLocal;
 }
 
 ContentSecurityPolicyResponseHeaders
diff --git a/third_party/blink/renderer/core/workers/installed_scripts_manager.h b/third_party/blink/renderer/core/workers/installed_scripts_manager.h
index 62317bf..7f21620 100644
--- a/third_party/blink/renderer/core/workers/installed_scripts_manager.h
+++ b/third_party/blink/renderer/core/workers/installed_scripts_manager.h
@@ -6,7 +6,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_WORKERS_INSTALLED_SCRIPTS_MANAGER_H_
 
 #include "base/optional.h"
-#include "third_party/blink/public/mojom/net/ip_address_space.mojom-blink.h"
+#include "services/network/public/mojom/ip_address_space.mojom-blink.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/platform/network/content_security_policy_response_headers.h"
 #include "third_party/blink/renderer/platform/network/http_header_map.h"
@@ -44,7 +44,7 @@
     ContentSecurityPolicyResponseHeaders
     GetContentSecurityPolicyResponseHeaders();
     String GetReferrerPolicy();
-    mojom::IPAddressSpace GetResponseAddressSpace() const {
+    network::mojom::IPAddressSpace GetResponseAddressSpace() const {
       return response_address_space_;
     }
     std::unique_ptr<Vector<String>> CreateOriginTrialTokens();
@@ -54,7 +54,7 @@
     String source_text_;
     std::unique_ptr<Vector<uint8_t>> meta_data_;
     HTTPHeaderMap headers_;
-    mojom::IPAddressSpace response_address_space_;
+    network::mojom::IPAddressSpace response_address_space_;
 
     DISALLOW_COPY_AND_ASSIGN(ScriptData);
   };
diff --git a/third_party/blink/renderer/core/workers/shared_worker_global_scope.cc b/third_party/blink/renderer/core/workers/shared_worker_global_scope.cc
index 270a997..74157dd 100644
--- a/third_party/blink/renderer/core/workers/shared_worker_global_scope.cc
+++ b/third_party/blink/renderer/core/workers/shared_worker_global_scope.cc
@@ -77,7 +77,7 @@
 void SharedWorkerGlobalScope::Initialize(
     const KURL& response_url,
     network::mojom::ReferrerPolicy response_referrer_policy,
-    mojom::IPAddressSpace response_address_space,
+    network::mojom::IPAddressSpace response_address_space,
     const Vector<CSPHeaderAndType>& response_csp_headers,
     const Vector<String>* response_origin_trial_tokens) {
   // Step 12.3. "Set worker global scope's url to response's url."
diff --git a/third_party/blink/renderer/core/workers/shared_worker_global_scope.h b/third_party/blink/renderer/core/workers/shared_worker_global_scope.h
index 7e6f70f..ecf5e59 100644
--- a/third_party/blink/renderer/core/workers/shared_worker_global_scope.h
+++ b/third_party/blink/renderer/core/workers/shared_worker_global_scope.h
@@ -70,7 +70,7 @@
   // WorkerGlobalScope
   void Initialize(const KURL& response_url,
                   network::mojom::ReferrerPolicy response_referrer_policy,
-                  mojom::IPAddressSpace response_address_space,
+                  network::mojom::IPAddressSpace response_address_space,
                   const Vector<CSPHeaderAndType>& response_csp_headers,
                   const Vector<String>* response_origin_trial_tokens) override;
   void FetchAndRunClassicScript(
diff --git a/third_party/blink/renderer/core/workers/threaded_messaging_proxy_base.cc b/third_party/blink/renderer/core/workers/threaded_messaging_proxy_base.cc
index 0b36523..f980309 100644
--- a/third_party/blink/renderer/core/workers/threaded_messaging_proxy_base.cc
+++ b/third_party/blink/renderer/core/workers/threaded_messaging_proxy_base.cc
@@ -75,8 +75,7 @@
       global_scope_creation_params->global_scope_name.IsolatedCopy());
 
   worker_thread_->Start(std::move(global_scope_creation_params),
-                        thread_startup_data, std::move(devtools_params),
-                        GetParentExecutionContextTaskRunners());
+                        thread_startup_data, std::move(devtools_params));
 
   if (auto* scope = DynamicTo<WorkerGlobalScope>(*execution_context_)) {
     scope->GetThread()->ChildThreadStartedOnWorkerThread(worker_thread_.get());
diff --git a/third_party/blink/renderer/core/workers/threaded_worklet_test.cc b/third_party/blink/renderer/core/workers/threaded_worklet_test.cc
index 04974bd..d797d527 100644
--- a/third_party/blink/renderer/core/workers/threaded_worklet_test.cc
+++ b/third_party/blink/renderer/core/workers/threaded_worklet_test.cc
@@ -89,9 +89,8 @@
     // the owner Document's SecurityOrigin shouldn't.
     EXPECT_TRUE(global_scope->GetSecurityOrigin()->IsOpaque());
     EXPECT_FALSE(global_scope->DocumentSecurityOrigin()->IsOpaque());
-    PostCrossThreadTask(
-        *GetParentExecutionContextTaskRunners()->Get(TaskType::kInternalTest),
-        FROM_HERE, CrossThreadBindOnce(&test::ExitRunLoop));
+    PostCrossThreadTask(*GetParentTaskRunnerForTesting(), FROM_HERE,
+                        CrossThreadBindOnce(&test::ExitRunLoop));
   }
 
   void TestContentSecurityPolicy() {
@@ -112,9 +111,8 @@
         KURL("https://disallowed.example.com"), String(),
         IntegrityMetadataSet(), kParserInserted));
 
-    PostCrossThreadTask(
-        *GetParentExecutionContextTaskRunners()->Get(TaskType::kInternalTest),
-        FROM_HERE, CrossThreadBindOnce(&test::ExitRunLoop));
+    PostCrossThreadTask(*GetParentTaskRunnerForTesting(), FROM_HERE,
+                        CrossThreadBindOnce(&test::ExitRunLoop));
   }
 
   // Test that having an invalid CSP does not result in an exception.
@@ -129,18 +127,16 @@
     EXPECT_EQ(kContentSecurityPolicyHeaderTypeEnforce,
               csp->Headers().at(0).second);
 
-    PostCrossThreadTask(
-        *GetParentExecutionContextTaskRunners()->Get(TaskType::kInternalTest),
-        FROM_HERE, CrossThreadBindOnce(&test::ExitRunLoop));
+    PostCrossThreadTask(*GetParentTaskRunnerForTesting(), FROM_HERE,
+                        CrossThreadBindOnce(&test::ExitRunLoop));
   }
 
   // Emulates API use on threaded WorkletGlobalScope.
   void CountFeature(WebFeature feature) {
     EXPECT_TRUE(IsCurrentThread());
     GlobalScope()->CountFeature(feature);
-    PostCrossThreadTask(
-        *GetParentExecutionContextTaskRunners()->Get(TaskType::kInternalTest),
-        FROM_HERE, CrossThreadBindOnce(&test::ExitRunLoop));
+    PostCrossThreadTask(*GetParentTaskRunnerForTesting(), FROM_HERE,
+                        CrossThreadBindOnce(&test::ExitRunLoop));
   }
 
   // Emulates deprecated API use on threaded WorkletGlobalScope.
@@ -153,9 +149,8 @@
     String console_message = GetConsoleMessageStorage()->at(0)->Message();
     EXPECT_TRUE(console_message.Contains("deprecated"));
 
-    PostCrossThreadTask(
-        *GetParentExecutionContextTaskRunners()->Get(TaskType::kInternalTest),
-        FROM_HERE, CrossThreadBindOnce(&test::ExitRunLoop));
+    PostCrossThreadTask(*GetParentTaskRunnerForTesting(), FROM_HERE,
+                        CrossThreadBindOnce(&test::ExitRunLoop));
   }
 
   void TestTaskRunner() {
@@ -163,9 +158,8 @@
     scoped_refptr<base::SingleThreadTaskRunner> task_runner =
         GlobalScope()->GetTaskRunner(TaskType::kInternalTest);
     EXPECT_TRUE(task_runner->RunsTasksInCurrentSequence());
-    PostCrossThreadTask(
-        *GetParentExecutionContextTaskRunners()->Get(TaskType::kInternalTest),
-        FROM_HERE, CrossThreadBindOnce(&test::ExitRunLoop));
+    PostCrossThreadTask(*GetParentTaskRunnerForTesting(), FROM_HERE,
+                        CrossThreadBindOnce(&test::ExitRunLoop));
   }
 
  private:
diff --git a/third_party/blink/renderer/core/workers/worker_classic_script_loader.cc b/third_party/blink/renderer/core/workers/worker_classic_script_loader.cc
index 873bf34..b1b9f4519 100644
--- a/third_party/blink/renderer/core/workers/worker_classic_script_loader.cc
+++ b/third_party/blink/renderer/core/workers/worker_classic_script_loader.cc
@@ -29,7 +29,7 @@
 
 #include <memory>
 #include "base/memory/scoped_refptr.h"
-#include "third_party/blink/public/mojom/net/ip_address_space.mojom-blink.h"
+#include "services/network/public/mojom/ip_address_space.mojom-blink.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
 #include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
 #include "third_party/blink/renderer/core/html/parser/text_resource_decoder.h"
@@ -97,7 +97,7 @@
 }  // namespace
 
 WorkerClassicScriptLoader::WorkerClassicScriptLoader()
-    : response_address_space_(mojom::IPAddressSpace::kPublic) {}
+    : response_address_space_(network::mojom::IPAddressSpace::kPublic) {}
 
 void WorkerClassicScriptLoader::LoadSynchronously(
     ExecutionContext& execution_context,
@@ -211,8 +211,8 @@
   if (network_utils::IsReservedIPAddress(response.RemoteIPAddress())) {
     response_address_space_ =
         SecurityOrigin::Create(response_url_)->IsLocalhost()
-            ? mojom::IPAddressSpace::kLocal
-            : mojom::IPAddressSpace::kPrivate;
+            ? network::mojom::IPAddressSpace::kLocal
+            : network::mojom::IPAddressSpace::kPrivate;
   }
 
   if (response_callback_)
diff --git a/third_party/blink/renderer/core/workers/worker_classic_script_loader.h b/third_party/blink/renderer/core/workers/worker_classic_script_loader.h
index ed7040f3..0ee2070 100644
--- a/third_party/blink/renderer/core/workers/worker_classic_script_loader.h
+++ b/third_party/blink/renderer/core/workers/worker_classic_script_loader.h
@@ -31,7 +31,7 @@
 #include <memory>
 #include "base/memory/scoped_refptr.h"
 #include "services/network/public/mojom/fetch_api.mojom-blink.h"
-#include "third_party/blink/public/mojom/net/ip_address_space.mojom-blink.h"
+#include "services/network/public/mojom/ip_address_space.mojom-blink.h"
 #include "third_party/blink/public/platform/web_url_request.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/loader/threadable_loader.h"
@@ -103,7 +103,7 @@
 
   const String& GetReferrerPolicy() const { return referrer_policy_; }
 
-  mojom::IPAddressSpace ResponseAddressSpace() const {
+  network::mojom::IPAddressSpace ResponseAddressSpace() const {
     return response_address_space_;
   }
 
@@ -152,7 +152,7 @@
   int64_t app_cache_id_ = 0;
   std::unique_ptr<Vector<uint8_t>> cached_metadata_;
   Member<ContentSecurityPolicy> content_security_policy_;
-  mojom::IPAddressSpace response_address_space_;
+  network::mojom::IPAddressSpace response_address_space_;
   std::unique_ptr<Vector<String>> origin_trial_tokens_;
   String referrer_policy_;
 
diff --git a/third_party/blink/renderer/core/workers/worker_global_scope.h b/third_party/blink/renderer/core/workers/worker_global_scope.h
index be657a1e..d102fc92 100644
--- a/third_party/blink/renderer/core/workers/worker_global_scope.h
+++ b/third_party/blink/renderer/core/workers/worker_global_scope.h
@@ -29,9 +29,9 @@
 
 #include <memory>
 #include "services/network/public/mojom/fetch_api.mojom-blink.h"
+#include "services/network/public/mojom/ip_address_space.mojom-blink.h"
 #include "services/service_manager/public/cpp/interface_provider.h"
 #include "services/service_manager/public/mojom/interface_provider.mojom-blink.h"
-#include "third_party/blink/public/mojom/net/ip_address_space.mojom-blink.h"
 #include "third_party/blink/public/mojom/script/script_type.mojom-blink.h"
 #include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
 #include "third_party/blink/renderer/core/core_export.h"
@@ -148,7 +148,7 @@
   virtual void Initialize(
       const KURL& response_url,
       network::mojom::ReferrerPolicy response_referrer_policy,
-      mojom::IPAddressSpace response_address_space,
+      network::mojom::IPAddressSpace response_address_space,
       const Vector<CSPHeaderAndType>& response_csp_headers,
       const Vector<String>* response_origin_trial_tokens) = 0;
 
diff --git a/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.cc b/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.cc
index 1c33b7f..363e526 100644
--- a/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.cc
+++ b/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.cc
@@ -81,7 +81,7 @@
   // off-the-main-thread shared worker/service worker top-level script fetch.
   // https://crbug.com/924041 https://crbug.com/924043
   void SetSandboxFlags(SandboxFlags) override {}
-  void SetAddressSpace(mojom::IPAddressSpace) override {}
+  void SetAddressSpace(network::mojom::IPAddressSpace) override {}
   void SetRequireTrustedTypes() override {}
   void AddInsecureRequestPolicy(WebInsecureRequestPolicy) override {}
   void DisableEval(const String& error_message) override {}
diff --git a/third_party/blink/renderer/core/workers/worker_thread.cc b/third_party/blink/renderer/core/workers/worker_thread.cc
index 78031c2..21ecd0a 100644
--- a/third_party/blink/renderer/core/workers/worker_thread.cc
+++ b/third_party/blink/renderer/core/workers/worker_thread.cc
@@ -137,6 +137,7 @@
 };
 
 WorkerThread::~WorkerThread() {
+  DCHECK_CALLED_ON_VALID_THREAD(parent_thread_checker_);
   MutexLocker lock(ThreadSetMutex());
   DCHECK(WorkerThreads().Contains(this));
   WorkerThreads().erase(this);
@@ -152,12 +153,8 @@
 void WorkerThread::Start(
     std::unique_ptr<GlobalScopeCreationParams> global_scope_creation_params,
     const base::Optional<WorkerBackingThreadStartupData>& thread_startup_data,
-    std::unique_ptr<WorkerDevToolsParams> devtools_params,
-    ParentExecutionContextTaskRunners* parent_execution_context_task_runners) {
+    std::unique_ptr<WorkerDevToolsParams> devtools_params) {
   DCHECK_CALLED_ON_VALID_THREAD(parent_thread_checker_);
-  DCHECK(!parent_execution_context_task_runners_);
-  parent_execution_context_task_runners_ =
-      parent_execution_context_task_runners;
   devtools_worker_token_ = devtools_params->devtools_worker_token;
 
   // Synchronously initialize the per-global-scope scheduler to prevent someone
@@ -440,16 +437,21 @@
       worker_thread_id_(GetNextWorkerThreadId()),
       forcible_termination_delay_(kForcibleTerminationDelay),
       worker_reporting_proxy_(worker_reporting_proxy),
+      parent_thread_default_task_runner_(Thread::Current()->GetTaskRunner()),
       shutdown_event_(RefCountedWaitableEvent::Create()) {
+  DCHECK_CALLED_ON_VALID_THREAD(parent_thread_checker_);
   MutexLocker lock(ThreadSetMutex());
   WorkerThreads().insert(this);
 }
 
 void WorkerThread::ScheduleToTerminateScriptExecution() {
+  DCHECK_CALLED_ON_VALID_THREAD(parent_thread_checker_);
   DCHECK(!forcible_termination_task_handle_.IsActive());
+  // It's safe to post a task bound with |this| to the parent thread default
+  // task runner because this task is canceled on the destructor of this
+  // class on the parent thread.
   forcible_termination_task_handle_ = PostDelayedCancellableTask(
-      *parent_execution_context_task_runners_->Get(TaskType::kInternalDefault),
-      FROM_HERE,
+      *parent_thread_default_task_runner_, FROM_HERE,
       WTF::Bind(&WorkerThread::EnsureScriptExecutionTerminates,
                 WTF::Unretained(this), ExitCode::kAsyncForciblyTerminated),
       forcible_termination_delay_);
diff --git a/third_party/blink/renderer/core/workers/worker_thread.h b/third_party/blink/renderer/core/workers/worker_thread.h
index 35759a0..745e3c6d 100644
--- a/third_party/blink/renderer/core/workers/worker_thread.h
+++ b/third_party/blink/renderer/core/workers/worker_thread.h
@@ -104,8 +104,7 @@
   // (https://crbug.com/710364)
   void Start(std::unique_ptr<GlobalScopeCreationParams>,
              const base::Optional<WorkerBackingThreadStartupData>&,
-             std::unique_ptr<WorkerDevToolsParams>,
-             ParentExecutionContextTaskRunners*);
+             std::unique_ptr<WorkerDevToolsParams>);
 
   // Posts a task to evaluate a top-level classic script on the worker thread.
   // Called on the main thread after Start().
@@ -209,10 +208,8 @@
 
   void WaitForShutdownForTesting();
   ExitCode GetExitCodeForTesting() LOCKS_EXCLUDED(mutex_);
-
-  ParentExecutionContextTaskRunners* GetParentExecutionContextTaskRunners()
-      const {
-    return parent_execution_context_task_runners_.Get();
+  scoped_refptr<base::SingleThreadTaskRunner> GetParentTaskRunnerForTesting() {
+    return parent_thread_default_task_runner_;
   }
 
   // For ServiceWorkerScriptStreaming. Returns nullptr otherwise.
@@ -375,8 +372,12 @@
 
   WorkerReportingProxy& worker_reporting_proxy_;
 
-  CrossThreadPersistent<ParentExecutionContextTaskRunners>
-      parent_execution_context_task_runners_;
+  // Task runner bound with the parent thread's default task queue. Be careful
+  // that a task runner may run even after the parent execution context and
+  // |this| are destroyed.
+  // This is used only for scheduling a worker termination and for testing.
+  scoped_refptr<base::SingleThreadTaskRunner>
+      parent_thread_default_task_runner_;
 
   // Tasks managed by this scheduler are canceled when the global scope is
   // closed.
diff --git a/third_party/blink/renderer/core/workers/worker_thread_test.cc b/third_party/blink/renderer/core/workers/worker_thread_test.cc
index 3694a79..359b159 100644
--- a/third_party/blink/renderer/core/workers/worker_thread_test.cc
+++ b/third_party/blink/renderer/core/workers/worker_thread_test.cc
@@ -55,10 +55,8 @@
 
   worker_thread->DebuggerTaskStarted();
   // Notify the main thread that the debugger task is waiting for the signal.
-  PostCrossThreadTask(
-      *worker_thread->GetParentExecutionContextTaskRunners()->Get(
-          TaskType::kInternalTest),
-      FROM_HERE, CrossThreadBindOnce(&test::ExitRunLoop));
+  PostCrossThreadTask(*worker_thread->GetParentTaskRunnerForTesting(),
+                      FROM_HERE, CrossThreadBindOnce(&test::ExitRunLoop));
   waitable_event->Wait();
   worker_thread->DebuggerTaskFinished();
 }
@@ -120,15 +118,13 @@
       *nested_worker_helper->reporting_proxy);
   nested_worker_helper->worker_thread->StartWithSourceCode(
       SecurityOrigin::Create(KURL("http://fake.url/")).get(),
-      "//fake source code", ParentExecutionContextTaskRunners::Create());
+      "//fake source code");
   nested_worker_helper->worker_thread->WaitForInit();
 
   // Ask the main threat to terminate this parent thread.
   base::WaitableEvent child_waitable;
   PostCrossThreadTask(
-      *parent_thread->GetParentExecutionContextTaskRunners()->Get(
-          TaskType::kInternalTest),
-      FROM_HERE,
+      *parent_thread->GetParentTaskRunnerForTesting(), FROM_HERE,
       CrossThreadBindOnce(&TerminateParentOfNestedWorker,
                           CrossThreadUnretained(parent_thread),
                           CrossThreadUnretained(&child_waitable)));
@@ -137,10 +133,8 @@
 
   parent_thread->ChildThreadStartedOnWorkerThread(
       nested_worker_helper->worker_thread.get());
-  PostCrossThreadTask(
-      *parent_thread->GetParentExecutionContextTaskRunners()->Get(
-          TaskType::kInternalTest),
-      FROM_HERE, CrossThreadBindOnce(&test::ExitRunLoop));
+  PostCrossThreadTask(*parent_thread->GetParentTaskRunnerForTesting(),
+                      FROM_HERE, CrossThreadBindOnce(&test::ExitRunLoop));
 }
 
 void VerifyParentAndChildAreTerminated(WorkerThread* parent_thread,
@@ -175,17 +169,15 @@
   void TearDown() override {}
 
   void Start() {
-    worker_thread_->StartWithSourceCode(
-        security_origin_.get(), "//fake source code",
-        ParentExecutionContextTaskRunners::Create());
+    worker_thread_->StartWithSourceCode(security_origin_.get(),
+                                        "//fake source code");
   }
 
   void StartWithSourceCodeNotToFinish() {
     // Use a JavaScript source code that makes an infinite loop so that we
     // can catch some kind of issues as a timeout.
-    worker_thread_->StartWithSourceCode(
-        security_origin_.get(), "while(true) {}",
-        ParentExecutionContextTaskRunners::Create());
+    worker_thread_->StartWithSourceCode(security_origin_.get(),
+                                        "while(true) {}");
   }
 
   void SetForcibleTerminationDelay(base::TimeDelta forcible_termination_delay) {
@@ -405,7 +397,8 @@
           false /* starter_secure_context */,
           CalculateHttpsState(security_origin_.get()),
           MakeGarbageCollected<WorkerClients>(),
-          nullptr /* content_settings_client */, mojom::IPAddressSpace::kLocal,
+          nullptr /* content_settings_client */,
+          network::mojom::IPAddressSpace::kLocal,
           nullptr /* originTrialToken */, base::UnguessableToken::Create(),
           std::make_unique<WorkerSettings>(std::make_unique<Settings>().get()),
           kV8CacheOptionsDefault, nullptr /* worklet_module_responses_map */);
@@ -417,8 +410,7 @@
 
   worker_thread_->Start(std::move(global_scope_creation_params),
                         WorkerBackingThreadStartupData::CreateDefault(),
-                        std::move(devtools_params),
-                        ParentExecutionContextTaskRunners::Create());
+                        std::move(devtools_params));
 
   // Used to wait for worker thread termination in a debugger task on the
   // worker thread.
diff --git a/third_party/blink/renderer/core/workers/worker_thread_test_helper.h b/third_party/blink/renderer/core/workers/worker_thread_test_helper.h
index ac38165f..44b4d6ec 100644
--- a/third_party/blink/renderer/core/workers/worker_thread_test_helper.h
+++ b/third_party/blink/renderer/core/workers/worker_thread_test_helper.h
@@ -9,8 +9,8 @@
 
 #include "base/macros.h"
 #include "base/synchronization/waitable_event.h"
+#include "services/network/public/mojom/ip_address_space.mojom-blink.h"
 #include "testing/gmock/include/gmock/gmock.h"
-#include "third_party/blink/public/mojom/net/ip_address_space.mojom-blink.h"
 #include "third_party/blink/renderer/bindings/core/v8/source_location.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_cache_options.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_gc_controller.h"
@@ -63,7 +63,7 @@
   // WorkerGlobalScope
   void Initialize(const KURL& response_url,
                   network::mojom::ReferrerPolicy response_referrer_policy,
-                  mojom::IPAddressSpace response_address_space,
+                  network::mojom::IPAddressSpace response_address_space,
                   const Vector<CSPHeaderAndType>& response_csp_headers,
                   const Vector<String>* response_origin_trial_tokens) override {
     InitializeURL(response_url);
@@ -117,7 +117,6 @@
   void StartWithSourceCode(
       const SecurityOrigin* security_origin,
       const String& source,
-      ParentExecutionContextTaskRunners* parent_execution_context_task_runners,
       const KURL& script_url = KURL("http://fake.url/"),
       WorkerClients* worker_clients = nullptr) {
     Vector<CSPHeaderAndType> headers{
@@ -130,15 +129,15 @@
         network::mojom::ReferrerPolicy::kDefault, security_origin,
         false /* starter_secure_context */,
         CalculateHttpsState(security_origin), worker_clients,
-        nullptr /* content_settings_client */, mojom::IPAddressSpace::kLocal,
-        nullptr, base::UnguessableToken::Create(),
+        nullptr /* content_settings_client */,
+        network::mojom::IPAddressSpace::kLocal, nullptr,
+        base::UnguessableToken::Create(),
         std::make_unique<WorkerSettings>(std::make_unique<Settings>().get()),
         kV8CacheOptionsDefault, nullptr /* worklet_module_responses_map */);
 
     Start(std::move(creation_params),
           WorkerBackingThreadStartupData::CreateDefault(),
-          std::make_unique<WorkerDevToolsParams>(),
-          parent_execution_context_task_runners);
+          std::make_unique<WorkerDevToolsParams>());
     EvaluateClassicScript(script_url, source, nullptr /* cached_meta_data */,
                           v8_inspector::V8StackTraceId());
   }
diff --git a/third_party/blink/renderer/modules/BUILD.gn b/third_party/blink/renderer/modules/BUILD.gn
index 18f4f0f..4fd5171 100644
--- a/third_party/blink/renderer/modules/BUILD.gn
+++ b/third_party/blink/renderer/modules/BUILD.gn
@@ -417,6 +417,8 @@
     "webdatabase/quota_tracker_test.cc",
     "webshare/navigator_share_test.cc",
     "websockets/dom_websocket_test.cc",
+    "websockets/mock_websocket_channel.cc",
+    "websockets/mock_websocket_channel.h",
     "websockets/websocket_channel_impl_test.cc",
     "websockets/websocket_common_test.cc",
     "worklet/animation_and_paint_worklet_thread_test.cc",
diff --git a/third_party/blink/renderer/modules/accessibility/ax_node_object.cc b/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
index a506231..d90ee2b 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
@@ -488,7 +488,7 @@
     return ax::mojom::Role::kAnchor;
   }
 
-  if (IsHTMLButtonElement(*GetNode()))
+  if (IsA<HTMLButtonElement>(*GetNode()))
     return ButtonRoleType();
 
   if (IsHTMLDetailsElement(*GetNode()))
diff --git a/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.cc b/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.cc
index 93539192..092f5a3b 100644
--- a/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.cc
+++ b/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.cc
@@ -102,17 +102,18 @@
 bool ShouldBlockGateWayAttacks(ExecutionContext* execution_context,
                                const KURL& request_url) {
   if (RuntimeEnabledFeatures::CorsRFC1918Enabled()) {
-    mojom::IPAddressSpace requestor_space =
+    network::mojom::IPAddressSpace requestor_space =
         execution_context->GetSecurityContext().AddressSpace();
 
     // TODO(mkwst): This only checks explicit IP addresses. We'll have to move
     // all this up to //net and //content in order to have any real impact on
     // gateway attacks. That turns out to be a TON of work (crbug.com/378566).
-    mojom::IPAddressSpace target_space = mojom::IPAddressSpace::kPublic;
+    network::mojom::IPAddressSpace target_space =
+        network::mojom::IPAddressSpace::kPublic;
     if (network_utils::IsReservedIPAddress(request_url.Host()))
-      target_space = mojom::IPAddressSpace::kPrivate;
+      target_space = network::mojom::IPAddressSpace::kPrivate;
     if (SecurityOrigin::Create(request_url)->IsLocalhost())
-      target_space = mojom::IPAddressSpace::kLocal;
+      target_space = network::mojom::IPAddressSpace::kLocal;
 
     bool is_external_request = requestor_space > target_space;
     if (is_external_request)
diff --git a/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.cc b/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.cc
index 10bd9be..f7c35c2 100644
--- a/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.cc
+++ b/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.cc
@@ -55,7 +55,6 @@
 #include "third_party/blink/renderer/core/loader/worker_fetch_context.h"
 #include "third_party/blink/renderer/core/probe/core_probes.h"
 #include "third_party/blink/renderer/core/script/script.h"
-#include "third_party/blink/renderer/core/workers/parent_execution_context_task_runners.h"
 #include "third_party/blink/renderer/core/workers/worker_backing_thread_startup_data.h"
 #include "third_party/blink/renderer/core/workers/worker_classic_script_loader.h"
 #include "third_party/blink/renderer/core/workers/worker_global_scope.h"
@@ -167,11 +166,11 @@
   //
   // https://crbug.com/590714
   KURL script_url = worker_start_data_.script_url;
-  worker_start_data_.address_space = mojom::IPAddressSpace::kPublic;
+  worker_start_data_.address_space = network::mojom::IPAddressSpace::kPublic;
   if (network_utils::IsReservedIPAddress(script_url.Host()))
-    worker_start_data_.address_space = mojom::IPAddressSpace::kPrivate;
+    worker_start_data_.address_space = network::mojom::IPAddressSpace::kPrivate;
   if (SecurityOrigin::Create(script_url)->IsLocalhost())
-    worker_start_data_.address_space = mojom::IPAddressSpace::kLocal;
+    worker_start_data_.address_space = network::mojom::IPAddressSpace::kLocal;
 
   if (data.pause_after_download_mode ==
       WebEmbeddedWorkerStartData::kPauseAfterDownload)
@@ -487,13 +486,9 @@
       document, worker_thread_.get(), worker_start_data_.script_url,
       global_scope_name);
 
-  // We have a dummy document here for loading but it doesn't really represent
-  // the document/frame of associated document(s) for this worker. Here we
-  // populate the task runners with default task runners of the main thread.
   worker_thread_->Start(std::move(global_scope_creation_params),
                         WorkerBackingThreadStartupData::CreateDefault(),
-                        std::move(devtools_params),
-                        ParentExecutionContextTaskRunners::Create());
+                        std::move(devtools_params));
 
   // If this is an installed service worker, the installed script will be read
   // from the service worker script storage on the worker thread.
diff --git a/third_party/blink/renderer/modules/geolocation/geolocation_watchers.h b/third_party/blink/renderer/modules/geolocation/geolocation_watchers.h
index 00584e0..0ea8abc 100644
--- a/third_party/blink/renderer/modules/geolocation/geolocation_watchers.h
+++ b/third_party/blink/renderer/modules/geolocation/geolocation_watchers.h
@@ -12,8 +12,8 @@
 
 class GeoNotifier;
 
-class GeolocationWatchers : public GarbageCollected<GeolocationWatchers>,
-                            public NameClient {
+class GeolocationWatchers final : public GarbageCollected<GeolocationWatchers>,
+                                  public NameClient {
  public:
   GeolocationWatchers() = default;
   void Trace(blink::Visitor*);
diff --git a/third_party/blink/renderer/modules/media_controls/resources/mediaControls.css b/third_party/blink/renderer/modules/media_controls/resources/mediaControls.css
index a1f063e5..6cb8ca30 100644
--- a/third_party/blink/renderer/modules/media_controls/resources/mediaControls.css
+++ b/third_party/blink/renderer/modules/media_controls/resources/mediaControls.css
@@ -1065,6 +1065,12 @@
   display: none !important;
 }
 
+/** TODO(crbug.com/985623): Remove these hard-coded audio tag size.
+ * This fixed audio tag width/height leads to fail the wpt tests below.
+ * crbug.com/955170 external/wpt/css/css-contain/contain-size-replaced-003a.html
+ * crbug.com/955163 external/wpt/css/css-contain/contain-size-replaced-003b.html
+ * crbug.com/955163 external/wpt/css/css-contain/contain-size-replaced-003c.html
+ */
 audio {
   width: 300px;
   height: 54px;
diff --git a/third_party/blink/renderer/modules/mediastream/BUILD.gn b/third_party/blink/renderer/modules/mediastream/BUILD.gn
index 8b59bf59..3b6fc69a 100644
--- a/third_party/blink/renderer/modules/mediastream/BUILD.gn
+++ b/third_party/blink/renderer/modules/mediastream/BUILD.gn
@@ -30,6 +30,7 @@
     "media_stream_constraints_util_sets.cc",
     "media_stream_constraints_util_video_content.cc",
     "media_stream_constraints_util_video_device.cc",
+    "media_stream_constraints_util_video_device.h",
     "media_stream_device_observer.cc",
     "media_stream_device_observer.h",
     "media_stream_event.cc",
diff --git a/third_party/blink/renderer/modules/mediastream/apply_constraints_processor.cc b/third_party/blink/renderer/modules/mediastream/apply_constraints_processor.cc
index 9b074af2..f824902b 100644
--- a/third_party/blink/renderer/modules/mediastream/apply_constraints_processor.cc
+++ b/third_party/blink/renderer/modules/mediastream/apply_constraints_processor.cc
@@ -16,9 +16,9 @@
 #include "third_party/blink/public/platform/web_string.h"
 #include "third_party/blink/public/web/modules/mediastream/media_stream_constraints_util_audio.h"
 #include "third_party/blink/public/web/modules/mediastream/media_stream_constraints_util_video_content.h"
-#include "third_party/blink/public/web/modules/mediastream/media_stream_constraints_util_video_device.h"
 #include "third_party/blink/public/web/modules/mediastream/media_stream_video_source.h"
 #include "third_party/blink/public/web/modules/mediastream/media_stream_video_track.h"
+#include "third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_video_device.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
 namespace blink {
@@ -34,14 +34,6 @@
   request.RequestSucceeded();
 }
 
-media::VideoCaptureFormats ToVideoCaptureFormats(
-    const Vector<media::VideoCaptureFormat>& format_vector) {
-  media::VideoCaptureFormats formats;
-  std::copy(format_vector.begin(), format_vector.end(),
-            std::back_inserter(formats));
-  return formats;
-}
-
 }  // namespace
 
 ApplyConstraintsProcessor::ApplyConstraintsProcessor(
@@ -248,16 +240,12 @@
   DCHECK_GT(formats.size(), 0U);
 
   blink::VideoInputDeviceCapabilities device_capabilities;
-  device_capabilities.device_id =
-      current_request_.Track().Source().Id().Ascii();
-  device_capabilities.group_id =
-      current_request_.Track().Source().GroupId().Ascii();
+  device_capabilities.device_id = current_request_.Track().Source().Id();
+  device_capabilities.group_id = current_request_.Track().Source().GroupId();
   device_capabilities.facing_mode =
       GetCurrentVideoSource() ? GetCurrentVideoSource()->device().video_facing
                               : media::MEDIA_VIDEO_FACING_NONE;
-  // TODO(crbug.com/704136): Eliminate need for this extra conversion
-  // round from WTF::Vector to std::vector.
-  device_capabilities.formats = ToVideoCaptureFormats(formats);
+  device_capabilities.formats = std::move(formats);
 
   blink::VideoDeviceCaptureCapabilities video_capabilities;
   video_capabilities.noise_reduction_capabilities.push_back(
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util.cc b/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util.cc
index d5b7621..3bf00e9 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util.cc
@@ -11,7 +11,7 @@
 #include "third_party/blink/public/common/mediastream/media_stream_request.h"
 #include "third_party/blink/public/platform/web_string.h"
 #include "third_party/blink/public/web/modules/mediastream/media_stream_constraints_util_sets.h"
-#include "third_party/blink/public/web/modules/mediastream/media_stream_constraints_util_video_device.h"
+#include "third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_video_device.h"
 
 namespace blink {
 
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_video_device.cc b/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_video_device.cc
index f51179d..67c8bab 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_video_device.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_video_device.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "third_party/blink/public/web/modules/mediastream/media_stream_constraints_util_video_device.h"
+#include "third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_video_device.h"
 
 #include <algorithm>
 #include <cmath>
@@ -17,6 +17,7 @@
 #include "third_party/blink/public/web/modules/mediastream/media_stream_constraints_util.h"
 #include "third_party/blink/public/web/modules/mediastream/media_stream_constraints_util_sets.h"
 #include "third_party/blink/public/web/modules/mediastream/media_stream_video_source.h"
+#include "third_party/blink/renderer/platform/wtf/wtf_size_t.h"
 
 namespace blink {
 
@@ -407,14 +408,13 @@
     const DeviceInfo& device,
     const WebMediaTrackConstraintSet& constraint_set,
     const char** failed_constraint_name = nullptr) {
-  if (!constraint_set.device_id.Matches(
-          WebString::FromUTF8(device.device_id))) {
+  if (!constraint_set.device_id.Matches(WebString(device.device_id))) {
     UpdateFailedConstraintName(constraint_set.device_id,
                                failed_constraint_name);
     return false;
   }
 
-  if (!constraint_set.group_id.Matches(WebString::FromUTF8(device.group_id))) {
+  if (!constraint_set.group_id.Matches(WebString(device.group_id))) {
     UpdateFailedConstraintName(constraint_set.group_id, failed_constraint_name);
     return false;
   }
@@ -448,9 +448,9 @@
 
 double DeviceFitness(const DeviceInfo& device,
                      const WebMediaTrackConstraintSet& constraint_set) {
-  return StringConstraintFitnessDistance(WebString::FromUTF8(device.device_id),
+  return StringConstraintFitnessDistance(WebString(device.device_id),
                                          constraint_set.device_id) +
-         StringConstraintFitnessDistance(WebString::FromUTF8(device.group_id),
+         StringConstraintFitnessDistance(WebString(device.group_id),
                                          constraint_set.group_id) +
          StringConstraintFitnessDistance(ToWebString(device.facing_mode),
                                          constraint_set.facing_mode);
@@ -488,7 +488,8 @@
     double default_frame_rate,
     DistanceVector* distance_vector) {
   // Favor IDs that appear first in the enumeration.
-  for (size_t i = 0; i < capabilities.device_capabilities.size(); ++i) {
+  for (WTF::wtf_size_t i = 0; i < capabilities.device_capabilities.size();
+       ++i) {
     if (device.device_id == capabilities.device_capabilities[i].device_id) {
       distance_vector->push_back(i);
       break;
@@ -518,9 +519,9 @@
 VideoInputDeviceCapabilities::VideoInputDeviceCapabilities() = default;
 
 VideoInputDeviceCapabilities::VideoInputDeviceCapabilities(
-    std::string device_id,
-    std::string group_id,
-    std::vector<media::VideoCaptureFormat> formats,
+    String device_id,
+    String group_id,
+    Vector<media::VideoCaptureFormat> formats,
     media::VideoFacingMode facing_mode)
     : device_id(std::move(device_id)),
       group_id(std::move(group_id)),
@@ -655,8 +656,8 @@
           media::VideoCaptureParams capture_params;
           capture_params.requested_format = candidate_format.format();
           result = VideoCaptureSettings(
-              device.device_id, capture_params, noise_reduction, track_settings,
-              candidate_format.constrained_frame_rate().Min(),
+              device.device_id.Utf8(), capture_params, noise_reduction,
+              track_settings, candidate_format.constrained_frame_rate().Min(),
               candidate_format.constrained_frame_rate().Max());
         }
       }
diff --git a/third_party/blink/public/web/modules/mediastream/media_stream_constraints_util_video_device.h b/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_video_device.h
similarity index 82%
rename from third_party/blink/public/web/modules/mediastream/media_stream_constraints_util_video_device.h
rename to third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_video_device.h
index 50787ff..94d8ed96 100644
--- a/third_party/blink/public/web/modules/mediastream/media_stream_constraints_util_video_device.h
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_video_device.h
@@ -2,16 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef THIRD_PARTY_BLINK_PUBLIC_WEB_MODULES_MEDIASTREAM_MEDIA_STREAM_CONSTRAINTS_UTIL_VIDEO_DEVICE_H_
-#define THIRD_PARTY_BLINK_PUBLIC_WEB_MODULES_MEDIASTREAM_MEDIA_STREAM_CONSTRAINTS_UTIL_VIDEO_DEVICE_H_
-
-#include <string>
-#include <vector>
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASTREAM_MEDIA_STREAM_CONSTRAINTS_UTIL_VIDEO_DEVICE_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASTREAM_MEDIA_STREAM_CONSTRAINTS_UTIL_VIDEO_DEVICE_H_
 
 #include "base/optional.h"
 #include "media/capture/video_capture_types.h"
-#include "third_party/blink/public/platform/web_common.h"
 #include "third_party/blink/public/web/modules/mediastream/media_stream_constraints_util.h"
+#include "third_party/blink/renderer/modules/modules_export.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+#include "third_party/blink/renderer/platform/wtf/vector.h"
 
 namespace blink {
 class WebString;
@@ -22,32 +21,30 @@
 
 // Calculates and returns videoKind value for |format|.
 // See https://w3c.github.io/mediacapture-depth.
-BLINK_MODULES_EXPORT WebString
+MODULES_EXPORT WebString
 GetVideoKindForFormat(const media::VideoCaptureFormat& format);
 
-BLINK_MODULES_EXPORT WebMediaStreamTrack::FacingMode ToWebFacingMode(
+MODULES_EXPORT WebMediaStreamTrack::FacingMode ToWebFacingMode(
     media::VideoFacingMode video_facing);
 
 // This is a temporary struct to bridge blink and content mojo types.
-// TODO(crbug.com/704136): Replace references to this type with the blink mojo
-// type once all dependent types are migrated to Blink.
-struct BLINK_MODULES_EXPORT VideoInputDeviceCapabilities {
-  VideoInputDeviceCapabilities(std::string device_id,
-                               std::string group_id,
-                               std::vector<media::VideoCaptureFormat> formats,
+struct MODULES_EXPORT VideoInputDeviceCapabilities {
+  VideoInputDeviceCapabilities(String device_id,
+                               String group_id,
+                               Vector<media::VideoCaptureFormat> formats,
                                media::VideoFacingMode facing_mode);
   VideoInputDeviceCapabilities();
   VideoInputDeviceCapabilities(VideoInputDeviceCapabilities&& other);
   VideoInputDeviceCapabilities& operator=(VideoInputDeviceCapabilities&& other);
   ~VideoInputDeviceCapabilities();
 
-  std::string device_id;
-  std::string group_id;
-  std::vector<media::VideoCaptureFormat> formats;
+  String device_id;
+  String group_id;
+  Vector<media::VideoCaptureFormat> formats;
   media::VideoFacingMode facing_mode;
 };
 
-struct BLINK_MODULES_EXPORT VideoDeviceCaptureCapabilities {
+struct MODULES_EXPORT VideoDeviceCaptureCapabilities {
   VideoDeviceCaptureCapabilities();
   VideoDeviceCaptureCapabilities(VideoDeviceCaptureCapabilities&& other);
   ~VideoDeviceCaptureCapabilities();
@@ -59,8 +56,8 @@
   // |device_capabilities| definition with the Blink mojo
   // VideoInputDeviceCapabilitiesPtr type once dependent types are migrated to
   // Blink.
-  std::vector<VideoInputDeviceCapabilities> device_capabilities;
-  std::vector<base::Optional<bool>> noise_reduction_capabilities;
+  Vector<VideoInputDeviceCapabilities> device_capabilities;
+  Vector<base::Optional<bool>> noise_reduction_capabilities;
 };
 
 // This function performs source, source-settings and track-settings selection
@@ -125,7 +122,7 @@
 // the track_adapter_settings() accessor. For more details about the algorithm
 // for track adapter settings, see the SelectVideoTrackAdapterSettings
 // documentation.
-VideoCaptureSettings BLINK_MODULES_EXPORT SelectSettingsVideoDeviceCapture(
+VideoCaptureSettings MODULES_EXPORT SelectSettingsVideoDeviceCapture(
     const VideoDeviceCaptureCapabilities& capabilities,
     const WebMediaConstraints& constraints,
     int default_width,
@@ -134,4 +131,4 @@
 
 }  // namespace blink
 
-#endif  // THIRD_PARTY_BLINK_PUBLIC_WEB_MODULES_MEDIASTREAM_MEDIA_STREAM_CONSTRAINTS_UTIL_VIDEO_DEVICE_H_
+#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_MEDIASTREAM_MEDIA_STREAM_CONSTRAINTS_UTIL_VIDEO_DEVICE_H_
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_video_device_test.cc b/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_video_device_test.cc
index 4a40229..1f188c9f 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_video_device_test.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_video_device_test.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "third_party/blink/public/web/modules/mediastream/media_stream_constraints_util_video_device.h"
+#include "third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_video_device.h"
 
 #include <algorithm>
 #include <utility>
@@ -205,7 +205,7 @@
   auto result = SelectSettings();
   EXPECT_TRUE(result.HasValue());
   // Should select the default device with closest-to-default settings.
-  EXPECT_EQ(default_device_->device_id, result.device_id());
+  EXPECT_EQ(default_device_->device_id.Utf8(), result.device_id());
   EXPECT_EQ(*default_closest_format_, result.Format());
   // Should select default settings for other constraints.
   EXPECT_EQ(base::Optional<bool>(), result.noise_reduction());
@@ -412,24 +412,24 @@
 TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, MandatoryDeviceID) {
   constraint_factory_.Reset();
   constraint_factory_.basic().device_id.SetExact(
-      WebString::FromASCII(default_device_->device_id));
+      WebString(default_device_->device_id));
   auto result = SelectSettings();
   EXPECT_TRUE(result.HasValue());
-  EXPECT_EQ(default_device_->device_id, result.device_id());
+  EXPECT_EQ(default_device_->device_id.Utf8(), result.device_id());
   EXPECT_EQ(*default_closest_format_, result.Format());
   CheckTrackAdapterSettingsEqualsFormat(result);
 
   constraint_factory_.basic().device_id.SetExact(
-      WebString::FromASCII(low_res_device_->device_id));
+      WebString(low_res_device_->device_id));
   result = SelectSettings();
-  EXPECT_EQ(low_res_device_->device_id, result.device_id());
+  EXPECT_EQ(low_res_device_->device_id.Utf8(), result.device_id());
   EXPECT_EQ(*low_res_closest_format_, result.Format());
   CheckTrackAdapterSettingsEqualsFormat(result);
 
   constraint_factory_.basic().device_id.SetExact(
-      WebString::FromASCII(high_res_device_->device_id));
+      WebString(high_res_device_->device_id));
   result = SelectSettings();
-  EXPECT_EQ(high_res_device_->device_id, result.device_id());
+  EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id());
   EXPECT_EQ(*high_res_closest_format_, result.Format());
   CheckTrackAdapterSettingsEqualsFormat(result);
 }
@@ -437,24 +437,24 @@
 TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, MandatoryGroupID) {
   constraint_factory_.Reset();
   constraint_factory_.basic().group_id.SetExact(
-      WebString::FromASCII(default_device_->group_id));
+      WebString(default_device_->group_id));
   auto result = SelectSettings();
   EXPECT_TRUE(result.HasValue());
-  EXPECT_EQ(default_device_->device_id, result.device_id());
+  EXPECT_EQ(default_device_->device_id.Utf8(), result.device_id());
   EXPECT_EQ(*default_closest_format_, result.Format());
   CheckTrackAdapterSettingsEqualsFormat(result);
 
   constraint_factory_.basic().group_id.SetExact(
-      WebString::FromASCII(low_res_device_->group_id));
+      WebString(low_res_device_->group_id));
   result = SelectSettings();
-  EXPECT_EQ(low_res_device_->device_id, result.device_id());
+  EXPECT_EQ(low_res_device_->device_id.Utf8(), result.device_id());
   EXPECT_EQ(*low_res_closest_format_, result.Format());
   CheckTrackAdapterSettingsEqualsFormat(result);
 
   constraint_factory_.basic().group_id.SetExact(
-      WebString::FromASCII(high_res_device_->group_id));
+      WebString(high_res_device_->group_id));
   result = SelectSettings();
-  EXPECT_EQ(high_res_device_->device_id, result.device_id());
+  EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id());
   EXPECT_EQ(*high_res_closest_format_, result.Format());
   CheckTrackAdapterSettingsEqualsFormat(result);
 }
@@ -467,7 +467,7 @@
   EXPECT_TRUE(result.HasValue());
   // Only the low-res device supports environment facing mode. Should select
   // default settings for everything else.
-  EXPECT_EQ(low_res_device_->device_id, result.device_id());
+  EXPECT_EQ(low_res_device_->device_id.Utf8(), result.device_id());
   EXPECT_EQ(media::MEDIA_VIDEO_FACING_ENVIRONMENT,
             low_res_device_->facing_mode);
   EXPECT_EQ(*low_res_closest_format_, result.Format());
@@ -479,7 +479,7 @@
   EXPECT_TRUE(result.HasValue());
   // Only the high-res device supports user facing mode. Should select default
   // settings for everything else.
-  EXPECT_EQ(high_res_device_->device_id, result.device_id());
+  EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id());
   EXPECT_EQ(media::MEDIA_VIDEO_FACING_USER, high_res_device_->facing_mode);
   EXPECT_EQ(*high_res_closest_format_, result.Format());
   CheckTrackAdapterSettingsEqualsFormat(result);
@@ -499,7 +499,7 @@
       WebString::FromASCII("color"));
   result = SelectSettings();
   EXPECT_TRUE(result.HasValue());
-  EXPECT_EQ(default_device_->device_id, result.device_id());
+  EXPECT_EQ(default_device_->device_id.Utf8(), result.device_id());
   CheckTrackAdapterSettingsEqualsFormat(result);
 }
 
@@ -513,7 +513,7 @@
     EXPECT_EQ(noise_reduction, result.noise_reduction());
     // The default device and settings closest to the default should be
     // selected.
-    EXPECT_EQ(default_device_->device_id, result.device_id());
+    EXPECT_EQ(default_device_->device_id.Utf8(), result.device_id());
     EXPECT_EQ(*default_closest_format_, result.Format());
     CheckTrackAdapterSettingsEqualsFormat(result);
   }
@@ -528,7 +528,7 @@
   // All devices in |capabilities_| support the requested height. The algorithm
   // should prefer the first device that supports the requested height natively,
   // which is the low-res device.
-  EXPECT_EQ(low_res_device_->device_id, result.device_id());
+  EXPECT_EQ(low_res_device_->device_id.Utf8(), result.device_id());
   EXPECT_EQ(kHeight, result.Height());
   EXPECT_FALSE(result.track_adapter_settings().target_size().has_value());
 
@@ -538,7 +538,7 @@
   EXPECT_TRUE(result.HasValue());
   // Only the high-res device at the highest resolution supports the requested
   // height, even if not natively.
-  EXPECT_EQ(high_res_device_->device_id, result.device_id());
+  EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id());
   EXPECT_EQ(*high_res_highest_format_, result.Format());
   EXPECT_EQ(kLargeHeight, result.track_adapter_settings().target_height());
   EXPECT_EQ(std::round(kLargeHeight * AspectRatio(*high_res_highest_format_)),
@@ -553,7 +553,7 @@
   EXPECT_TRUE(result.HasValue());
   // All devices in |capabilities_| support the requested height range. The
   // algorithm should prefer the default device.
-  EXPECT_EQ(default_device_->device_id, result.device_id());
+  EXPECT_EQ(default_device_->device_id.Utf8(), result.device_id());
   EXPECT_LE(kHeight, result.Height());
   EXPECT_FALSE(result.track_adapter_settings().target_size().has_value());
   EXPECT_EQ(static_cast<double>(result.Width()) / kHeight,
@@ -568,7 +568,7 @@
   EXPECT_TRUE(result.HasValue());
   // Only the high-res device at the highest resolution supports the requested
   // height range.
-  EXPECT_EQ(high_res_device_->device_id, result.device_id());
+  EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id());
   EXPECT_EQ(*high_res_highest_format_, result.Format());
   EXPECT_LE(kHeight, result.Height());
   EXPECT_FALSE(result.track_adapter_settings().target_size().has_value());
@@ -588,7 +588,7 @@
   // All devices in |capabilities_| support the requested height range. The
   // algorithm should prefer the settings that natively exceed the requested
   // maximum by the lowest amount. In this case it is the low-res device.
-  EXPECT_EQ(low_res_device_->device_id, result.device_id());
+  EXPECT_EQ(low_res_device_->device_id.Utf8(), result.device_id());
   EXPECT_EQ(low_res_device_->formats[0], result.Format());
   EXPECT_EQ(kLowHeight, result.track_adapter_settings().target_height());
   EXPECT_EQ(std::round(kLowHeight * AspectRatio(result.Format())),
@@ -615,7 +615,7 @@
     // algorithm should prefer the default device since it has at least one
     // native format (the closest-to-default format) included in the requested
     // range.
-    EXPECT_EQ(default_device_->device_id, result.device_id());
+    EXPECT_EQ(default_device_->device_id.Utf8(), result.device_id());
     EXPECT_EQ(*default_closest_format_, result.Format());
     EXPECT_FALSE(result.track_adapter_settings().target_size().has_value());
     EXPECT_EQ(static_cast<double>(result.Width()) / kMinHeight,
@@ -637,7 +637,7 @@
     // In this case, the algorithm should prefer the low-res device since it is
     // the first device with a native format (800x600) included in the requested
     // range.
-    EXPECT_EQ(low_res_device_->device_id, result.device_id());
+    EXPECT_EQ(low_res_device_->device_id.Utf8(), result.device_id());
     EXPECT_EQ(800, result.Width());
     EXPECT_EQ(600, result.Height());
     EXPECT_FALSE(result.track_adapter_settings().target_size().has_value());
@@ -660,7 +660,7 @@
     // In this case, the algorithm should prefer the high-res device since it is
     // the only device with a native format (1280x720) included in the requested
     // range.
-    EXPECT_EQ(high_res_device_->device_id, result.device_id());
+    EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id());
     EXPECT_EQ(1280, result.Width());
     EXPECT_EQ(720, result.Height());
     EXPECT_FALSE(result.track_adapter_settings().target_size().has_value());
@@ -681,7 +681,7 @@
     EXPECT_TRUE(result.HasValue());
     // The algorithm should select the first device that supports the ideal
     // height natively.
-    EXPECT_EQ(low_res_device_->device_id, result.device_id());
+    EXPECT_EQ(low_res_device_->device_id.Utf8(), result.device_id());
     EXPECT_EQ(kIdealHeight, result.Height());
     CheckTrackAdapterSettingsEqualsFormat(result);
   }
@@ -695,7 +695,7 @@
     // ideal at a lower cost than the other devices (500 vs 600 or 720).
     // Note that a native resolution of 480 is further from the ideal than
     // 500 cropped to 480.
-    EXPECT_EQ(default_device_->device_id, result.device_id());
+    EXPECT_EQ(default_device_->device_id.Utf8(), result.device_id());
     EXPECT_EQ(*default_closest_format_, result.Format());
     // The track is cropped to the ideal height, maintaining the source aspect
     // ratio.
@@ -717,7 +717,7 @@
     // In this case, the high-res device has two configurations that satisfy
     // the ideal value (1920x1080 and 2304x1536). Select the one with shortest
     // native distance to the ideal value (1920x1080).
-    EXPECT_EQ(high_res_device_->device_id, result.device_id());
+    EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id());
     EXPECT_EQ(1920, result.Width());
     EXPECT_EQ(1080, result.Height());
     EXPECT_EQ(kIdealHeight, result.track_adapter_settings().target_height());
@@ -737,7 +737,7 @@
     EXPECT_TRUE(result.HasValue());
     // The algorithm must the select the only device that can satisfy the ideal,
     // which is the high-res device at the highest resolution.
-    EXPECT_EQ(high_res_device_->device_id, result.device_id());
+    EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id());
     EXPECT_EQ(*high_res_highest_format_, result.Format());
     EXPECT_EQ(kIdealHeight, result.track_adapter_settings().target_height());
     EXPECT_EQ(std::round(kIdealHeight * AspectRatio(result.Format())),
@@ -759,7 +759,7 @@
   // All devices in |capabilities_| support the requested width. The algorithm
   // should prefer the first device that supports the requested width natively,
   // which is the low-res device.
-  EXPECT_EQ(low_res_device_->device_id, result.device_id());
+  EXPECT_EQ(low_res_device_->device_id.Utf8(), result.device_id());
   EXPECT_EQ(kWidth, result.Width());
   EXPECT_FALSE(result.track_adapter_settings().target_size().has_value());
   EXPECT_EQ(kWidth, result.track_adapter_settings().max_aspect_ratio());
@@ -774,7 +774,7 @@
   EXPECT_LE(kLargeWidth, result.Width());
   // Only the high-res device at the highest resolution supports the requested
   // width, even if not natively.
-  EXPECT_EQ(high_res_device_->device_id, result.device_id());
+  EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id());
   EXPECT_EQ(*high_res_highest_format_, result.Format());
   EXPECT_EQ(std::round(kLargeWidth / AspectRatio(result.Format())),
             result.track_adapter_settings().target_height());
@@ -794,7 +794,7 @@
   // All devices in |capabilities_| support the requested width range. The
   // algorithm should prefer the default device at 1000x1000, which is the
   // first configuration that satisfies the minimum width.
-  EXPECT_EQ(default_device_->device_id, result.device_id());
+  EXPECT_EQ(default_device_->device_id.Utf8(), result.device_id());
   EXPECT_LE(kWidth, result.Width());
   EXPECT_EQ(1000, result.Width());
   EXPECT_EQ(1000, result.Height());
@@ -810,7 +810,7 @@
   EXPECT_TRUE(result.HasValue());
   // Only the high-res device at the highest resolution supports the requested
   // minimum width.
-  EXPECT_EQ(high_res_device_->device_id, result.device_id());
+  EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id());
   EXPECT_LE(kLargeWidth, result.Width());
   EXPECT_EQ(*high_res_highest_format_, result.Format());
   EXPECT_FALSE(result.track_adapter_settings().target_size().has_value());
@@ -830,7 +830,7 @@
   // algorithm should prefer the settings that natively exceed the requested
   // maximum by the lowest amount. In this case it is the low-res device at its
   // lowest resolution.
-  EXPECT_EQ(low_res_device_->device_id, result.device_id());
+  EXPECT_EQ(low_res_device_->device_id.Utf8(), result.device_id());
   EXPECT_EQ(low_res_device_->formats[0], result.Format());
   // The track is cropped to kLowWidth and keeps the source aspect ratio.
   EXPECT_EQ(std::round(kLowWidth / AspectRatio(result.Format())),
@@ -856,7 +856,7 @@
     // All devices in |capabilities_| support the constraint range. The
     // algorithm should prefer the default device since it has at least one
     // native format (1000x1000) included in the requested range.
-    EXPECT_EQ(default_device_->device_id, result.device_id());
+    EXPECT_EQ(default_device_->device_id.Utf8(), result.device_id());
     EXPECT_EQ(1000, result.Width());
     EXPECT_EQ(1000, result.Height());
     EXPECT_FALSE(result.track_adapter_settings().target_size().has_value());
@@ -879,7 +879,7 @@
     // In this case, the algorithm should prefer the low-res device since it is
     // the first device with a native format (800x600) included in the requested
     // range.
-    EXPECT_EQ(low_res_device_->device_id, result.device_id());
+    EXPECT_EQ(low_res_device_->device_id.Utf8(), result.device_id());
     EXPECT_EQ(800, result.Width());
     EXPECT_EQ(600, result.Height());
     EXPECT_FALSE(result.track_adapter_settings().target_size().has_value());
@@ -902,7 +902,7 @@
     // In this case, the algorithm should prefer the high-res device since it is
     // the only device with a native format (1920x1080) included in the
     // requested range.
-    EXPECT_EQ(high_res_device_->device_id, result.device_id());
+    EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id());
     EXPECT_EQ(1920, result.Width());
     EXPECT_EQ(1080, result.Height());
     EXPECT_FALSE(result.track_adapter_settings().target_size().has_value());
@@ -923,7 +923,7 @@
     EXPECT_TRUE(result.HasValue());
     // The algorithm should select the first device that supports the ideal
     // width natively, which is the low-res device at 320x240.
-    EXPECT_EQ(low_res_device_->device_id, result.device_id());
+    EXPECT_EQ(low_res_device_->device_id.Utf8(), result.device_id());
     EXPECT_EQ(kIdealWidth, result.Width());
     // The ideal value is satisfied with a native resolution, so no rescaling.
     EXPECT_FALSE(result.track_adapter_settings().target_size().has_value());
@@ -942,7 +942,7 @@
     // can satisfy the ideal at a lower cost than other devices (480 vs 500).
     // Note that a native resolution of 320 is further from the ideal value of
     // 321 than 480 cropped to 321.
-    EXPECT_EQ(high_res_device_->device_id, result.device_id());
+    EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id());
     EXPECT_EQ(480, result.Width());
     // The track is cropped to kIdealWidth and keeps the source aspect ratio.
     EXPECT_EQ(std::round(kIdealWidth / AspectRatio(result.Format())),
@@ -961,7 +961,7 @@
     auto result = SelectSettings();
     EXPECT_TRUE(result.HasValue());
     // The algorithm must the select the only device that can satisfy the ideal.
-    EXPECT_EQ(high_res_device_->device_id, result.device_id());
+    EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id());
     EXPECT_EQ(*high_res_highest_format_, result.Format());
     // The track is cropped to kIdealWidth and keeps the source aspect ratio.
     EXPECT_EQ(std::round(kIdealWidth / AspectRatio(result.Format())),
@@ -981,7 +981,7 @@
     EXPECT_TRUE(result.HasValue());
     // The algorithm must the select the device and setting with less distance
     // to the ideal.
-    EXPECT_EQ(high_res_device_->device_id, result.device_id());
+    EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id());
     EXPECT_EQ(*high_res_highest_format_, result.Format());
     CheckTrackAdapterSettingsEqualsFormat(result);
   }
@@ -996,7 +996,7 @@
   // All devices in |capabilities_| support the requested frame rate. The
   // algorithm should prefer the first device that supports the requested frame
   // rate natively, which is the low-res device at 640x480x30Hz.
-  EXPECT_EQ(low_res_device_->device_id, result.device_id());
+  EXPECT_EQ(low_res_device_->device_id.Utf8(), result.device_id());
   EXPECT_EQ(kFrameRate, result.FrameRate());
   EXPECT_EQ(640, result.Width());
   EXPECT_EQ(480, result.Height());
@@ -1010,7 +1010,7 @@
   // Only the high-res device supports the requested frame rate, even if not
   // natively. The least expensive configuration that supports the requested
   // frame rate is 1280x720x60Hz.
-  EXPECT_EQ(high_res_device_->device_id, result.device_id());
+  EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id());
   EXPECT_EQ(60.0, result.FrameRate());
   EXPECT_EQ(1280, result.Width());
   EXPECT_EQ(720, result.Height());
@@ -1028,7 +1028,7 @@
     EXPECT_TRUE(result.HasValue());
     // All devices in |capabilities_| support the requested frame-rate range.
     // The algorithm should prefer the default device.
-    EXPECT_EQ(default_device_->device_id, result.device_id());
+    EXPECT_EQ(default_device_->device_id.Utf8(), result.device_id());
     // The format closest to the default satisfies the constraint.
     EXPECT_EQ(*default_closest_format_, result.Format());
     CheckTrackAdapterSettingsEqualsFormat(result);
@@ -1045,7 +1045,7 @@
     EXPECT_TRUE(result.HasValue());
     // Only the high-res device supports the requested frame-rate range.
     // The least expensive configuration is 1280x720x60Hz.
-    EXPECT_EQ(high_res_device_->device_id, result.device_id());
+    EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id());
     EXPECT_LE(kMinFrameRate, result.FrameRate());
     EXPECT_EQ(1280, result.Width());
     EXPECT_EQ(720, result.Height());
@@ -1062,7 +1062,7 @@
     auto result = SelectSettings();
     EXPECT_TRUE(result.HasValue());
     // The minimum frame rate is ignored. Default settings should be used.
-    EXPECT_EQ(default_device_->device_id, result.device_id());
+    EXPECT_EQ(default_device_->device_id.Utf8(), result.device_id());
     EXPECT_EQ(*default_closest_format_, result.Format());
     EXPECT_FALSE(result.min_frame_rate().has_value());
     EXPECT_FALSE(result.max_frame_rate().has_value());
@@ -1092,7 +1092,7 @@
     // The algorithm should prefer the settings that natively exceed the
     // requested maximum by the lowest amount. In this case it is the high-res
     // device with default resolution .
-    EXPECT_EQ(high_res_device_->device_id, result.device_id());
+    EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id());
     EXPECT_EQ(kMaxFrameRate, result.FrameRate());
     EXPECT_EQ(MediaStreamVideoSource::kDefaultHeight, result.Height());
     EXPECT_EQ(MediaStreamVideoSource::kDefaultWidth, result.Width());
@@ -1111,7 +1111,7 @@
     auto result = SelectSettings();
     EXPECT_TRUE(result.HasValue());
     // The maximum frame rate should be ignored. Default settings apply.
-    EXPECT_EQ(default_device_->device_id, result.device_id());
+    EXPECT_EQ(default_device_->device_id.Utf8(), result.device_id());
     EXPECT_EQ(*default_closest_format_, result.Format());
     EXPECT_FALSE(result.min_frame_rate().has_value());
     EXPECT_FALSE(result.max_frame_rate().has_value());
@@ -1146,7 +1146,7 @@
     // All devices in |capabilities_| support the constraint range. The
     // algorithm should prefer the default device since its closest-to-default
     // format has a frame rate included in the requested range.
-    EXPECT_EQ(default_device_->device_id, result.device_id());
+    EXPECT_EQ(default_device_->device_id.Utf8(), result.device_id());
     EXPECT_EQ(*default_closest_format_, result.Format());
     CheckTrackAdapterSettingsEqualsFormat(result);
   }
@@ -1163,7 +1163,7 @@
     // In this case, the algorithm should prefer the low-res device since it is
     // the first device with a native frame rate included in the requested
     // range. The default resolution should be preferred as secondary criterion.
-    EXPECT_EQ(low_res_device_->device_id, result.device_id());
+    EXPECT_EQ(low_res_device_->device_id.Utf8(), result.device_id());
     EXPECT_EQ(*low_res_closest_format_, result.Format());
     CheckTrackAdapterSettingsEqualsFormat(result);
   }
@@ -1181,7 +1181,7 @@
     // the only device with a native format included in the requested range.
     // The 1280x720 resolution should be selected due to closeness to default
     // settings, which is the second tie-breaker criterion that applies.
-    EXPECT_EQ(high_res_device_->device_id, result.device_id());
+    EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id());
     EXPECT_EQ(1280, result.Width());
     EXPECT_EQ(720, result.Height());
     CheckTrackAdapterSettingsEqualsFormat(result);
@@ -1198,7 +1198,7 @@
     // The algorithm should select the first configuration that supports the
     // ideal frame rate natively, which is the low-res device. Default
     // resolution should be selected as secondary criterion.
-    EXPECT_EQ(low_res_device_->device_id, result.device_id());
+    EXPECT_EQ(low_res_device_->device_id.Utf8(), result.device_id());
     EXPECT_EQ(*low_res_closest_format_, result.Format());
     CheckTrackAdapterSettingsEqualsResolution(result);
     CheckTrackAdapterSettingsEqualsFrameRate(result, kIdealFrameRate);
@@ -1213,7 +1213,7 @@
     // ideal at a lower cost than the other devices (40 vs 60).
     // Note that a native frame rate of 30 is further from the ideal than
     // 31 adjusted to 30.
-    EXPECT_EQ(default_device_->device_id, result.device_id());
+    EXPECT_EQ(default_device_->device_id.Utf8(), result.device_id());
     EXPECT_EQ(*default_closest_format_, result.Format());
     CheckTrackAdapterSettingsEqualsResolution(result);
     CheckTrackAdapterSettingsEqualsFrameRate(result, kIdealFrameRate);
@@ -1227,7 +1227,7 @@
     // The high-res device format 1280x720x60.0 must be selected because its
     // frame rate can satisfy the ideal frame rate and has resolution closest
     // to the default.
-    EXPECT_EQ(high_res_device_->device_id, result.device_id());
+    EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id());
     EXPECT_EQ(1280, result.Width());
     EXPECT_EQ(720, result.Height());
     EXPECT_EQ(60, result.FrameRate());
@@ -1244,7 +1244,7 @@
     // The high-res device format 1280x720x60.0 must be selected because its
     // frame rate it closest to the ideal value and it has resolution closest to
     // the default.
-    EXPECT_EQ(high_res_device_->device_id, result.device_id());
+    EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id());
     EXPECT_EQ(1280, result.Width());
     EXPECT_EQ(720, result.Height());
     EXPECT_EQ(60, result.FrameRate());
@@ -1270,7 +1270,7 @@
   // All devices in |capabilities_| support the requested aspect ratio.
   // The algorithm should prefer the first device that supports the requested
   // aspect ratio.
-  EXPECT_EQ(default_device_->device_id, result.device_id());
+  EXPECT_EQ(default_device_->device_id.Utf8(), result.device_id());
   EXPECT_EQ(*default_closest_format_, result.Format());
   EXPECT_EQ(std::round(result.Width() / kAspectRatio),
             result.track_adapter_settings().target_height());
@@ -1299,7 +1299,7 @@
   EXPECT_LE(kAspectRatio, max_aspect_ratio);
   // The default device can support the requested aspect ratio with the default
   // settings (500x500) using cropping.
-  EXPECT_EQ(default_device_->device_id, result.device_id());
+  EXPECT_EQ(default_device_->device_id.Utf8(), result.device_id());
   EXPECT_EQ(*default_closest_format_, result.Format());
   EXPECT_EQ(std::round(result.Width() / kAspectRatio),
             result.track_adapter_settings().target_height());
@@ -1331,7 +1331,7 @@
   // resolution of 640x480. Higher resolutions for the default device are more
   // penalized by the constraints than the default native resolution of the
   // low-res device.
-  EXPECT_EQ(low_res_device_->device_id, result.device_id());
+  EXPECT_EQ(low_res_device_->device_id.Utf8(), result.device_id());
   EXPECT_EQ(*low_res_closest_format_, result.Format());
   // Native resolution, so no rescaling.
   EXPECT_FALSE(result.track_adapter_settings().target_size().has_value());
@@ -1355,7 +1355,7 @@
   // All devices in |capabilities_| support the requested aspect-ratio range.
   // The algorithm should prefer the first device that supports the requested
   // aspect-ratio range, which in this case is the default device.
-  EXPECT_EQ(default_device_->device_id, result.device_id());
+  EXPECT_EQ(default_device_->device_id.Utf8(), result.device_id());
   EXPECT_EQ(*default_closest_format_, result.Format());
   // Adjust the track resolution to use the minimum aspect ratio, which is
   // greater than the source's aspect ratio.
@@ -1389,7 +1389,7 @@
   // resolution of 640x480.
   // Higher resolutions for the default device are more penalized by the
   // constraints than the default native resolution of the low-res device.
-  EXPECT_EQ(low_res_device_->device_id, result.device_id());
+  EXPECT_EQ(low_res_device_->device_id.Utf8(), result.device_id());
   EXPECT_EQ(*low_res_closest_format_, result.Format());
   EXPECT_FALSE(result.track_adapter_settings().target_size().has_value());
   // The source's native aspect ratio equals the minimum aspect ratio.
@@ -1414,7 +1414,7 @@
   // All devices in |capabilities_| support the requested aspect-ratio range.
   // The algorithm should prefer the first device that supports the requested
   // aspect-ratio range, which in this case is the default device.
-  EXPECT_EQ(default_device_->device_id, result.device_id());
+  EXPECT_EQ(default_device_->device_id.Utf8(), result.device_id());
   EXPECT_EQ(*default_closest_format_, result.Format());
   // The track's aspect ratio is adjusted to the maximum, which is lower than
   // the source's native aspect ratio.
@@ -1447,7 +1447,7 @@
   // The high-res device with a native resolution of 1280x720 can support
   // 360x720 with cropping with less penalty than the default device at
   // 1000x1000.
-  EXPECT_EQ(high_res_device_->device_id, result.device_id());
+  EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id());
   EXPECT_EQ(1280, result.Width());
   EXPECT_EQ(720, result.Height());
   // The track's aspect ratio is adjusted to the maximum, which is lower than
@@ -1484,7 +1484,7 @@
     // All devices in |capabilities_| support the requested aspect-ratio range.
     // The algorithm should prefer the first device that supports the requested
     // aspect-ratio range, which in this case is the default device.
-    EXPECT_EQ(default_device_->device_id, result.device_id());
+    EXPECT_EQ(default_device_->device_id.Utf8(), result.device_id());
     EXPECT_EQ(*default_closest_format_, result.Format());
     // The source's aspect ratio matches the maximum aspect ratio. No adjustment
     // is required.
@@ -1519,7 +1519,7 @@
     EXPECT_GE(kMaxAspectRatio, min_aspect_ratio);
     // The only device that supports the resolution and aspect ratio constraint
     // is the high-res device. The 1920x1080 is the least expensive format.
-    EXPECT_EQ(high_res_device_->device_id, result.device_id());
+    EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id());
     EXPECT_EQ(1920, result.Width());
     EXPECT_EQ(1080, result.Height());
     // The track is cropped to support the minimum aspect ratio.
@@ -1552,7 +1552,7 @@
     // settings.
     EXPECT_LE(kIdealAspectRatio, max_aspect_ratio);
     EXPECT_GE(kIdealAspectRatio, min_aspect_ratio);
-    EXPECT_EQ(default_device_->device_id, result.device_id());
+    EXPECT_EQ(default_device_->device_id.Utf8(), result.device_id());
     EXPECT_EQ(*default_closest_format_, result.Format());
     // The track is cropped to support the ideal aspect ratio.
     EXPECT_EQ(result.Height(), result.track_adapter_settings().target_height());
@@ -1572,7 +1572,7 @@
     EXPECT_TRUE(result.HasValue());
     // The only device that supports the ideal aspect ratio is the high-res
     // device.
-    EXPECT_EQ(high_res_device_->device_id, result.device_id());
+    EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id());
     EXPECT_EQ(1280, result.Width());
     EXPECT_EQ(720, result.Height());
     // The most exact way to support the ideal aspect ratio would be to crop to
@@ -1603,7 +1603,7 @@
     // and then round. Since 1920x1 has an aspect ratio closer to 2000, it is
     // selected over 2304x1. The only device that supports this resolution is
     // the high-res device open at 1920x1080.
-    EXPECT_EQ(high_res_device_->device_id, result.device_id());
+    EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id());
     EXPECT_EQ(1920, result.Width());
     EXPECT_EQ(1080, result.Height());
     EXPECT_EQ(std::round(result.Width() / kIdealAspectRatio),
@@ -1623,7 +1623,7 @@
     EXPECT_TRUE(result.HasValue());
     // The configuration closest to the ideal aspect ratio is is the high-res
     // device with its highest resolution, cropped to 2304x1.
-    EXPECT_EQ(high_res_device_->device_id, result.device_id());
+    EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id());
     EXPECT_EQ(*high_res_highest_format_, result.Format());
     // In this case there is no rounding error.
     EXPECT_EQ(1, result.track_adapter_settings().target_height());
@@ -1645,7 +1645,7 @@
     // The first device to support the ideal aspect ratio and the resolution
     // constraint is the low-res device. The 800x600 format cropped to 800x400
     // is the lest expensive way to achieve it.
-    EXPECT_EQ(low_res_device_->device_id, result.device_id());
+    EXPECT_EQ(low_res_device_->device_id.Utf8(), result.device_id());
     EXPECT_EQ(800, result.Width());
     EXPECT_EQ(600, result.Height());
     EXPECT_EQ(kExactHeight, result.track_adapter_settings().target_height());
@@ -1668,7 +1668,7 @@
     // The only device that supports the ideal aspect ratio and the resolution
     // constraint is the high-res device. The 1280x720 cropped to 1200x400 is
     // the lest expensive way to achieve it.
-    EXPECT_EQ(high_res_device_->device_id, result.device_id());
+    EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id());
     EXPECT_EQ(1280, result.Width());
     EXPECT_EQ(720, result.Height());
     EXPECT_EQ(kExactHeight, result.track_adapter_settings().target_height());
@@ -1717,7 +1717,7 @@
   // Since no constraints are given, the default device with resolution closest
   // to default is selected. However, rescaling is enabled due to the ideal
   // resize mode.
-  EXPECT_EQ(result.device_id(), default_device_->device_id);
+  EXPECT_EQ(result.device_id(), default_device_->device_id.Utf8());
   EXPECT_EQ(result.Width(), 500);
   EXPECT_EQ(result.Height(), 500);
   EXPECT_TRUE(result.track_adapter_settings().target_size().has_value());
@@ -1792,7 +1792,7 @@
   auto result = SelectSettings();
   EXPECT_TRUE(result.HasValue());
   // The native mode closest to 1x1 is 40x30 with the low-res device.
-  EXPECT_EQ(result.device_id(), low_res_device_->device_id);
+  EXPECT_EQ(result.device_id(), low_res_device_->device_id.Utf8());
   EXPECT_EQ(result.Width(), 40);
   EXPECT_EQ(result.Height(), 30);
   // Despite resize_mode being ideal "none", SelectSettings opts for rescaling
@@ -1810,7 +1810,7 @@
   result = SelectSettings();
   EXPECT_TRUE(result.HasValue());
   // The native mode closest to 1x1 is 40x30 with the low-res device.
-  EXPECT_EQ(result.device_id(), low_res_device_->device_id);
+  EXPECT_EQ(result.device_id(), low_res_device_->device_id.Utf8());
   EXPECT_EQ(result.Width(), 40);
   EXPECT_EQ(result.Height(), 30);
   // In this case, SelectSettings opts for not rescaling since the fitness
@@ -1828,7 +1828,7 @@
   auto result = SelectSettings();
   EXPECT_TRUE(result.HasValue());
   // 800x600 rescaled to 641x481 is closest to the specified ideal values.
-  EXPECT_EQ(result.device_id(), low_res_device_->device_id);
+  EXPECT_EQ(result.device_id(), low_res_device_->device_id.Utf8());
   EXPECT_EQ(result.Width(), 800);
   EXPECT_EQ(result.Height(), 600);
   // Since both resize modes are considered ideal, rescaling is preferred
@@ -1844,7 +1844,7 @@
   EXPECT_TRUE(result.HasValue());
   // Given that both resize modes are ideal, the default device with the
   // resolution closest to the default without rescaling is selected.
-  EXPECT_EQ(result.device_id(), default_device_->device_id);
+  EXPECT_EQ(result.device_id(), default_device_->device_id.Utf8());
   EXPECT_EQ(result.Width(), 500);
   EXPECT_EQ(result.Height(), 500);
   EXPECT_FALSE(result.track_adapter_settings().target_size().has_value());
@@ -1862,7 +1862,7 @@
   // set is therefore ignored in all calls to SelectSettings().
   // Tie-breaker rule that applies is closeness to default settings.
   auto result = SelectSettings();
-  EXPECT_EQ(default_device_->device_id, result.device_id());
+  EXPECT_EQ(default_device_->device_id.Utf8(), result.device_id());
   EXPECT_EQ(*default_closest_format_, result.Format());
   CheckTrackAdapterSettingsEqualsFormat(result);
 
@@ -1874,7 +1874,7 @@
   result = SelectSettings();
   // The device that best supports this advanced set is the low-res device,
   // which natively supports the maximum resolution.
-  EXPECT_EQ(low_res_device_->device_id, result.device_id());
+  EXPECT_EQ(low_res_device_->device_id.Utf8(), result.device_id());
   EXPECT_EQ(640, result.Width());
   EXPECT_EQ(480, result.Height());
   EXPECT_FALSE(result.track_adapter_settings().target_size().has_value());
@@ -1888,7 +1888,7 @@
   EXPECT_TRUE(result.HasValue());
   // The high-res device natively supports the third advanced set in addition
   // to the previous set and should be selected.
-  EXPECT_EQ(high_res_device_->device_id, result.device_id());
+  EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id());
   EXPECT_EQ(640, result.Width());
   EXPECT_EQ(480, result.Height());
   EXPECT_FALSE(result.track_adapter_settings().target_size().has_value());
@@ -1903,7 +1903,7 @@
   // The fourth advanced set does not change the allowed range set by previous
   // sets, so the selection is the same as in the previous case.
   EXPECT_TRUE(result.HasValue());
-  EXPECT_EQ(high_res_device_->device_id, result.device_id());
+  EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id());
   EXPECT_EQ(640, result.Width());
   EXPECT_EQ(480, result.Height());
   EXPECT_FALSE(result.track_adapter_settings().target_size().has_value());
@@ -1925,7 +1925,7 @@
   // is lower than the distance between 640x400@10Hz and 320x240@10Hz.
   // Both candidates support standard fitness distance equally, since both can
   // use adjusments to produce 320x240@10Hz.
-  EXPECT_EQ(low_res_device_->device_id, result.device_id());
+  EXPECT_EQ(low_res_device_->device_id.Utf8(), result.device_id());
   EXPECT_EQ(320, result.Width());
   EXPECT_EQ(240, result.Height());
   EXPECT_FALSE(result.track_adapter_settings().target_size().has_value());
@@ -1939,7 +1939,7 @@
   EXPECT_TRUE(result.HasValue());
   // The high-res device at 640x480@10Hz is closer to the large ideal
   // resolution.
-  EXPECT_EQ(high_res_device_->device_id, result.device_id());
+  EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id());
   EXPECT_EQ(640, result.Width());
   EXPECT_EQ(480, result.Height());
   EXPECT_FALSE(result.track_adapter_settings().target_size().has_value());
@@ -1965,7 +1965,7 @@
   // set. 2304x1536x10.0 satisfies sets 1 and 3, while 1920x1080x60.0
   // satisfies sets 1, and 2. The latter must be selected, regardless of
   // any other criteria.
-  EXPECT_EQ(high_res_device_->device_id, result.device_id());
+  EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id());
   EXPECT_EQ(1920, result.Width());
   EXPECT_EQ(1080, result.Height());
   EXPECT_EQ(60.0, result.FrameRate());
@@ -1988,7 +1988,7 @@
   advanced2.goog_noise_reduction.SetExact(false);
   auto result = SelectSettings();
   EXPECT_TRUE(result.HasValue());
-  EXPECT_EQ(high_res_device_->device_id, result.device_id());
+  EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id());
   EXPECT_LE(1920, result.Width());
   EXPECT_LE(1080, result.Height());
   EXPECT_TRUE(result.noise_reduction() && !*result.noise_reduction());
@@ -2017,7 +2017,7 @@
     // The second advanced set cannot be satisfied because it contradicts the
     // first set. The default device supports the first set and should be
     // selected.
-    EXPECT_EQ(default_device_->device_id, result.device_id());
+    EXPECT_EQ(default_device_->device_id.Utf8(), result.device_id());
     EXPECT_LE(640, result.Width());
     EXPECT_LE(480, result.Height());
     EXPECT_TRUE(result.noise_reduction() && *result.noise_reduction());
@@ -2041,7 +2041,7 @@
     auto result = SelectSettings();
     EXPECT_TRUE(result.HasValue());
     // Only the high-res device can satisfy the second advanced set.
-    EXPECT_EQ(high_res_device_->device_id, result.device_id());
+    EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id());
     EXPECT_LE(1920, result.Width());
     EXPECT_LE(1080, result.Height());
     // Should select default noise reduction setting.
@@ -2069,7 +2069,7 @@
   // The second advanced set must be ignored because it contradicts the first
   // set. The low-res device is the one that best supports the requested
   // resolution.
-  EXPECT_EQ(low_res_device_->device_id, result.device_id());
+  EXPECT_EQ(low_res_device_->device_id.Utf8(), result.device_id());
   EXPECT_EQ(640, result.Width());
   EXPECT_EQ(480, result.Height());
   EXPECT_FALSE(result.track_adapter_settings().target_size().has_value());
@@ -2094,7 +2094,7 @@
   // set. The default device with the 200x200@40Hz format should be selected.
   // That format satisfies the first advanced set as well as any other, so the
   // tie breaker rule that applies is default device ID.
-  EXPECT_EQ(default_device_->device_id, result.device_id());
+  EXPECT_EQ(default_device_->device_id.Utf8(), result.device_id());
   EXPECT_EQ(200, result.Width());
   EXPECT_EQ(200, result.Height());
   EXPECT_EQ(40, result.FrameRate());
@@ -2121,7 +2121,7 @@
   // set. The default device with the 1000x1000@20Hz format should be selected.
   // That format satisfies the first advanced set as well as any other, so the
   // tie breaker rule that applies is default device ID.
-  EXPECT_EQ(default_device_->device_id, result.device_id());
+  EXPECT_EQ(default_device_->device_id.Utf8(), result.device_id());
   EXPECT_EQ(1000, result.Width());
   EXPECT_EQ(1000, result.Height());
   EXPECT_EQ(20, result.FrameRate());
@@ -2145,7 +2145,7 @@
   // The second advanced set must be ignored because it contradicts the first
   // set. Only the high-res device in the highest-resolution format supports the
   // requested aspect ratio.
-  EXPECT_EQ(high_res_device_->device_id, result.device_id());
+  EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id());
   EXPECT_EQ(*high_res_highest_format_, result.Format());
   // The track is cropped to support the exact aspect ratio.
   EXPECT_EQ(result.Width(), result.track_adapter_settings().target_width());
@@ -2168,7 +2168,7 @@
   // The second advanced set must be ignored because it contradicts the first
   // set. Only the high-res device in the highest-resolution format supports the
   // requested aspect ratio.
-  EXPECT_EQ(high_res_device_->device_id, result.device_id());
+  EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id());
   EXPECT_EQ(*high_res_highest_format_, result.Format());
   // The track is cropped to support the min aspect ratio.
   EXPECT_EQ(result.Width(), result.track_adapter_settings().target_width());
@@ -2226,7 +2226,7 @@
   // The low-res device at 320x240@30Hz satisfies advanced sets 1 and 3.
   // The high-res device at 2304x1536@10.0f can satisfy sets 1 and 2, but not
   // both at the same time. Thus, low-res device must be preferred.
-  EXPECT_EQ(low_res_device_->device_id, result.device_id());
+  EXPECT_EQ(low_res_device_->device_id.Utf8(), result.device_id());
   EXPECT_EQ(30.0, result.FrameRate());
   EXPECT_GE(1920, result.Width());
   CheckTrackAdapterSettingsEqualsFormat(result);
@@ -2248,7 +2248,7 @@
   // sets 1 and 3. The same device at 2304x1536@10.0f can satisfy sets 1 and 2,
   // but not both at the same time. Thus, the format closest to default that
   // satisfies sets 1 and 3 must be chosen.
-  EXPECT_EQ(high_res_device_->device_id, result.device_id());
+  EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id());
   EXPECT_EQ(60.0, result.FrameRate());
   EXPECT_GE(1080, result.Height());
   CheckTrackAdapterSettingsEqualsFormat(result);
@@ -2319,12 +2319,10 @@
        AdvancedContradictoryDeviceIDAndResolution) {
   constraint_factory_.Reset();
   WebMediaTrackConstraintSet& advanced1 = constraint_factory_.AddAdvanced();
-  advanced1.device_id.SetExact(
-      {WebString::FromASCII(low_res_device_->device_id)});
+  advanced1.device_id.SetExact({WebString(low_res_device_->device_id)});
 
   WebMediaTrackConstraintSet& advanced2 = constraint_factory_.AddAdvanced();
-  advanced2.device_id.SetExact(
-      {WebString::FromASCII(high_res_device_->device_id)});
+  advanced2.device_id.SetExact({WebString(high_res_device_->device_id)});
   advanced2.width.SetMax(50);
   advanced2.height.SetMax(50);
 
@@ -2336,7 +2334,7 @@
   EXPECT_TRUE(result.HasValue());
   // The second advanced set must be ignored because it contradicts the first
   // set, but the third set must be applied.
-  EXPECT_EQ(result.device_id(), low_res_device_->device_id);
+  EXPECT_EQ(result.device_id(), low_res_device_->device_id.Utf8());
   EXPECT_EQ(result.Width(), 800);
   EXPECT_EQ(result.Height(), 600);
   EXPECT_FALSE(result.track_adapter_settings().target_size().has_value());
@@ -2376,7 +2374,7 @@
     // The second advanced set cannot be satisfied because it contradicts the
     // second set. The default device supports the first set and should be
     // selected.
-    EXPECT_EQ(default_device_->device_id, result.device_id());
+    EXPECT_EQ(default_device_->device_id.Utf8(), result.device_id());
     EXPECT_EQ(*default_closest_format_, result.Format());
     EXPECT_EQ(result.Width(), result.track_adapter_settings().target_width());
     EXPECT_EQ(std::round(result.Width() / 17.0),
@@ -2398,7 +2396,7 @@
   auto result = SelectSettings();
   EXPECT_TRUE(result.HasValue());
   // The native mode closest to 1x1 is 40x30 with the low-res device.
-  EXPECT_EQ(result.device_id(), low_res_device_->device_id);
+  EXPECT_EQ(result.device_id(), low_res_device_->device_id.Utf8());
   EXPECT_EQ(result.Width(), 40);
   EXPECT_EQ(result.Height(), 30);
   // No rescaling occurs due to the advanced constraint specifying resizeMode
@@ -2428,7 +2426,7 @@
   EXPECT_EQ(result.track_adapter_settings().max_frame_rate(), 0.0);
 
   // The low-res device at 640x480@30Hz is the
-  EXPECT_EQ(result.device_id(), low_res_device_->device_id);
+  EXPECT_EQ(result.device_id(), low_res_device_->device_id.Utf8());
   EXPECT_EQ(result.Width(), 640);
   EXPECT_EQ(result.Height(), 480);
   EXPECT_EQ(result.FrameRate(), 30.0);
@@ -2481,10 +2479,10 @@
 TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, InvalidFrameRateDevice) {
   constraint_factory_.Reset();
   constraint_factory_.basic().device_id.SetExact(
-      WebString::FromASCII(invalid_frame_rate_device_->device_id));
+      WebString(invalid_frame_rate_device_->device_id));
   auto result = SelectSettings();
   EXPECT_TRUE(result.HasValue());
-  EXPECT_EQ(invalid_frame_rate_device_->device_id, result.device_id());
+  EXPECT_EQ(invalid_frame_rate_device_->device_id.Utf8(), result.device_id());
   EXPECT_EQ(invalid_frame_rate_device_->formats[0].frame_rate,
             result.FrameRate());
   EXPECT_EQ(result.FrameRate(), 0.0);
@@ -2495,7 +2493,7 @@
   constraint_factory_.basic().width.SetExact(500);
   result = SelectSettings();
   EXPECT_TRUE(result.HasValue());
-  EXPECT_EQ(invalid_frame_rate_device_->device_id, result.device_id());
+  EXPECT_EQ(invalid_frame_rate_device_->device_id.Utf8(), result.device_id());
   EXPECT_EQ(invalid_frame_rate_device_->formats[1].frame_rate,
             result.FrameRate());
   EXPECT_LT(result.FrameRate(), 1.0);
@@ -2508,10 +2506,10 @@
 TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, InvertedDefaultResolution) {
   constraint_factory_.Reset();
   constraint_factory_.basic().device_id.SetExact(
-      WebString::FromASCII(high_res_device_->device_id));
+      WebString(high_res_device_->device_id));
   auto result = SelectSettings();
   EXPECT_TRUE(result.HasValue());
-  EXPECT_EQ(high_res_device_->device_id, result.device_id());
+  EXPECT_EQ(high_res_device_->device_id.Utf8(), result.device_id());
   EXPECT_EQ(result.Width(), MediaStreamVideoSource::kDefaultWidth);
   EXPECT_EQ(result.Height(), MediaStreamVideoSource::kDefaultHeight);
 }
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_video_source.cc b/third_party/blink/renderer/modules/mediastream/media_stream_video_source.cc
index 3cd44975..b4fafe9 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream_video_source.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_video_source.cc
@@ -17,8 +17,8 @@
 #include "base/strings/string_number_conversions.h"
 #include "third_party/blink/public/mojom/mediastream/media_stream.mojom-blink.h"
 #include "third_party/blink/public/platform/platform.h"
-#include "third_party/blink/public/web/modules/mediastream/media_stream_constraints_util_video_device.h"
 #include "third_party/blink/public/web/modules/mediastream/media_stream_video_track.h"
+#include "third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_video_device.h"
 #include "third_party/blink/renderer/modules/mediastream/video_track_adapter.h"
 #include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
 #include "third_party/blink/renderer/platform/scheduler/public/thread.h"
diff --git a/third_party/blink/renderer/modules/mediastream/media_stream_video_track.cc b/third_party/blink/renderer/modules/mediastream/media_stream_video_track.cc
index 054f7fc7..8508564ed 100644
--- a/third_party/blink/renderer/modules/mediastream/media_stream_video_track.cc
+++ b/third_party/blink/renderer/modules/mediastream/media_stream_video_track.cc
@@ -15,8 +15,8 @@
 #include "build/build_config.h"
 #include "media/base/bind_to_current_loop.h"
 #include "media/capture/video_capture_types.h"
-#include "third_party/blink/public/web/modules/mediastream/media_stream_constraints_util_video_device.h"
 #include "third_party/blink/public/web/web_local_frame.h"
+#include "third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_video_device.h"
 #include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
 #include "third_party/blink/renderer/platform/scheduler/public/thread.h"
 #include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
diff --git a/third_party/blink/renderer/modules/mediastream/user_media_processor.cc b/third_party/blink/renderer/modules/mediastream/user_media_processor.cc
index 4ad5ea943..a0d9de18 100644
--- a/third_party/blink/renderer/modules/mediastream/user_media_processor.cc
+++ b/third_party/blink/renderer/modules/mediastream/user_media_processor.cc
@@ -7,7 +7,6 @@
 #include <stddef.h>
 
 #include <algorithm>
-#include <map>
 #include <utility>
 
 #include "base/bind.h"
@@ -36,7 +35,6 @@
 #include "third_party/blink/public/web/modules/mediastream/media_stream_constraints_util.h"
 #include "third_party/blink/public/web/modules/mediastream/media_stream_constraints_util_audio.h"
 #include "third_party/blink/public/web/modules/mediastream/media_stream_constraints_util_video_content.h"
-#include "third_party/blink/public/web/modules/mediastream/media_stream_constraints_util_video_device.h"
 #include "third_party/blink/public/web/modules/mediastream/media_stream_video_capturer_source.h"
 #include "third_party/blink/public/web/modules/mediastream/media_stream_video_track.h"
 #include "third_party/blink/public/web/modules/mediastream/processed_local_audio_source.h"
@@ -44,6 +42,7 @@
 #include "third_party/blink/public/web/web_local_frame.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/page/chrome_client.h"
+#include "third_party/blink/renderer/modules/mediastream/media_stream_constraints_util_video_device.h"
 #include "third_party/blink/renderer/modules/mediastream/user_media_client_impl.h"
 #include "third_party/blink/renderer/platform/wtf/wtf_size_t.h"
 #include "ui/gfx/geometry/size.h"
@@ -217,20 +216,16 @@
   return media::MEDIA_VIDEO_FACING_NONE;
 }
 
-std::vector<blink::VideoInputDeviceCapabilities> ToVideoInputDeviceCapabilities(
+Vector<blink::VideoInputDeviceCapabilities> ToVideoInputDeviceCapabilities(
     const Vector<blink::mojom::blink::VideoInputDeviceCapabilitiesPtr>&
         input_capabilities) {
-  std::vector<blink::VideoInputDeviceCapabilities> capabilities;
+  Vector<blink::VideoInputDeviceCapabilities> capabilities;
   for (const auto& capability : input_capabilities) {
-    // TODO(crbug.com/704136): Change VideoInputDeviceCapabilities to operate
-    // over WTF::Vector and WTF::String, in its ctor's.
-    //
     // TODO(crbug.com/704136): Make the conversion from mojom::blink::FacingMode
     // to be handled automatically, eg by making media_devices.typemap work in
     // blink/renderer/platform/mojo/blink_typemaps.gni.
-    capabilities.emplace_back(capability->device_id.Utf8(),
-                              capability->group_id.Utf8(),
-                              ToStdVector(capability->formats),
+    capabilities.emplace_back(capability->device_id, capability->group_id,
+                              capability->formats,
                               ToMediaVideoFacingMode(capability->facing_mode));
   }
 
@@ -316,15 +311,15 @@
 
   void AddNativeVideoFormats(const String& device_id,
                              Vector<media::VideoCaptureFormat> formats) {
-    video_formats_map_[device_id.Utf8()] = std::move(formats);
+    video_formats_map_.insert(device_id, std::move(formats));
   }
 
   // Do not store or delete the returned pointer.
   Vector<media::VideoCaptureFormat>* GetNativeVideoFormats(
       const String& device_id) {
-    auto it = video_formats_map_.find(device_id.Utf8());
+    auto it = video_formats_map_.find(device_id);
     CHECK(it != video_formats_map_.end());
-    return &it->second;
+    return &it->value;
   }
 
   const Vector<MediaStreamDevice>& audio_devices() const {
@@ -372,12 +367,9 @@
   MediaStreamRequestResult request_result_ = MediaStreamRequestResult::OK;
   blink::WebString request_result_name_;
   // Sources used in this request.
-  // TODO(crbug.com/704136): Switch away from std::vector.
-  std::vector<blink::WebMediaStreamSource> sources_;
-  std::vector<blink::WebPlatformMediaStreamSource*>
-      sources_waiting_for_callback_;
-  // TODO(crbug.com/704136): Switch away from std::string and std::map.
-  std::map<std::string, Vector<media::VideoCaptureFormat>> video_formats_map_;
+  Vector<blink::WebMediaStreamSource> sources_;
+  Vector<blink::WebPlatformMediaStreamSource*> sources_waiting_for_callback_;
+  HashMap<String, Vector<media::VideoCaptureFormat>> video_formats_map_;
   Vector<MediaStreamDevice> audio_devices_;
   Vector<MediaStreamDevice> video_devices_;
 };
@@ -443,8 +435,8 @@
     MediaStreamRequestResult result,
     const blink::WebString& result_name) {
   DVLOG(1) << "OnTrackStarted result " << result;
-  auto it = std::find(sources_waiting_for_callback_.begin(),
-                      sources_waiting_for_callback_.end(), source);
+  auto** it = std::find(sources_waiting_for_callback_.begin(),
+                        sources_waiting_for_callback_.end(), source);
   DCHECK(it != sources_waiting_for_callback_.end());
   sources_waiting_for_callback_.erase(it);
   // All tracks must be started successfully. Otherwise the request is a
@@ -458,7 +450,7 @@
 }
 
 void UserMediaProcessor::RequestInfo::CheckAllTracksStarted() {
-  if (ready_callback_ && sources_waiting_for_callback_.empty()) {
+  if (ready_callback_ && sources_waiting_for_callback_.IsEmpty()) {
     std::move(ready_callback_).Run(this, request_result_, request_result_name_);
     // NOTE: |this| might now be deleted.
   }
@@ -714,9 +706,6 @@
       current_request_info_->stream_controls()->video.stream_type));
 
   blink::VideoDeviceCaptureCapabilities capabilities;
-  // TODO(crbug.com/704136): Change
-  // VideoDeviceCaptureCapabilities.device_capabilities to operate over
-  // WTF::Vector.
   capabilities.device_capabilities =
       ToVideoInputDeviceCapabilities(video_input_capabilities);
   capabilities.noise_reduction_capabilities = {base::Optional<bool>(),
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc
index acbf831..49741f7 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc
@@ -208,7 +208,7 @@
   KURL response_url = creation_params->script_url;
   network::mojom::ReferrerPolicy response_referrer_policy =
       creation_params->referrer_policy;
-  mojom::IPAddressSpace response_address_space =
+  network::mojom::IPAddressSpace response_address_space =
       *creation_params->response_address_space;
   std::unique_ptr<Vector<String>> response_origin_trial_tokens =
       std::move(creation_params->origin_trial_tokens);
@@ -518,7 +518,7 @@
 void ServiceWorkerGlobalScope::Initialize(
     const KURL& response_url,
     network::mojom::ReferrerPolicy response_referrer_policy,
-    mojom::IPAddressSpace response_address_space,
+    network::mojom::IPAddressSpace response_address_space,
     const Vector<CSPHeaderAndType>& response_csp_headers,
     const Vector<String>* response_origin_trial_tokens) {
   // Step 4.5. "Set workerGlobalScope's url to serviceWorker's script url."
@@ -565,7 +565,7 @@
 void ServiceWorkerGlobalScope::RunClassicScript(
     const KURL& response_url,
     network::mojom::ReferrerPolicy response_referrer_policy,
-    mojom::IPAddressSpace response_address_space,
+    network::mojom::IPAddressSpace response_address_space,
     const Vector<CSPHeaderAndType> response_csp_headers,
     const Vector<String>* response_origin_trial_tokens,
     const String& source_code,
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h
index 3ea3f4f..fed2e37b 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.h
@@ -95,7 +95,7 @@
   // Implements WorkerGlobalScope:
   void Initialize(const KURL& response_url,
                   network::mojom::ReferrerPolicy response_referrer_policy,
-                  mojom::IPAddressSpace response_address_space,
+                  network::mojom::IPAddressSpace response_address_space,
                   const Vector<CSPHeaderAndType>& response_csp_headers,
                   const Vector<String>* response_origin_trial_tokens) override;
   // Fetches and runs the top-level classic worker script for the 'new' or
@@ -311,7 +311,7 @@
   // https://w3c.github.io/ServiceWorker/#run-service-worker-algorithm
   void RunClassicScript(const KURL& response_url,
                         network::mojom::ReferrerPolicy response_referrer_policy,
-                        mojom::IPAddressSpace response_address_space,
+                        network::mojom::IPAddressSpace response_address_space,
                         const Vector<CSPHeaderAndType> response_csp_headers,
                         const Vector<String>* response_origin_trial_tokens,
                         const String& source_code,
diff --git a/third_party/blink/renderer/modules/service_worker/web_embedded_worker_impl_test.cc b/third_party/blink/renderer/modules/service_worker/web_embedded_worker_impl_test.cc
index ae0b604dc..e49be88 100644
--- a/third_party/blink/renderer/modules/service_worker/web_embedded_worker_impl_test.cc
+++ b/third_party/blink/renderer/modules/service_worker/web_embedded_worker_impl_test.cc
@@ -55,8 +55,7 @@
   std::unique_ptr<WebURLLoader> CreateURLLoader(
       const WebURLRequest& request,
       std::unique_ptr<scheduler::WebResourceLoadingTaskRunnerHandle>) override {
-    return Platform::Current()->GetURLLoaderMockFactory()->CreateURLLoader(
-        nullptr);
+    return Platform::Current()->GetURLLoaderMockFactory()->CreateURLLoader();
   }
 
   blink::mojom::ControllerServiceWorkerMode GetControllerServiceWorkerMode()
diff --git a/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope_test.cc b/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope_test.cc
index 34fa137..190b3381 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope_test.cc
+++ b/third_party/blink/renderer/modules/webaudio/audio_worklet_global_scope_test.cc
@@ -78,8 +78,7 @@
             base::UnguessableToken::Create(), nullptr /* worker_settings */,
             kV8CacheOptionsDefault,
             MakeGarbageCollected<WorkletModuleResponsesMap>()),
-        base::nullopt, std::make_unique<WorkerDevToolsParams>(),
-        ParentExecutionContextTaskRunners::Create());
+        base::nullopt, std::make_unique<WorkerDevToolsParams>());
     return thread;
   }
 
diff --git a/third_party/blink/renderer/modules/webaudio/audio_worklet_thread_test.cc b/third_party/blink/renderer/modules/webaudio/audio_worklet_thread_test.cc
index 46e213b..3b2aa18 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_worklet_thread_test.cc
+++ b/third_party/blink/renderer/modules/webaudio/audio_worklet_thread_test.cc
@@ -60,8 +60,7 @@
             base::UnguessableToken::Create(), nullptr /* worker_settings */,
             kV8CacheOptionsDefault,
             MakeGarbageCollected<WorkletModuleResponsesMap>()),
-        base::nullopt, std::make_unique<WorkerDevToolsParams>(),
-        ParentExecutionContextTaskRunners::Create());
+        base::nullopt, std::make_unique<WorkerDevToolsParams>());
     return thread;
   }
 
diff --git a/third_party/blink/renderer/modules/websockets/dom_websocket_test.cc b/third_party/blink/renderer/modules/websockets/dom_websocket_test.cc
index 0d254386..6803da8 100644
--- a/third_party/blink/renderer/modules/websockets/dom_websocket_test.cc
+++ b/third_party/blink/renderer/modules/websockets/dom_websocket_test.cc
@@ -20,6 +20,7 @@
 #include "third_party/blink/renderer/core/fileapi/blob.h"
 #include "third_party/blink/renderer/core/testing/dummy_page_holder.h"
 #include "third_party/blink/renderer/core/typed_arrays/dom_typed_array.h"
+#include "third_party/blink/renderer/modules/websockets/mock_websocket_channel.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
@@ -41,45 +42,6 @@
 typedef testing::StrictMock<testing::MockFunction<void(int)>>
     Checkpoint;  // NOLINT
 
-class MockWebSocketChannel : public WebSocketChannel {
- public:
-  static MockWebSocketChannel* Create() {
-    return MakeGarbageCollected<testing::StrictMock<MockWebSocketChannel>>();
-  }
-
-  ~MockWebSocketChannel() override = default;
-
-  MOCK_METHOD2(Connect, bool(const KURL&, const String&));
-  MOCK_METHOD2(Send,
-               WebSocketChannel::SendResult(const std::string&,
-                                            base::OnceClosure));
-  MOCK_METHOD4(Send,
-               WebSocketChannel::SendResult(const DOMArrayBuffer&,
-                                            unsigned,
-                                            unsigned,
-                                            base::OnceClosure));
-  MOCK_METHOD1(SendMock, void(BlobDataHandle*));
-  void Send(scoped_refptr<BlobDataHandle> handle) override {
-    SendMock(handle.get());
-  }
-  MOCK_CONST_METHOD0(BufferedAmount, unsigned());
-  MOCK_METHOD2(Close, void(int, const String&));
-  MOCK_METHOD3(FailMock,
-               void(const String&,
-                    mojom::ConsoleMessageLevel,
-                    SourceLocation*));
-  void Fail(const String& reason,
-            mojom::ConsoleMessageLevel level,
-            std::unique_ptr<SourceLocation> location) override {
-    FailMock(reason, level, location.get());
-  }
-  MOCK_METHOD0(Disconnect, void());
-  MOCK_METHOD0(ApplyBackpressure, void());
-  MOCK_METHOD0(RemoveBackpressure, void());
-
-  MockWebSocketChannel() = default;
-};
-
 class DOMWebSocketWithMockChannel final : public DOMWebSocket {
  public:
   static DOMWebSocketWithMockChannel* Create(ExecutionContext* context) {
diff --git a/third_party/blink/renderer/modules/websockets/mock_websocket_channel.cc b/third_party/blink/renderer/modules/websockets/mock_websocket_channel.cc
new file mode 100644
index 0000000..d5111871
--- /dev/null
+++ b/third_party/blink/renderer/modules/websockets/mock_websocket_channel.cc
@@ -0,0 +1,19 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/websockets/mock_websocket_channel.h"
+
+// Generated constructors and destructors for GMock objects are very large. By
+// putting them in a separate file we can speed up compile times.
+
+namespace blink {
+
+MockWebSocketChannel* MockWebSocketChannel::Create() {
+  return MakeGarbageCollected<testing::StrictMock<MockWebSocketChannel>>();
+}
+
+MockWebSocketChannel::MockWebSocketChannel() = default;
+MockWebSocketChannel::~MockWebSocketChannel() = default;
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/modules/websockets/mock_websocket_channel.h b/third_party/blink/renderer/modules/websockets/mock_websocket_channel.h
new file mode 100644
index 0000000..3c9e0aa
--- /dev/null
+++ b/third_party/blink/renderer/modules/websockets/mock_websocket_channel.h
@@ -0,0 +1,61 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WEBSOCKETS_MOCK_WEBSOCKET_CHANNEL_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBSOCKETS_MOCK_WEBSOCKET_CHANNEL_H_
+
+#include <memory>
+
+#include "base/memory/scoped_refptr.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "third_party/blink/public/mojom/devtools/console_message.mojom-blink.h"
+#include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h"
+#include "third_party/blink/renderer/modules/websockets/websocket_channel.h"
+#include "third_party/blink/renderer/platform/blob/blob_data.h"
+#include "third_party/blink/renderer/platform/weborigin/kurl.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+
+namespace blink {
+
+class SourceLocation;
+
+class MockWebSocketChannel : public WebSocketChannel {
+ public:
+  static MockWebSocketChannel* Create();
+
+  MockWebSocketChannel();
+  ~MockWebSocketChannel() override;
+
+  MOCK_METHOD2(Connect, bool(const KURL&, const String&));
+  MOCK_METHOD2(Send,
+               WebSocketChannel::SendResult(const std::string&,
+                                            base::OnceClosure));
+  MOCK_METHOD4(Send,
+               WebSocketChannel::SendResult(const DOMArrayBuffer&,
+                                            unsigned,
+                                            unsigned,
+                                            base::OnceClosure));
+  MOCK_METHOD1(SendMock, void(BlobDataHandle*));
+  void Send(scoped_refptr<BlobDataHandle> handle) override {
+    SendMock(handle.get());
+  }
+  MOCK_CONST_METHOD0(BufferedAmount, unsigned());
+  MOCK_METHOD2(Close, void(int, const String&));
+  MOCK_METHOD3(FailMock,
+               void(const String&,
+                    mojom::ConsoleMessageLevel,
+                    SourceLocation*));
+  void Fail(const String& reason,
+            mojom::ConsoleMessageLevel level,
+            std::unique_ptr<SourceLocation> location) override {
+    FailMock(reason, level, location.get());
+  }
+  MOCK_METHOD0(Disconnect, void());
+  MOCK_METHOD0(ApplyBackpressure, void());
+  MOCK_METHOD0(RemoveBackpressure, void());
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_WEBSOCKETS_MOCK_WEBSOCKET_CHANNEL_H_
diff --git a/third_party/blink/renderer/modules/websockets/websocket_handle_impl.cc b/third_party/blink/renderer/modules/websockets/websocket_handle_impl.cc
index acd288de..5cedd803 100644
--- a/third_party/blink/renderer/modules/websockets/websocket_handle_impl.cc
+++ b/third_party/blink/renderer/modules/websockets/websocket_handle_impl.cc
@@ -55,12 +55,9 @@
       mojo::MakeRequest(&handshake_client_proxy, task_runner_), task_runner_);
   handshake_client_binding_.set_connection_error_with_reason_handler(WTF::Bind(
       &WebSocketHandleImpl::OnConnectionError, WTF::Unretained(this)));
-  network::mojom::blink::WebSocketClientPtr client_proxy;
-  pending_client_receiver_ = mojo::MakeRequest(&client_proxy);
 
   connector->Connect(url, protocols, site_for_cookies, user_agent_override,
-                     std::move(handshake_client_proxy),
-                     std::move(client_proxy));
+                     std::move(handshake_client_proxy));
 }
 
 void WebSocketHandleImpl::Send(bool fin,
@@ -151,6 +148,8 @@
 
 void WebSocketHandleImpl::OnConnectionEstablished(
     network::mojom::blink::WebSocketPtr websocket,
+    mojo::PendingReceiver<network::mojom::blink::WebSocketClient>
+        client_receiver,
     const String& protocol,
     const String& extensions,
     uint64_t receive_quota_threshold) {
@@ -162,7 +161,7 @@
 
   // From now on, we will detect mojo errors via |client_binding_|.
   handshake_client_binding_.Close();
-  client_binding_.Bind(std::move(pending_client_receiver_), task_runner_);
+  client_binding_.Bind(std::move(client_receiver), task_runner_);
   client_binding_.set_connection_error_with_reason_handler(WTF::Bind(
       &WebSocketHandleImpl::OnConnectionError, WTF::Unretained(this)));
 
diff --git a/third_party/blink/renderer/modules/websockets/websocket_handle_impl.h b/third_party/blink/renderer/modules/websockets/websocket_handle_impl.h
index 5354633..1548405c 100644
--- a/third_party/blink/renderer/modules/websockets/websocket_handle_impl.h
+++ b/third_party/blink/renderer/modules/websockets/websocket_handle_impl.h
@@ -72,10 +72,13 @@
       network::mojom::blink::WebSocketHandshakeRequestPtr) override;
   void OnResponseReceived(
       network::mojom::blink::WebSocketHandshakeResponsePtr) override;
-  void OnConnectionEstablished(network::mojom::blink::WebSocketPtr websocket,
-                               const String& selected_protocol,
-                               const String& extensions,
-                               uint64_t receive_quota_threshold) override;
+  void OnConnectionEstablished(
+      network::mojom::blink::WebSocketPtr websocket,
+      mojo::PendingReceiver<network::mojom::blink::WebSocketClient>
+          client_receiver,
+      const String& selected_protocol,
+      const String& extensions,
+      uint64_t receive_quota_threshold) override;
   // network::mojom::blink::WebSocketClient methods:
   void OnDataFrame(bool fin,
                    network::mojom::blink::WebSocketMessageType,
@@ -90,7 +93,6 @@
   WeakPersistent<WebSocketChannelImpl> channel_;
 
   network::mojom::blink::WebSocketPtr websocket_;
-  network::mojom::blink::WebSocketClientRequest pending_client_receiver_;
   mojo::Binding<network::mojom::blink::WebSocketHandshakeClient>
       handshake_client_binding_;
   mojo::Binding<network::mojom::blink::WebSocketClient> client_binding_;
diff --git a/third_party/blink/renderer/modules/worklet/worklet_thread_test_common.cc b/third_party/blink/renderer/modules/worklet/worklet_thread_test_common.cc
index 4adc63d..d46d14a 100644
--- a/third_party/blink/renderer/modules/worklet/worklet_thread_test_common.cc
+++ b/third_party/blink/renderer/modules/worklet/worklet_thread_test_common.cc
@@ -39,8 +39,7 @@
           base::UnguessableToken::Create(), nullptr /* worker_settings */,
           kV8CacheOptionsDefault,
           MakeGarbageCollected<WorkletModuleResponsesMap>()),
-      base::nullopt, std::make_unique<WorkerDevToolsParams>(),
-      ParentExecutionContextTaskRunners::Create());
+      base::nullopt, std::make_unique<WorkerDevToolsParams>());
   return thread;
 }
 
diff --git a/third_party/blink/renderer/platform/heap/heap_page.h b/third_party/blink/renderer/platform/heap/heap_page.h
index c2e2ef9..cd5543c0 100644
--- a/third_party/blink/renderer/platform/heap/heap_page.h
+++ b/third_party/blink/renderer/platform/heap/heap_page.h
@@ -1212,7 +1212,8 @@
   }
   internal::AsanUnpoisonScope unpoison_scope(
       static_cast<const void*>(&encoded_low_), sizeof(encoded_low_));
-  auto* atomic_encoded = reinterpret_cast<std::atomic<uint16_t>*>(encoded_low_);
+  auto* atomic_encoded =
+      reinterpret_cast<std::atomic<uint16_t>*>(&encoded_low_);
   uint16_t old_value = atomic_encoded->load(std::memory_order_relaxed);
   if (old_value & kHeaderMarkBitMask)
     return false;
diff --git a/third_party/blink/renderer/platform/heap/marking_visitor.cc b/third_party/blink/renderer/platform/heap/marking_visitor.cc
index da3561c..4a8c8ee2 100644
--- a/third_party/blink/renderer/platform/heap/marking_visitor.cc
+++ b/third_party/blink/renderer/platform/heap/marking_visitor.cc
@@ -106,7 +106,8 @@
   }
 
   // Mark and push trace callback.
-  header->Mark();
+  if (!header->TryMark<HeapObjectHeader::AccessMode::kAtomic>())
+    return;
   MarkingVisitor* visitor = thread_state->CurrentVisitor();
   visitor->AccountMarkedBytes(header);
   visitor->marking_worklist_.Push(
diff --git a/third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object.h b/third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object.h
index 1ebddbf0..6c77652 100644
--- a/third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object.h
+++ b/third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object.h
@@ -6,8 +6,8 @@
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_LOADER_FETCH_FETCH_CLIENT_SETTINGS_OBJECT_H_
 
 #include "base/optional.h"
+#include "services/network/public/mojom/ip_address_space.mojom-blink.h"
 #include "services/network/public/mojom/referrer_policy.mojom-blink.h"
-#include "third_party/blink/public/mojom/net/ip_address_space.mojom-blink.h"
 #include "third_party/blink/public/platform/web_insecure_request_policy.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
 #include "third_party/blink/renderer/platform/heap/heap.h"
@@ -78,7 +78,7 @@
       const = 0;
 
   // https://wicg.github.io/cors-rfc1918/#address-space
-  virtual mojom::IPAddressSpace GetAddressSpace() const = 0;
+  virtual network::mojom::IPAddressSpace GetAddressSpace() const = 0;
 
   // https://w3c.github.io/webappsec-upgrade-insecure-requests/#insecure-requests-policy
   virtual WebInsecureRequestPolicy GetInsecureRequestsPolicy() const = 0;
diff --git a/third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.cc b/third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.cc
index 6dc4434..a86ef0dd 100644
--- a/third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.cc
@@ -46,7 +46,7 @@
     const String& outgoing_referrer,
     HttpsState https_state,
     AllowedByNosniff::MimeTypeCheck mime_type_check_for_classic_worker_script,
-    mojom::IPAddressSpace address_space,
+    network::mojom::IPAddressSpace address_space,
     WebInsecureRequestPolicy insecure_requests_policy,
     InsecureNavigationsSet insecure_navigations_set,
     bool mixed_autoupgrade_opt_out)
diff --git a/third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.h b/third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.h
index cdc2c5f7..f594c709 100644
--- a/third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.h
+++ b/third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.h
@@ -36,7 +36,7 @@
       String outgoing_referrer,
       HttpsState https_state,
       AllowedByNosniff::MimeTypeCheck mime_type_check_for_classic_worker_script,
-      mojom::IPAddressSpace address_space,
+      network::mojom::IPAddressSpace address_space,
       WebInsecureRequestPolicy insecure_requests_policy,
       FetchClientSettingsObject::InsecureNavigationsSet
           insecure_navigations_set,
@@ -62,7 +62,7 @@
   const HttpsState https_state;
   const AllowedByNosniff::MimeTypeCheck
       mime_type_check_for_classic_worker_script;
-  const mojom::IPAddressSpace address_space;
+  const network::mojom::IPAddressSpace address_space;
   const WebInsecureRequestPolicy insecure_requests_policy;
   const FetchClientSettingsObject::InsecureNavigationsSet
       insecure_navigations_set;
@@ -96,7 +96,7 @@
       const String& outgoing_referrer,
       HttpsState https_state,
       AllowedByNosniff::MimeTypeCheck,
-      mojom::IPAddressSpace,
+      network::mojom::IPAddressSpace,
       WebInsecureRequestPolicy,
       InsecureNavigationsSet,
       bool mixed_autoupgrade_opt_out);
@@ -116,7 +116,7 @@
   }
   HttpsState GetHttpsState() const override { return https_state_; }
 
-  mojom::IPAddressSpace GetAddressSpace() const override {
+  network::mojom::IPAddressSpace GetAddressSpace() const override {
     return address_space_;
   }
 
@@ -158,7 +158,7 @@
   const HttpsState https_state_;
   const AllowedByNosniff::MimeTypeCheck
       mime_type_check_for_classic_worker_script_;
-  const mojom::IPAddressSpace address_space_;
+  const network::mojom::IPAddressSpace address_space_;
 
   const WebInsecureRequestPolicy insecure_requests_policy_;
   const InsecureNavigationsSet insecure_navigations_set_;
diff --git a/third_party/blink/renderer/platform/loader/fetch/null_resource_fetcher_properties.cc b/third_party/blink/renderer/platform/loader/fetch/null_resource_fetcher_properties.cc
index e9b7611..541caf3 100644
--- a/third_party/blink/renderer/platform/loader/fetch/null_resource_fetcher_properties.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/null_resource_fetcher_properties.cc
@@ -23,7 +23,7 @@
               String(),
               HttpsState::kNone,
               AllowedByNosniff::MimeTypeCheck::kStrict,
-              mojom::IPAddressSpace::kPublic,
+              network::mojom::IPAddressSpace::kPublic,
               kLeaveInsecureRequestsAlone,
               FetchClientSettingsObject::InsecureNavigationsSet(),
               false /* mixed_autoupgrade_opt_out */)) {}
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_properties_test.cc b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_properties_test.cc
index a914377..dfa5788 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_properties_test.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_properties_test.cc
@@ -16,7 +16,7 @@
 class DetachableResourceFetcherPropertiesTest : public testing::Test {
  public:
   const FetchClientSettingsObjectSnapshot& CreateFetchClientSettingsObject(
-      mojom::IPAddressSpace address_space) {
+      network::mojom::IPAddressSpace address_space) {
     return *MakeGarbageCollected<FetchClientSettingsObjectSnapshot>(
         KURL("https://example.com/foo.html"),
         KURL("https://example.com/foo.html"),
@@ -32,7 +32,7 @@
 
 TEST_F(DetachableResourceFetcherPropertiesTest, DetachWithDefaultValues) {
   const auto& original_client_settings_object =
-      CreateFetchClientSettingsObject(mojom::IPAddressSpace::kPublic);
+      CreateFetchClientSettingsObject(network::mojom::IPAddressSpace::kPublic);
   auto& properties = *MakeGarbageCollected<DetachableResourceFetcherProperties>(
       *MakeGarbageCollected<TestResourceFetcherProperties>(
           original_client_settings_object));
@@ -71,7 +71,7 @@
 
 TEST_F(DetachableResourceFetcherPropertiesTest, DetachWithNonDefaultValues) {
   const auto& original_client_settings_object =
-      CreateFetchClientSettingsObject(mojom::IPAddressSpace::kPublic);
+      CreateFetchClientSettingsObject(network::mojom::IPAddressSpace::kPublic);
   auto& original_properties =
       *MakeGarbageCollected<TestResourceFetcherProperties>(
           original_client_settings_object);
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_test.cc b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_test.cc
index 02c9fad..71e4e96a 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_test.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher_test.cc
@@ -95,7 +95,7 @@
 }
 
 const FetchClientSettingsObjectSnapshot& CreateFetchClientSettingsObject(
-    mojom::IPAddressSpace address_space) {
+    network::mojom::IPAddressSpace address_space) {
   return *MakeGarbageCollected<FetchClientSettingsObjectSnapshot>(
       KURL("https://example.com/foo.html"),
       KURL("https://example.com/foo.html"),
@@ -1111,9 +1111,9 @@
                {"http://127.0.0.1/", true, true, false},
                {"http://127.0.0.1:8000/", true, true, false}};
 
-  for (const auto address_space :
-       {mojom::IPAddressSpace::kPublic, mojom::IPAddressSpace::kPrivate,
-        mojom::IPAddressSpace::kLocal}) {
+  for (const auto address_space : {network::mojom::IPAddressSpace::kPublic,
+                                   network::mojom::IPAddressSpace::kPrivate,
+                                   network::mojom::IPAddressSpace::kLocal}) {
     auto* fetcher =
         CreateFetcher(*MakeGarbageCollected<TestResourceFetcherProperties>(
                           CreateFetchClientSettingsObject(address_space)),
@@ -1136,13 +1136,13 @@
         if (enabled) {
           bool expected;
           switch (address_space) {
-            case mojom::IPAddressSpace::kPublic:
+            case network::mojom::IPAddressSpace::kPublic:
               expected = test.is_external_expectation_public;
               break;
-            case mojom::IPAddressSpace::kPrivate:
+            case network::mojom::IPAddressSpace::kPrivate:
               expected = test.is_external_expectation_private;
               break;
-            case mojom::IPAddressSpace::kLocal:
+            case network::mojom::IPAddressSpace::kLocal:
               expected = test.is_external_expectation_local;
               break;
           }
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_request.cc b/third_party/blink/renderer/platform/loader/fetch/resource_request.cc
index b67b3f43..26d4d3d 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_request.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_request.cc
@@ -312,14 +312,16 @@
 }
 
 void ResourceRequest::SetExternalRequestStateFromRequestorAddressSpace(
-    mojom::IPAddressSpace requestor_space) {
-  static_assert(mojom::IPAddressSpace::kLocal < mojom::IPAddressSpace::kPrivate,
+    network::mojom::IPAddressSpace requestor_space) {
+  static_assert(network::mojom::IPAddressSpace::kLocal <
+                    network::mojom::IPAddressSpace::kPrivate,
                 "Local is inside Private");
-  static_assert(mojom::IPAddressSpace::kLocal < mojom::IPAddressSpace::kPublic,
+  static_assert(network::mojom::IPAddressSpace::kLocal <
+                    network::mojom::IPAddressSpace::kPublic,
                 "Local is inside Public");
-  static_assert(
-      mojom::IPAddressSpace::kPrivate < mojom::IPAddressSpace::kPublic,
-      "Private is inside Public");
+  static_assert(network::mojom::IPAddressSpace::kPrivate <
+                    network::mojom::IPAddressSpace::kPublic,
+                "Private is inside Public");
 
   // TODO(mkwst): This only checks explicit IP addresses. We'll have to move all
   // this up to //net and //content in order to have any real impact on gateway
@@ -329,11 +331,12 @@
     return;
   }
 
-  mojom::IPAddressSpace target_space = mojom::IPAddressSpace::kPublic;
+  network::mojom::IPAddressSpace target_space =
+      network::mojom::IPAddressSpace::kPublic;
   if (network_utils::IsReservedIPAddress(url_.Host()))
-    target_space = mojom::IPAddressSpace::kPrivate;
+    target_space = network::mojom::IPAddressSpace::kPrivate;
   if (SecurityOrigin::Create(url_)->IsLocalhost())
-    target_space = mojom::IPAddressSpace::kLocal;
+    target_space = network::mojom::IPAddressSpace::kLocal;
 
   is_external_request_ = requestor_space > target_space;
 }
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_request.h b/third_party/blink/renderer/platform/loader/fetch/resource_request.h
index d61a3c8..f51421e 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_request.h
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_request.h
@@ -37,8 +37,8 @@
 #include "services/metrics/public/cpp/ukm_source_id.h"
 #include "services/network/public/mojom/cors.mojom-blink.h"
 #include "services/network/public/mojom/fetch_api.mojom-blink.h"
+#include "services/network/public/mojom/ip_address_space.mojom-blink.h"
 #include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
-#include "third_party/blink/public/mojom/net/ip_address_space.mojom-blink.h"
 #include "third_party/blink/public/platform/resource_request_blocked_reason.h"
 #include "third_party/blink/public/platform/web_url_request.h"
 #include "third_party/blink/renderer/platform/loader/fetch/resource_load_priority.h"
@@ -323,7 +323,8 @@
 
   // https://wicg.github.io/cors-rfc1918/#external-request
   bool IsExternalRequest() const { return is_external_request_; }
-  void SetExternalRequestStateFromRequestorAddressSpace(mojom::IPAddressSpace);
+  void SetExternalRequestStateFromRequestorAddressSpace(
+      network::mojom::IPAddressSpace);
 
   network::mojom::CorsPreflightPolicy CorsPreflightPolicy() const {
     return cors_preflight_policy_;
diff --git a/third_party/blink/renderer/platform/loader/testing/test_resource_fetcher_properties.cc b/third_party/blink/renderer/platform/loader/testing/test_resource_fetcher_properties.cc
index f0682f4..62a3c3a 100644
--- a/third_party/blink/renderer/platform/loader/testing/test_resource_fetcher_properties.cc
+++ b/third_party/blink/renderer/platform/loader/testing/test_resource_fetcher_properties.cc
@@ -27,7 +27,7 @@
               String(),
               HttpsState::kNone,
               AllowedByNosniff::MimeTypeCheck::kStrict,
-              mojom::IPAddressSpace::kPublic,
+              network::mojom::IPAddressSpace::kPublic,
               kLeaveInsecureRequestsAlone,
               FetchClientSettingsObject::InsecureNavigationsSet(),
               false /* mixed_autoupgrade_opt_out */)) {}
diff --git a/third_party/blink/renderer/platform/loader/testing/web_url_loader_factory_with_mock.cc b/third_party/blink/renderer/platform/loader/testing/web_url_loader_factory_with_mock.cc
index 674b469..a7bc68fc 100644
--- a/third_party/blink/renderer/platform/loader/testing/web_url_loader_factory_with_mock.cc
+++ b/third_party/blink/renderer/platform/loader/testing/web_url_loader_factory_with_mock.cc
@@ -18,7 +18,7 @@
 std::unique_ptr<WebURLLoader> WebURLLoaderFactoryWithMock::CreateURLLoader(
     const WebURLRequest& request,
     std::unique_ptr<blink::scheduler::WebResourceLoadingTaskRunnerHandle>) {
-  return mock_factory_->CreateURLLoader(nullptr);
+  return mock_factory_->CreateURLLoader();
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 91a93119..f261ce3d 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -1343,6 +1343,7 @@
     },
     {
       name: "RestrictedWebkitAppearance",
+      status: "experimental",
     },
     {
       name: "RtcAudioJitterBufferMaxPackets",
diff --git a/third_party/blink/renderer/platform/testing/weburl_loader_mock.cc b/third_party/blink/renderer/platform/testing/weburl_loader_mock.cc
index f11d1d3..49f71b9 100644
--- a/third_party/blink/renderer/platform/testing/weburl_loader_mock.cc
+++ b/third_party/blink/renderer/platform/testing/weburl_loader_mock.cc
@@ -17,21 +17,8 @@
 
 namespace blink {
 
-namespace {
-
-void AssertFallbackLoaderAvailability(const WebURL& url,
-                                      const WebURLLoader* default_loader) {
-  DCHECK(KURL(url).ProtocolIsData())
-      << "shouldn't be falling back: " << url.GetString().Utf8();
-  DCHECK(default_loader) << "default_loader wasn't set: "
-                         << url.GetString().Utf8();
-}
-
-}  // namespace
-
-WebURLLoaderMock::WebURLLoaderMock(WebURLLoaderMockFactoryImpl* factory,
-                                   std::unique_ptr<WebURLLoader> default_loader)
-    : factory_(factory), default_loader_(std::move(default_loader)) {}
+WebURLLoaderMock::WebURLLoaderMock(WebURLLoaderMockFactoryImpl* factory)
+    : factory_(factory) {}
 
 WebURLLoaderMock::~WebURLLoaderMock() {
   Cancel();
@@ -42,7 +29,6 @@
     const WebURLResponse& response,
     const WebData& data,
     const base::Optional<WebURLError>& error) {
-  DCHECK(!using_default_loader_);
   if (!client_)
     return;
 
@@ -115,47 +101,26 @@
     int64_t& encoded_data_length,
     int64_t& encoded_body_length,
     blink::WebBlobInfo& downloaded_blob) {
-  if (factory_->IsMockedURL(request.Url())) {
-    factory_->LoadSynchronously(request, &response, &error, &data,
-                                &encoded_data_length);
-    return;
-  }
-  AssertFallbackLoaderAvailability(request.Url(), default_loader_.get());
-  using_default_loader_ = true;
-  default_loader_->LoadSynchronously(request, client, response, error, data,
-                                     encoded_data_length, encoded_body_length,
-                                     downloaded_blob);
+  DCHECK(factory_->IsMockedURL(request.Url()));
+  factory_->LoadSynchronously(request, &response, &error, &data,
+                              &encoded_data_length);
 }
 
 void WebURLLoaderMock::LoadAsynchronously(const WebURLRequest& request,
                                           WebURLLoaderClient* client) {
   DCHECK(client);
-  if (factory_->IsMockedURL(request.Url())) {
-    client_ = client;
-    factory_->LoadAsynchronouly(request, this);
-    return;
-  }
-  AssertFallbackLoaderAvailability(request.Url(), default_loader_.get());
-  using_default_loader_ = true;
-  default_loader_->LoadAsynchronously(request, client);
+  DCHECK(factory_->IsMockedURL(request.Url()));
+  client_ = client;
+  factory_->LoadAsynchronouly(request, this);
 }
 
 void WebURLLoaderMock::Cancel() {
-  if (using_default_loader_ && default_loader_) {
-    default_loader_.reset();
-    return;
-  }
   client_ = nullptr;
   factory_->CancelLoad(this);
 }
 
 void WebURLLoaderMock::SetDefersLoading(bool deferred) {
   is_deferred_ = deferred;
-  if (using_default_loader_) {
-    default_loader_->SetDefersLoading(deferred);
-    return;
-  }
-
   // Ignores setDefersLoading(false) safely.
   if (!deferred)
     return;
diff --git a/third_party/blink/renderer/platform/testing/weburl_loader_mock.h b/third_party/blink/renderer/platform/testing/weburl_loader_mock.h
index e5e74f8..45d418e 100644
--- a/third_party/blink/renderer/platform/testing/weburl_loader_mock.h
+++ b/third_party/blink/renderer/platform/testing/weburl_loader_mock.h
@@ -29,9 +29,7 @@
 // forwards it to the default loader.
 class WebURLLoaderMock : public WebURLLoader {
  public:
-  // This object becomes the owner of |default_loader|.
-  WebURLLoaderMock(WebURLLoaderMockFactoryImpl* factory,
-                   std::unique_ptr<WebURLLoader> default_loader);
+  explicit WebURLLoaderMock(WebURLLoaderMockFactoryImpl* factory);
   ~WebURLLoaderMock() override;
 
   // Simulates the asynchronous request being served.
@@ -70,8 +68,6 @@
 
   WebURLLoaderMockFactoryImpl* factory_ = nullptr;
   WebURLLoaderClient* client_ = nullptr;
-  std::unique_ptr<WebURLLoader> default_loader_;
-  bool using_default_loader_ = false;
   bool is_deferred_ = false;
 
   base::WeakPtrFactory<WebURLLoaderMock> weak_factory_{this};
diff --git a/third_party/blink/renderer/platform/testing/weburl_loader_mock_factory_impl.cc b/third_party/blink/renderer/platform/testing/weburl_loader_mock_factory_impl.cc
index 5ec2fd4a..e27fe6d 100644
--- a/third_party/blink/renderer/platform/testing/weburl_loader_mock_factory_impl.cc
+++ b/third_party/blink/renderer/platform/testing/weburl_loader_mock_factory_impl.cc
@@ -39,9 +39,8 @@
 
 WebURLLoaderMockFactoryImpl::~WebURLLoaderMockFactoryImpl() = default;
 
-std::unique_ptr<WebURLLoader> WebURLLoaderMockFactoryImpl::CreateURLLoader(
-    std::unique_ptr<WebURLLoader> default_loader) {
-  return std::make_unique<WebURLLoaderMock>(this, std::move(default_loader));
+std::unique_ptr<WebURLLoader> WebURLLoaderMockFactoryImpl::CreateURLLoader() {
+  return std::make_unique<WebURLLoaderMock>(this);
 }
 
 void WebURLLoaderMockFactoryImpl::RegisterURL(const WebURL& url,
diff --git a/third_party/blink/renderer/platform/testing/weburl_loader_mock_factory_impl.h b/third_party/blink/renderer/platform/testing/weburl_loader_mock_factory_impl.h
index 1eb5bc1e..2af483e 100644
--- a/third_party/blink/renderer/platform/testing/weburl_loader_mock_factory_impl.h
+++ b/third_party/blink/renderer/platform/testing/weburl_loader_mock_factory_impl.h
@@ -35,8 +35,7 @@
   ~WebURLLoaderMockFactoryImpl() override;
 
   // WebURLLoaderMockFactory:
-  std::unique_ptr<WebURLLoader> CreateURLLoader(
-      std::unique_ptr<WebURLLoader> default_loader) override;
+  std::unique_ptr<WebURLLoader> CreateURLLoader() override;
   void RegisterURL(const WebURL& url,
                    const WebURLResponse& response,
                    const WebString& file_path = WebString()) override;
diff --git a/third_party/blink/web_tests/device_orientation/orientation/absolute-fallback.html b/third_party/blink/web_tests/device_orientation/orientation/absolute-fallback.html
index 7b17a41..7da9b4b 100644
--- a/third_party/blink/web_tests/device_orientation/orientation/absolute-fallback.html
+++ b/third_party/blink/web_tests/device_orientation/orientation/absolute-fallback.html
@@ -15,7 +15,7 @@
 
   // Make the relative orientation sensor unavailable and set mock data for
   // the absolute one.
-  sensorProvider.setGetSensorShouldFail('RelativeOrientationEulerAngles', true);
+  sensorProvider.getSensorTypeSettings('RelativeOrientationEulerAngles').unavailable = true;
   setMockOrientationData(sensorProvider, orientationData);
   return waitForOrientation(orientationData);
 }, 'Tests that deviceorientation falls back to using absolute orientation data if relative is unavailable.');
diff --git a/third_party/blink/web_tests/external/wpt/css/css-contain/contain-size-replaced-004-ref.html b/third_party/blink/web_tests/external/wpt/css/css-contain/contain-size-replaced-004-ref.html
new file mode 100644
index 0000000..eba5e8c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-contain/contain-size-replaced-004-ref.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Reference: Size containment replaced elements intrinsic size</title>
+<style>
+  body > div, video, audio, img, canvas, svg, iframe {
+    border: 3px solid orange;
+    contain: size;
+    margin-bottom: 15px;
+    width: 0px;
+    height: 0px;
+    float: left;
+    clear: both;
+  }
+</style>
+<div>abc</div>
+<video></video><br>
+<video controls></video><br>
+<img src="../support/60x60-green.png"><br>
+<picture>
+<source srcset="../support/60x60-green.png">
+    <img>
+</picture><br>
+<canvas></canvas><br>
+<svg></svg><br>
+<iframe></iframe>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-contain/contain-size-replaced-004.html b/third_party/blink/web_tests/external/wpt/css/css-contain/contain-size-replaced-004.html
new file mode 100644
index 0000000..511edadc
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-contain/contain-size-replaced-004.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Size containment replaced elements intrinsic size</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-size">
+<link rel="match" href="contain-size-replaced-004-ref.html">
+<meta name=assert content="This test checks that intrinsic size of replaced elements with 'contain: size' is zero.">
+<style>
+  body > div, video, audio, img, canvas, svg, iframe {
+    border: 3px solid orange;
+    contain: size;
+    margin-bottom: 15px;
+    width: min-content;
+    height: min-content;
+    float: left;
+    clear: both;
+  }
+</style>
+<div>abc</div>
+<video></video><br>
+<video controls></video><br>
+<img src="../support/60x60-green.png"><br>
+<picture>
+<source srcset="../support/60x60-green.png">
+    <img>
+</picture><br>
+<canvas></canvas><br>
+<svg></svg><br>
+<iframe></iframe>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-contain/contain-size-replaced-005-ref.html b/third_party/blink/web_tests/external/wpt/css/css-contain/contain-size-replaced-005-ref.html
new file mode 100644
index 0000000..a5328c7
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-contain/contain-size-replaced-005-ref.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Reference: Size containment replaced elements intrinsic size</title>
+<style>
+  body > div, video, audio, img, canvas, svg, iframe {
+    position: absolute;
+    border: 3px solid orange;
+    contain: size;
+    margin-bottom: 15px;
+    width: 0px;
+    height: 0px;
+    float: left;
+    clear: both;
+  }
+</style>
+<div>abc</div>
+<video></video><br>
+<video controls></video><br>
+<img src="../support/60x60-green.png"><br>
+<picture>
+<source srcset="../support/60x60-green.png">
+    <img>
+</picture><br>
+<canvas></canvas><br>
+<svg></svg><br>
+<iframe></iframe>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-contain/contain-size-replaced-005.html b/third_party/blink/web_tests/external/wpt/css/css-contain/contain-size-replaced-005.html
new file mode 100644
index 0000000..e889dcc
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-contain/contain-size-replaced-005.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Size containment replaced elements intrinsic size</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-size">
+<link rel="match" href="contain-size-replaced-005-ref.html">
+<meta name=assert content="This test checks that intrinsic size of out-of-flow replaced elements with 'contain: size' is zero.">
+<style>
+  body > div, video, audio, img, canvas, svg, iframe {
+    position: absolute;
+    border: 3px solid orange;
+    contain: size;
+    margin-bottom: 15px;
+    width: min-content;
+    height: min-content;
+    float: left;
+    clear: both;
+  }
+</style>
+<div>abc</div>
+<video></video><br>
+<video controls></video><br>
+<img src="../support/60x60-green.png"><br>
+<picture>
+<source srcset="../support/60x60-green.png">
+    <img>
+</picture><br>
+<canvas></canvas><br>
+<svg></svg><br>
+<iframe></iframe>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-contain/contain-size-replaced-006-ref.html b/third_party/blink/web_tests/external/wpt/css/css-contain/contain-size-replaced-006-ref.html
new file mode 100644
index 0000000..2f638d7
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-contain/contain-size-replaced-006-ref.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Reference: Size containment replaced elements intrinsic size</title>
+<style>
+  body > div, video, audio, img, canvas, svg, iframe {
+    border: 3px solid orange;
+    contain: size;
+    margin-bottom: 15px;
+    width: 25px;
+    height: 35px;
+    float: left;
+    clear: both;
+  }
+</style>
+<div>abc</div>
+<video></video><br>
+<video controls></video><br>
+<img src="../support/60x60-green.png"><br>
+<picture>
+<source srcset="../support/60x60-green.png">
+    <img>
+</picture><br>
+<canvas></canvas><br>
+<svg></svg><br>
+<iframe></iframe>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-contain/contain-size-replaced-006.html b/third_party/blink/web_tests/external/wpt/css/css-contain/contain-size-replaced-006.html
new file mode 100644
index 0000000..dccb799
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-contain/contain-size-replaced-006.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Size containment replaced elements intrinsic size</title>
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-size">
+<link rel="match" href="contain-size-replaced-006-ref.html">
+<meta name=assert content="This test checks that min-width/min-height of replaced elements with 'contain: size' works.">
+<style>
+  body > div, video, audio, img, canvas, svg, iframe {
+    border: 3px solid orange;
+    contain: size;
+    margin-bottom: 15px;
+    min-width: 25px;
+    min-height: 35px;
+    width: min-content;
+    height: min-content;
+    float: left;
+    clear: both;
+  }
+</style>
+<div>abc</div>
+<video></video><br>
+<video controls></video><br>
+<img src="../support/60x60-green.png"><br>
+<picture>
+<source srcset="../support/60x60-green.png">
+    <img>
+</picture><br>
+<canvas></canvas><br>
+<svg></svg><br>
+<iframe></iframe>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-lists/list-and-margin-collapse-003.html b/third_party/blink/web_tests/external/wpt/css/css-lists/list-and-margin-collapse-003.html
deleted file mode 100644
index 78dcbc6..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-lists/list-and-margin-collapse-003.html
+++ /dev/null
@@ -1,39 +0,0 @@
-<!DOCTYPE html>
-<meta charset="utf-8">
-<title>CSS Lists: test the margin collapse of marker</title>
-<link rel=help href="https://www.w3.org/TR/CSS22/generate.html#lists">
-<link rel="help" href="http://crbug.com/969741">
-
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-
-<style type="text/css">
-.checkbox{
-  -moz-appearance: checkbox;
-  -webkit-appearance: checkbox;
-  height: 0px;
-}
-</style>
-
-<div id="log"></div>
-
-<div id="target_with_marker" style="overflow:hidden; width:100px;">
-  <div style="margin-bottom:100px;"></div>
-  <div style="display:list-item; margin-left:100px; height:0px;"><div class="checkbox"></div></div>
-  <div style="margin-top:100px;"></div>
-</div>
-
-<div id="target_without_marker" style="overflow:hidden; width:100px;">
-  <div style="margin-bottom:100px;"></div>
-  <div style="display:list-item; margin-left:100px; list-style:none;"><div class="checkbox"></div></div>
-  <div style="margin-top:100px;"></div>
-</div>
-
-<script>
-test(function() {
-  var height_with_marker = document.getElementById("target_with_marker").clientHeight;
-  assert_equals(height_with_marker, 200, "Should not allow margin-collapsing through if list is with marker.");
-  var height_without_marker = document.getElementById("target_without_marker").clientHeight;
-  assert_equals(height_without_marker, 100, "Should allow margin-collapsing through if list is without marker.");
-}, "list and margin collapse");
-</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-lists/list-and-margin-collapse-004.html b/third_party/blink/web_tests/external/wpt/css/css-lists/list-and-margin-collapse-004.html
deleted file mode 100644
index 4a92f8b..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-lists/list-and-margin-collapse-004.html
+++ /dev/null
@@ -1,23 +0,0 @@
-<!DOCTYPE html>
-<title>Test if it doesn't crash when resolving BFC block-offset abort</title>
-<link rel=help href="https://www.w3.org/TR/CSS22/generate.html#lists">
-<link rel="help" href="http://crbug.com/969741">
-
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<style type="text/css">
-#checkbox{
-  -moz-appearance: checkbox;
-  -webkit-appearance: checkbox;
-  height: 0px;
-}
-</style>
-<body>
-  <div style="float: left; width: 100px; height: 100px;"></div>
-  <div style="display: list-item;">
-    <div id="checkbox"></div>
-  </div>
-<script>
-test(() => {}, "Layout should not crash");
-</script>
-</body>
diff --git a/third_party/blink/web_tests/fast/css/invalid-appearance-expected.txt b/third_party/blink/web_tests/fast/css/invalid-appearance-expected.txt
deleted file mode 100644
index 0b0fcb3..0000000
--- a/third_party/blink/web_tests/fast/css/invalid-appearance-expected.txt
+++ /dev/null
@@ -1,26 +0,0 @@
-CONSOLE WARNING: '-webkit-appearance: checkbox' for elements other than input[type=checkbox] is deprecated and will be removed in M79, around December 2019. See https://www.chromestatus.com/features/5070237827334144 for more details.
-CONSOLE WARNING: '-webkit-appearance: radio' for elements other than input[type=radio] is deprecated and will be removed in M79, around December 2019. See https://www.chromestatus.com/features/5070237827334144 for more details.
-CONSOLE WARNING: '-webkit-appearance: push-button' for elements other than input[type=button], input[type=reset], and input[type=submit] is deprecated and will be removed in M79, around December 2019. See https://www.chromestatus.com/features/5070237827334144 for more details.
-CONSOLE WARNING: '-webkit-appearance: square-button' for elements other than input[type=color] is deprecated and will be removed in M79, around December 2019. See https://www.chromestatus.com/features/5070237827334144 for more details.
-CONSOLE WARNING: '-webkit-appearance: button' for a is deprecated and will be removed in M79, around December 2019. See https://www.chromestatus.com/features/5070237827334144 for more details.
-CONSOLE WARNING: '-webkit-appearance: button' for drop-down box select is deprecated and will be removed in M79, around December 2019. See https://www.chromestatus.com/features/5070237827334144 for more details.
-CONSOLE WARNING: '-webkit-appearance: inner-spin-button' for elements other than :-webkit-inner-spin-button is deprecated and will be removed in M79, around December 2019. See https://www.chromestatus.com/features/5070237827334144 for more details.
-CONSOLE WARNING: '-webkit-appearance: listbox' for elements other than listbox select is deprecated and will be removed in M79, around December 2019. See https://www.chromestatus.com/features/5070237827334144 for more details.
-CONSOLE WARNING: '-webkit-appearance: menulist' for elements other than select and input[type=color][list] is deprecated and will be removed in M79, around December 2019. See https://www.chromestatus.com/features/5070237827334144 for more details.
-CONSOLE WARNING: '-webkit-appearance: menulist-button' for elements other than select and input[type=color][list] is deprecated and will be removed in M79, around December 2019. See https://www.chromestatus.com/features/5070237827334144 for more details.
-CONSOLE WARNING: '-webkit-appearance: meter' for elements other than meter is deprecated and will be removed in M79, around December 2019. See https://www.chromestatus.com/features/5070237827334144 for more details.
-CONSOLE WARNING: '-webkit-appearance: progress-bar' for elements other than progress is deprecated and will be removed in M79, around December 2019. See https://www.chromestatus.com/features/5070237827334144 for more details.
-CONSOLE WARNING: '-webkit-appearance: slider-horizontal' for elements other than input[type=range] is deprecated and will be removed in M79, around December 2019. See https://www.chromestatus.com/features/5070237827334144 for more details.
-CONSOLE WARNING: '-webkit-appearance: slider-vertical' for elements other than input[type=range] is deprecated and will be removed in M79, around December 2019. See https://www.chromestatus.com/features/5070237827334144 for more details.
-CONSOLE WARNING: '-webkit-appearance: sliderthumb-horizontal' for elements other than ::-webkit-slider-thumb and ::-webkit-media-slider-thumb is deprecated and will be removed in M79, around December 2019. See https://www.chromestatus.com/features/5070237827334144 for more details.
-CONSOLE WARNING: '-webkit-appearance: sliderthumb-vertical' for elements other than ::-webkit-slider-thumb and ::-webkit-media-slider-thumb is deprecated and will be removed in M79, around December 2019. See https://www.chromestatus.com/features/5070237827334144 for more details.
-CONSOLE WARNING: '-webkit-appearance: searchfield' for elements other than input[type=search] is deprecated and will be removed in M79, around December 2019. See https://www.chromestatus.com/features/5070237827334144 for more details.
-CONSOLE WARNING: '-webkit-appearance: searchfield-cancel-button' for elements other than ::-webkit-clear-button and ::-webkit-search-cancel-button is deprecated and will be removed in M79, around December 2019. See https://www.chromestatus.com/features/5070237827334144 for more details.
-CONSOLE WARNING: '-webkit-appearance: textfield' for elements other than input[type=email], input[type=number], input[type=password], input[type=search], input[type=tel], input[type=text], input[type=url], input[type=date], input[type=datetime-local], input[type=month], input[type=time], and input[type=week] is deprecated and will be removed in M79, around December 2019. See https://www.chromestatus.com/features/5070237827334144 for more details.
-CONSOLE WARNING: '-webkit-appearance: textarea' for elements other than textarea is deprecated and will be removed in M79, around December 2019. See https://www.chromestatus.com/features/5070237827334144 for more details.
-
-
-
-See if we have deprecation messages for -webkit-appearance.
-
-         menulist           
diff --git a/third_party/blink/web_tests/fast/css/invalid-appearance-progress-bar-meter-expected.txt b/third_party/blink/web_tests/fast/css/invalid-appearance-progress-bar-meter-expected.txt
index 3b5f382..7554c0d 100644
--- a/third_party/blink/web_tests/fast/css/invalid-appearance-progress-bar-meter-expected.txt
+++ b/third_party/blink/web_tests/fast/css/invalid-appearance-progress-bar-meter-expected.txt
@@ -1,5 +1,3 @@
-CONSOLE WARNING: '-webkit-appearance: progress-bar' for elements other than progress is deprecated and will be removed in M79, around December 2019. See https://www.chromestatus.com/features/5070237827334144 for more details.
-CONSOLE WARNING: '-webkit-appearance: meter' for elements other than meter is deprecated and will be removed in M79, around December 2019. See https://www.chromestatus.com/features/5070237827334144 for more details.
 PASS if it doesn't crash. See Bug 40158.
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
diff --git a/third_party/blink/web_tests/fast/css/invalid-appearance.html b/third_party/blink/web_tests/fast/css/invalid-appearance.html
deleted file mode 100644
index 266bc8e36..0000000
--- a/third_party/blink/web_tests/fast/css/invalid-appearance.html
+++ /dev/null
@@ -1,39 +0,0 @@
-<!DOCTYPE html>
-<style>
-span, a {
-  display: inline-block;
-  width: 1em;
-  height: 1em;
-}
-</style>
-<body>
-<br>
-<p>See if we have deprecation messages for -webkit-appearance.</p>
-
-<span style="-webkit-appearance: checkbox"></span>
-<span style="-webkit-appearance: radio"></span>
-<span style="-webkit-appearance: push-button"></span>
-<span style="-webkit-appearance: square-button"></span>
-<a style="-webkit-appearance: button"></a>
-<select style="-webkit-appearance: button"></select>
-<span style="-webkit-appearance: inner-spin-button"></span>
-<select style="-webkit-appearance: listbox"></select>
-<span style="-webkit-appearance: listbox"></span>
-<!-- font and height are necessary to avoid fallback to 'menulist-button'. -->
-<span style="-webkit-appearance: menulist; font: -webkit-small-control; height: auto">menulist</span>
-<span style="-webkit-appearance: menulist-button"></span>
-<span style="-webkit-appearance: meter"></span>
-<span style="-webkit-appearance: progress-bar"></span>
-<span style="-webkit-appearance: slider-horizontal"></span>
-<span style="-webkit-appearance: slider-vertical"></span>
-<span style="-webkit-appearance: sliderthumb-horizontal"></span>
-<span style="-webkit-appearance: sliderthumb-vertical"></span>
-<span style="-webkit-appearance: searchfield"></span>
-<span style="-webkit-appearance: searchfield-cancel-button"></span>
-<textarea style="-webkit-appearance: textfield"></textarea>
-<input style="-webkit-appearance: textarea">
-
-<script>
-testRunner.dumpAsText();
-</script>
-</body>
diff --git a/third_party/blink/web_tests/fast/css/square-button-appearance-expected.txt b/third_party/blink/web_tests/fast/css/square-button-appearance-expected.txt
deleted file mode 100644
index b79d4d4..0000000
--- a/third_party/blink/web_tests/fast/css/square-button-appearance-expected.txt
+++ /dev/null
@@ -1 +0,0 @@
-CONSOLE WARNING: '-webkit-appearance: square-button' for elements other than input[type=color] is deprecated and will be removed in M79, around December 2019. See https://www.chromestatus.com/features/5070237827334144 for more details.
diff --git a/third_party/blink/web_tests/fast/css/square-button-appearance.html b/third_party/blink/web_tests/fast/css/square-button-appearance.html
deleted file mode 100644
index 20927f9..0000000
--- a/third_party/blink/web_tests/fast/css/square-button-appearance.html
+++ /dev/null
@@ -1,20 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<script>
-enablePixelTesting = true;
-</script>
-<script src="../resources/js-test.js"></script>
-<style>
-.squarebutton {
-    -webkit-appearance: square-button;
-    width: 100px;
-    height: 100px;
-}
-</style>
-</head>
-<body>
-<!-- Test if square-button appearance is rendered properly. -->
-<div class="squarebutton"></div>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/fast/forms/datalist/slider-appearance-with-ticks-crash-expected.txt b/third_party/blink/web_tests/fast/forms/datalist/slider-appearance-with-ticks-crash-expected.txt
index 46fd5e2..fa7b04eb 100644
--- a/third_party/blink/web_tests/fast/forms/datalist/slider-appearance-with-ticks-crash-expected.txt
+++ b/third_party/blink/web_tests/fast/forms/datalist/slider-appearance-with-ticks-crash-expected.txt
@@ -1,5 +1,3 @@
-CONSOLE WARNING: '-webkit-appearance: slider-vertical' for elements other than input[type=range] is deprecated and will be removed in M79, around December 2019. See https://www.chromestatus.com/features/5070237827334144 for more details.
-CONSOLE WARNING: '-webkit-appearance: slider-horizontal' for elements other than input[type=range] is deprecated and will be removed in M79, around December 2019. See https://www.chromestatus.com/features/5070237827334144 for more details.
 No crash means test PASS.
 
  
diff --git a/third_party/blink/web_tests/fast/forms/file/file-style-inheritance-expected.txt b/third_party/blink/web_tests/fast/forms/file/file-style-inheritance-expected.txt
index fb18d613..603cfea 100644
--- a/third_party/blink/web_tests/fast/forms/file/file-style-inheritance-expected.txt
+++ b/third_party/blink/web_tests/fast/forms/file/file-style-inheritance-expected.txt
@@ -1,4 +1,3 @@
-CONSOLE WARNING: '-webkit-appearance: square-button' for elements other than input[type=color] is deprecated and will be removed in M79, around December 2019. See https://www.chromestatus.com/features/5070237827334144 for more details.
 Tests internal components of a file upload control correctly inherit the style of the container input element.
 
 PASS document.defaultView.getComputedStyle(button1, null).getPropertyValue("font-size") is "30px"
diff --git a/third_party/blink/web_tests/fast/forms/file/file-style-inheritance.html b/third_party/blink/web_tests/fast/forms/file/file-style-inheritance.html
index 57ba9f4..f2614ef 100644
--- a/third_party/blink/web_tests/fast/forms/file/file-style-inheritance.html
+++ b/third_party/blink/web_tests/fast/forms/file/file-style-inheritance.html
@@ -5,8 +5,8 @@
     font-size: 30px;
 }
 #large::-webkit-file-upload-button {
-    /* Uses square-button for ease of testing on Mac. */
-    -webkit-appearance: square-button;
+    /* Uses none for ease of testing on Mac. */
+    -webkit-appearance: none;
 }
 
 #dark {
diff --git a/third_party/blink/web_tests/fast/forms/range/slider-appearance-crash-expected.txt b/third_party/blink/web_tests/fast/forms/range/slider-appearance-crash-expected.txt
index e859cec7..67c7060b 100644
--- a/third_party/blink/web_tests/fast/forms/range/slider-appearance-crash-expected.txt
+++ b/third_party/blink/web_tests/fast/forms/range/slider-appearance-crash-expected.txt
@@ -1,2 +1 @@
-CONSOLE WARNING: '-webkit-appearance: slider-horizontal' for elements other than input[type=range] is deprecated and will be removed in M79, around December 2019. See https://www.chromestatus.com/features/5070237827334144 for more details.
 Checks that slider appearance on regular node doesn't crash.
diff --git a/third_party/blink/web_tests/fast/forms/range/thumbslider-crash-expected.txt b/third_party/blink/web_tests/fast/forms/range/thumbslider-crash-expected.txt
index 409b565..544f49a 100644
--- a/third_party/blink/web_tests/fast/forms/range/thumbslider-crash-expected.txt
+++ b/third_party/blink/web_tests/fast/forms/range/thumbslider-crash-expected.txt
@@ -1,2 +1 @@
-CONSOLE WARNING: '-webkit-appearance: sliderthumb-horizontal' for elements other than ::-webkit-slider-thumb and ::-webkit-media-slider-thumb is deprecated and will be removed in M79, around December 2019. See https://www.chromestatus.com/features/5070237827334144 for more details.
 PASS If this test does not crash. http://bugs.webkit.org/show_bug.cgi?id=12045
diff --git a/third_party/blink/web_tests/fast/forms/range/thumbslider-no-parent-slider-expected.html b/third_party/blink/web_tests/fast/forms/range/thumbslider-no-parent-slider-expected.html
new file mode 100644
index 0000000..0e76edd6
--- /dev/null
+++ b/third_party/blink/web_tests/fast/forms/range/thumbslider-no-parent-slider-expected.html
@@ -0,0 +1 @@
+<!DOCTYPE html>
diff --git a/third_party/blink/web_tests/fast/forms/range/thumbslider-no-parent-slider-expected.txt b/third_party/blink/web_tests/fast/forms/range/thumbslider-no-parent-slider-expected.txt
deleted file mode 100644
index 5302387..0000000
--- a/third_party/blink/web_tests/fast/forms/range/thumbslider-no-parent-slider-expected.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-CONSOLE WARNING: '-webkit-appearance: sliderthumb-horizontal' for elements other than ::-webkit-slider-thumb and ::-webkit-media-slider-thumb is deprecated and will be removed in M79, around December 2019. See https://www.chromestatus.com/features/5070237827334144 for more details.
-CONSOLE WARNING: '-webkit-appearance: sliderthumb-vertical' for elements other than ::-webkit-slider-thumb and ::-webkit-media-slider-thumb is deprecated and will be removed in M79, around December 2019. See https://www.chromestatus.com/features/5070237827334144 for more details.
diff --git a/third_party/blink/web_tests/fast/forms/range/thumbslider-no-parent-slider.html b/third_party/blink/web_tests/fast/forms/range/thumbslider-no-parent-slider.html
index c28609bd..1fade9f 100644
--- a/third_party/blink/web_tests/fast/forms/range/thumbslider-no-parent-slider.html
+++ b/third_party/blink/web_tests/fast/forms/range/thumbslider-no-parent-slider.html
@@ -16,7 +16,7 @@
 </style>
 </head>
 <body>
-<!-- There should be a horizontal slider thumb and a vertical slider thumb. -->
+<!-- There should be nothing. -->
 <span id="thumbHorizontal"></span><br>
 <span id="thumbVertical"></span>
 </body>
diff --git a/third_party/blink/web_tests/fast/text/whitespace/pre-block-normal-inline-crash-2-expected.txt b/third_party/blink/web_tests/fast/text/whitespace/pre-block-normal-inline-crash-2-expected.txt
index 0d382bc..97296481 100644
--- a/third_party/blink/web_tests/fast/text/whitespace/pre-block-normal-inline-crash-2-expected.txt
+++ b/third_party/blink/web_tests/fast/text/whitespace/pre-block-normal-inline-crash-2-expected.txt
@@ -1,2 +1 @@
-CONSOLE WARNING: '-webkit-appearance: sliderthumb-vertical' for elements other than ::-webkit-slider-thumb and ::-webkit-media-slider-thumb is deprecated and will be removed in M79, around December 2019. See https://www.chromestatus.com/features/5070237827334144 for more details.
 This test passes if it does not CRASH.
diff --git a/third_party/blink/web_tests/http/tests/resources/sensor-helpers.js b/third_party/blink/web_tests/http/tests/resources/sensor-helpers.js
index 20a8bd0e..fca19e5b 100644
--- a/third_party/blink/web_tests/http/tests/resources/sensor-helpers.js
+++ b/third_party/blink/web_tests/http/tests/resources/sensor-helpers.js
@@ -30,11 +30,17 @@
       });
     }
 
+    // device.mojom.Sensor implementation
+    // Mojo functions that return a value must be async and return an object
+    // whose keys match the names declared in Mojo.
+
+    // GetDefaultConfiguration() => (SensorConfiguration configuration)
     // Returns default configuration.
     async getDefaultConfiguration() {
       return { frequency: DEFAULT_FREQUENCY };
     }
 
+    // AddConfiguration(SensorConfiguration configuration) => (bool success)
     // Adds configuration for the sensor and starts reporting fake data
     // through setSensorReading function.
     async addConfiguration(configuration) {
@@ -54,6 +60,7 @@
       return { success: !this.startShouldFail_ };
     }
 
+    // RemoveConfiguration(SensorConfiguration configuration)
     // Removes sensor configuration from the list of active configurations and
     // stops notification about sensor reading changes if
     // requestedFrequencies_ is empty.
@@ -71,7 +78,7 @@
         this.stopReading();
     }
 
-    // Suspends sensor.
+    // Suspend()
     suspend() {
       this.stopReading();
       if (this.suspendCalled_ != null) {
@@ -79,7 +86,7 @@
       }
     }
 
-    // Resumes sensor.
+    // Resume()
     resume() {
       assert_equals(this.sensorReadingTimerId_, null);
       this.startReading();
@@ -88,6 +95,13 @@
       }
     }
 
+    // ConfigureReadingChangeNotifications(bool enabled)
+    // Configures whether to report a reading change when in ON_CHANGE
+    // reporting mode.
+    configureReadingChangeNotifications(notifyOnReadingChange) {
+      this.notifyOnReadingChange_ = notifyOnReadingChange;
+    }
+
     // Mock functions
 
     // Resets mock Sensor state.
@@ -123,12 +137,6 @@
       this.startShouldFail_ = shouldFail;
     }
 
-    // Configures whether to report a reading change when in ON_CHANGE
-    // reporting mode.
-    configureReadingChangeNotifications(notifyOnReadingChange) {
-      this.notifyOnReadingChange_ = notifyOnReadingChange;
-    }
-
     // Returns resolved promise if suspend() was called, rejected otherwise.
     suspendCalled() {
       return new Promise(resolve => {
@@ -190,6 +198,63 @@
     }
   }
 
+  // This class aggregates information about a given sensor type that is used by
+  // MockSensorProvider when it is asked to create a new MockSensor.
+  class SensorTypeSettings {
+    constructor(mojoSensorType) {
+      this.mojoSensorType_ = mojoSensorType;
+      assert_true(device.mojom.SensorType.isKnownEnumValue(mojoSensorType));
+
+      this.shouldDenyRequests_ = false;
+      this.unavailable_ = false;
+    }
+
+    get mojoSensorType() {
+      return this.mojoSensorType_;
+    }
+
+    get shouldDenyRequests() {
+      return this.shouldDenyRequests_;
+    }
+
+    set shouldDenyRequests(deny) {
+      this.shouldDenyRequests_ = deny;
+    }
+
+    get unavailable() {
+      return this.unavailable_;
+    }
+
+    set unavailable(is_unavailable) {
+      this.unavailable_ = is_unavailable;
+    }
+  }
+
+  // Maps a given device.mojom.SensorType enum value to a suitable name as a
+  // string.
+  function getSensorTypeName(mojoSensorType) {
+    switch (mojoSensorType) {
+      case device.mojom.SensorType.ACCELEROMETER:
+        return 'Accelerometer';
+      case device.mojom.SensorType.LINEAR_ACCELERATION:
+        return 'LinearAccelerationSensor';
+      case device.mojom.SensorType.AMBIENT_LIGHT:
+        return 'AmbientLightSensor';
+      case device.mojom.SensorType.GYROSCOPE:
+        return 'Gyroscope';
+      case device.mojom.SensorType.MAGNETOMETER:
+        return 'Magnetometer';
+      case device.mojom.SensorType.ABSOLUTE_ORIENTATION_QUATERNION:
+        return 'AbsoluteOrientationSensor';
+      case device.mojom.SensorType.ABSOLUTE_ORIENTATION_EULER_ANGLES:
+        return 'AbsoluteOrientationEulerAngles';
+      case device.mojom.SensorType.RELATIVE_ORIENTATION_QUATERNION:
+        return 'RelativeOrientationSensor';
+      case device.mojom.SensorType.RELATIVE_ORIENTATION_EULER_ANGLES:
+        return 'RelativeOrientationEulerAngles';
+    }
+  }
+
   // Class that mocks SensorProvider interface defined in
   // sensor_provider.mojom
   class MockSensorProvider {
@@ -203,24 +268,11 @@
       this.sharedBufferHandle_ = rv.handle;
       this.activeSensors_ = new Map();
       this.resolveFuncs_ = new Map();
-      this.getSensorShouldFail_ = new Map();
-      this.permissionsDenied_ = new Map();
       this.isContinuous_ = false;
       this.maxFrequency_ = 60;
       this.minFrequency_ = 1;
-      this.mojomSensorType_ = new Map([
-        ['Accelerometer', device.mojom.SensorType.ACCELEROMETER],
-        ['LinearAccelerationSensor', device.mojom.SensorType.LINEAR_ACCELERATION],
-        ['AmbientLightSensor', device.mojom.SensorType.AMBIENT_LIGHT],
-        ['Gyroscope', device.mojom.SensorType.GYROSCOPE],
-        ['Magnetometer', device.mojom.SensorType.MAGNETOMETER],
-        ['AbsoluteOrientationSensor', device.mojom.SensorType.ABSOLUTE_ORIENTATION_QUATERNION],
-        ['AbsoluteOrientationEulerAngles', device.mojom.SensorType.ABSOLUTE_ORIENTATION_EULER_ANGLES],
-        ['RelativeOrientationSensor', device.mojom.SensorType.RELATIVE_ORIENTATION_QUATERNION],
-        ['RelativeOrientationEulerAngles', device.mojom.SensorType.RELATIVE_ORIENTATION_EULER_ANGLES]
-      ]);
+      this.resetSensorTypeSettings();
       this.binding_ = new mojo.Binding(device.mojom.SensorProvider, this);
-
       this.interceptor_ = new MojoInterfaceInterceptor(
           device.mojom.SensorProvider.name);
       this.interceptor_.oninterfacerequest = e => {
@@ -229,29 +281,36 @@
       this.interceptor_.start();
     }
 
+    // device.mojom.SensorProvider implementation
+    // Mojo functions that return a value must be async and return an object
+    // whose keys match the names declared in Mojo.
+
+    // GetSensor(SensorType type) => (SensorCreationResult result,
+    //                                SensorInitParams? init_params)
     // Returns initialized Sensor proxy to the client.
-    async getSensor(type) {
-      if (this.getSensorShouldFail_.get(type)) {
+    async getSensor(mojoSensorType) {
+      const sensorSettings = this.sensorTypeSettings_.get(getSensorTypeName(mojoSensorType));
+      if (sensorSettings.unavailable) {
         return {result: device.mojom.SensorCreationResult.ERROR_NOT_AVAILABLE,
                 initParams: null};
       }
-      if (this.permissionsDenied_.get(type)) {
+      if (sensorSettings.shouldDenyRequests) {
         return {result: device.mojom.SensorCreationResult.ERROR_NOT_ALLOWED,
                 initParams: null};
       }
 
-      const offset = type * this.readingSizeInBytes_;
+      const offset = mojoSensorType * this.readingSizeInBytes_;
       const reportingMode = this.isContinuous_ ?
           device.mojom.ReportingMode.CONTINUOUS :
           device.mojom.ReportingMode.ON_CHANGE;
 
       const sensorPtr = new device.mojom.SensorPtr();
-      if (!this.activeSensors_.has(type)) {
+      if (!this.activeSensors_.has(mojoSensorType)) {
         const mockSensor = new MockSensor(
             mojo.makeRequest(sensorPtr), this.sharedBufferHandle_, offset,
             this.readingSizeInBytes_, reportingMode);
-        this.activeSensors_.set(type, mockSensor);
-        this.activeSensors_.get(type).client_ = new device.mojom.SensorClientPtr();
+        this.activeSensors_.set(mojoSensorType, mockSensor);
+        this.activeSensors_.get(mojoSensorType).client_ = new device.mojom.SensorClientPtr();
       }
 
       const rv = this.sharedBufferHandle_.duplicateBufferHandle();
@@ -261,14 +320,14 @@
       const defaultConfig = { frequency: DEFAULT_FREQUENCY };
       // Consider sensor traits to meet assertions in C++ code (see
       // services/device/public/cpp/generic_sensor/sensor_traits.h)
-      if (type == device.mojom.SensorType.AMBIENT_LIGHT ||
-          type == device.mojom.SensorType.MAGNETOMETER) {
+      if (mojoSensorType == device.mojom.SensorType.AMBIENT_LIGHT ||
+          mojoSensorType == device.mojom.SensorType.MAGNETOMETER) {
         this.maxFrequency_ = Math.min(10, this.maxFrequency_);
       }
 
       const initParams = new device.mojom.SensorInitParams({
         sensor: sensorPtr,
-        clientRequest: mojo.makeRequest(this.activeSensors_.get(type).client_),
+        clientRequest: mojo.makeRequest(this.activeSensors_.get(mojoSensorType).client_),
         memory: rv.handle,
         bufferOffset: offset,
         mode: reportingMode,
@@ -277,11 +336,11 @@
         maximumFrequency: this.maxFrequency_
       });
 
-      if (this.resolveFuncs_.has(type)) {
-        for (let resolveFunc of this.resolveFuncs_.get(type)) {
-          resolveFunc(this.activeSensors_.get(type));
+      if (this.resolveFuncs_.has(mojoSensorType)) {
+        for (let resolveFunc of this.resolveFuncs_.get(mojoSensorType)) {
+          resolveFunc(this.activeSensors_.get(mojoSensorType));
         }
-        this.resolveFuncs_.delete(type);
+        this.resolveFuncs_.delete(mojoSensorType);
       }
 
       return {result: device.mojom.SensorCreationResult.SUCCESS,
@@ -298,6 +357,28 @@
 
     // Mock functions
 
+    // Returns a SensorTypeSettings instance corresponding to the name |type|, a
+    // string.
+    getSensorTypeSettings(type) {
+      return this.sensorTypeSettings_.get(type);
+    }
+
+    // Recreates |this.sensorTypeSettings_| with a new map and values reset to
+    // their defaults.
+    resetSensorTypeSettings() {
+      this.sensorTypeSettings_ = new Map([
+        ['Accelerometer', new SensorTypeSettings(device.mojom.SensorType.ACCELEROMETER)],
+        ['LinearAccelerationSensor', new SensorTypeSettings(device.mojom.SensorType.LINEAR_ACCELERATION)],
+        ['AmbientLightSensor', new SensorTypeSettings(device.mojom.SensorType.AMBIENT_LIGHT)],
+        ['Gyroscope', new SensorTypeSettings(device.mojom.SensorType.GYROSCOPE)],
+        ['Magnetometer', new SensorTypeSettings(device.mojom.SensorType.MAGNETOMETER)],
+        ['AbsoluteOrientationSensor', new SensorTypeSettings(device.mojom.SensorType.ABSOLUTE_ORIENTATION_QUATERNION)],
+        ['AbsoluteOrientationEulerAngles', new SensorTypeSettings(device.mojom.SensorType.ABSOLUTE_ORIENTATION_EULER_ANGLES)],
+        ['RelativeOrientationSensor', new SensorTypeSettings(device.mojom.SensorType.RELATIVE_ORIENTATION_QUATERNION)],
+        ['RelativeOrientationEulerAngles', new SensorTypeSettings(device.mojom.SensorType.RELATIVE_ORIENTATION_EULER_ANGLES)]
+      ]);
+    }
+
     // Resets state of mock SensorProvider between test runs.
     reset() {
       for (const sensor of this.activeSensors_.values()) {
@@ -305,8 +386,7 @@
       }
       this.activeSensors_.clear();
       this.resolveFuncs_.clear();
-      this.getSensorShouldFail_.clear();
-      this.permissionsDenied_.clear();
+      this.resetSensorTypeSettings();
       this.maxFrequency_ = 60;
       this.minFrequency_ = 1;
       this.isContinuous_ = false;
@@ -314,20 +394,9 @@
       this.interceptor_.stop();
     }
 
-    // Sets flag that forces mock SensorProvider to fail when getSensor() is
-    // invoked.
-    setGetSensorShouldFail(sensorType, shouldFail) {
-      this.getSensorShouldFail_.set(this.mojomSensorType_.get(sensorType), shouldFail);
-    }
-
-    setPermissionsDenied(sensorType, permissionsDenied) {
-      this.permissionsDenied_.set(this.mojomSensorType_.get(sensorType), permissionsDenied);
-    }
-
     // Returns mock sensor that was created in getSensor to the layout test.
-    getCreatedSensor(sensorType) {
-      const type = this.mojomSensorType_.get(sensorType);
-      assert_equals(typeof type, "number", "A sensor type must be specified.");
+    getCreatedSensor(sensorName) {
+      const type = this.sensorTypeSettings_.get(sensorName).mojoSensorType;
 
       if (this.activeSensors_.has(type)) {
         return Promise.resolve(this.activeSensors_.get(type));
diff --git a/third_party/blink/web_tests/paint/invalidation/selection/multiple-body-remove-selection-crash-expected.txt b/third_party/blink/web_tests/paint/invalidation/selection/multiple-body-remove-selection-crash-expected.txt
index 5d9c7d90..8b13789 100644
--- a/third_party/blink/web_tests/paint/invalidation/selection/multiple-body-remove-selection-crash-expected.txt
+++ b/third_party/blink/web_tests/paint/invalidation/selection/multiple-body-remove-selection-crash-expected.txt
@@ -1,2 +1 @@
-CONSOLE WARNING: '-webkit-appearance: radio' for elements other than input[type=radio] is deprecated and will be removed in M79, around December 2019. See https://www.chromestatus.com/features/5070237827334144 for more details.
 
diff --git a/third_party/blink/web_tests/paint/theme/anonymous-element-menulist-painting-expected.txt b/third_party/blink/web_tests/paint/theme/anonymous-element-menulist-painting-expected.txt
index a2a805d..8b13789 100644
--- a/third_party/blink/web_tests/paint/theme/anonymous-element-menulist-painting-expected.txt
+++ b/third_party/blink/web_tests/paint/theme/anonymous-element-menulist-painting-expected.txt
@@ -1,2 +1 @@
-CONSOLE WARNING: '-webkit-appearance: menulist-button' for elements other than select and input[type=color][list] is deprecated and will be removed in M79, around December 2019. See https://www.chromestatus.com/features/5070237827334144 for more details.
 
diff --git a/third_party/blink/web_tests/platform/linux/scrollbars/custom-scrollbar-appearance-property-expected.png b/third_party/blink/web_tests/platform/linux/scrollbars/custom-scrollbar-appearance-property-expected.png
deleted file mode 100644
index 00fb009..0000000
--- a/third_party/blink/web_tests/platform/linux/scrollbars/custom-scrollbar-appearance-property-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/prefer_compositing_to_lcd_text/scrollbars/custom-scrollbar-appearance-property-expected.png b/third_party/blink/web_tests/platform/linux/virtual/prefer_compositing_to_lcd_text/scrollbars/custom-scrollbar-appearance-property-expected.png
deleted file mode 100644
index 00fb009..0000000
--- a/third_party/blink/web_tests/platform/linux/virtual/prefer_compositing_to_lcd_text/scrollbars/custom-scrollbar-appearance-property-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/css/square-button-appearance-expected.png b/third_party/blink/web_tests/platform/mac/fast/css/square-button-appearance-expected.png
deleted file mode 100644
index 09079b0c..0000000
--- a/third_party/blink/web_tests/platform/mac/fast/css/square-button-appearance-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/fast/forms/range/thumbslider-no-parent-slider-expected.png b/third_party/blink/web_tests/platform/mac/fast/forms/range/thumbslider-no-parent-slider-expected.png
deleted file mode 100644
index 8be02db4..0000000
--- a/third_party/blink/web_tests/platform/mac/fast/forms/range/thumbslider-no-parent-slider-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/scrollbars/custom-scrollbar-appearance-property-expected.png b/third_party/blink/web_tests/platform/mac/scrollbars/custom-scrollbar-appearance-property-expected.png
deleted file mode 100644
index 5b0bf80..0000000
--- a/third_party/blink/web_tests/platform/mac/scrollbars/custom-scrollbar-appearance-property-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/css/square-button-appearance-expected.png b/third_party/blink/web_tests/platform/win/fast/css/square-button-appearance-expected.png
deleted file mode 100644
index 1cf171c..0000000
--- a/third_party/blink/web_tests/platform/win/fast/css/square-button-appearance-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/forms/range/thumbslider-no-parent-slider-expected.png b/third_party/blink/web_tests/platform/win/fast/forms/range/thumbslider-no-parent-slider-expected.png
deleted file mode 100644
index e835f608..0000000
--- a/third_party/blink/web_tests/platform/win/fast/forms/range/thumbslider-no-parent-slider-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/paint/theme/anonymous-element-menulist-painting-expected.txt b/third_party/blink/web_tests/platform/win/paint/theme/anonymous-element-menulist-painting-expected.txt
deleted file mode 100644
index df8487b..0000000
--- a/third_party/blink/web_tests/platform/win/paint/theme/anonymous-element-menulist-painting-expected.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-CONSOLE WARNING: '-webkit-appearance: menulist' for elements other than select and input[type=color][list] is deprecated and will be removed in M79, around December 2019. See https://www.chromestatus.com/features/5070237827334144 for more details.
-
diff --git a/third_party/blink/web_tests/platform/win/scrollbars/custom-scrollbar-appearance-property-expected.png b/third_party/blink/web_tests/platform/win/scrollbars/custom-scrollbar-appearance-property-expected.png
deleted file mode 100644
index b32d484..0000000
--- a/third_party/blink/web_tests/platform/win/scrollbars/custom-scrollbar-appearance-property-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/scrollbars/custom-scrollbar-appearance-property-expected.txt b/third_party/blink/web_tests/scrollbars/custom-scrollbar-appearance-property-expected.txt
deleted file mode 100644
index 1f3d28d..0000000
--- a/third_party/blink/web_tests/scrollbars/custom-scrollbar-appearance-property-expected.txt
+++ /dev/null
@@ -1 +0,0 @@
-CONSOLE WARNING: '-webkit-appearance: searchfield-cancel-button' for elements other than ::-webkit-clear-button and ::-webkit-search-cancel-button is deprecated and will be removed in M79, around December 2019. See https://www.chromestatus.com/features/5070237827334144 for more details.
diff --git a/third_party/blink/web_tests/scrollbars/custom-scrollbar-appearance-property.html b/third_party/blink/web_tests/scrollbars/custom-scrollbar-appearance-property.html
index dab9d67..3cc6fbf 100644
--- a/third_party/blink/web_tests/scrollbars/custom-scrollbar-appearance-property.html
+++ b/third_party/blink/web_tests/scrollbars/custom-scrollbar-appearance-property.html
@@ -1,6 +1,9 @@
 <!DOCTYPE html>
 <html>
 <head>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<script src="../resources/run-after-layout-and-paint.js"></script>
 <style>
 ::-webkit-scrollbar {
     width: 16px;
@@ -32,5 +35,10 @@
 <body>
 PASS if not crashed.
 <div class="scroll-container"><div class="overflowing"></div></div>
+<script>
+async_test(t => {
+  runAfterLayoutAndPaint(t.step_func_done(() => {}));
+}, 'Do not crash if -webkit-scrollbar* has -webkit-appearance:searchfield-cancel-button');
+</script>
 </body>
 </html>
diff --git a/third_party/blink/web_tests/sensor/resources/generic-sensor-tests.js b/third_party/blink/web_tests/sensor/resources/generic-sensor-tests.js
index f41d665..b270254 100644
--- a/third_party/blink/web_tests/sensor/resources/generic-sensor-tests.js
+++ b/third_party/blink/web_tests/sensor/resources/generic-sensor-tests.js
@@ -30,7 +30,7 @@
   }
 
   sensor_test(sensorProvider => {
-    sensorProvider.setGetSensorShouldFail(sensorType.name, true);
+    sensorProvider.getSensorTypeSettings(sensorType.name).unavailable = true;
     let sensorObject = new sensorType;
     sensorObject.start();
     return new Promise((resolve, reject) => {
@@ -46,7 +46,7 @@
   }, `${sensorType.name}: Test that onerror is sent when sensor is not supported.`);
 
   sensor_test(sensorProvider => {
-    sensorProvider.setPermissionsDenied(sensorType.name, true);
+    sensorProvider.getSensorTypeSettings(sensorType.name).shouldDenyRequests = true;
     let sensorObject = new sensorType;
     sensorObject.start();
     return new Promise((resolve, reject) => {
diff --git a/third_party/jacoco/BUILD.gn b/third_party/jacoco/BUILD.gn
index 9ce40ff..7ffec01 100644
--- a/third_party/jacoco/BUILD.gn
+++ b/third_party/jacoco/BUILD.gn
@@ -21,6 +21,7 @@
   include_java_resources = true
   supports_android = true
   jar_path = "lib/jacocoagent.jar"
+  proguard_configs = [ "jacoco_instrument.flags" ]
 }
 
 java_prebuilt("jacocoant_java") {
diff --git a/third_party/jacoco/OWNERS b/third_party/jacoco/OWNERS
index fb9288c..8e85536 100644
--- a/third_party/jacoco/OWNERS
+++ b/third_party/jacoco/OWNERS
@@ -1,4 +1,5 @@
 agrieve@chromium.org
-bjoyce@chromium.org
 aluo@chromium.org
+bjoyce@chromium.org
+yliuyliu@google.com
 yzjr@chromium.org
diff --git a/third_party/jacoco/README.chromium b/third_party/jacoco/README.chromium
index eb1da97..18ea162 100644
--- a/third_party/jacoco/README.chromium
+++ b/third_party/jacoco/README.chromium
@@ -1,4 +1,4 @@
-Name: Jacoco
+Name: JaCoCo
 URL: http://central.maven.org/maven2/org/jacoco/jacoco/0.8.3/
 Version: 8.3.2
 License: EPL 1.0
@@ -7,4 +7,4 @@
 License Android Compatible: no
 
 Description:
-Jacoco is a java code coverage tool.
+JaCoCo is a Java code coverage tool.
diff --git a/third_party/jacoco/jacoco_instrument.flags b/third_party/jacoco/jacoco_instrument.flags
new file mode 100644
index 0000000..ceab228
--- /dev/null
+++ b/third_party/jacoco/jacoco_instrument.flags
@@ -0,0 +1,3 @@
+# This package is only used when Java coverage is enabled.
+# JaCoCo libraries contain all dependencies so we can ignore warning here.
+-dontwarn java.lang.instrument.**
diff --git a/tools/gritsettings/resource_ids b/tools/gritsettings/resource_ids
index c098073..def08e61 100644
--- a/tools/gritsettings/resource_ids
+++ b/tools/gritsettings/resource_ids
@@ -158,7 +158,7 @@
   "chrome/browser/resources/webapks/webapks_ui_resources.grd": {
     "includes": [13910],
   },
-  "chrome/browser/resources/welcome/welcome_resources.grd": {
+  "chrome/browser/resources/welcome/onboarding_welcome_resources.grd": {
     "includes": [13920],
     "structures": [13970],
   },
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml
index 72938f4..cc6d991a 100644
--- a/tools/metrics/actions/actions.xml
+++ b/tools/metrics/actions/actions.xml
@@ -1671,6 +1671,15 @@
   </description>
 </action>
 
+<action name="Android.DirectAction.List">
+  <owner>szermatt@chromium.org</owner>
+  <owner>autofill_assistant@google.com</owner>
+  <description>
+    Call to Activity.onListDirectActions made by the system on behalf of the
+    assist app. Available starting with Android Q.
+  </description>
+</action>
+
 <action name="Android.Download.InfoBar.Accelerated">
   <owner>shaktisahu@chromium.org</owner>
   <description>
@@ -21508,6 +21517,11 @@
   <description>Please enter the description of this user action.</description>
 </action>
 
+<action name="Test_Action">
+  <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
+  <description>Please enter the description of the metric.</description>
+</action>
+
 <action name="TextToSpeech.Pause">
   <owner>dmazzoni@chromium.org</owner>
   <description>Synthesized speech is paused.</description>
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index d76cfb8..450e954 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -4985,6 +4985,7 @@
   <int value="216" label="RFH_NO_MATCHING_NAVIGATION_REQUEST_ON_COMMIT"/>
   <int value="217" label="AUTH_INVALID_ICON_URL"/>
   <int value="218" label="MDDH_INVALID_STREAM_SELECTION_INFO"/>
+  <int value="219" label="REGISTER_PROTOCOL_HANDLER_INVALID_URL"/>
 </enum>
 
 <enum name="BadMessageReasonExtensions">
@@ -13459,6 +13460,22 @@
   <int value="2" label="Migration resumed"/>
 </enum>
 
+<enum name="DirectActionId">
+  <int value="0" label="Unknown action"/>
+  <int value="1" label="A direct action not on this enum"/>
+  <int value="2" label="go_back"/>
+  <int value="3" label="reload"/>
+  <int value="4" label="go_forward"/>
+  <int value="5" label="bookmark_this_page"/>
+  <int value="6" label="downloads"/>
+  <int value="7" label="preferences"/>
+  <int value="8" label="open_history"/>
+  <int value="9" label="help"/>
+  <int value="10" label="new_tab"/>
+  <int value="11" label="close_tab"/>
+  <int value="12" label="close_all_tabs"/>
+</enum>
+
 <enum name="DirectCompositionVideoPresentationMode">
   <int value="0" label="Zero copy decode swap chain"/>
   <int value="1" label="Upload and video processor blit"/>
@@ -20233,6 +20250,7 @@
   <int value="1363" label="ACTION_ENABLE"/>
   <int value="1364" label="ACTION_DISABLE"/>
   <int value="1365" label="FILEMANAGERPRIVATEINTERNAL_IMPORTCROSTINIIMAGE"/>
+  <int value="1366" label="AUTOTESTPRIVATE_GETSHELFITEMS"/>
 </enum>
 
 <enum name="ExtensionIconState">
@@ -61836,6 +61854,13 @@
   <int value="5" label="Unknown"/>
 </enum>
 
+<enum name="WebPushDeviceState">
+  <int value="0" label="Not idle, not high priority"/>
+  <int value="1" label="Not idle, high priority"/>
+  <int value="2" label="Idle, not high priority"/>
+  <int value="3" label="Idle, high priority"/>
+</enum>
+
 <enum name="WebRequest.RequestHeader">
   <int value="0" label="kNone"/>
   <int value="1" label="kOther"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 156079b..760178d 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -1992,6 +1992,17 @@
   </summary>
 </histogram>
 
+<histogram name="Android.DirectAction.Perform" enum="DirectActionId"
+    expires_after="M78">
+  <owner>szermatt@chromium.org</owner>
+  <owner>autofill_assistant@google.com</owner>
+  <summary>
+    Counts calls to Activity.onPerformDirectAction made by the system on behalf
+    of the assist app and which action was performed, if any. Available starting
+    with Android Q.
+  </summary>
+</histogram>
+
 <histogram name="Android.Download.InfoBar.CloseButtonClicked"
     enum="DownloadInfoBarState" expires_after="M85">
   <owner>shaktisahu@chromium.org</owner>
@@ -6459,9 +6470,10 @@
 </histogram>
 
 <histogram name="Ash.Display.PrimaryDisplayZoomAtStartup" units="%"
-    expires_after="M79">
+    expires_after="2019-12-31">
   <owner>jamescook@chromium.org</owner>
   <owner>jessejames@chromium.org</owner>
+  <owner>cros-system-services@google.com</owner>
   <summary>
     The display zoom setting for the primary display, recorded on startup.
   </summary>
@@ -46466,6 +46478,17 @@
   </summary>
 </histogram>
 
+<histogram name="GCM.WebPushReceived.DeviceState" enum="WebPushDeviceState"
+    expires_after="M88">
+  <owner>knollr@chromium.org</owner>
+  <owner>peter@chromium.org</owner>
+  <summary>
+    Device state when receiving a web push message. Indicates if the message was
+    sent with a high priority and if the device was in idle mode. Recorded when
+    a web push message got received.
+  </summary>
+</histogram>
+
 <histogram name="GCMInvalidations.IncomingMessageStatus"
     enum="GCMInvalidationsIncomingMessageStatus" expires_after="M76">
   <owner>pavely@chromium.org</owner>
@@ -55606,9 +55629,10 @@
   </summary>
 </histogram>
 
-<histogram name="Login.DefaultPageZoom" units="%" expires_after="M79">
+<histogram name="Login.DefaultPageZoom" units="%" expires_after="2019-12-31">
   <owner>jamescook@chromium.org</owner>
   <owner>jessejames@chromium.org</owner>
+  <owner>cros-system-services@google.com</owner>
   <summary>The user's default page zoom setting, recorded on login.</summary>
 </histogram>
 
@@ -97076,7 +97100,7 @@
 </histogram>
 
 <histogram name="PasswordManager.PrefilledUsernameFillOutcome"
-    enum="PrefilledUsernameFillOutcome" expires_after="M78">
+    enum="PrefilledUsernameFillOutcome" expires_after="M82">
   <owner>ioanap@chromium.org</owner>
   <summary>
     Records successful fills of prefilled username values known as placeholders
@@ -114439,6 +114463,9 @@
 
 <histogram name="SafeBrowsing.ThreatReport.DomIsAmbiguous" enum="Boolean"
     expires_after="M77">
+  <obsolete>
+    Removed in M78 due to lack of use and utility. See crbug.com/975258
+  </obsolete>
   <owner>lpz@chromium.org</owner>
   <summary>
     A threat report contains a DOM hierarchy that is ambiguous. This indicates
@@ -114449,6 +114476,9 @@
 
 <histogram name="SafeBrowsing.ThreatReport.MaxNodesExceededInFrame"
     enum="BooleanExceeded" expires_after="M77">
+  <obsolete>
+    Removed in M78 due to lack of use and utility. See crbug.com/975258
+  </obsolete>
   <owner>lpz@chromium.org</owner>
   <summary>
     Whether the threat report generated for a subframe of a page hit the maximum
diff --git a/ui/file_manager/file_manager/background/js/volume_manager_impl.js b/ui/file_manager/file_manager/background/js/volume_manager_impl.js
index 8cb60e5..52e76153 100644
--- a/ui/file_manager/file_manager/background/js/volume_manager_impl.js
+++ b/ui/file_manager/file_manager/background/js/volume_manager_impl.js
@@ -161,67 +161,70 @@
   async onMountCompleted_(event) {
     const unlock = await this.mutex_.lock();
     try {
-      switch (event.eventType) {
-        case 'mount':
-          var requestKey = this.makeRequestKey_(
-              'mount', event.volumeMetadata.sourcePath || '');
+      const {eventType, status, volumeMetadata} = event;
+      const {sourcePath = '', volumeId} = volumeMetadata;
 
-          if (event.status === 'success' ||
-              event.status ===
-                  VolumeManagerCommon.VolumeError.UNKNOWN_FILESYSTEM ||
-              event.status ===
-                  VolumeManagerCommon.VolumeError.UNSUPPORTED_FILESYSTEM) {
-            const volumeInfo =
-                await this.addVolumeMetadata_(event.volumeMetadata);
-            this.finishRequest_(requestKey, event.status, volumeInfo);
-            console.warn(`Mounted '${event.volumeMetadata.sourcePath}' as '${
-                event.volumeMetadata.volumeId}'`);
-            break;
+      switch (eventType) {
+        case 'mount': {
+          const requestKey = this.makeRequestKey_('mount', sourcePath);
+
+          switch (status) {
+            case 'success':
+            case VolumeManagerCommon.VolumeError.UNKNOWN_FILESYSTEM:
+            case VolumeManagerCommon.VolumeError.UNSUPPORTED_FILESYSTEM: {
+              console.warn(`Mounted '${sourcePath}' as '${volumeId}'`);
+              const volumeInfo = await this.addVolumeMetadata_(volumeMetadata);
+              this.finishRequest_(requestKey, status, volumeInfo);
+              return;
+            }
+
+            case VolumeManagerCommon.VolumeError.ALREADY_MOUNTED: {
+              console.warn(`'Cannot mount ${sourcePath}': Already mounted as '${
+                  volumeId}'`);
+              const navigationEvent =
+                  new Event(VolumeManagerCommon.VOLUME_ALREADY_MOUNTED);
+              navigationEvent.volumeId = volumeId;
+              this.dispatchEvent(navigationEvent);
+              this.finishRequest_(requestKey, status);
+              return;
+            }
+
+            default:
+              console.error(`Cannot mount '${sourcePath}': ${status}`);
+              this.finishRequest_(requestKey, status);
+              return;
           }
+        }
 
-          if (event.status ===
-              VolumeManagerCommon.VolumeError.ALREADY_MOUNTED) {
-            const navigationEvent =
-                new Event(VolumeManagerCommon.VOLUME_ALREADY_MOUNTED);
-            navigationEvent.volumeId = event.volumeMetadata.volumeId;
-            this.dispatchEvent(navigationEvent);
-            this.finishRequest_(requestKey, event.status);
-            console.error(`'Cannot mount ${
-                event.volumeMetadata.sourcePath}': Already mounted as '${
-                event.volumeMetadata.volumeId}'`);
-            break;
-          }
-
-          console.error(`Cannot mount '${event.volumeMetadata.sourcePath}': ${
-              event.status}`);
-          this.finishRequest_(requestKey, event.status);
-          break;
-
-        case 'unmount':
-          const volumeId = event.volumeMetadata.volumeId;
-          const status = event.status;
-          var requestKey = this.makeRequestKey_('unmount', volumeId);
-          const requested = requestKey in this.requests_;
+        case 'unmount': {
+          const requestKey = this.makeRequestKey_('unmount', volumeId);
           const volumeInfoIndex = this.volumeInfoList.findIndex(volumeId);
           const volumeInfo = volumeInfoIndex !== -1 ?
               this.volumeInfoList.item(volumeInfoIndex) :
               null;
 
-          if (event.status === 'success' && !requested && volumeInfo) {
-            console.warn(`Unmounted '${volumeId}' without request`);
-            this.dispatchEvent(
-                new CustomEvent('externally-unmounted', {detail: volumeInfo}));
-          }
+          switch (status) {
+            case 'success': {
+              const requested = requestKey in this.requests_;
+              if (!requested && volumeInfo) {
+                console.warn(`Unmounted '${volumeId}' without request`);
+                this.dispatchEvent(new CustomEvent(
+                    'externally-unmounted', {detail: volumeInfo}));
+              } else {
+                console.warn(`Unmounted '${volumeId}'`);
+              }
 
-          this.finishRequest_(requestKey, status);
-          if (event.status === 'success') {
-            this.volumeInfoList.remove(event.volumeMetadata.volumeId);
-            console.warn(`Unmounted '${volumeId}'`);
-          } else {
-            console.error(`Cannot unmount '${volumeId}': ${event.status}`);
-          }
+              this.volumeInfoList.remove(volumeId);
+              this.finishRequest_(requestKey, status);
+              return;
+            }
 
-          break;
+            default:
+              console.error(`Cannot unmount '${volumeId}': ${status}`);
+              this.finishRequest_(requestKey, status);
+              return;
+          }
+        }
       }
     } finally {
       unlock();
@@ -252,10 +255,10 @@
   }
 
   /** @override */
-  async unmount(volumeInfo) {
-    console.warn(`Unmounting '${volumeInfo.volumeId}'`);
-    chrome.fileManagerPrivate.removeMount(volumeInfo.volumeId);
-    const key = this.makeRequestKey_('unmount', volumeInfo.volumeId);
+  async unmount({volumeId}) {
+    console.warn(`Unmounting '${volumeId}'`);
+    chrome.fileManagerPrivate.removeMount(volumeId);
+    const key = this.makeRequestKey_('unmount', volumeId);
     await this.startRequest_(key);
   }
 
diff --git a/ui/file_manager/file_manager/foreground/elements/xf_display_panel.js b/ui/file_manager/file_manager/foreground/elements/xf_display_panel.js
index 57b1afb..3d17381 100644
--- a/ui/file_manager/file_manager/foreground/elements/xf_display_panel.js
+++ b/ui/file_manager/file_manager/foreground/elements/xf_display_panel.js
@@ -107,12 +107,12 @@
                 }
                 75% {
                   max-height: calc(192px + 28px);
-                  max-width: 400px;
+                  width: 400px;
                   opacity: 0;
                 }
                 100% {
                   max-height: calc(192px + 28px);
-                  max-width: 400px;
+                  width: 400px;
                   opacity: 1;
                 }
               }
@@ -136,6 +136,7 @@
               }
               .expanded {
                 animation: setcollapse 200ms forwards;
+                width: 400px;
               }
               .collapsed {
                 animation: setexpand 200ms forwards;
@@ -187,9 +188,14 @@
     const summaryPanel = panel.summary_.querySelector('xf-panel-item');
     const expandButton =
         summaryPanel.shadowRoot.querySelector('#primary-action');
+    // TODO(crbug.com/989322) i18n for this string.
+    const fbWindow = ' Files feedback panels';
     if (panel.collapsed_) {
       panel.collapsed_ = false;
       expandButton.setAttribute('data-category', 'collapse');
+      // TODO(crbug.com/989322) create a i18n{COLLAPSE_LABEL} to replace this..
+      expandButton.setAttribute('aria-label', '$i18n{CLOSE_LABEL}' + fbWindow);
+      expandButton.setAttribute('aria-expanded', 'true');
       panel.panels_.hidden = false;
       panel.separator_.hidden = false;
       panel.panels_.listener_ = panel.panelExpandFinished;
@@ -198,6 +204,8 @@
     } else {
       panel.collapsed_ = true;
       expandButton.setAttribute('data-category', 'expand');
+      expandButton.setAttribute('aria-label', '$i18n{EXPAND_LABEL}' + fbWindow);
+      expandButton.setAttribute('aria-expanded', 'false');
       panel.separator_.hidden = true;
       panel.panels_.listener_ = panel.panelCollapseFinished;
       panel.panels_.addEventListener(
diff --git a/ui/file_manager/file_manager/foreground/elements/xf_panel_item.js b/ui/file_manager/file_manager/foreground/elements/xf_panel_item.js
index e747d9e..e201df9 100644
--- a/ui/file_manager/file_manager/foreground/elements/xf_panel_item.js
+++ b/ui/file_manager/file_manager/foreground/elements/xf_panel_item.js
@@ -194,11 +194,14 @@
         buttonSpacer.insertAdjacentElement('afterend', secondaryButton);
         break;
       case this.panelTypeSummary:
+        // TODO(crbug.com/989322) i18n for this string.
+        const fbWindow = ' Files feedback panels';
         this.setAttribute('indicator', 'largeprogress');
         primaryButton = document.createElement('xf-button');
         primaryButton.id = 'primary-action';
         primaryButton.dataset.category = 'expand';
-        primaryButton.setAttribute('aria-label', '$i18n{EXPAND_LABEL}');
+        primaryButton.setAttribute(
+            'aria-label', '$i18n{EXPAND_LABEL}' + fbWindow);
         buttonSpacer.insertAdjacentElement('afterend', primaryButton);
         break;
       case this.panelTypeDone:
diff --git a/ui/ozone/platform/drm/host/drm_window_host.cc b/ui/ozone/platform/drm/host/drm_window_host.cc
index 6ffe44f..8a7131e0 100644
--- a/ui/ozone/platform/drm/host/drm_window_host.cc
+++ b/ui/ozone/platform/drm/host/drm_window_host.cc
@@ -126,6 +126,8 @@
   NOTIMPLEMENTED_LOG_ONCE();
 }
 
+void DrmWindowHost::SetUseNativeFrame(bool use_native_frame) {}
+
 void DrmWindowHost::SetCursor(PlatformCursor cursor) {
   cursor_->SetCursor(widget_, cursor);
 }
diff --git a/ui/ozone/platform/drm/host/drm_window_host.h b/ui/ozone/platform/drm/host/drm_window_host.h
index 62fc547b..b4374978 100644
--- a/ui/ozone/platform/drm/host/drm_window_host.h
+++ b/ui/ozone/platform/drm/host/drm_window_host.h
@@ -75,6 +75,7 @@
   PlatformWindowState GetPlatformWindowState() const override;
   void Activate() override;
   void Deactivate() override;
+  void SetUseNativeFrame(bool use_native_frame) override;
   void SetCursor(PlatformCursor cursor) override;
   void MoveCursorTo(const gfx::Point& location) override;
   void ConfineCursorToBounds(const gfx::Rect& bounds) override;
diff --git a/ui/ozone/platform/scenic/scenic_window.cc b/ui/ozone/platform/scenic/scenic_window.cc
index f1f02b9e..1963776 100644
--- a/ui/ozone/platform/scenic/scenic_window.cc
+++ b/ui/ozone/platform/scenic/scenic_window.cc
@@ -143,6 +143,8 @@
   NOTIMPLEMENTED_LOG_ONCE();
 }
 
+void ScenicWindow::SetUseNativeFrame(bool use_native_frame) {}
+
 void ScenicWindow::SetCursor(PlatformCursor cursor) {
   NOTIMPLEMENTED_LOG_ONCE();
 }
diff --git a/ui/ozone/platform/scenic/scenic_window.h b/ui/ozone/platform/scenic/scenic_window.h
index 5f547b9..9d02b0e 100644
--- a/ui/ozone/platform/scenic/scenic_window.h
+++ b/ui/ozone/platform/scenic/scenic_window.h
@@ -60,6 +60,7 @@
   PlatformWindowState GetPlatformWindowState() const override;
   void Activate() override;
   void Deactivate() override;
+  void SetUseNativeFrame(bool use_native_frame) override;
   void SetCursor(PlatformCursor cursor) override;
   void MoveCursorTo(const gfx::Point& location) override;
   void ConfineCursorToBounds(const gfx::Rect& bounds) override;
diff --git a/ui/ozone/platform/wayland/host/wayland_window.cc b/ui/ozone/platform/wayland/host/wayland_window.cc
index 568fd4e0..d0a9861 100644
--- a/ui/ozone/platform/wayland/host/wayland_window.cc
+++ b/ui/ozone/platform/wayland/host/wayland_window.cc
@@ -498,6 +498,8 @@
   NOTIMPLEMENTED_LOG_ONCE();
 }
 
+void WaylandWindow::SetUseNativeFrame(bool use_native_frame) {}
+
 void WaylandWindow::SetCursor(PlatformCursor cursor) {
   scoped_refptr<BitmapCursorOzone> bitmap =
       BitmapCursorFactoryOzone::GetBitmapCursor(cursor);
diff --git a/ui/ozone/platform/wayland/host/wayland_window.h b/ui/ozone/platform/wayland/host/wayland_window.h
index 2237968..c5f4e556 100644
--- a/ui/ozone/platform/wayland/host/wayland_window.h
+++ b/ui/ozone/platform/wayland/host/wayland_window.h
@@ -131,6 +131,7 @@
   PlatformWindowState GetPlatformWindowState() const override;
   void Activate() override;
   void Deactivate() override;
+  void SetUseNativeFrame(bool use_native_frame) override;
   void SetCursor(PlatformCursor cursor) override;
   void MoveCursorTo(const gfx::Point& location) override;
   void ConfineCursorToBounds(const gfx::Rect& bounds) override;
diff --git a/ui/ozone/platform/x11/ozone_platform_x11.cc b/ui/ozone/platform/x11/ozone_platform_x11.cc
index bc8f9b5..78bee94 100644
--- a/ui/ozone/platform/x11/ozone_platform_x11.cc
+++ b/ui/ozone/platform/x11/ozone_platform_x11.cc
@@ -41,7 +41,7 @@
 constexpr OzonePlatform::PlatformProperties kX11PlatformProperties{
     /*needs_view_token=*/false,
     /*custom_frame_pref_default=*/false,
-    /*use_system_title_bar=*/false,
+    /*use_system_title_bar=*/true,
     /*requires_mojo=*/false,
 
     // When the Ozone X11 backend is running, use a UI loop to grab Expose
diff --git a/ui/ozone/platform/x11/x11_window_ozone.cc b/ui/ozone/platform/x11/x11_window_ozone.cc
index ae01fad..cf67534 100644
--- a/ui/ozone/platform/x11/x11_window_ozone.cc
+++ b/ui/ozone/platform/x11/x11_window_ozone.cc
@@ -206,6 +206,10 @@
   x11_window_->Deactivate();
 }
 
+void X11WindowOzone::SetUseNativeFrame(bool use_native_frame) {
+  x11_window_->SetUseNativeFrame(use_native_frame);
+}
+
 void X11WindowOzone::MoveCursorTo(const gfx::Point& location) {
   x11_window_->MoveCursorTo(location);
 }
diff --git a/ui/ozone/platform/x11/x11_window_ozone.h b/ui/ozone/platform/x11/x11_window_ozone.h
index 06a1c571..671c7aa 100644
--- a/ui/ozone/platform/x11/x11_window_ozone.h
+++ b/ui/ozone/platform/x11/x11_window_ozone.h
@@ -55,6 +55,7 @@
   void Restore() override;
   void Activate() override;
   void Deactivate() override;
+  void SetUseNativeFrame(bool use_native_frame) override;
   PlatformWindowState GetPlatformWindowState() const override;
   void MoveCursorTo(const gfx::Point& location) override;
   void ConfineCursorToBounds(const gfx::Rect& bounds) override;
diff --git a/ui/platform_window/platform_window.h b/ui/platform_window/platform_window.h
index 1f56add8..f78f718 100644
--- a/ui/platform_window/platform_window.h
+++ b/ui/platform_window/platform_window.h
@@ -15,7 +15,7 @@
 namespace gfx {
 class Point;
 class Rect;
-}
+}  // namespace gfx
 
 namespace ui {
 
@@ -56,6 +56,12 @@
   virtual void Activate() = 0;
   virtual void Deactivate() = 0;
 
+  // Sets whether the window should have the standard title bar provided by the
+  // underlying windowing system.  For the main browser window, this may be
+  // changed by the user at any time via 'Show system title bar' option in the
+  // tab strip menu.
+  virtual void SetUseNativeFrame(bool use_native_frame) = 0;
+
   virtual void SetCursor(PlatformCursor cursor) = 0;
 
   // Moves the cursor to |location|. Location is in platform window coordinates.
diff --git a/ui/platform_window/stub/stub_window.cc b/ui/platform_window/stub/stub_window.cc
index 2a937869..82d28c8 100644
--- a/ui/platform_window/stub/stub_window.cc
+++ b/ui/platform_window/stub/stub_window.cc
@@ -72,6 +72,8 @@
   NOTIMPLEMENTED_LOG_ONCE();
 }
 
+void StubWindow::SetUseNativeFrame(bool use_native_frame) {}
+
 void StubWindow::SetCursor(PlatformCursor cursor) {}
 
 void StubWindow::MoveCursorTo(const gfx::Point& location) {}
diff --git a/ui/platform_window/stub/stub_window.h b/ui/platform_window/stub/stub_window.h
index 752b227..0593f4db 100644
--- a/ui/platform_window/stub/stub_window.h
+++ b/ui/platform_window/stub/stub_window.h
@@ -46,6 +46,7 @@
   PlatformWindowState GetPlatformWindowState() const override;
   void Activate() override;
   void Deactivate() override;
+  void SetUseNativeFrame(bool use_native_frame) override;
   void SetCursor(PlatformCursor cursor) override;
   void MoveCursorTo(const gfx::Point& location) override;
   void ConfineCursorToBounds(const gfx::Rect& bounds) override;
diff --git a/ui/platform_window/win/win_window.cc b/ui/platform_window/win/win_window.cc
index ae9aad9..8cd1ce8 100644
--- a/ui/platform_window/win/win_window.cc
+++ b/ui/platform_window/win/win_window.cc
@@ -133,6 +133,8 @@
   NOTIMPLEMENTED_LOG_ONCE();
 }
 
+void WinWindow::SetUseNativeFrame(bool use_native_frame) {}
+
 void WinWindow::SetCursor(PlatformCursor cursor) {
   ::SetCursor(cursor);
 }
diff --git a/ui/platform_window/win/win_window.h b/ui/platform_window/win/win_window.h
index 26a959c..1e4bd938 100644
--- a/ui/platform_window/win/win_window.h
+++ b/ui/platform_window/win/win_window.h
@@ -45,6 +45,7 @@
   PlatformWindowState GetPlatformWindowState() const override;
   void Activate() override;
   void Deactivate() override;
+  void SetUseNativeFrame(bool use_native_frame) override;
   void SetCursor(PlatformCursor cursor) override;
   void MoveCursorTo(const gfx::Point& location) override;
   void ConfineCursorToBounds(const gfx::Rect& bounds) override;
diff --git a/ui/platform_window/x11/x11_window.cc b/ui/platform_window/x11/x11_window.cc
index d63c67e..c466ef0e 100644
--- a/ui/platform_window/x11/x11_window.cc
+++ b/ui/platform_window/x11/x11_window.cc
@@ -28,6 +28,10 @@
   PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this);
 }
 
+void X11Window::SetUseNativeFrame(bool use_native_frame) {
+  NOTIMPLEMENTED_LOG_ONCE();
+}
+
 void X11Window::SetCursor(PlatformCursor cursor) {
   XDefineCursor(xdisplay(), xwindow(), cursor);
 }
diff --git a/ui/platform_window/x11/x11_window.h b/ui/platform_window/x11/x11_window.h
index 710efa6..2b91e5c 100644
--- a/ui/platform_window/x11/x11_window.h
+++ b/ui/platform_window/x11/x11_window.h
@@ -21,6 +21,7 @@
 
   // PlatformWindow:
   void PrepareForShutdown() override;
+  void SetUseNativeFrame(bool use_native_frame) override;
   void SetCursor(PlatformCursor cursor) override;
 
  private:
diff --git a/ui/views/layout/flex_layout_types.h b/ui/views/layout/flex_layout_types.h
index d74f11ad..b86c8a5 100644
--- a/ui/views/layout/flex_layout_types.h
+++ b/ui/views/layout/flex_layout_types.h
@@ -57,7 +57,7 @@
 
 // Describes a simple rule for how a child view should grow in a layout when
 // there is extra size avaialble for that view to occupy.
-enum MaximumFlexSizeRule {
+enum class MaximumFlexSizeRule {
   kPreferred,  // Don't resize above preferred size.
   kUnbounded   // Allow resize to arbitrary size.
 };
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc
index 505c5f7..c2ddb4c 100644
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc
@@ -113,6 +113,10 @@
     const Widget::InitParams& params) {
   native_widget_delegate_->OnNativeWidgetCreated();
 
+  platform_window()->SetUseNativeFrame(params.type ==
+                                           Widget::InitParams::TYPE_WINDOW &&
+                                       !params.remove_standard_frame);
+
 #if defined(OS_LINUX)
   // Setup a non_client_window_event_filter, which handles resize/move, double
   // click and other events.
@@ -422,7 +426,21 @@
   return false;
 }
 
-void DesktopWindowTreeHostPlatform::FrameTypeChanged() {}
+void DesktopWindowTreeHostPlatform::FrameTypeChanged() {
+  Widget::FrameType new_type =
+      native_widget_delegate_->AsWidget()->frame_type();
+  if (new_type == Widget::FRAME_TYPE_DEFAULT) {
+    // The default is determined by Widget::InitParams::remove_standard_frame
+    // and does not change.
+    return;
+  }
+  platform_window()->SetUseNativeFrame(new_type ==
+                                       Widget::FRAME_TYPE_FORCE_NATIVE);
+  // Replace the frame and layout the contents. Even though we don't have a
+  // swappable glass frame like on Windows, we still replace the frame because
+  // the button assets don't update otherwise.
+  native_widget_delegate_->AsWidget()->non_client_view()->UpdateFrame();
+}
 
 void DesktopWindowTreeHostPlatform::SetFullscreen(bool fullscreen) {
   if (IsFullscreen() != fullscreen)